[
  {
    "path": ".gitignore",
    "content": "*.iml\n.gradle\n/.idea\n/screenshots\n/local.properties\n.DS_Store\n/build\n/captures\nlibs/\n"
  },
  {
    "path": "LICENSE",
    "content": "                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"{}\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright 2016 jeasonlzy(廖子尧)\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n\n"
  },
  {
    "path": "README.md",
    "content": "![](http://7xss53.com1.z0.glb.clouddn.com/markdown/aqyyw.jpg)\n\n## OkGo - 3.0 震撼来袭, 一个基于okhttp的标准RESTful风格的网络框架\n\n> 工程结构全新优化  \n支持RxJava  \n支持RxJava2  \n支持自定义缓存策略  \n支持下载管理  \n支持上传管理  \n\n该库部分思想借鉴了以下项目：\n\n * [https://github.com/yanzhenjie/NoHttp](https://github.com/Y0LANDA/NoHttp) \n * [https://github.com/square/retrofit](https://github.com/square/retrofit)\n\n在此特别感谢上述作者，喜欢原作的可以去使用原项目。同时欢迎大家下载体验本项目，如果使用过程中遇到什么问题，欢迎反馈。\n\n## 友情链接\n本项目中使用的图片选择是我的另一个开源项目\n> 完全仿微信的图片选择库，自带矩形图片裁剪和圆形图片裁剪功能，有需要的可以去下载使用。  \n附上地址：[https://github.com/jeasonlzy/ImagePicker](https://github.com/jeasonlzy/ImagePicker)\n\n本项目中的九宫格控件也是我的开源项目\n> 类似QQ空间，微信朋友圈，微博主页等，展示图片的九宫格控件，自动根据图片的数量确定图片大小和控件大小，使用Adapter模式设置图片，对外提供接口回调，使用接口加载图片，支持任意的图片加载框架如：Glide、ImageLoader、xUtils3、Picasso 等，支持点击图片全屏预览大图。  \n附上地址：[https://github.com/jeasonlzy/NineGridView](https://github.com/jeasonlzy/NineGridView)\n\n## 联系方式\n * email： liaojeason@126.com\n * QQ群： 489873144 <a target=\"_blank\" href=\"//shang.qq.com/wpa/qunwpa?idkey=ba5dbb5115a165866ec77d96cb46685d1ad159ab765b796699d6763011ffe151\"><img border=\"0\" src=\"http://pub.idqqimg.com/wpa/images/group.png\" alt=\"Android 格调小窝\" title=\"Android 格调小窝\"></a>（点击图标，可以直接加入，建议使用QQ群，邮箱使用较少，可能看的不及时）\n * 如果遇到问题欢迎在群里提问，个人能力也有限，希望一起学习一起进步。\n\n## 演示\n![image](https://github.com/jeasonlzy/Screenshots/blob/master/okgo/demo13.gif)![image](https://github.com/jeasonlzy/Screenshots/blob/master/okgo/demo8.gif)![image](https://github.com/jeasonlzy/Screenshots/blob/master/okgo/demo11.gif)![image](https://github.com/jeasonlzy/Screenshots/blob/master/okgo/demo9.gif)![image](https://github.com/jeasonlzy/Screenshots/blob/master/okgo/demo10.gif)![image](https://github.com/jeasonlzy/Screenshots/blob/master/okgo/demo12.gif)\n\n## 未来版本\n### [v3.1.x]版本\n- 计划分离params参数的具体作用，分为paramsPath，paramsQuery和params，支持url路径动态替换\n- 计划支持请求优先级，方便有些重要请求优先进行\n- 计划支持自定义线程池，使用自己的线程池管理网络请求\n\n### [v3.2.x]版本\n- 计划增加扩展库OkAnno，作用是让okgo支持注解方式请求，具体写法与Retrofit相似，但是更简单方便，也更强大，方便Retrofit用户平滑过渡到OkGo\n\n### 其他功能暂时还没想出来，大家有想法的可以积极加群讨论，或者直接在issue里面提出你的想法，我会第一时间回复。\n\n## 使用\n\n[![](https://img.shields.io/badge/API-14%2B-brightgreen.svg?style=flat)](https://android-arsenal.com/api?level=14) [![](https://img.shields.io/badge/platform-android-brightgreen.svg)](https://developer.android.com/index.html) [![Codacy Badge](https://api.codacy.com/project/badge/Grade/5b244560c35c445cbb00b9500b0c5d2a)](https://www.codacy.com/app/jeasonlzy/okhttp-OkGo?utm_source=github.com&amp;utm_medium=referral&amp;utm_content=jeasonlzy/okhttp-OkGo&amp;utm_campaign=Badge_Grade)  [![](https://img.shields.io/hexpm/l/plug.svg)](https://github.com/jeasonlzy/okhttp-OkGo/blob/master/LICENSE)  [![](https://img.shields.io/badge/%E4%BD%9C%E8%80%85-jeasonlzy-orange.svg)](https://github.com/jeasonlzy)\n\n[![](https://img.shields.io/badge/OkGo-v3.0.4-brightgreen.svg)](https://github.com/jeasonlzy/okhttp-OkGo) [![](https://img.shields.io/badge/OkRx-v1.0.2-brightgreen.svg)](https://github.com/jeasonlzy/okhttp-OkGo) [![](https://img.shields.io/badge/OkRx2-v2.0.2-brightgreen.svg)](https://github.com/jeasonlzy/okhttp-OkGo) [![](https://img.shields.io/badge/OkServer-v2.0.5-brightgreen.svg)](https://github.com/jeasonlzy/okhttp-OkGo)\n\nAndroid Studio用户\n\n> 一般来说，只需要添加第一个okgo的核心包即可，其余的三个库根据自己的需要选择添加！！！\n\n```java\n//必须使用\ncompile 'com.lzy.net:okgo:3.0.4'\n\n//以下三个选择添加，okrx和okrx2不能同时使用\ncompile 'com.lzy.net:okrx:1.0.2'\ncompile 'com.lzy.net:okrx2:2.0.2'  \ncompile 'com.lzy.net:okserver:2.0.5'\n```\n\nEclipse的用户(赶紧换AS吧)，可以选择添加本项目根目录中 `/jar` 目录下的jar包:\n\n> 一般来说，至少需要okhttp、okio、okgo三个jar包，其余的三个扩展jar包根据自己的需要选择添加！！！\n\n必须使用\n> [okhttp-3.8.1.jar](https://raw.githubusercontent.com/jeasonlzy/okhttp-OkGo/master/jar/okhttp-3.8.1.jar)  \n[okio-1.13.0.jar](https://raw.githubusercontent.com/jeasonlzy/okhttp-OkGo/master/jar/okio-1.13.0.jar)   \n[okgo-3.0.4.jar](https://raw.githubusercontent.com/jeasonlzy/okhttp-OkGo/master/jar/okgo-3.0.4.jar)   \n\n以下三个选择添加，okrx和okrx2不能同时使用\n> [okrx-1.0.2.jar](https://raw.githubusercontent.com/jeasonlzy/okhttp-OkGo/master/jar/okrx-1.0.2.jar)  \n[okrx2-2.0.2.jar](https://raw.githubusercontent.com/jeasonlzy/okhttp-OkGo/master/jar/okrx2-2.0.2.jar)   \n[okserver-2.0.5.jar](https://raw.githubusercontent.com/jeasonlzy/okhttp-OkGo/master/jar/okserver-2.0.5.jar)  \n\n## 文档\n### 该项目的文档全部以Wiki的形式展示，wiki文档永远与最新版本的库保持同步，如果你发现文档的说明与你的写法不一样，那么请升级到最新版本，重要的事情说三遍\n- [点我，点我，我是3.x文档，Wiki文档首页请猛戳这里](https://github.com/jeasonlzy/okhttp-OkGo/wiki)\n- [点我，点我，我是3.x文档，Wiki文档首页请猛戳这里](https://github.com/jeasonlzy/okhttp-OkGo/wiki)\n- [点我，点我，我是3.x文档，Wiki文档首页请猛戳这里](https://github.com/jeasonlzy/okhttp-OkGo/wiki)\n\n如果你实在不愿意升级到3.x版本，[这里有2.x版本的文档，点击查看](https://github.com/jeasonlzy/okhttp-OkGo/tree/v2.1.4)，注意：老版本库的问题将不在维护，所有bug会在最新版本修复，所以建议跟随最新版本的库。\n\n[![](http://7xss53.com1.z0.glb.clouddn.com/markdown/w0ujl.jpg)](https://github.com/jeasonlzy/okhttp-OkGo/wiki)\n\n如果遇到使用问题，解决办法如下：\n1. 看上述文档中是否有相关描述\n2. 看别人提的issues是否有你的问题，这里面有很多人的提问，[点击这里看别人的提问](https://github.com/jeasonlzy/okhttp-OkGo/issues?q=is%3Aissue+is%3Aclosed)。\n3. 如果你感觉是bug，或者有疑问，也欢迎在issues里面提问，我每天都会认真解答，[点击这里提问](https://github.com/jeasonlzy/okhttp-OkGo/issues)。\n4. 还有疑问，加入联系方式中的QQ群，大家一起讨论。\n\n如果你不想编译项目，提供了apk供直接运行，方便查看效果，点击图标下载：[![](https://img.shields.io/badge/downloads-okgo__v3.0.4.apk-blue.svg)](http://7xss53.com1.z0.glb.clouddn.com/file/okgo_v3.0.4.apk)\n\n本项目Demo使用的是我自己的服务器，有时候可能不稳定，网速比较慢时请耐心等待，尴尬呀。。\n\n如果你想查看历史版本信息，请点击图标：[![](https://img.shields.io/badge/release-tags-ff69b4.svg)](https://github.com/jeasonlzy/okhttp-OkGo/releases)\n\n如果你使用遇到了问题，首先请看控制台log，如果log无法看出问题，无法确定是该库的bug还是服务端的问题，建议抓包查看网络数据，[详细的抓包方法猛戳这里](https://github.com/jeasonlzy/okhttp-OkGo/wiki#网络抓包)\n\n### 如果你觉得好，对你有过帮助，请给我一点打赏鼓励吧，一分也是爱呀！\n![](https://ws2.sinaimg.cn/large/006tNbRwly1fgidan2gc9j30jg0a2wg6.jpg)\n\n## 混淆\nokgo, okrx, okrx2, okserver 所有代码均可以混淆,但是由于底层使用的是 okhttp,它不能混淆,所以只需要添加以下混淆代码就可以了\n```java\n#okhttp\n-dontwarn okhttp3.**\n-keep class okhttp3.**{*;}\n\n#okio\n-dontwarn okio.**\n-keep class okio.**{*;}\n```\n\n当然如果你确实不需要混淆okgo的代码,可以继续添加以下代码\n```java\n#okgo\n-dontwarn com.lzy.okgo.**\n-keep class com.lzy.okgo.**{*;}\n\n#okrx\n-dontwarn com.lzy.okrx.**\n-keep class com.lzy.okrx.**{*;}\n\n#okrx2\n-dontwarn com.lzy.okrx2.**\n-keep class com.lzy.okrx2.**{*;}\n\n#okserver\n-dontwarn com.lzy.okserver.**\n-keep class com.lzy.okserver.**{*;}\n```\n\n## Licenses\n```\n Copyright 2016 jeasonlzy(廖子尧)\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n```\n\n\n\n"
  },
  {
    "path": "build.gradle",
    "content": "// Top-level build file where you can add configuration options common to all sub-projects/modules.\nbuildscript {\n    repositories {\n        jcenter()\n    }\n    dependencies {\n        classpath 'com.android.tools.build:gradle:2.3.3'\n\n        classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.7'\n        classpath 'com.github.dcendents:android-maven-gradle-plugin:1.5'\n        // NOTE: Do not place your application dependencies here; they belong\n        // in the individual module build.gradle files\n    }\n}\n\nallprojects {\n    repositories {\n        jcenter()\n        maven { url \"https://jitpack.io\" }\n    }\n}\n\ntask clean(type: Delete) {\n    delete rootProject.buildDir\n}\n\next {\n    versionCode = 29\n    versionName_okgo = '3.0.4'\n    versionName_okserver = '2.0.5'\n    versionName_okrx = '1.0.2'\n    versionName_okrx2 = '2.0.2'\n\n    libMinSdkVersion = 14\n    appMinSdkVersion = 16\n    targetSdkVersion = 25\n    compileSdkVersion = 25\n    buildToolsVersion = '25.0.2'\n    supportVersion = '25.3.1'\n}"
  },
  {
    "path": "demo/.gitignore",
    "content": "/build\n"
  },
  {
    "path": "demo/build.gradle",
    "content": "apply plugin: 'com.android.application'\n\nandroid {\n    compileSdkVersion rootProject.ext.compileSdkVersion\n    buildToolsVersion rootProject.ext.buildToolsVersion\n\n    defaultConfig {\n        applicationId \"com.lzy.demo\"\n        minSdkVersion rootProject.ext.appMinSdkVersion\n        targetSdkVersion rootProject.ext.targetSdkVersion\n        versionCode rootProject.ext.versionCode\n        versionName rootProject.ext.versionName_okgo\n    }\n\n    signingConfigs {\n        appkey {\n            keyAlias 'OkGo'\n            keyPassword '111111'\n            storeFile file('../appkey.jks')\n            storePassword '111111'\n        }\n    }\n    buildTypes {\n        release {\n            minifyEnabled true\n            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'\n            debuggable false\n            signingConfig signingConfigs.appkey\n        }\n        debug {\n            minifyEnabled false\n            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'\n            debuggable true\n            signingConfig signingConfigs.appkey\n        }\n    }\n    productFlavors {\n        miui {\n            proguardFile './proguard-rules.pro'\n            signingConfig signingConfigs.appkey\n        }\n        qihu360 {\n            proguardFile './proguard-rules.pro'\n            signingConfig signingConfigs.appkey\n        }\n    }\n    lintOptions {\n        abortOnError false\n    }\n    packagingOptions {\n        exclude 'META-INF/NOTICE'\n        exclude 'META-INF/LICENSE'\n        exclude 'META-INF/notice'\n        exclude 'META-INF/notice.txt'\n        exclude 'META-INF/license'\n        exclude 'META-INF/license.txt'\n        exclude 'META-INF/rxjava.properties'\n    }\n}\n\ntask makeApk {\n    doLast {\n        def versionName = rootProject.ext.versionName_okgo\n        def appName = \"okgo_v${versionName}.apk\"\n        copy {\n            from \"./build/outputs/apk/demo-miui-debug.apk\"\n            into \"../\"\n            rename {\n                appName\n            }\n        }\n    }\n}\n\ndependencies {\n    compile fileTree(include: ['*.jar'], dir: 'libs')\n    compile \"com.android.support:appcompat-v7:$supportVersion\"\n    compile \"com.android.support:design:$supportVersion\"\n    compile \"com.android.support:recyclerview-v7:$supportVersion\"\n    compile \"com.android.support:cardview-v7:$supportVersion\"\n\n    compile 'com.github.CymChad:BaseRecyclerViewAdapterHelper:v2.0.7'\n    compile 'com.github.bumptech.glide:glide:3.7.0'\n    compile 'com.squareup.picasso:picasso:2.5.2'\n    compile 'com.jakewharton:butterknife:7.0.1'\n    compile 'com.google.code.gson:gson:2.8.0'\n    compile 'io.reactivex.rxjava2:rxandroid:2.0.1'\n    compile 'com.readystatesoftware.chuck:library:1.0.4'\n\n    compile project(':okgo')\n    compile project(':okrx')\n    compile project(':okrx2')\n    compile project(':okserver')\n//    compile 'com.lzy.net:okgo:3.0.4'\n//    compile 'com.lzy.net:okrx:1.0.2'\n//    compile 'com.lzy.net:okrx2:2.0.2'\n//    compile 'com.lzy.net:okserver:2.0.5'\n    compile 'com.lzy.widget:ninegridview:0.2.1'\n    compile 'com.lzy.widget:imagepicker:0.3.2'\n    compile 'com.lzy.widget:view-core:0.2.1'\n}"
  },
  {
    "path": "demo/proguard-rules.pro",
    "content": "# Add project specific ProGuard rules here.\n# By default, the flags in this file are appended to flags specified\n# in E:\\Android\\SDK/tools/proguard/proguard-android.txt\n# You can edit the include path and order by changing the proguardFiles\n# directive in build.gradle.\n#\n# For more details, see\n#   http://developer.android.com/guide/developing/tools/proguard.html\n\n# Add any project specific keep options here:\n\n# If your project uses WebView with JS, uncomment the following\n# and specify the fully qualified class name to the JavaScript interface\n# class:\n#-keepclassmembers class fqcn.of.javascript.interface.for.webview {\n#   public *;\n#}\n\n#---------------------------------1.实体类---------------------------------\n\n-keep class com.lzy.okhttpdemo.Bean.** { *; }\n\n#-------------------------------------------------------------------------\n\n#---------------------------------2.第三方包-------------------------------\n#okgo\n#-dontwarn com.lzy.okgo.**\n#-keep class com.lzy.okgo.**{*;}\n\n#okrx\n#-dontwarn com.lzy.okrx.**\n#-keep class com.lzy.okrx.**{*;}\n\n#okserver\n#-dontwarn com.lzy.okserver.**\n#-keep class com.lzy.okserver.**{*;}\n\n#okhttp\n-dontwarn okhttp3.**\n-keep class okhttp3.**{*;}\n\n-keepattributes SourceFile,LineNumberTable\n-keep class com.parse.*{ *; }\n-dontwarn com.parse.**\n-dontwarn com.squareup.picasso.**\n-keepclasseswithmembernames class * {\n    native <methods>;\n}\n\n#okio\n-dontwarn okio.**\n-keep class okio.**{*;}\n\n#rxjava\n-dontwarn sun.misc.**\n-keepclassmembers class rx.internal.util.unsafe.*ArrayQueue*Field* {\n long producerIndex;\n long consumerIndex;\n}\n-keepclassmembers class rx.internal.util.unsafe.BaseLinkedQueueProducerNodeRef {\n rx.internal.util.atomic.LinkedQueueNode producerNode;\n}\n-keepclassmembers class rx.internal.util.unsafe.BaseLinkedQueueConsumerNodeRef {\n rx.internal.util.atomic.LinkedQueueNode consumerNode;\n}\n\n#imagepicker\n-dontwarn com.lzy.imagepicker.**\n-keep class com.lzy.imagepicker.**{*;}\n\n#imagepicker\n-dontwarn com.lzy.widget.**\n-keep class com.lzy.widget.**{*;}\n\n#butterknife\n-keep class butterknife.** { *; }\n-dontwarn butterknife.internal.**\n-keep class **$$ViewBinder { *; }\n\n-keepclasseswithmembernames class * {\n    @butterknife.* <fields>;\n}\n\n-keepclasseswithmembernames class * {\n    @butterknife.* <methods>;\n}\n\n#gson\n-keep class sun.misc.Unsafe { *; }\n-keep class com.google.gson.stream.**{ *; }\n-keep class com.google.gson.examples.android.model.**{ *; }\n-keep class com.google.gson.**{ *;}\n\n#eventBus\n-keepattributes *Annotation*\n-keepclassmembers class ** {\n    @org.greenrobot.eventbus.Subscribe <methods>;\n}\n-keep enum org.greenrobot.eventbus.ThreadMode { *; }\n-keepclassmembers class * extends org.greenrobot.eventbus.util.ThrowableFailureEvent {\n    <init>(java.lang.Throwable);\n}\n-keepclassmembers class ** {\n    public void onEvent*(**);\n}\n\n#glide\n-keep public class * implements com.bumptech.glide.module.GlideModule\n-keep public enum com.bumptech.glide.load.resource.bitmap.ImageHeaderParser$** {\n  **[] $VALUES;\n  public *;\n}\n\n#log4j\n#-libraryjars log4j-1.2.17.jar\n-dontwarn org.apache.log4j.**\n-keep class  org.apache.log4j.** { *;}\n\n#------------------------------------------------------------------------\n\n#---------------------------------3.与js互相调用的类------------------------\n\n#-keepclasseswithmembers class com.demo.login.bean.ui.MainActivity$JSInterface {\n#      <methods>;\n#}\n\n#------------------------------------------------------------------------\n\n#---------------------------------4.反射相关的类和方法-----------------------\n\n\n#------------------------------------------------------------------------\n\n#---------------------------------基本指令区-------------------------------\n#代码混淆的压缩比例，值在0-7之间\n-optimizationpasses 5\n#混淆后类名都为小写\n-dontusemixedcaseclassnames\n#指定不去忽略非公共的库的类\n-dontskipnonpubliclibraryclasses\n#指定不去忽略非公共的库的类的成员\n-dontskipnonpubliclibraryclassmembers\n#不做预校验的操作\n-dontpreverify\n#生成原类名和混淆后的类名的映射文件\n-verbose\n-printmapping proguardMapping.txt\n#指定混淆是采用的算法\n-optimizations !code/simplification/cast,!field/*,!class/merging/*\n#不混淆Annotation\n-keepattributes *Annotation*,InnerClasses\n#不混淆泛型\n-keepattributes Signature\n#抛出异常时保留代码行号\n-keepattributes SourceFile,LineNumberTable\n#------------------------------------------------------------------------\n\n#-keep class XXXX   保留类名不变，也就是类名不混淆，而类中的成员名不保证。当然也可以是继承XXX类的所有类名不混淆\n#-keepclasseswithmembers class XXXX 保留类名和成员名,当然也可以是类中特定方法\n\n#---------------------------------默认保留区-------------------------------\n-keep public class * extends android.app.Activity\n-keep public class * extends android.app.Application\n-keep public class * extends android.app.Service\n-keep public class * extends android.content.BroadcastReceiver\n-keep public class * extends android.content.ContentProvider\n-keep public class * extends android.app.backup.BackupAgentHelper\n-keep public class * extends android.preference.Preference\n-keep public class * extends android.view.View\n-keep public class com.android.vending.licensing.ILicensingService\n-keep public class * extends android.support.**\n-keep public class * extends android.app.Fragment\n-dontwarn android.support.**\n-keep class android.support.** {*;}\n\n#自定义控件不要混淆\n-keep public class * extends android.view.View {*;}\n#adapter不能混淆\n-keep public class * extends android.widget.BaseAdapter {*;}\n#CusorAdapter不混淆\n-keep public class * extends android.widget.CusorAdapter{*;}\n\n-keepclasseswithmembernames class * {\n    native <methods>;\n}\n-keepclassmembers class * extends android.app.Activity{\n    public void *(android.view.View);\n}\n-keepclassmembers enum * {\n    public static **[] values();\n    public static ** valueOf(java.lang.String);\n}\n-keep public class * extends android.view.View{\n    *** get*();\n    void set*(***);\n    public <init>(android.content.Context);\n    public <init>(android.content.Context, android.util.AttributeSet);\n    public <init>(android.content.Context, android.util.AttributeSet, int);\n}\n-keepclasseswithmembers class * {\n    public <init>(android.content.Context, android.util.AttributeSet);\n    public <init>(android.content.Context, android.util.AttributeSet, int);\n}\n-keep class * implements android.os.Parcelable {\n  public static final android.os.Parcelable$Creator *;\n}\n-keep class * extends java.util.ListResourceBundle {\n    protected Object[][] getContents();\n}\n-keepnames class * implements java.io.Serializable\n-keepclassmembers class * implements java.io.Serializable {*;}\n\n-keep class **.R$* {*;}\n-keepclassmembers class * {\n    void *(**On*Event);\n}\n#----------------------------------------------------------------------------\n\n#---------------------------------webview------------------------------------\n-keepclassmembers class fqcn.of.javascript.interface.for.Webview {\n   public *;\n}\n-keepclassmembers class * extends android.webkit.WebViewClient {\n    public void *(android.webkit.WebView, java.lang.String, android.graphics.Bitmap);\n    public boolean *(android.webkit.WebView, java.lang.String);\n}\n-keepclassmembers class * extends android.webkit.WebViewClient {\n    public void *(android.webkit.WebView, jav.lang.String);\n}\n#----------------------------------------------------------------------------"
  },
  {
    "path": "demo/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n    Copyright 2016 jeasonlzy(廖子尧)\n    \n    Licensed under the Apache License, Version 2.0 (the \"License\");\n    you may not use this file except in compliance with the License.\n    You may obtain a copy of the License at\n    \n       http://www.apache.org/licenses/LICENSE-2.0\n       \n    Unless required by applicable law or agreed to in writing, software\n    distributed under the License is distributed on an \"AS IS\" BASIS,\n    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n    See the License for the specific language governing permissions and\n    limitations under the License.\n-->\n<manifest package=\"com.lzy.demo\"\n          xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <uses-permission android:name=\"android.permission.INTERNET\"/>\n    <uses-permission android:name=\"android.permission.READ_EXTERNAL_STORAGE\"/>\n    <uses-permission android:name=\"android.permission.WRITE_EXTERNAL_STORAGE\"/>\n    <uses-permission android:name=\"android.permission.MOUNT_UNMOUNT_FILESYSTEMS\"/>\n\n    <application\n        android:name=\".GApp\"\n        android:allowBackup=\"true\"\n        android:icon=\"@mipmap/ic_launcher\"\n        android:label=\"@string/app_name\"\n        android:supportsRtl=\"true\"\n        android:theme=\"@style/AppTheme\">\n        <activity\n            android:name=\".MainActivity\"\n            android:theme=\"@style/AppTheme.NoActionBar\">\n            <intent-filter>\n                <action android:name=\"android.intent.action.MAIN\"/>\n\n                <category android:name=\"android.intent.category.LAUNCHER\"/>\n            </intent-filter>\n        </activity>\n        <activity android:name=\".okgo.MethodActivity\"/>\n        <activity android:name=\".okgo.JsonActivity\"/>\n        <activity android:name=\".okgo.BitmapRequestActivity\"/>\n        <activity android:name=\".okgo.UpActivity\"/>\n        <activity android:name=\".okgo.CookieActivity\"/>\n        <activity android:name=\".okgo.FormUploadActivity\"/>\n        <activity android:name=\".okgo.SimpleDownloadActivity\"/>\n        <activity android:name=\".okgo.CacheActivity\"/>\n        <activity android:name=\".okgo.HttpsActivity\"/>\n        <activity android:name=\".okgo.SyncActivity\"/>\n        <activity android:name=\".okgo.RedirectActivity\"/>\n        <activity android:name=\".okgo.TestActivity\"/>\n        <activity\n            android:name=\".supercache.SuperCacheActivity\"\n            android:theme=\"@style/AppTheme.NoActionBar\"/>\n        <activity\n            android:name=\".WebActivity\"\n            android:theme=\"@style/AppTheme.NoActionBar\"/>\n        <activity\n            android:name=\".okgo.CommonActivity\"\n            android:theme=\"@style/AppTheme.NoActionBar\"/>\n        <activity\n            android:name=\".okdownload.DownloadAllActivity\"\n            android:theme=\"@style/AppTheme.NoActionBar\"/>\n        <activity\n            android:name=\".okdownload.DownloadingActivity\"\n            android:theme=\"@style/AppTheme.NoActionBar\"/>\n        <activity\n            android:name=\".okdownload.DownloadFinishActivity\"\n            android:theme=\"@style/AppTheme.NoActionBar\"/>\n        <activity\n            android:name=\".okdownload.DesActivity\"\n            android:theme=\"@style/AppTheme.NoActionBar\"/>\n        <activity\n            android:name=\".okdownload.DownloadListActivity\"\n            android:theme=\"@style/AppTheme.NoActionBar\"/>\n        <activity\n            android:name=\".okupload.UploadListActivity\"\n            android:theme=\"@style/AppTheme.NoActionBar\"/>\n        <activity\n            android:name=\".okupload.UploadAllActivity\"\n            android:theme=\"@style/AppTheme.NoActionBar\"/>\n        <activity\n            android:name=\".okupload.UploadFinishActivity\"\n            android:theme=\"@style/AppTheme.NoActionBar\"/>\n        <activity\n            android:name=\".okupload.UploadingActivity\"\n            android:theme=\"@style/AppTheme.NoActionBar\"/>\n        <!-- Rx相关 -->\n        <activity android:name=\".okrx2.RxCommonActivity\"/>\n        <activity android:name=\".okrx2.RxCacheActivity\"/>\n        <activity android:name=\".okrx2.RxRetrofitActivity\"/>\n        <activity android:name=\".okrx2.RxBitmapActivity\"/>\n        <activity android:name=\".okrx2.RxFileDownloadActivity\"/>\n        <activity android:name=\".okrx2.RxFormUploadActivity\"/>\n    </application>\n\n</manifest>\n"
  },
  {
    "path": "demo/src/main/java/com/lzy/demo/GApp.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.demo;\n\nimport android.app.Application;\n\nimport com.lzy.okgo.OkGo;\nimport com.lzy.okgo.cache.CacheEntity;\nimport com.lzy.okgo.cache.CacheMode;\nimport com.lzy.okgo.cookie.CookieJarImpl;\nimport com.lzy.okgo.cookie.store.DBCookieStore;\nimport com.lzy.okgo.https.HttpsUtils;\nimport com.lzy.okgo.interceptor.HttpLoggingInterceptor;\nimport com.lzy.okgo.model.HttpHeaders;\nimport com.lzy.okgo.model.HttpParams;\n\nimport java.security.cert.CertificateException;\nimport java.security.cert.X509Certificate;\nimport java.util.concurrent.TimeUnit;\nimport java.util.logging.Level;\n\nimport javax.net.ssl.HostnameVerifier;\nimport javax.net.ssl.SSLSession;\nimport javax.net.ssl.X509TrustManager;\n\nimport okhttp3.OkHttpClient;\n\n/**\n * ================================================\n * 作    者：廖子尧   github 地址  https://github.com/jeasonlzy/\n * 版    本：1.0\n * 创建日期：2015/9/23\n * 描    述：\n * 修订历史：\n * ================================================\n */\npublic class GApp extends Application {\n\n    @Override\n    public void onCreate() {\n        super.onCreate();\n\n//        System.setProperty(\"http.proxyHost\", \"192.168.1.104\");   //个人测试网络时用的，删掉即可\n//        System.setProperty(\"http.proxyPort\", \"8888\");\n\n        initOkGo();\n    }\n\n    private void initOkGo() {\n        //---------这里给出的是示例代码,告诉你可以这么传,实际使用的时候,根据需要传,不需要就不传-------------//\n        HttpHeaders headers = new HttpHeaders();\n        headers.put(\"commonHeaderKey1\", \"commonHeaderValue1\");    //header不支持中文，不允许有特殊字符\n        headers.put(\"commonHeaderKey2\", \"commonHeaderValue2\");\n        HttpParams params = new HttpParams();\n        params.put(\"commonParamsKey1\", \"commonParamsValue1\");     //param支持中文,直接传,不要自己编码\n        params.put(\"commonParamsKey2\", \"这里支持中文参数\");\n        //----------------------------------------------------------------------------------------//\n\n        OkHttpClient.Builder builder = new OkHttpClient.Builder();\n        //log相关\n        HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor(\"OkGo\");\n        loggingInterceptor.setPrintLevel(HttpLoggingInterceptor.Level.BODY);        //log打印级别，决定了log显示的详细程度\n        loggingInterceptor.setColorLevel(Level.INFO);                               //log颜色级别，决定了log在控制台显示的颜色\n        builder.addInterceptor(loggingInterceptor);                                 //添加OkGo默认debug日志\n        //第三方的开源库，使用通知显示当前请求的log，不过在做文件下载的时候，这个库好像有问题，对文件判断不准确\n        //builder.addInterceptor(new ChuckInterceptor(this));\n\n        //超时时间设置，默认60秒\n        builder.readTimeout(OkGo.DEFAULT_MILLISECONDS, TimeUnit.MILLISECONDS);      //全局的读取超时时间\n        builder.writeTimeout(OkGo.DEFAULT_MILLISECONDS, TimeUnit.MILLISECONDS);     //全局的写入超时时间\n        builder.connectTimeout(OkGo.DEFAULT_MILLISECONDS, TimeUnit.MILLISECONDS);   //全局的连接超时时间\n\n        //自动管理cookie（或者叫session的保持），以下几种任选其一就行\n        //builder.cookieJar(new CookieJarImpl(new SPCookieStore(this)));            //使用sp保持cookie，如果cookie不过期，则一直有效\n        builder.cookieJar(new CookieJarImpl(new DBCookieStore(this)));              //使用数据库保持cookie，如果cookie不过期，则一直有效\n        //builder.cookieJar(new CookieJarImpl(new MemoryCookieStore()));            //使用内存保持cookie，app退出后，cookie消失\n\n        //https相关设置，以下几种方案根据需要自己设置\n        //方法一：信任所有证书,不安全有风险\n        HttpsUtils.SSLParams sslParams1 = HttpsUtils.getSslSocketFactory();\n        //方法二：自定义信任规则，校验服务端证书\n        HttpsUtils.SSLParams sslParams2 = HttpsUtils.getSslSocketFactory(new SafeTrustManager());\n        //方法三：使用预埋证书，校验服务端证书（自签名证书）\n        //HttpsUtils.SSLParams sslParams3 = HttpsUtils.getSslSocketFactory(getAssets().open(\"srca.cer\"));\n        //方法四：使用bks证书和密码管理客户端证书（双向认证），使用预埋证书，校验服务端证书（自签名证书）\n        //HttpsUtils.SSLParams sslParams4 = HttpsUtils.getSslSocketFactory(getAssets().open(\"xxx.bks\"), \"123456\", getAssets().open(\"yyy.cer\"));\n        builder.sslSocketFactory(sslParams1.sSLSocketFactory, sslParams1.trustManager);\n        //配置https的域名匹配规则，详细看demo的初始化介绍，不需要就不要加入，使用不当会导致https握手失败\n        builder.hostnameVerifier(new SafeHostnameVerifier());\n\n        // 其他统一的配置\n        // 详细说明看GitHub文档：https://github.com/jeasonlzy/\n        OkGo.getInstance().init(this)                           //必须调用初始化\n                .setOkHttpClient(builder.build())               //建议设置OkHttpClient，不设置会使用默认的\n                .setCacheMode(CacheMode.NO_CACHE)               //全局统一缓存模式，默认不使用缓存，可以不传\n                .setCacheTime(CacheEntity.CACHE_NEVER_EXPIRE)   //全局统一缓存时间，默认永不过期，可以不传\n                .setRetryCount(3)                               //全局统一超时重连次数，默认为三次，那么最差的情况会请求4次(一次原始请求，三次重连请求)，不需要可以设置为0\n                .addCommonHeaders(headers)                      //全局公共头\n                .addCommonParams(params);                       //全局公共参数\n    }\n\n    /**\n     * 这里只是我谁便写的认证规则，具体每个业务是否需要验证，以及验证规则是什么，请与服务端或者leader确定\n     * 这里只是我谁便写的认证规则，具体每个业务是否需要验证，以及验证规则是什么，请与服务端或者leader确定\n     * 这里只是我谁便写的认证规则，具体每个业务是否需要验证，以及验证规则是什么，请与服务端或者leader确定\n     * 重要的事情说三遍，以下代码不要直接使用\n     */\n    private class SafeTrustManager implements X509TrustManager {\n        @Override\n        public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {\n        }\n\n        @Override\n        public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {\n            try {\n                for (X509Certificate certificate : chain) {\n                    certificate.checkValidity(); //检查证书是否过期，签名是否通过等\n                }\n            } catch (Exception e) {\n                throw new CertificateException(e);\n            }\n        }\n\n        @Override\n        public X509Certificate[] getAcceptedIssuers() {\n            return new X509Certificate[0];\n        }\n    }\n\n    /**\n     * 这里只是我谁便写的认证规则，具体每个业务是否需要验证，以及验证规则是什么，请与服务端或者leader确定\n     * 这里只是我谁便写的认证规则，具体每个业务是否需要验证，以及验证规则是什么，请与服务端或者leader确定\n     * 这里只是我谁便写的认证规则，具体每个业务是否需要验证，以及验证规则是什么，请与服务端或者leader确定\n     * 重要的事情说三遍，以下代码不要直接使用\n     */\n    private class SafeHostnameVerifier implements HostnameVerifier {\n        @Override\n        public boolean verify(String hostname, SSLSession session) {\n            //验证主机名是否匹配\n            //return hostname.equals(\"server.jeasonlzy.com\");\n            return true;\n        }\n    }\n}\n"
  },
  {
    "path": "demo/src/main/java/com/lzy/demo/MainActivity.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.demo;\n\nimport android.os.Bundle;\nimport android.support.design.widget.TabLayout;\nimport android.support.v4.app.Fragment;\nimport android.support.v4.app.FragmentManager;\nimport android.support.v4.app.FragmentPagerAdapter;\nimport android.support.v4.view.ViewPager;\nimport android.support.v7.widget.Toolbar;\nimport android.util.Pair;\nimport android.view.View;\n\nimport com.lzy.demo.base.BaseActivity;\nimport com.lzy.demo.okdownload.OkDownloadFragment;\nimport com.lzy.demo.okgo.OkGoFragment;\nimport com.lzy.demo.okrx2.OkRx2Fragment;\nimport com.lzy.demo.okrx2.OkRxFragment;\nimport com.lzy.demo.okupload.OkUploadFragment;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport butterknife.Bind;\nimport butterknife.OnClick;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：16/9/11\n * 描    述：\n * 修订历史：\n * ================================================\n */\npublic class MainActivity extends BaseActivity {\n\n    @Bind(R.id.toolbar) Toolbar toolbar;\n    @Bind(R.id.viewPager) ViewPager viewPager;\n    @Bind(R.id.tab) TabLayout tab;\n\n    private List<Pair<String, Fragment>> items;\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.activity_main);\n        initToolBar(toolbar, false, \"\");\n\n        items = new ArrayList<>();\n        items.add(new Pair<String, Fragment>(\"OkGo\", new OkGoFragment()));\n        items.add(new Pair<String, Fragment>(\"打赏\", new PayFragment()));\n        items.add(new Pair<String, Fragment>(\"OkRx2\", new OkRx2Fragment()));\n        items.add(new Pair<String, Fragment>(\"OkRx\", new OkRxFragment()));\n        items.add(new Pair<String, Fragment>(\"OkDownload\", new OkDownloadFragment()));\n        items.add(new Pair<String, Fragment>(\"OkUpload\", new OkUploadFragment()));\n\n        viewPager.setAdapter(new MainAdapter(getSupportFragmentManager()));\n        tab.setupWithViewPager(viewPager);\n    }\n\n    @OnClick(R.id.fab)\n    public void fab(View view) {\n        WebActivity.runActivity(this, \"我的Github,欢迎star\", \"https://github.com/jeasonlzy\");\n    }\n\n    @Override\n    protected boolean translucentStatusBar() {\n        return true;\n    }\n\n    private class MainAdapter extends FragmentPagerAdapter {\n\n        MainAdapter(FragmentManager fm) {\n            super(fm);\n        }\n\n        @Override\n        public Fragment getItem(int position) {\n            return items.get(position).second;\n        }\n\n        @Override\n        public int getCount() {\n            return items.size();\n        }\n\n        @Override\n        public CharSequence getPageTitle(int position) {\n            return items.get(position).first;\n        }\n    }\n}\n"
  },
  {
    "path": "demo/src/main/java/com/lzy/demo/PayFragment.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.demo;\n\nimport android.os.Bundle;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\n\nimport com.lzy.demo.base.BaseFragment;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：2017/6/9\n * 描    述：\n * 修订历史：\n * ================================================\n */\npublic class PayFragment extends BaseFragment {\n\n    @Override\n    protected View initView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {\n        return inflater.inflate(R.layout.fragment_pay, container, false);\n    }\n\n    @Override\n    protected void initData() {\n\n    }\n}\n"
  },
  {
    "path": "demo/src/main/java/com/lzy/demo/WebActivity.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.demo;\n\nimport android.content.Context;\nimport android.content.Intent;\nimport android.os.Bundle;\nimport android.support.v7.widget.Toolbar;\nimport android.view.View;\nimport android.webkit.WebChromeClient;\nimport android.webkit.WebView;\nimport android.webkit.WebViewClient;\nimport android.widget.ProgressBar;\n\nimport com.lzy.demo.base.BaseActivity;\n\nimport butterknife.Bind;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：16/9/11\n * 描    述：\n * 修订历史：\n * ================================================\n */\npublic class WebActivity extends BaseActivity {\n\n    public final static String URL = \"url\";\n    public final static String TITLE = \"title\";\n\n    @Bind(R.id.toolbar) Toolbar toolbar;\n    @Bind(R.id.pb) ProgressBar pb;\n    @Bind(R.id.webView) WebView webView;\n\n    public static void runActivity(Context context, String title, String url) {\n        Intent intent = new Intent(context, WebActivity.class);\n        intent.putExtra(URL, url);\n        intent.putExtra(TITLE, title);\n        context.startActivity(intent);\n    }\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.activity_web);\n        String url = getIntent().getStringExtra(URL);\n        String title = getIntent().getStringExtra(TITLE);\n        initToolBar(toolbar, true, title);\n\n        pb.setMax(100);\n        webView.getSettings().setJavaScriptEnabled(true);\n        webView.getSettings().setSupportZoom(true);\n        webView.getSettings().setBuiltInZoomControls(true);\n        webView.setWebChromeClient(new WebChromeClient() {\n            @Override\n            public void onProgressChanged(WebView view, int newProgress) {\n                pb.setProgress(newProgress);\n                if (newProgress >= 100) {\n                    pb.setVisibility(View.GONE);\n                }\n            }\n        });\n        webView.setWebViewClient(new WebViewClient() {\n            @Override\n            public boolean shouldOverrideUrlLoading(WebView view, String url) {\n                view.loadUrl(url);\n                return true;\n            }\n        });\n        webView.loadUrl(url);\n    }\n}\n"
  },
  {
    "path": "demo/src/main/java/com/lzy/demo/base/BaseActivity.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.demo.base;\n\nimport android.app.ProgressDialog;\nimport android.graphics.Color;\nimport android.os.Build;\nimport android.os.Bundle;\nimport android.support.annotation.LayoutRes;\nimport android.support.v7.app.AppCompatActivity;\nimport android.support.v7.widget.Toolbar;\nimport android.util.TypedValue;\nimport android.view.MenuItem;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.view.Window;\nimport android.view.WindowManager;\nimport android.widget.ImageView;\nimport android.widget.Toast;\n\nimport com.bumptech.glide.Glide;\nimport com.lzy.demo.R;\nimport com.lzy.imagepicker.view.SystemBarTintManager;\n\nimport butterknife.ButterKnife;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：16/9/11\n * 描    述：\n * 修订历史：\n * ================================================\n */\npublic abstract class BaseActivity extends AppCompatActivity {\n\n    @SuppressWarnings(\"unchecked\")\n    public <T extends View> T findView(int id) {\n        return (T) findViewById(id);\n    }\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        initSystemBarTint();\n    }\n\n    @Override\n    public void setContentView(@LayoutRes int layoutResID) {\n        super.setContentView(layoutResID);\n        ButterKnife.bind(this);\n    }\n\n    @Override\n    public void setContentView(View view) {\n        super.setContentView(view);\n        ButterKnife.bind(this);\n    }\n\n    @Override\n    public void setContentView(View view, ViewGroup.LayoutParams params) {\n        super.setContentView(view, params);\n        ButterKnife.bind(this);\n    }\n\n    @Override\n    public boolean onOptionsItemSelected(MenuItem item) {\n        switch (item.getItemId()) {\n            case android.R.id.home:// 点击返回图标事件\n                finish();\n            default:\n                return super.onOptionsItemSelected(item);\n        }\n    }\n\n    /** 子类可以重写改变状态栏颜色 */\n    protected int setStatusBarColor() {\n        return getColorPrimary();\n    }\n\n    /** 子类可以重写决定是否使用透明状态栏 */\n    protected boolean translucentStatusBar() {\n        return false;\n    }\n\n    /** 设置状态栏颜色 */\n    protected void initSystemBarTint() {\n        Window window = getWindow();\n        if (translucentStatusBar()) {\n            // 设置状态栏全透明\n            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {\n                window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);\n                window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);\n                window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);\n                window.setStatusBarColor(Color.TRANSPARENT);\n            } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {\n                getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);\n            }\n            return;\n        }\n        // 沉浸式状态栏\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {\n            //5.0以上使用原生方法\n            window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);\n            window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);\n            window.setStatusBarColor(setStatusBarColor());\n        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {\n            //4.4-5.0使用三方工具类，有些4.4的手机有问题，这里为演示方便，不使用沉浸式\n//            getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);\n            SystemBarTintManager tintManager = new SystemBarTintManager(this);\n            tintManager.setStatusBarTintEnabled(true);\n            tintManager.setStatusBarTintColor(setStatusBarColor());\n        }\n    }\n\n    /** 获取主题色 */\n    public int getColorPrimary() {\n        TypedValue typedValue = new TypedValue();\n        getTheme().resolveAttribute(R.attr.colorPrimary, typedValue, true);\n        return typedValue.data;\n    }\n\n    /** 获取深主题色 */\n    public int getDarkColorPrimary() {\n        TypedValue typedValue = new TypedValue();\n        getTheme().resolveAttribute(R.attr.colorPrimaryDark, typedValue, true);\n        return typedValue.data;\n    }\n\n    /** 初始化 Toolbar */\n    public void initToolBar(Toolbar toolbar, boolean homeAsUpEnabled, String title) {\n        toolbar.setTitle(title);\n        setSupportActionBar(toolbar);\n        getSupportActionBar().setDisplayHomeAsUpEnabled(homeAsUpEnabled);\n    }\n\n    public void initToolBar(Toolbar toolbar, boolean homeAsUpEnabled, int resTitle) {\n        initToolBar(toolbar, homeAsUpEnabled, getString(resTitle));\n    }\n\n    public void showToast(String msg) {\n        Toast.makeText(this, msg, Toast.LENGTH_SHORT).show();\n    }\n\n    private ProgressDialog dialog;\n\n    public void showLoading() {\n        if (dialog != null && dialog.isShowing()) return;\n        dialog = new ProgressDialog(this);\n        dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);\n        dialog.setCanceledOnTouchOutside(false);\n        dialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);\n        dialog.setMessage(\"请求网络中...\");\n        dialog.show();\n    }\n\n    public void dismissLoading() {\n        if (dialog != null && dialog.isShowing()) {\n            dialog.dismiss();\n        }\n    }\n\n    public void displayImage(String url, ImageView imageView) {\n        Glide.with(getApplicationContext())//\n                .load(url)//\n                .error(R.mipmap.ic_launcher)//\n                .into(imageView);\n    }\n}\n"
  },
  {
    "path": "demo/src/main/java/com/lzy/demo/base/BaseDetailActivity.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.demo.base;\n\nimport android.graphics.Bitmap;\nimport android.os.Bundle;\nimport android.support.v7.app.ActionBar;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.view.Window;\nimport android.widget.FrameLayout;\nimport android.widget.TextView;\n\nimport com.lzy.demo.R;\nimport com.lzy.demo.utils.Convert;\nimport com.lzy.okgo.model.Response;\n\nimport java.io.File;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\n\nimport okhttp3.Call;\nimport okhttp3.Headers;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：16/9/11\n * 描    述：\n * 修订历史：\n * ================================================\n */\npublic abstract class BaseDetailActivity extends BaseActivity {\n\n    protected ActionBar actionBar;\n    protected TextView requestState;\n    protected TextView requestHeaders;\n    protected TextView responseData;\n    protected TextView responseHeader;\n    protected FrameLayout rootContent;\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        actionBar = getSupportActionBar();\n        if (actionBar != null) {\n            actionBar.setDisplayShowTitleEnabled(true);\n            actionBar.setDisplayHomeAsUpEnabled(true);\n            actionBar.setDisplayShowHomeEnabled(true);\n        }\n        getDelegate().setContentView(R.layout.activity_base);\n        Window window = getWindow();\n        requestState = (TextView) window.findViewById(R.id.requestState);\n        requestHeaders = (TextView) window.findViewById(R.id.requestHeaders);\n        responseData = (TextView) window.findViewById(R.id.responseData);\n        responseHeader = (TextView) window.findViewById(R.id.responseHeader);\n        rootContent = (FrameLayout) window.findViewById(R.id.content);\n        onActivityCreate(savedInstanceState);\n    }\n\n    protected abstract void onActivityCreate(Bundle savedInstanceState);\n\n    @Override\n    public void setTitle(CharSequence title) {\n        if (actionBar != null) actionBar.setTitle(title);\n    }\n\n    @Override\n    public void setTitle(int titleId) {\n        if (actionBar != null) actionBar.setTitle(titleId);\n    }\n\n    @Override\n    public View findViewById(int id) {\n        return rootContent.findViewById(id);\n    }\n\n    private void clearContentView() {\n        rootContent.removeAllViews();\n    }\n\n    @Override\n    public void setContentView(int layoutResID) {\n        clearContentView();\n        getLayoutInflater().inflate(layoutResID, rootContent, true);\n    }\n\n    @Override\n    public void setContentView(View view) {\n        clearContentView();\n        rootContent.addView(view);\n    }\n\n    @Override\n    public void setContentView(View view, ViewGroup.LayoutParams params) {\n        clearContentView();\n        rootContent.addView(view, params);\n    }\n\n    protected <T> void handleResponse(T data) {\n        Response<T> response = new Response<>();\n        response.setBody(data);\n        handleResponse(response);\n    }\n\n    protected <T> void handleResponse(Response<T> response) {\n        StringBuilder sb;\n        Call call = response.getRawCall();\n        if (call != null) {\n            requestState.setText(\"请求成功  请求方式：\" + call.request().method() + \"\\n\" + \"url：\" + call.request().url());\n\n            Headers requestHeadersString = call.request().headers();\n            Set<String> requestNames = requestHeadersString.names();\n            sb = new StringBuilder();\n            for (String name : requestNames) {\n                sb.append(name).append(\" ： \").append(requestHeadersString.get(name)).append(\"\\n\");\n            }\n            requestHeaders.setText(sb.toString());\n        } else {\n            requestState.setText(\"--\");\n            requestHeaders.setText(\"--\");\n        }\n        T body = response.body();\n        if (body == null) {\n            responseData.setText(\"--\");\n        } else {\n            if (body instanceof String) {\n                responseData.setText((String) body);\n            } else if (body instanceof List) {\n                sb = new StringBuilder();\n                List list = (List) body;\n                for (Object obj : list) {\n                    sb.append(obj.toString()).append(\"\\n\");\n                }\n                responseData.setText(sb.toString());\n            } else if (body instanceof Set) {\n                sb = new StringBuilder();\n                Set set = (Set) body;\n                for (Object obj : set) {\n                    sb.append(obj.toString()).append(\"\\n\");\n                }\n                responseData.setText(sb.toString());\n            } else if (body instanceof Map) {\n                sb = new StringBuilder();\n                Map map = (Map) body;\n                Set keySet = map.keySet();\n                for (Object key : keySet) {\n                    sb.append(key.toString()).append(\" ： \").append(map.get(key)).append(\"\\n\");\n                }\n                responseData.setText(sb.toString());\n            } else if (body instanceof File) {\n                File file = (File) body;\n                responseData.setText(\"数据内容即为文件内容\\n下载文件路径：\" + file.getAbsolutePath());\n            } else if (body instanceof Bitmap) {\n                responseData.setText(\"图片的内容即为数据\");\n            } else {\n                responseData.setText(Convert.formatJson(body));\n            }\n        }\n\n        okhttp3.Response rawResponse = response.getRawResponse();\n        if (rawResponse != null) {\n            Headers responseHeadersString = rawResponse.headers();\n            Set<String> names = responseHeadersString.names();\n            sb = new StringBuilder();\n            sb.append(\"url ： \").append(rawResponse.request().url()).append(\"\\n\\n\");\n            sb.append(\"stateCode ： \").append(rawResponse.code()).append(\"\\n\");\n            for (String name : names) {\n                sb.append(name).append(\" ： \").append(responseHeadersString.get(name)).append(\"\\n\");\n            }\n            responseHeader.setText(sb.toString());\n        } else {\n            responseHeader.setText(\"--\");\n        }\n    }\n\n    protected <T> void handleError() {\n        Response<T> response = new Response<>();\n        handleResponse(response);\n    }\n\n    protected <T> void handleError(Response<T> response) {\n        if (response == null) return;\n        if (response.getException() != null) response.getException().printStackTrace();\n        StringBuilder sb;\n        Call call = response.getRawCall();\n        if (call != null) {\n            requestState.setText(\"请求失败  请求方式：\" + call.request().method() + \"\\n\" + \"url：\" + call.request().url());\n\n            Headers requestHeadersString = call.request().headers();\n            Set<String> requestNames = requestHeadersString.names();\n            sb = new StringBuilder();\n            for (String name : requestNames) {\n                sb.append(name).append(\" ： \").append(requestHeadersString.get(name)).append(\"\\n\");\n            }\n            requestHeaders.setText(sb.toString());\n        } else {\n            requestState.setText(\"--\");\n            requestHeaders.setText(\"--\");\n        }\n\n        responseData.setText(\"--\");\n        okhttp3.Response rawResponse = response.getRawResponse();\n        if (rawResponse != null) {\n            Headers responseHeadersString = rawResponse.headers();\n            Set<String> names = responseHeadersString.names();\n            sb = new StringBuilder();\n            sb.append(\"stateCode ： \").append(rawResponse.code()).append(\"\\n\");\n            for (String name : names) {\n                sb.append(name).append(\" ： \").append(responseHeadersString.get(name)).append(\"\\n\");\n            }\n            responseHeader.setText(sb.toString());\n        } else {\n            responseHeader.setText(\"--\");\n        }\n    }\n}\n"
  },
  {
    "path": "demo/src/main/java/com/lzy/demo/base/BaseFragment.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.demo.base;\n\nimport android.os.Bundle;\nimport android.support.v4.app.Fragment;\nimport android.text.TextUtils;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\n\n/**\n * 若把初始化内容放到initData实现,就是采用Lazy方式加载的Fragment\n * 若不需要Lazy加载则initData方法内留空,初始化内容放到initViews即可\n * -\n * -注1: 如果是与ViewPager一起使用，调用的是setUserVisibleHint。\n * ------可以调用mViewPager.setOffscreenPageLimit(size),若设置了该属性 则viewpager会缓存指定数量的Fragment\n * -注2: 如果是通过FragmentTransaction的show和hide的方法来控制显示，调用的是onHiddenChanged.\n * -注3: 针对初始就show的Fragment 为了触发onHiddenChanged事件 达到lazy效果 需要先hide再show\n */\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：16/9/11\n * 描    述：\n * 修订历史：\n * ================================================\n */\npublic abstract class BaseFragment extends Fragment {\n\n    protected String fragmentTitle;             //fragment标题\n    private boolean isVisible;                  //是否可见状态\n    private boolean isPrepared;                 //标志位，View已经初始化完成。\n    private boolean isFirstLoad = true;         //是否第一次加载\n    protected LayoutInflater inflater;\n\n    @Override\n    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {\n        this.inflater = inflater;\n        isFirstLoad = true;\n        View view = initView(inflater, container, savedInstanceState);\n        isPrepared = true;\n        lazyLoad();\n        return view;\n    }\n\n    /** 如果是与ViewPager一起使用，调用的是setUserVisibleHint */\n    @Override\n    public void setUserVisibleHint(boolean isVisibleToUser) {\n        super.setUserVisibleHint(isVisibleToUser);\n        if (getUserVisibleHint()) {\n            isVisible = true;\n            onVisible();\n        } else {\n            isVisible = false;\n            onInvisible();\n        }\n    }\n\n    /**\n     * 如果是通过FragmentTransaction的show和hide的方法来控制显示，调用的是onHiddenChanged.\n     * 若是初始就show的Fragment 为了触发该事件 需要先hide再show\n     */\n    @Override\n    public void onHiddenChanged(boolean hidden) {\n        super.onHiddenChanged(hidden);\n        if (!hidden) {\n            isVisible = true;\n            onVisible();\n        } else {\n            isVisible = false;\n            onInvisible();\n        }\n    }\n\n    protected void onVisible() {\n        lazyLoad();\n    }\n\n    protected void onInvisible() {\n    }\n\n    protected void lazyLoad() {\n        if (!isPrepared || !isVisible || !isFirstLoad) {\n            return;\n        }\n        isFirstLoad = false;\n        initData();\n    }\n\n    protected abstract View initView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState);\n\n    protected abstract void initData();\n\n    public String getTitle() {\n        return TextUtils.isEmpty(fragmentTitle) ? \"\" : fragmentTitle;\n    }\n\n    public void setTitle(String title) {\n        fragmentTitle = title;\n    }\n}\n"
  },
  {
    "path": "demo/src/main/java/com/lzy/demo/base/BaseRecyclerAdapter.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.demo.base;\n\nimport android.content.Context;\nimport android.support.v7.widget.RecyclerView;\nimport android.view.LayoutInflater;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.ListIterator;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：16/9/11\n * 描    述：\n * 修订历史：\n * ================================================\n */\npublic abstract class BaseRecyclerAdapter<T, VH extends RecyclerView.ViewHolder> extends RecyclerView.Adapter<VH> {\n\n    protected Context mContext;\n    protected List<T> mDatas;\n    protected LayoutInflater inflater;\n\n    public BaseRecyclerAdapter(Context context) {\n        this.mContext = context;\n        this.mDatas = new ArrayList<>();\n        inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);\n    }\n\n    public BaseRecyclerAdapter(Context context, List<T> datas) {\n        if (datas == null) datas = new ArrayList<>();\n        this.mContext = context;\n        this.mDatas = datas;\n        inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);\n    }\n\n    public BaseRecyclerAdapter(Context context, T[] datas) {\n        this.mContext = context;\n        this.mDatas = new ArrayList<T>();\n        inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);\n        Collections.addAll(mDatas, datas);\n    }\n\n    @Override\n    public int getItemCount() {\n        return mDatas == null ? 0 : mDatas.size();\n    }\n\n    /** 更新数据，替换原有数据 */\n    public void updateItems(List<T> items) {\n        mDatas = items;\n        notifyDataSetChanged();\n    }\n\n    /** 插入一条数据 */\n    public void addItem(T item) {\n        mDatas.add(0, item);\n        notifyItemInserted(0);\n    }\n\n    /** 插入一条数据 */\n    public void addItem(T item, int position) {\n        position = Math.min(position, mDatas.size());\n        mDatas.add(position, item);\n        notifyItemInserted(position);\n    }\n\n    /** 在列表尾添加一串数据 */\n    public void addItems(List<T> items) {\n        int start = mDatas.size();\n        mDatas.addAll(items);\n        notifyItemRangeChanged(start, items.size());\n    }\n\n    /** 移除一条数据 */\n    public void removeItem(int position) {\n        if (position > mDatas.size() - 1) {\n            return;\n        }\n        mDatas.remove(position);\n        notifyItemRemoved(position);\n    }\n\n    /** 移除一条数据 */\n    public void removeItem(T item) {\n        int position = 0;\n        ListIterator<T> iterator = mDatas.listIterator();\n        while (iterator.hasNext()) {\n            T next = iterator.next();\n            if (next == item) {\n                iterator.remove();\n                notifyItemRemoved(position);\n            }\n            position++;\n        }\n    }\n\n    /** 清除所有数据 */\n    public void removeAllItems() {\n        mDatas.clear();\n        notifyDataSetChanged();\n    }\n}\n"
  },
  {
    "path": "demo/src/main/java/com/lzy/demo/base/BaseRxDetailActivity.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.demo.base;\n\nimport io.reactivex.disposables.CompositeDisposable;\nimport io.reactivex.disposables.Disposable;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：16/10/1\n * 描    述：统一管理所有的订阅生命周期\n * 修订历史：\n * ================================================\n */\npublic abstract class BaseRxDetailActivity extends BaseDetailActivity {\n\n    private CompositeDisposable compositeDisposable;\n\n    public void addDisposable(Disposable disposable) {\n        if (compositeDisposable == null) {\n            compositeDisposable = new CompositeDisposable();\n        }\n        compositeDisposable.add(disposable);\n    }\n\n    public void dispose() {\n        if (compositeDisposable != null) compositeDisposable.dispose();\n    }\n}\n"
  },
  {
    "path": "demo/src/main/java/com/lzy/demo/base/DividerItemDecoration.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.demo.base;\n\nimport android.content.Context;\nimport android.content.res.TypedArray;\nimport android.graphics.Canvas;\nimport android.graphics.Rect;\nimport android.graphics.drawable.Drawable;\nimport android.support.v7.widget.LinearLayoutManager;\nimport android.support.v7.widget.RecyclerView;\nimport android.view.View;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）\n * 版    本：1.0\n * 创建日期：2016/4/7\n * 描    述：我的Github地址  https://github.com/jeasonlzy\n * 修订历史：\n * ================================================\n */\npublic class DividerItemDecoration extends RecyclerView.ItemDecoration {\n\n    private static final int[] ATTRS = new int[]{android.R.attr.listDivider};\n\n    public static final int HORIZONTAL_LIST = LinearLayoutManager.HORIZONTAL;\n    public static final int VERTICAL_LIST = LinearLayoutManager.VERTICAL;\n    private Drawable mDivider;\n    private int mOrientation;\n\n    public DividerItemDecoration(Context context, int orientation) {\n        final TypedArray a = context.obtainStyledAttributes(ATTRS);\n        mDivider = a.getDrawable(0);\n        a.recycle();\n        setOrientation(orientation);\n    }\n\n    public void setOrientation(int orientation) {\n        if (orientation != HORIZONTAL_LIST && orientation != VERTICAL_LIST) {\n            throw new IllegalArgumentException(\"invalid orientation\");\n        }\n        mOrientation = orientation;\n    }\n\n    @Override\n    public void onDraw(Canvas c, RecyclerView parent) {\n        if (mOrientation == VERTICAL_LIST) {\n            drawVertical(c, parent);\n        } else {\n            drawHorizontal(c, parent);\n        }\n\n    }\n\n    public void drawVertical(Canvas c, RecyclerView parent) {\n        final int left = parent.getPaddingLeft();\n        final int right = parent.getWidth() - parent.getPaddingRight();\n\n        final int childCount = parent.getChildCount();\n        for (int i = 0; i < childCount; i++) {\n            final View child = parent.getChildAt(i);\n            final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();\n            final int top = child.getBottom() + params.bottomMargin;\n            final int bottom = top + mDivider.getIntrinsicHeight();\n            mDivider.setBounds(left, top, right, bottom);\n            mDivider.draw(c);\n        }\n    }\n\n    public void drawHorizontal(Canvas c, RecyclerView parent) {\n        final int top = parent.getPaddingTop();\n        final int bottom = parent.getHeight() - parent.getPaddingBottom();\n\n        final int childCount = parent.getChildCount();\n        for (int i = 0; i < childCount; i++) {\n            final View child = parent.getChildAt(i);\n            final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();\n            final int left = child.getRight() + params.rightMargin;\n            final int right = left + mDivider.getIntrinsicHeight();\n            mDivider.setBounds(left, top, right, bottom);\n            mDivider.draw(c);\n        }\n    }\n\n    @Override\n    public void getItemOffsets(Rect outRect, int itemPosition, RecyclerView parent) {\n        if (mOrientation == VERTICAL_LIST) {\n            outRect.set(0, 0, 0, mDivider.getIntrinsicHeight());\n        } else {\n            outRect.set(0, 0, mDivider.getIntrinsicWidth(), 0);\n        }\n    }\n}\n"
  },
  {
    "path": "demo/src/main/java/com/lzy/demo/base/MainFragment.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.demo.base;\n\nimport android.content.Context;\nimport android.graphics.Color;\nimport android.os.Bundle;\nimport android.support.v4.widget.SwipeRefreshLayout;\nimport android.support.v7.widget.DefaultItemAnimator;\nimport android.support.v7.widget.LinearLayoutManager;\nimport android.support.v7.widget.RecyclerView;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\n\nimport com.chad.library.adapter.base.BaseQuickAdapter;\nimport com.chad.library.adapter.base.BaseViewHolder;\nimport com.lzy.demo.R;\nimport com.lzy.demo.model.ItemModel;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport butterknife.Bind;\nimport butterknife.ButterKnife;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：2017/6/9\n * 描    述：\n * 修订历史：\n * ================================================\n */\npublic abstract class MainFragment extends BaseFragment implements SwipeRefreshLayout.OnRefreshListener, BaseQuickAdapter.RequestLoadMoreListener {\n\n    @Bind(R.id.refreshLayout) SwipeRefreshLayout refreshLayout;\n    @Bind(R.id.recyclerView) RecyclerView recyclerView;\n\n    protected Context context;\n    private MainAdapter adapter;\n\n    @Override\n    public void onAttach(Context context) {\n        super.onAttach(context);\n        this.context = context;\n    }\n\n    @Override\n    protected View initView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {\n        View view = inflater.inflate(R.layout.item_refresh, container, false);\n        ButterKnife.bind(this, view);\n        return view;\n    }\n\n    @Override\n    public void onRefresh() {\n        setRefreshing(false);\n    }\n\n    @Override\n    public void onLoadMoreRequested() {\n        refreshLayout.postDelayed(new Runnable() {\n            @Override\n            public void run() {\n                adapter.loadComplete();\n            }\n        }, 500);\n    }\n\n    @Override\n    protected void initData() {\n        List<ItemModel> items = new ArrayList<>();\n        fillData(items);\n\n        adapter = new MainAdapter(items);\n        adapter.openLoadAnimation(BaseQuickAdapter.SCALEIN);\n        adapter.isFirstOnly(false);\n        adapter.setOnLoadMoreListener(this);\n\n        refreshLayout.setColorSchemeColors(Color.RED, Color.BLUE, Color.GREEN);\n        refreshLayout.setOnRefreshListener(this);\n\n        recyclerView.setLayoutManager(new LinearLayoutManager(context));\n        recyclerView.setItemAnimator(new DefaultItemAnimator());\n        recyclerView.addItemDecoration(new DividerItemDecoration(context, LinearLayoutManager.VERTICAL));\n\n        recyclerView.setAdapter(adapter);\n    }\n\n    public abstract void fillData(List<ItemModel> items);\n\n    public abstract void onItemClick(int position);\n\n    private class MainAdapter extends BaseQuickAdapter<ItemModel> {\n\n        MainAdapter(List<ItemModel> data) {\n            super(R.layout.item_main_list, data);\n        }\n\n        @Override\n        protected void convert(final BaseViewHolder baseViewHolder, ItemModel itemModel) {\n            baseViewHolder.setText(R.id.title, itemModel.title);\n            baseViewHolder.setText(R.id.des, itemModel.des);\n            baseViewHolder.getConvertView().setOnClickListener(new View.OnClickListener() {\n                @Override\n                public void onClick(View v) {\n                    onItemClick(baseViewHolder.getAdapterPosition());\n                }\n            });\n        }\n    }\n\n    public void setRefreshing(final boolean refreshing) {\n        refreshLayout.post(new Runnable() {\n            @Override\n            public void run() {\n                refreshLayout.setRefreshing(refreshing);\n            }\n        });\n    }\n}\n"
  },
  {
    "path": "demo/src/main/java/com/lzy/demo/callback/BitmapDialogCallback.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.demo.callback;\n\nimport android.app.Activity;\nimport android.app.ProgressDialog;\nimport android.graphics.Bitmap;\nimport android.view.Window;\n\nimport com.lzy.okgo.callback.BitmapCallback;\nimport com.lzy.okgo.request.base.Request;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：2016/1/14\n * 描    述：请求图图片的时候显示对话框\n * 修订历史：\n * ================================================\n */\npublic abstract class BitmapDialogCallback extends BitmapCallback {\n\n    private ProgressDialog dialog;\n\n    public BitmapDialogCallback(Activity activity) {\n        super(1000, 1000);\n        dialog = new ProgressDialog(activity);\n        dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);\n        dialog.setCanceledOnTouchOutside(false);\n        dialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);\n        dialog.setMessage(\"请求网络中...\");\n    }\n\n    @Override\n    public void onStart(Request<Bitmap, ? extends Request> request) {\n        if (dialog != null && !dialog.isShowing()) {\n            dialog.show();\n        }\n    }\n\n    @Override\n    public void onFinish() {\n        if (dialog != null && dialog.isShowing()) {\n            dialog.dismiss();\n        }\n    }\n}\n"
  },
  {
    "path": "demo/src/main/java/com/lzy/demo/callback/DialogCallback.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.demo.callback;\n\nimport android.app.Activity;\nimport android.app.ProgressDialog;\nimport android.view.Window;\n\nimport com.lzy.okgo.request.base.Request;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：2016/1/14\n * 描    述：对于网络请求是否需要弹出进度对话框\n * 修订历史：\n * ================================================\n */\npublic abstract class DialogCallback<T> extends JsonCallback<T> {\n\n    private ProgressDialog dialog;\n\n    private void initDialog(Activity activity) {\n        dialog = new ProgressDialog(activity);\n        dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);\n        dialog.setCanceledOnTouchOutside(false);\n        dialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);\n        dialog.setMessage(\"请求网络中...\");\n    }\n\n    public DialogCallback(Activity activity) {\n        super();\n        initDialog(activity);\n    }\n\n    @Override\n    public void onStart(Request<T, ? extends Request> request) {\n        if (dialog != null && !dialog.isShowing()) {\n            dialog.show();\n        }\n    }\n\n    @Override\n    public void onFinish() {\n        //网络请求结束后关闭对话框\n        if (dialog != null && dialog.isShowing()) {\n            dialog.dismiss();\n        }\n    }\n}\n"
  },
  {
    "path": "demo/src/main/java/com/lzy/demo/callback/EncryptCallback.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.demo.callback;\n\nimport com.lzy.demo.utils.MD5Utils;\nimport com.lzy.okgo.model.HttpParams;\nimport com.lzy.okgo.request.base.Request;\n\nimport java.util.Comparator;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Random;\nimport java.util.TreeMap;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：2017/6/11\n * 描    述：\n * 修订历史：\n * ================================================\n */\npublic abstract class EncryptCallback<T> extends JsonCallback<T> {\n\n    private static final Random RANDOM = new Random();\n    private static final String CHARS = \"0123456789abcdefghijklmnopqrstuvwxyz\";\n\n    @Override\n    public void onStart(Request<T, ? extends Request> request) {\n        super.onStart(request);\n        //以下是示例加密代码，根据自己的业务需求和服务器的配合，算法自行决定，这里只是demo，不能用于商业项目\n        sign(request.getParams());\n    }\n\n    /**\n     * 针对URL进行签名，关于这几个参数的作用，详细请看\n     * http://www.cnblogs.com/bestzrz/archive/2011/09/03/2164620.html\n     */\n    private void sign(HttpParams params) {\n        params.put(\"nonce\", getRndStr(6 + RANDOM.nextInt(8)));\n        params.put(\"timestamp\", \"\" + (System.currentTimeMillis() / 1000L));\n        StringBuilder sb = new StringBuilder();\n        Map<String, String> map = new HashMap<>();\n        for (Map.Entry<String, List<String>> entry : params.urlParamsMap.entrySet()) {\n            map.put(entry.getKey(), entry.getValue().get(0));\n        }\n        for (Map.Entry<String, String> entry : getSortedMapByKey(map).entrySet()) {\n            sb.append(entry.getKey()).append(\"=\").append(entry.getValue()).append(\"&\");\n        }\n        sb.delete(sb.length() - 1, sb.length());\n        String sign = MD5Utils.encode(sb.toString());\n        params.put(\"sign\", sign);\n    }\n\n    /** 获取随机数 */\n    private String getRndStr(int length) {\n        StringBuilder sb = new StringBuilder();\n        char ch;\n        for (int i = 0; i < length; i++) {\n            ch = CHARS.charAt(RANDOM.nextInt(CHARS.length()));\n            sb.append(ch);\n        }\n        return sb.toString();\n    }\n\n    /** 按照key的自然顺序进行排序，并返回 */\n    private Map<String, String> getSortedMapByKey(Map<String, String> map) {\n        Comparator<String> comparator = new Comparator<String>() {\n            @Override\n            public int compare(String lhs, String rhs) {\n                return lhs.compareTo(rhs);\n            }\n        };\n        Map<String, String> treeMap = new TreeMap<>(comparator);\n        for (Map.Entry<String, String> entry : map.entrySet()) {\n            treeMap.put(entry.getKey(), entry.getValue());\n        }\n        return treeMap;\n    }\n}\n"
  },
  {
    "path": "demo/src/main/java/com/lzy/demo/callback/JsonCallback.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.demo.callback;\n\nimport com.lzy.okgo.callback.AbsCallback;\nimport com.lzy.okgo.request.base.Request;\n\nimport java.lang.reflect.ParameterizedType;\nimport java.lang.reflect.Type;\n\nimport okhttp3.Response;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：2016/1/14\n * 描    述：默认将返回的数据解析成需要的Bean,可以是 BaseBean，String，List，Map\n * 修订历史：\n * ================================================\n */\npublic abstract class JsonCallback<T> extends AbsCallback<T> {\n\n    private Type type;\n    private Class<T> clazz;\n\n    public JsonCallback() {\n    }\n\n    public JsonCallback(Type type) {\n        this.type = type;\n    }\n\n    public JsonCallback(Class<T> clazz) {\n        this.clazz = clazz;\n    }\n\n    @Override\n    public void onStart(Request<T, ? extends Request> request) {\n        super.onStart(request);\n        // 主要用于在所有请求之前添加公共的请求头或请求参数\n        // 例如登录授权的 token\n        // 使用的设备信息\n        // 可以随意添加,也可以什么都不传\n        // 还可以在这里对所有的参数进行加密，均在这里实现\n        request.headers(\"header1\", \"HeaderValue1\")//\n                .params(\"params1\", \"ParamsValue1\")//\n                .params(\"token\", \"3215sdf13ad1f65asd4f3ads1f\");\n    }\n\n    /**\n     * 该方法是子线程处理，不能做ui相关的工作\n     * 主要作用是解析网络返回的 response 对象,生产onSuccess回调中需要的数据对象\n     * 这里的解析工作不同的业务逻辑基本都不一样,所以需要自己实现,以下给出的时模板代码,实际使用根据需要修改\n     */\n    @Override\n    public T convertResponse(Response response) throws Throwable {\n\n        // 重要的事情说三遍，不同的业务，这里的代码逻辑都不一样，如果你不修改，那么基本不可用\n        // 重要的事情说三遍，不同的业务，这里的代码逻辑都不一样，如果你不修改，那么基本不可用\n        // 重要的事情说三遍，不同的业务，这里的代码逻辑都不一样，如果你不修改，那么基本不可用\n\n        //详细自定义的原理和文档，看这里： https://github.com/jeasonlzy/okhttp-OkGo/wiki/JsonCallback\n\n        if (type == null) {\n            if (clazz == null) {\n                Type genType = getClass().getGenericSuperclass();\n                type = ((ParameterizedType) genType).getActualTypeArguments()[0];\n            } else {\n                JsonConvert<T> convert = new JsonConvert<>(clazz);\n                return convert.convertResponse(response);\n            }\n        }\n\n        JsonConvert<T> convert = new JsonConvert<>(type);\n        return convert.convertResponse(response);\n    }\n}\n"
  },
  {
    "path": "demo/src/main/java/com/lzy/demo/callback/JsonConvert.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.demo.callback;\n\nimport com.google.gson.stream.JsonReader;\nimport com.lzy.demo.model.LzyResponse;\nimport com.lzy.demo.model.SimpleResponse;\nimport com.lzy.demo.utils.Convert;\nimport com.lzy.okgo.convert.Converter;\n\nimport org.json.JSONArray;\nimport org.json.JSONObject;\n\nimport java.lang.reflect.ParameterizedType;\nimport java.lang.reflect.Type;\n\nimport okhttp3.Response;\nimport okhttp3.ResponseBody;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：16/9/11\n * 描    述：\n * 修订历史：\n * ================================================\n */\npublic class JsonConvert<T> implements Converter<T> {\n\n    private Type type;\n    private Class<T> clazz;\n\n    public JsonConvert() {\n    }\n\n    public JsonConvert(Type type) {\n        this.type = type;\n    }\n\n    public JsonConvert(Class<T> clazz) {\n        this.clazz = clazz;\n    }\n\n    /**\n     * 该方法是子线程处理，不能做ui相关的工作\n     * 主要作用是解析网络返回的 response 对象，生成onSuccess回调中需要的数据对象\n     * 这里的解析工作不同的业务逻辑基本都不一样,所以需要自己实现,以下给出的时模板代码,实际使用根据需要修改\n     */\n    @Override\n    public T convertResponse(Response response) throws Throwable {\n\n        // 重要的事情说三遍，不同的业务，这里的代码逻辑都不一样，如果你不修改，那么基本不可用\n        // 重要的事情说三遍，不同的业务，这里的代码逻辑都不一样，如果你不修改，那么基本不可用\n        // 重要的事情说三遍，不同的业务，这里的代码逻辑都不一样，如果你不修改，那么基本不可用\n\n        // 如果你对这里的代码原理不清楚，可以看这里的详细原理说明: https://github.com/jeasonlzy/okhttp-OkGo/wiki/JsonCallback\n        // 如果你对这里的代码原理不清楚，可以看这里的详细原理说明: https://github.com/jeasonlzy/okhttp-OkGo/wiki/JsonCallback\n        // 如果你对这里的代码原理不清楚，可以看这里的详细原理说明: https://github.com/jeasonlzy/okhttp-OkGo/wiki/JsonCallback\n\n        if (type == null) {\n            if (clazz == null) {\n                // 如果没有通过构造函数传进来，就自动解析父类泛型的真实类型（有局限性，继承后就无法解析到）\n                Type genType = getClass().getGenericSuperclass();\n                type = ((ParameterizedType) genType).getActualTypeArguments()[0];\n            } else {\n                return parseClass(response, clazz);\n            }\n        }\n\n        if (type instanceof ParameterizedType) {\n            return parseParameterizedType(response, (ParameterizedType) type);\n        } else if (type instanceof Class) {\n            return parseClass(response, (Class<?>) type);\n        } else {\n            return parseType(response, type);\n        }\n    }\n\n    private T parseClass(Response response, Class<?> rawType) throws Exception {\n        if (rawType == null) return null;\n        ResponseBody body = response.body();\n        if (body == null) return null;\n        JsonReader jsonReader = new JsonReader(body.charStream());\n\n        if (rawType == String.class) {\n            //noinspection unchecked\n            return (T) body.string();\n        } else if (rawType == JSONObject.class) {\n            //noinspection unchecked\n            return (T) new JSONObject(body.string());\n        } else if (rawType == JSONArray.class) {\n            //noinspection unchecked\n            return (T) new JSONArray(body.string());\n        } else {\n            T t = Convert.fromJson(jsonReader, rawType);\n            response.close();\n            return t;\n        }\n    }\n\n    private T parseType(Response response, Type type) throws Exception {\n        if (type == null) return null;\n        ResponseBody body = response.body();\n        if (body == null) return null;\n        JsonReader jsonReader = new JsonReader(body.charStream());\n\n        // 泛型格式如下： new JsonCallback<任意JavaBean>(this)\n        T t = Convert.fromJson(jsonReader, type);\n        response.close();\n        return t;\n    }\n\n    private T parseParameterizedType(Response response, ParameterizedType type) throws Exception {\n        if (type == null) return null;\n        ResponseBody body = response.body();\n        if (body == null) return null;\n        JsonReader jsonReader = new JsonReader(body.charStream());\n\n        Type rawType = type.getRawType();                     // 泛型的实际类型\n        Type typeArgument = type.getActualTypeArguments()[0]; // 泛型的参数\n        if (rawType != LzyResponse.class) {\n            // 泛型格式如下： new JsonCallback<外层BaseBean<内层JavaBean>>(this)\n            T t = Convert.fromJson(jsonReader, type);\n            response.close();\n            return t;\n        } else {\n            if (typeArgument == Void.class) {\n                // 泛型格式如下： new JsonCallback<LzyResponse<Void>>(this)\n                SimpleResponse simpleResponse = Convert.fromJson(jsonReader, SimpleResponse.class);\n                response.close();\n                //noinspection unchecked\n                return (T) simpleResponse.toLzyResponse();\n            } else {\n                // 泛型格式如下： new JsonCallback<LzyResponse<内层JavaBean>>(this)\n                LzyResponse lzyResponse = Convert.fromJson(jsonReader, type);\n                response.close();\n                int code = lzyResponse.code;\n                //这里的0是以下意思\n                //一般来说服务器会和客户端约定一个数表示成功，其余的表示失败，这里根据实际情况修改\n                if (code == 0) {\n                    //noinspection unchecked\n                    return (T) lzyResponse;\n                } else if (code == 104) {\n                    throw new IllegalStateException(\"用户授权信息无效\");\n                } else if (code == 105) {\n                    throw new IllegalStateException(\"用户收取信息已过期\");\n                } else {\n                    //直接将服务端的错误信息抛出，onError中可以获取\n                    throw new IllegalStateException(\"错误代码：\" + code + \"，错误信息：\" + lzyResponse.msg);\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "demo/src/main/java/com/lzy/demo/callback/StringDialogCallback.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.demo.callback;\n\nimport android.app.Activity;\nimport android.app.ProgressDialog;\nimport android.view.Window;\n\nimport com.lzy.okgo.callback.StringCallback;\nimport com.lzy.okgo.request.base.Request;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）\n * 版    本：1.0\n * 创建日期：2016/4/8\n * 描    述：我的Github地址  https://github.com/jeasonlzy\n * 修订历史：\n * ================================================\n */\npublic abstract class StringDialogCallback extends StringCallback {\n\n    private ProgressDialog dialog;\n\n    public StringDialogCallback(Activity activity) {\n        dialog = new ProgressDialog(activity);\n        dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);\n        dialog.setCanceledOnTouchOutside(false);\n        dialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);\n        dialog.setMessage(\"请求网络中...\");\n    }\n\n    @Override\n    public void onStart(Request<String, ? extends Request> request) {\n        if (dialog != null && !dialog.isShowing()) {\n            dialog.show();\n        }\n    }\n\n    @Override\n    public void onFinish() {\n        if (dialog != null && dialog.isShowing()) {\n            dialog.dismiss();\n        }\n    }\n}\n"
  },
  {
    "path": "demo/src/main/java/com/lzy/demo/model/ApkModel.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.demo.model;\n\nimport java.io.Serializable;\nimport java.util.Random;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：16/9/11\n * 描    述：\n * 修订历史：\n * ================================================\n */\npublic class ApkModel implements Serializable {\n    private static final long serialVersionUID = 2072893447591548402L;\n\n    public String name;\n    public String url;\n    public String iconUrl;\n    public int priority;\n\n    public ApkModel() {\n        Random random = new Random();\n        priority = random.nextInt(100);\n    }\n}\n"
  },
  {
    "path": "demo/src/main/java/com/lzy/demo/model/GankModel.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.demo.model;\n\nimport java.io.Serializable;\nimport java.util.Date;\nimport java.util.List;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：16/9/1\n * 描    述：\n * 修订历史：\n * ================================================\n */\npublic class GankModel implements Serializable {\n    private static final long serialVersionUID = 6753210234564872868L;\n\n    public String _id;\n    public Date createdAt;\n    public String desc;\n    public List<String> images;\n    public Date publishedAt;\n    public String source;\n    public String type;\n    public String url;\n    public boolean used;\n    public String who;\n}\n"
  },
  {
    "path": "demo/src/main/java/com/lzy/demo/model/GankResponse.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.demo.model;\n\nimport java.io.Serializable;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：16/9/29\n * 描    述：\n * 修订历史：\n * ================================================\n */\npublic class GankResponse<T> implements Serializable {\n    private static final long serialVersionUID = -686453405647539973L;\n\n    public boolean error;\n    public T results;\n}\n"
  },
  {
    "path": "demo/src/main/java/com/lzy/demo/model/ItemModel.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.demo.model;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：2017/6/9\n * 描    述：\n * 修订历史：\n * ================================================\n */\npublic class ItemModel {\n    public String title;\n    public String des;\n    public int type;\n\n    public ItemModel() {\n    }\n\n    public ItemModel(String title, String des) {\n        this.title = title;\n        this.des = des;\n    }\n\n    public ItemModel(String title, String des, int type) {\n        this.title = title;\n        this.des = des;\n        this.type = type;\n    }\n}\n"
  },
  {
    "path": "demo/src/main/java/com/lzy/demo/model/LzyResponse.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.demo.model;\n\nimport java.io.Serializable;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：16/9/28\n * 描    述：\n * 修订历史：\n * ================================================\n */\npublic class LzyResponse<T> implements Serializable {\n\n    private static final long serialVersionUID = 5213230387175987834L;\n\n    public int code;\n    public String msg;\n    public T data;\n\n    @Override\n    public String toString() {\n        return \"LzyResponse{\\n\" +//\n               \"\\tcode=\" + code + \"\\n\" +//\n               \"\\tmsg='\" + msg + \"\\'\\n\" +//\n               \"\\tdata=\" + data + \"\\n\" +//\n               '}';\n    }\n}\n"
  },
  {
    "path": "demo/src/main/java/com/lzy/demo/model/ServerModel.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.demo.model;\n\nimport java.io.Serializable;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）\n * 版    本：1.0\n * 创建日期：2016/4/7\n * 描    述：我的Github地址  https://github.com/jeasonlzy\n * 修订历史：\n * ================================================\n */\npublic class ServerModel implements Serializable {\n    private static final long serialVersionUID = -828322761336296999L;\n\n    public String method;\n    public String ip;\n    public String url;\n    public String des;\n    public String upload;\n    public Author author;\n\n    public class Author implements Serializable {\n        private static final long serialVersionUID = 2701611773813762723L;\n\n        public String name;\n        public String fullname;\n        public String github;\n        public String address;\n        public String qq;\n        public String email;\n        public String des;\n\n        @Override\n        public String toString() {\n            return \"Author{\\n\" +//\n                   \"\\tname='\" + name + \"\\'\\n\" +//\n                   \"\\tfullname='\" + fullname + \"\\'\\n\" +//\n                   \"\\tgithub='\" + github + \"\\'\\n\" +//\n                   \"\\taddress='\" + address + \"\\'\\n\" +//\n                   \"\\tqq='\" + qq + \"\\'\\n\" +//\n                   \"\\temail='\" + email + \"\\'\\n\" +//\n                   \"\\tdes='\" + des + \"\\'\\n\" +//\n                   '}';\n        }\n    }\n\n    @Override\n    public String toString() {\n        return \"ServerModel{\\n\" +//\n               \"\\tmethod='\" + method + \"\\'\\n\" +//\n               \"\\tip='\" + ip + \"\\'\\n\" +//\n               \"\\turl='\" + url + \"\\'\\n\" +//\n               \"\\tdes='\" + des + \"\\'\\n\" +//\n               \"\\tupload='\" + upload + \"\\'\\n\" +//\n               \"\\tauthor=\" + author + \"\\n\" +//\n               '}';\n    }\n}\n"
  },
  {
    "path": "demo/src/main/java/com/lzy/demo/model/SimpleResponse.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.demo.model;\n\nimport java.io.Serializable;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：16/9/28\n * 描    述：\n * 修订历史：\n * ================================================\n */\npublic class SimpleResponse implements Serializable {\n\n    private static final long serialVersionUID = -1477609349345966116L;\n\n    public int code;\n    public String msg;\n\n    public LzyResponse toLzyResponse() {\n        LzyResponse lzyResponse = new LzyResponse();\n        lzyResponse.code = code;\n        lzyResponse.msg = msg;\n        return lzyResponse;\n    }\n}\n"
  },
  {
    "path": "demo/src/main/java/com/lzy/demo/okdownload/DesActivity.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.demo.okdownload;\n\nimport android.os.Bundle;\nimport android.support.v7.widget.Toolbar;\nimport android.text.format.Formatter;\nimport android.widget.Button;\nimport android.widget.ImageView;\nimport android.widget.ProgressBar;\nimport android.widget.TextView;\n\nimport com.lzy.demo.R;\nimport com.lzy.demo.base.BaseActivity;\nimport com.lzy.demo.model.ApkModel;\nimport com.lzy.demo.utils.ApkUtils;\nimport com.lzy.okgo.OkGo;\nimport com.lzy.okgo.model.Progress;\nimport com.lzy.okgo.request.GetRequest;\nimport com.lzy.okserver.OkDownload;\nimport com.lzy.okserver.download.DownloadListener;\nimport com.lzy.okserver.download.DownloadTask;\n\nimport java.io.File;\nimport java.text.NumberFormat;\n\nimport butterknife.Bind;\nimport butterknife.OnClick;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：16/9/11\n * 描    述：\n * 修订历史：\n * ================================================\n */\npublic class DesActivity extends BaseActivity {\n\n    @Bind(R.id.toolbar) Toolbar toolbar;\n    @Bind(R.id.icon) ImageView icon;\n    @Bind(R.id.name) TextView name;\n    @Bind(R.id.downloadSize) TextView downloadSize;\n    @Bind(R.id.tvProgress) TextView tvProgress;\n    @Bind(R.id.netSpeed) TextView netSpeed;\n    @Bind(R.id.pbProgress) ProgressBar pbProgress;\n    @Bind(R.id.start) Button download;\n    @Bind(R.id.remove) Button remove;\n    @Bind(R.id.restart) Button restart;\n\n    private NumberFormat numberFormat;\n    private DownloadTask task;\n    private ApkModel apk;\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.activity_download_details);\n        initToolBar(toolbar, true, \"下载管理\");\n\n        apk = (ApkModel) getIntent().getSerializableExtra(\"apk\");\n        numberFormat = NumberFormat.getPercentInstance();\n        numberFormat.setMinimumFractionDigits(2);\n\n        // 写法一：从内存中获取\n        if (OkDownload.getInstance().hasTask(apk.url)) {\n            task = OkDownload.getInstance().getTask(apk.url)//\n                    .register(new DesListener(\"DesListener\"))//\n                    .register(new LogDownloadListener());\n        }\n\n        //写法二：从数据库中恢复\n//        Progress progress = DownloadManager.getInstance().get(apk.getUrl());\n//        if (progress != null) {\n//            task = OkDownload.restore(progress)//\n//                    .register(new DesListener(\"DesListener\"))//\n//                    .register(new LogDownloadListener());\n//        }\n\n        displayImage(apk.iconUrl, icon);\n        name.setText(apk.name);\n        if (task != null) refreshUi(task.progress);\n    }\n\n    private void refreshUi(Progress progress) {\n        String currentSize = Formatter.formatFileSize(this, progress.currentSize);\n        String totalSize = Formatter.formatFileSize(this, progress.totalSize);\n        downloadSize.setText(currentSize + \"/\" + totalSize);\n        String speed = Formatter.formatFileSize(this, progress.speed);\n        netSpeed.setText(String.format(\"%s/s\", speed));\n        tvProgress.setText(numberFormat.format(progress.fraction));\n        pbProgress.setMax(10000);\n        pbProgress.setProgress((int) (progress.fraction * 10000));\n        switch (progress.status) {\n            case Progress.NONE:\n                download.setText(\"下载\");\n                break;\n            case Progress.LOADING:\n                download.setText(\"暂停\");\n                break;\n            case Progress.PAUSE:\n                download.setText(\"继续\");\n                break;\n            case Progress.WAITING:\n                download.setText(\"等待\");\n                break;\n            case Progress.ERROR:\n                download.setText(\"出错\");\n                break;\n            case Progress.FINISH:\n                if (ApkUtils.isAvailable(this, new File(progress.filePath))) {\n                    download.setText(\"卸载\");\n                } else {\n                    download.setText(\"安装\");\n                }\n                break;\n        }\n    }\n\n    @Override\n    protected void onDestroy() {\n        super.onDestroy();\n        if (task != null) {\n            task.unRegister(\"DesListener\");\n        }\n    }\n\n    @OnClick(R.id.start)\n    public void start() {\n        if (task == null) {\n\n            //这里只是演示，表示请求可以传参，怎么传都行，和okgo使用方法一样\n            GetRequest<File> request = OkGo.<File>get(apk.url)//\n                    .headers(\"aaa\", \"111\")//\n                    .params(\"bbb\", \"222\");\n\n            task = OkDownload.request(apk.url, request)//\n                    .priority(apk.priority)//\n                    .extra1(apk)//\n                    .save()//\n                    .register(new DesListener(\"DesListener\"))//\n                    .register(new LogDownloadListener());\n        }\n        switch (task.progress.status) {\n            case Progress.PAUSE:\n            case Progress.NONE:\n            case Progress.ERROR:\n                task.start();\n                break;\n            case Progress.LOADING:\n                task.pause();\n                break;\n            case Progress.FINISH:\n                File file = new File(task.progress.filePath);\n                if (ApkUtils.isAvailable(this, file)) {\n                    ApkUtils.uninstall(this, ApkUtils.getPackageName(this, file.getAbsolutePath()));\n                } else {\n                    ApkUtils.install(this, file);\n                }\n                break;\n        }\n    }\n\n    @OnClick(R.id.remove)\n    public void remove() {\n        if (task != null) {\n            task.remove();\n            task = null;\n        }\n        downloadSize.setText(\"--M/--M\");\n        netSpeed.setText(\"---/s\");\n        tvProgress.setText(\"--.--%\");\n        pbProgress.setProgress(0);\n        download.setText(\"下载\");\n    }\n\n    @OnClick(R.id.restart)\n    public void restart() {\n        if (task != null) task.restart();\n    }\n\n    private class DesListener extends DownloadListener {\n\n        DesListener(String tag) {\n            super(tag);\n        }\n\n        @Override\n        public void onStart(Progress progress) {\n        }\n\n        @Override\n        public void onProgress(Progress progress) {\n            refreshUi(progress);\n        }\n\n        @Override\n        public void onFinish(File file, Progress progress) {\n        }\n\n        @Override\n        public void onRemove(Progress progress) {\n        }\n\n        @Override\n        public void onError(Progress progress) {\n            Throwable throwable = progress.exception;\n            if (throwable != null) throwable.printStackTrace();\n        }\n    }\n}\n"
  },
  {
    "path": "demo/src/main/java/com/lzy/demo/okdownload/DownloadAdapter.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.demo.okdownload;\n\nimport android.content.Context;\nimport android.support.v7.widget.RecyclerView;\nimport android.text.format.Formatter;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.Button;\nimport android.widget.ImageView;\nimport android.widget.TextView;\nimport android.widget.Toast;\n\nimport com.bumptech.glide.Glide;\nimport com.lzy.demo.R;\nimport com.lzy.demo.model.ApkModel;\nimport com.lzy.demo.ui.NumberProgressBar;\nimport com.lzy.demo.utils.ApkUtils;\nimport com.lzy.okgo.db.DownloadManager;\nimport com.lzy.okgo.model.Progress;\nimport com.lzy.okserver.OkDownload;\nimport com.lzy.okserver.download.DownloadListener;\nimport com.lzy.okserver.download.DownloadTask;\n\nimport java.io.File;\nimport java.text.NumberFormat;\nimport java.util.List;\nimport java.util.Map;\n\nimport butterknife.Bind;\nimport butterknife.ButterKnife;\nimport butterknife.OnClick;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：2017/6/5\n * 描    述：\n * 修订历史：\n * ================================================\n */\npublic class DownloadAdapter extends RecyclerView.Adapter<DownloadAdapter.ViewHolder> {\n\n    public static final int TYPE_ALL = 0;\n    public static final int TYPE_FINISH = 1;\n    public static final int TYPE_ING = 2;\n\n    private List<DownloadTask> values;\n    private NumberFormat numberFormat;\n    private LayoutInflater inflater;\n    private Context context;\n    private int type;\n\n    public DownloadAdapter(Context context) {\n        this.context = context;\n        numberFormat = NumberFormat.getPercentInstance();\n        numberFormat.setMinimumFractionDigits(2);\n        inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);\n    }\n\n    public void updateData(int type) {\n        //这里是将数据库的数据恢复\n        this.type = type;\n        if (type == TYPE_ALL) values = OkDownload.restore(DownloadManager.getInstance().getAll());\n        if (type == TYPE_FINISH) values = OkDownload.restore(DownloadManager.getInstance().getFinished());\n        if (type == TYPE_ING) values = OkDownload.restore(DownloadManager.getInstance().getDownloading());\n        notifyDataSetChanged();\n    }\n\n    @Override\n    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {\n        View view = inflater.inflate(R.layout.item_download_manager, parent, false);\n        return new ViewHolder(view);\n    }\n\n    @Override\n    public void onBindViewHolder(ViewHolder holder, int position) {\n        DownloadTask task = values.get(position);\n        String tag = createTag(task);\n        task.register(new ListDownloadListener(tag, holder))//\n                .register(new LogDownloadListener());\n        holder.setTag(tag);\n        holder.setTask(task);\n        holder.bind();\n        holder.refresh(task.progress);\n    }\n\n    public void unRegister() {\n        Map<String, DownloadTask> taskMap = OkDownload.getInstance().getTaskMap();\n        for (DownloadTask task : taskMap.values()) {\n            task.unRegister(createTag(task));\n        }\n    }\n\n    private String createTag(DownloadTask task) {\n        return type + \"_\" + task.progress.tag;\n    }\n\n    @Override\n    public int getItemCount() {\n        return values == null ? 0 : values.size();\n    }\n\n    public class ViewHolder extends RecyclerView.ViewHolder {\n\n        @Bind(R.id.icon) ImageView icon;\n        @Bind(R.id.name) TextView name;\n        @Bind(R.id.priority) TextView priority;\n        @Bind(R.id.downloadSize) TextView downloadSize;\n        @Bind(R.id.tvProgress) TextView tvProgress;\n        @Bind(R.id.netSpeed) TextView netSpeed;\n        @Bind(R.id.pbProgress) NumberProgressBar pbProgress;\n        @Bind(R.id.start) Button download;\n        private DownloadTask task;\n        private String tag;\n\n        public ViewHolder(View itemView) {\n            super(itemView);\n            ButterKnife.bind(this, itemView);\n        }\n\n        public void setTask(DownloadTask task) {\n            this.task = task;\n        }\n\n        public void bind() {\n            Progress progress = task.progress;\n            ApkModel apk = (ApkModel) progress.extra1;\n            if (apk != null) {\n                Glide.with(context).load(apk.iconUrl).error(R.mipmap.ic_launcher).into(icon);\n                name.setText(apk.name);\n                priority.setText(String.format(\"优先级：%s\", progress.priority));\n            } else {\n                name.setText(progress.fileName);\n            }\n        }\n\n        public void refresh(Progress progress) {\n            String currentSize = Formatter.formatFileSize(context, progress.currentSize);\n            String totalSize = Formatter.formatFileSize(context, progress.totalSize);\n            downloadSize.setText(currentSize + \"/\" + totalSize);\n            priority.setText(String.format(\"优先级：%s\", progress.priority));\n            switch (progress.status) {\n                case Progress.NONE:\n                    netSpeed.setText(\"停止\");\n                    download.setText(\"下载\");\n                    break;\n                case Progress.PAUSE:\n                    netSpeed.setText(\"暂停中\");\n                    download.setText(\"继续\");\n                    break;\n                case Progress.ERROR:\n                    netSpeed.setText(\"下载出错\");\n                    download.setText(\"出错\");\n                    break;\n                case Progress.WAITING:\n                    netSpeed.setText(\"等待中\");\n                    download.setText(\"等待\");\n                    break;\n                case Progress.FINISH:\n                    netSpeed.setText(\"下载完成\");\n                    download.setText(\"完成\");\n                    break;\n                case Progress.LOADING:\n                    String speed = Formatter.formatFileSize(context, progress.speed);\n                    netSpeed.setText(String.format(\"%s/s\", speed));\n                    download.setText(\"暂停\");\n                    break;\n            }\n            tvProgress.setText(numberFormat.format(progress.fraction));\n            pbProgress.setMax(10000);\n            pbProgress.setProgress((int) (progress.fraction * 10000));\n        }\n\n        @OnClick(R.id.start)\n        public void start() {\n            Progress progress = task.progress;\n            switch (progress.status) {\n                case Progress.PAUSE:\n                case Progress.NONE:\n                case Progress.ERROR:\n                    task.start();\n                    break;\n                case Progress.LOADING:\n                    task.pause();\n                    break;\n                case Progress.FINISH:\n                    if (ApkUtils.isAvailable(context, new File(progress.filePath))) {\n                        ApkUtils.uninstall(context, ApkUtils.getPackageName(context, progress.filePath));\n                    } else {\n                        ApkUtils.install(context, new File(progress.filePath));\n                    }\n                    break;\n            }\n            refresh(progress);\n        }\n\n        @OnClick(R.id.remove)\n        public void remove() {\n            task.remove(true);\n            updateData(type);\n        }\n\n        @OnClick(R.id.restart)\n        public void restart() {\n            task.restart();\n        }\n\n        public void setTag(String tag) {\n            this.tag = tag;\n        }\n\n        public String getTag() {\n            return tag;\n        }\n    }\n\n    private class ListDownloadListener extends DownloadListener {\n\n        private ViewHolder holder;\n\n        ListDownloadListener(Object tag, ViewHolder holder) {\n            super(tag);\n            this.holder = holder;\n        }\n\n        @Override\n        public void onStart(Progress progress) {\n        }\n\n        @Override\n        public void onProgress(Progress progress) {\n            if (tag == holder.getTag()) {\n                holder.refresh(progress);\n            }\n        }\n\n        @Override\n        public void onError(Progress progress) {\n            Throwable throwable = progress.exception;\n            if (throwable != null) throwable.printStackTrace();\n        }\n\n        @Override\n        public void onFinish(File file, Progress progress) {\n            Toast.makeText(context, \"下载完成:\" + progress.filePath, Toast.LENGTH_SHORT).show();\n            updateData(type);\n        }\n\n        @Override\n        public void onRemove(Progress progress) {\n        }\n    }\n}\n"
  },
  {
    "path": "demo/src/main/java/com/lzy/demo/okdownload/DownloadAllActivity.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.demo.okdownload;\n\nimport android.os.Bundle;\nimport android.support.v7.widget.LinearLayoutManager;\nimport android.support.v7.widget.RecyclerView;\nimport android.support.v7.widget.Toolbar;\nimport android.view.View;\n\nimport com.lzy.demo.R;\nimport com.lzy.demo.base.BaseActivity;\nimport com.lzy.okserver.OkDownload;\nimport com.lzy.okserver.task.XExecutor;\n\nimport butterknife.Bind;\nimport butterknife.OnClick;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：16/9/11\n * 描    述：\n * 修订历史：\n * ================================================\n */\npublic class DownloadAllActivity extends BaseActivity implements XExecutor.OnAllTaskEndListener {\n\n    @Bind(R.id.toolbar) Toolbar toolbar;\n    @Bind(R.id.recyclerView) RecyclerView recyclerView;\n\n    private DownloadAdapter adapter;\n    private OkDownload okDownload;\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.activity_download_all);\n        initToolBar(toolbar, true, \"所有任务\");\n\n        okDownload = OkDownload.getInstance();\n        adapter = new DownloadAdapter(this);\n        adapter.updateData(DownloadAdapter.TYPE_ALL);\n        recyclerView.setLayoutManager(new LinearLayoutManager(this));\n        recyclerView.setAdapter(adapter);\n\n        okDownload.addOnAllTaskEndListener(this);\n    }\n\n    @Override\n    public void onAllTaskEnd() {\n        showToast(\"所有下载任务已结束\");\n    }\n\n    @Override\n    protected void onDestroy() {\n        super.onDestroy();\n        okDownload.removeOnAllTaskEndListener(this);\n        adapter.unRegister();\n    }\n\n    @Override\n    protected void onResume() {\n        super.onResume();\n        adapter.notifyDataSetChanged();\n    }\n\n    @OnClick(R.id.removeAll)\n    public void removeAll(View view) {\n        okDownload.removeAll();\n        adapter.updateData(DownloadAdapter.TYPE_ALL);\n        adapter.notifyDataSetChanged();\n    }\n\n    @OnClick(R.id.pauseAll)\n    public void pauseAll(View view) {\n        okDownload.pauseAll();\n    }\n\n    @OnClick(R.id.startAll)\n    public void startAll(View view) {\n        okDownload.startAll();\n    }\n}\n"
  },
  {
    "path": "demo/src/main/java/com/lzy/demo/okdownload/DownloadFinishActivity.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.demo.okdownload;\n\nimport android.os.Bundle;\nimport android.support.v7.widget.LinearLayoutManager;\nimport android.support.v7.widget.RecyclerView;\nimport android.support.v7.widget.Toolbar;\nimport android.view.View;\nimport android.widget.Button;\n\nimport com.lzy.demo.R;\nimport com.lzy.demo.base.BaseActivity;\nimport com.lzy.okserver.OkDownload;\nimport com.lzy.okserver.task.XExecutor;\n\nimport butterknife.Bind;\nimport butterknife.OnClick;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：16/9/11\n * 描    述：\n * 修订历史：\n * ================================================\n */\npublic class DownloadFinishActivity extends BaseActivity implements XExecutor.OnAllTaskEndListener {\n\n    private DownloadAdapter adapter;\n    private OkDownload okDownload;\n\n    @Bind(R.id.toolbar) Toolbar toolbar;\n    @Bind(R.id.recyclerView) RecyclerView recyclerView;\n    @Bind(R.id.pauseAll) Button pauseAll;\n    @Bind(R.id.startAll) Button startAll;\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.activity_download_all);\n        initToolBar(toolbar, true, \"已完成任务\");\n\n        pauseAll.setVisibility(View.GONE);\n        startAll.setVisibility(View.GONE);\n\n        okDownload = OkDownload.getInstance();\n        adapter = new DownloadAdapter(this);\n        adapter.updateData(DownloadAdapter.TYPE_FINISH);\n        recyclerView.setLayoutManager(new LinearLayoutManager(this));\n        recyclerView.setAdapter(adapter);\n\n        okDownload.addOnAllTaskEndListener(this);\n    }\n\n    @Override\n    public void onAllTaskEnd() {\n        showToast(\"所有下载任务已结束\");\n    }\n\n    @Override\n    protected void onDestroy() {\n        super.onDestroy();\n        okDownload.removeOnAllTaskEndListener(this);\n        adapter.unRegister();\n    }\n\n    @Override\n    protected void onResume() {\n        super.onResume();\n        adapter.notifyDataSetChanged();\n    }\n\n    @OnClick(R.id.removeAll)\n    public void removeAll(View view) {\n        OkDownload.getInstance().removeAll();\n        adapter.updateData(DownloadAdapter.TYPE_FINISH);\n        adapter.notifyDataSetChanged();\n    }\n}\n"
  },
  {
    "path": "demo/src/main/java/com/lzy/demo/okdownload/DownloadListActivity.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.demo.okdownload;\n\nimport android.Manifest;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.pm.PackageManager;\nimport android.os.Bundle;\nimport android.os.Environment;\nimport android.support.annotation.NonNull;\nimport android.support.v4.app.ActivityCompat;\nimport android.support.v7.widget.DefaultItemAnimator;\nimport android.support.v7.widget.LinearLayoutManager;\nimport android.support.v7.widget.RecyclerView;\nimport android.support.v7.widget.Toolbar;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.Button;\nimport android.widget.ImageView;\nimport android.widget.TextView;\n\nimport com.lzy.demo.R;\nimport com.lzy.demo.base.BaseActivity;\nimport com.lzy.demo.base.BaseRecyclerAdapter;\nimport com.lzy.demo.base.DividerItemDecoration;\nimport com.lzy.demo.model.ApkModel;\nimport com.lzy.okgo.OkGo;\nimport com.lzy.okgo.db.DownloadManager;\nimport com.lzy.okgo.model.Progress;\nimport com.lzy.okgo.request.GetRequest;\nimport com.lzy.okserver.OkDownload;\n\nimport java.io.File;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport butterknife.Bind;\nimport butterknife.ButterKnife;\nimport butterknife.OnClick;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：16/9/11\n * 描    述：\n * 修订历史：\n * ================================================\n */\npublic class DownloadListActivity extends BaseActivity {\n\n    private static final int REQUEST_PERMISSION_STORAGE = 0x01;\n\n    @Bind(R.id.toolbar) Toolbar toolbar;\n    @Bind(R.id.targetFolder) TextView folder;\n    @Bind(R.id.recyclerView) RecyclerView recyclerView;\n\n    private List<ApkModel> apks;\n    private DownloadListAdapter adapter;\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.activity_download_list);\n        initToolBar(toolbar, true, \"开始下载\");\n\n        initData();\n        OkDownload.getInstance().setFolder(Environment.getExternalStorageDirectory().getAbsolutePath() + \"/aaa/\");\n        OkDownload.getInstance().getThreadPool().setCorePoolSize(3);\n\n        folder.setText(String.format(\"下载路径: %s\", OkDownload.getInstance().getFolder()));\n        recyclerView.setLayoutManager(new LinearLayoutManager(this));\n        recyclerView.setItemAnimator(new DefaultItemAnimator());\n        recyclerView.addItemDecoration(new DividerItemDecoration(this, LinearLayoutManager.VERTICAL));\n\n        //从数据库中恢复数据\n        List<Progress> progressList = DownloadManager.getInstance().getAll();\n        OkDownload.restore(progressList);\n        adapter = new DownloadListAdapter(this);\n        recyclerView.setAdapter(adapter);\n\n        checkSDCardPermission();\n    }\n\n    /** 检查SD卡权限 */\n    protected void checkSDCardPermission() {\n        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {\n            ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_PERMISSION_STORAGE);\n        }\n    }\n\n    @Override\n    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {\n        super.onRequestPermissionsResult(requestCode, permissions, grantResults);\n        if (requestCode == REQUEST_PERMISSION_STORAGE) {\n            if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {\n                //获取权限\n            } else {\n                showToast(\"权限被禁止，无法下载文件！\");\n            }\n        }\n    }\n\n    @OnClick(R.id.startAll)\n    public void startAll(View view) {\n        for (ApkModel apk : apks) {\n\n            //这里只是演示，表示请求可以传参，怎么传都行，和okgo使用方法一样\n            GetRequest<File> request = OkGo.<File>get(apk.url)//\n                    .headers(\"aaa\", \"111\")//\n                    .params(\"bbb\", \"222\");\n\n            //这里第一个参数是tag，代表下载任务的唯一标识，传任意字符串都行，需要保证唯一,我这里用url作为了tag\n            OkDownload.request(apk.url, request)//\n                    .priority(apk.priority)//\n                    .extra1(apk)//\n                    .save()//\n                    .register(new LogDownloadListener())//\n                    .start();\n            adapter.notifyDataSetChanged();\n        }\n    }\n\n    @Override\n    protected void onResume() {\n        super.onResume();\n        adapter.notifyDataSetChanged();\n    }\n\n    private class DownloadListAdapter extends BaseRecyclerAdapter<ApkModel, ViewHolder> {\n\n        DownloadListAdapter(Context context) {\n            super(context, apks);\n        }\n\n        @Override\n        public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {\n            View view = inflater.inflate(R.layout.item_download_list, parent, false);\n            return new ViewHolder(view);\n        }\n\n        @Override\n        public void onBindViewHolder(ViewHolder holder, int position) {\n            ApkModel apkModel = mDatas.get(position);\n            holder.bind(apkModel);\n        }\n    }\n\n    public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {\n\n        @Bind(R.id.name) TextView name;\n        @Bind(R.id.priority) TextView priority;\n        @Bind(R.id.icon) ImageView icon;\n        @Bind(R.id.download) Button download;\n\n        private ApkModel apk;\n\n        public ViewHolder(View itemView) {\n            super(itemView);\n            ButterKnife.bind(this, itemView);\n        }\n\n        public void bind(ApkModel apk) {\n            this.apk = apk;\n            if (OkDownload.getInstance().getTask(apk.url) != null) {\n                download.setText(\"已在队列\");\n                download.setEnabled(false);\n            } else {\n                download.setText(\"下载\");\n                download.setEnabled(true);\n            }\n            priority.setText(String.format(\"优先级：%s\", apk.priority));\n            name.setText(apk.name);\n            displayImage(apk.iconUrl, icon);\n            itemView.setOnClickListener(this);\n        }\n\n        @OnClick(R.id.download)\n        public void download() {\n\n            //这里只是演示，表示请求可以传参，怎么传都行，和okgo使用方法一样\n            GetRequest<File> request = OkGo.<File>get(apk.url)//\n                    .headers(\"aaa\", \"111\")//\n                    .params(\"bbb\", \"222\");\n\n            //这里第一个参数是tag，代表下载任务的唯一标识，传任意字符串都行，需要保证唯一,我这里用url作为了tag\n            OkDownload.request(apk.url, request)//\n                    .priority(apk.priority)//\n                    .extra1(apk)//\n                    .save()//\n                    .register(new LogDownloadListener())//\n                    .start();\n            adapter.notifyDataSetChanged();\n        }\n\n        @Override\n        public void onClick(View v) {\n            Intent intent = new Intent(getApplicationContext(), DesActivity.class);\n            intent.putExtra(\"apk\", apk);\n            startActivity(intent);\n        }\n    }\n\n    private void initData() {\n        apks = new ArrayList<>();\n        ApkModel apk1 = new ApkModel();\n        apk1.name = \"爱奇艺\";\n        apk1.iconUrl = \"http://file.market.xiaomi.com/thumbnail/PNG/l114/AppStore/0c10c4c0155c9adf1282af008ed329378d54112ac\";\n        apk1.url = \"http://121.29.10.1/f5.market.mi-img.com/download/AppStore/0b8b552a1df0a8bc417a5afae3a26b2fb1342a909/com.qiyi.video.apk\";\n        apks.add(apk1);\n        ApkModel apk2 = new ApkModel();\n        apk2.name = \"微信\";\n        apk2.iconUrl = \"http://file.market.xiaomi.com/thumbnail/PNG/l114/AppStore/00814b5dad9b54cc804466369c8cb18f23e23823f\";\n        apk2.url = \"http://116.117.158.129/f2.market.xiaomi.com/download/AppStore/04275951df2d94fee0a8210a3b51ae624cc34483a/com.tencent.mm.apk\";\n        apks.add(apk2);\n        ApkModel apk3 = new ApkModel();\n        apk3.name = \"新浪微博\";\n        apk3.iconUrl = \"http://file.market.xiaomi.com/thumbnail/PNG/l114/AppStore/01db44d7f809430661da4fff4d42e703007430f38\";\n        apk3.url = \"http://60.28.125.129/f1.market.xiaomi.com/download/AppStore/0ff41344f280f40c83a1bbf7f14279fb6542ebd2a/com.sina.weibo.apk\";\n        apks.add(apk3);\n        ApkModel apk4 = new ApkModel();\n        apk4.name = \"QQ\";\n        apk4.iconUrl = \"http://file.market.xiaomi.com/thumbnail/PNG/l114/AppStore/072725ca573700292b92e636ec126f51ba4429a50\";\n        apk4.url = \"http://121.29.10.1/f3.market.xiaomi.com/download/AppStore/0ff0604fd770f481927d1edfad35675a3568ba656/com.tencent.mobileqq.apk\";\n        apks.add(apk4);\n        ApkModel apk5 = new ApkModel();\n        apk5.name = \"陌陌\";\n        apk5.iconUrl = \"http://file.market.xiaomi.com/thumbnail/PNG/l114/AppStore/06006948e655c4dd11862d060bd055b4fd2b5c41b\";\n        apk5.url = \"http://121.18.239.1/f4.market.xiaomi.com/download/AppStore/096f34dec955dbde0597f4e701d1406000d432064/com.immomo.momo.apk\";\n        apks.add(apk5);\n        ApkModel apk6 = new ApkModel();\n        apk6.name = \"手机淘宝\";\n        apk6.iconUrl = \"http://file.market.xiaomi.com/thumbnail/PNG/l114/AppStore/017a859792d09d7394108e0a618411675ec43f220\";\n        apk6.url = \"http://121.29.10.1/f3.market.xiaomi.com/download/AppStore/0afc00452eb1a4dc42b20c9351eacacab4692a953/com.taobao.taobao.apk\";\n        apks.add(apk6);\n        ApkModel apk7 = new ApkModel();\n        apk7.name = \"酷狗音乐\";\n        apk7.iconUrl = \"http://file.market.xiaomi.com/thumbnail/PNG/l114/AppStore/0f2f050e21e42f75c7ecca55d01ac4e5e4e40ca8d\";\n        apk7.url = \"http://121.18.239.1/f5.market.xiaomi.com/download/AppStore/053ed49c1545c6eec3e3e23b31568c731f940934f/com.kugou.android.apk\";\n        apks.add(apk7);\n        ApkModel apk8 = new ApkModel();\n        apk8.name = \"网易云音乐\";\n        apk8.iconUrl = \"http://file.market.xiaomi.com/thumbnail/PNG/l114/AppStore/02374548ac39f3b7cdbf5bea4b0535b5d1f432f23\";\n        apk8.url = \"http://121.18.239.1/f4.market.xiaomi.com/download/AppStore/0f458c5661acb492e30b808a2e3e4c8672e6b55e2/com.netease.cloudmusic.apk\";\n        apks.add(apk8);\n        ApkModel apk9 = new ApkModel();\n        apk9.name = \"ofo共享单车\";\n        apk9.iconUrl = \"http://file.market.xiaomi.com/thumbnail/PNG/l114/AppStore/0fe1a5c6092f3d9fa5c4c1e3158e6ff33f6418152\";\n        apk9.url = \"http://60.28.125.1/f4.market.mi-img.com/download/AppStore/06954949fcd48414c16f726620cf2d52200550f56/so.ofo.labofo.apk\";\n        apks.add(apk9);\n        ApkModel apk10 = new ApkModel();\n        apk10.name = \"摩拜单车\";\n        apk10.iconUrl = \"http://file.market.xiaomi.com/thumbnail/PNG/l114/AppStore/0863a058a811148a5174d9784b7be2f1114191f83\";\n        apk10.url = \"http://60.28.125.1/f4.market.xiaomi.com/download/AppStore/00cdeb4865c5a4a7d350fe30b9f812908a569cc8a/com.mobike.mobikeapp.apk\";\n        apks.add(apk10);\n        ApkModel apk11 = new ApkModel();\n        apk11.name = \"贪吃蛇大作战\";\n        apk11.iconUrl = \"http://file.market.xiaomi.com/thumbnail/PNG/l114/AppStore/09f7f5756d9d63bb149b7149b8bdde0769941f09b\";\n        apk11.url = \"http://60.22.46.1/f3.market.xiaomi.com/download/AppStore/0b02f24ffa8334bd21b16bd70ecacdb42374eb9cb/com.wepie.snake.new.mi.apk\";\n        apks.add(apk11);\n        ApkModel apk12 = new ApkModel();\n        apk12.name = \"蘑菇街\";\n        apk12.iconUrl = \"http://file.market.xiaomi.com/thumbnail/PNG/l114/AppStore/0ab53044735e842c421a57954d86a77aea30cc1da\";\n        apk12.url = \"http://121.29.10.1/f5.market.xiaomi.com/download/AppStore/07a6ee4955e364c3f013b14055c37b8e4f6668161/com.mogujie.apk\";\n        apks.add(apk12);\n        ApkModel apk13 = new ApkModel();\n        apk13.name = \"聚美优品\";\n        apk13.iconUrl = \"http://file.market.xiaomi.com/thumbnail/PNG/l114/AppStore/080ed520b76d943e5533017a19bc76d9f554342d0\";\n        apk13.url = \"http://121.29.10.1/f5.market.mi-img.com/download/AppStore/0e70a572cd5fd6a3718941328238d78d71942aee0/com.jm.android.jumei.apk\";\n        apks.add(apk13);\n        ApkModel apk14 = new ApkModel();\n        apk14.name = \"全民K歌\";\n        apk14.iconUrl = \"http://file.market.xiaomi.com/thumbnail/PNG/l114/AppStore/0f1f653261ff8b3a64324097224e40eface432b99\";\n        apk14.url = \"http://60.28.123.129/f4.market.xiaomi.com/download/AppStore/04f515e21146022934085454a1121e11ae34396ae/com.tencent.karaoke.apk\";\n        apks.add(apk14);\n        ApkModel apk15 = new ApkModel();\n        apk15.name = \"书旗小说\";\n        apk15.iconUrl = \"http://file.market.xiaomi.com/thumbnail/PNG/l114/AppStore/0c9ce345aa2734b1202ddf32b6545d9407b18ba0b\";\n        apk15.url = \"http://60.28.125.129/f5.market.mi-img.com/download/AppStore/02d9c4035b248753314f46600cf7347a306426dc1/com.shuqi.controller.apk\";\n        apks.add(apk15);\n    }\n}\n"
  },
  {
    "path": "demo/src/main/java/com/lzy/demo/okdownload/DownloadingActivity.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.demo.okdownload;\n\nimport android.os.Bundle;\nimport android.support.v7.widget.LinearLayoutManager;\nimport android.support.v7.widget.RecyclerView;\nimport android.support.v7.widget.Toolbar;\nimport android.view.View;\n\nimport com.lzy.demo.R;\nimport com.lzy.demo.base.BaseActivity;\nimport com.lzy.okserver.OkDownload;\nimport com.lzy.okserver.task.XExecutor;\n\nimport butterknife.Bind;\nimport butterknife.OnClick;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：16/9/11\n * 描    述：\n * 修订历史：\n * ================================================\n */\npublic class DownloadingActivity extends BaseActivity implements XExecutor.OnAllTaskEndListener {\n\n    private DownloadAdapter adapter;\n    private OkDownload okDownload;\n\n    @Bind(R.id.toolbar) Toolbar toolbar;\n    @Bind(R.id.recyclerView) RecyclerView recyclerView;\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.activity_download_all);\n        initToolBar(toolbar, true, \"下载中任务\");\n\n        okDownload = OkDownload.getInstance();\n        adapter = new DownloadAdapter(this);\n        adapter.updateData(DownloadAdapter.TYPE_ING);\n        recyclerView.setLayoutManager(new LinearLayoutManager(this));\n        recyclerView.setAdapter(adapter);\n\n        okDownload.addOnAllTaskEndListener(this);\n    }\n\n    @Override\n    public void onAllTaskEnd() {\n        showToast(\"所有下载任务已结束\");\n    }\n\n    @Override\n    protected void onDestroy() {\n        super.onDestroy();\n        okDownload.removeOnAllTaskEndListener(this);\n        adapter.unRegister();\n    }\n\n    @Override\n    protected void onResume() {\n        super.onResume();\n        adapter.notifyDataSetChanged();\n    }\n\n    @OnClick(R.id.removeAll)\n    public void removeAll(View view) {\n        okDownload.removeAll();\n        adapter.updateData(DownloadAdapter.TYPE_ING);\n        adapter.notifyDataSetChanged();\n    }\n\n    @OnClick(R.id.pauseAll)\n    public void pauseAll(View view) {\n        okDownload.pauseAll();\n    }\n\n    @OnClick(R.id.startAll)\n    public void startAll(View view) {\n        okDownload.startAll();\n    }\n}\n"
  },
  {
    "path": "demo/src/main/java/com/lzy/demo/okdownload/LogDownloadListener.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.demo.okdownload;\n\nimport com.lzy.okgo.model.Progress;\nimport com.lzy.okserver.download.DownloadListener;\n\nimport java.io.File;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：2017/6/7\n * 描    述：\n * 修订历史：\n * ================================================\n */\npublic class LogDownloadListener extends DownloadListener {\n\n    public LogDownloadListener() {\n        super(\"LogDownloadListener\");\n    }\n\n    @Override\n    public void onStart(Progress progress) {\n        System.out.println(\"onStart: \" + progress);\n    }\n\n    @Override\n    public void onProgress(Progress progress) {\n        System.out.println(\"onProgress: \" + progress);\n    }\n\n    @Override\n    public void onError(Progress progress) {\n        System.out.println(\"onError: \" + progress);\n        progress.exception.printStackTrace();\n    }\n\n    @Override\n    public void onFinish(File file, Progress progress) {\n        System.out.println(\"onFinish: \" + progress);\n    }\n\n    @Override\n    public void onRemove(Progress progress) {\n        System.out.println(\"onRemove: \" + progress);\n    }\n}\n"
  },
  {
    "path": "demo/src/main/java/com/lzy/demo/okdownload/OkDownloadFragment.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.demo.okdownload;\n\nimport android.content.Intent;\n\nimport com.lzy.demo.base.MainFragment;\nimport com.lzy.demo.model.ItemModel;\n\nimport java.util.List;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：2017/6/9\n * 描    述：\n * 修订历史：\n * ================================================\n */\npublic class OkDownloadFragment extends MainFragment {\n\n    @Override\n    public void fillData(List<ItemModel> items) {\n        items.add(new ItemModel(\"开始下载\",//\n                                \"1. 这个属于OkServer依赖中的功能,并不属于OkGo\\n\" +//\n                                \"2. 支持断点下载和状态管理\\n\" +//\n                                \"3. 支持自定义下载任务优先级\\n\" +//\n                                \"4. 支持链试调用\\n\" +//\n                                \"5. 最多支持扩展3个额外数据\\n\" +//\n                                \"6. 支持同时指定多个下载目录\"));\n\n        items.add(new ItemModel(\"所有任务\",//\n                                \"1. 每个任务支持暂停，继续，重新下载，删除等操作\\n\" +//\n                                \"2. 支持全部暂停，全部开始，全部删除\\n\" +//\n                                \"3. 支持全局下载任务监听\\n\" +//\n                                \"4. 支持一个任务多个监听\\n\" +//\n                                \"5. 支持按下载中列表和下载完成列表筛选\"));\n\n        items.add(new ItemModel(\"下载中任务\",//\n                                \"1. 每个任务支持暂停，继续，重新下载，删除等操作\\n\" +//\n                                \"2. 支持全部暂停，全部开始，全部删除\\n\" +//\n                                \"3. 支持全局下载任务监听\\n\" +//\n                                \"4. 支持一个任务多个监听\\n\" +//\n                                \"5. 支持按下载中列表和下载完成列表筛选\"));\n\n        items.add(new ItemModel(\"已完成任务\",//\n                                \"1. 每个任务支持暂停，继续，重新下载，删除等操作\\n\" +//\n                                \"2. 支持全部暂停，全部开始，全部删除\\n\" +//\n                                \"3. 支持全局下载任务监听\\n\" +//\n                                \"4. 支持一个任务多个监听\\n\" +//\n                                \"5. 支持按下载中列表和下载完成列表筛选\"));\n\n    }\n\n    @Override\n    public void onItemClick(int position) {\n        if (position == 0) startActivity(new Intent(context, DownloadListActivity.class));\n        if (position == 1) startActivity(new Intent(context, DownloadAllActivity.class));\n        if (position == 2) startActivity(new Intent(context, DownloadingActivity.class));\n        if (position == 3) startActivity(new Intent(context, DownloadFinishActivity.class));\n    }\n}\n"
  },
  {
    "path": "demo/src/main/java/com/lzy/demo/okgo/BitmapRequestActivity.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.demo.okgo;\n\nimport android.graphics.Bitmap;\nimport android.os.Bundle;\nimport android.view.View;\nimport android.widget.ImageView;\n\nimport com.lzy.demo.R;\nimport com.lzy.demo.base.BaseDetailActivity;\nimport com.lzy.demo.callback.BitmapDialogCallback;\nimport com.lzy.demo.utils.Urls;\nimport com.lzy.okgo.OkGo;\nimport com.lzy.okgo.model.Response;\n\nimport butterknife.Bind;\nimport butterknife.ButterKnife;\nimport butterknife.OnClick;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：16/9/11\n * 描    述：\n * 修订历史：\n * ================================================\n */\npublic class BitmapRequestActivity extends BaseDetailActivity {\n\n    @Bind(R.id.imageView) ImageView imageView;\n\n    @Override\n    protected void onActivityCreate(Bundle savedInstanceState) {\n        setContentView(R.layout.activity_bitmap_request);\n        ButterKnife.bind(this);\n        setTitle(\"请求图片\");\n    }\n\n    @Override\n    protected void onDestroy() {\n        super.onDestroy();\n        //Activity销毁时，取消网络请求\n        OkGo.getInstance().cancelTag(this);\n    }\n\n    @OnClick(R.id.requestImage)\n    public void requestJson(View view) {\n        OkGo.<Bitmap>get(Urls.URL_IMAGE)//\n                .tag(this)//\n                .headers(\"header1\", \"headerValue1\")//\n                .params(\"param1\", \"paramValue1\")//\n                .execute(new BitmapDialogCallback(this) {\n                    @Override\n                    public void onSuccess(Response<Bitmap> response) {\n                        handleResponse(response);\n                        imageView.setImageBitmap(response.body());\n                    }\n\n                    @Override\n                    public void onError(Response<Bitmap> response) {\n                        handleError(response);\n                    }\n                });\n    }\n}\n"
  },
  {
    "path": "demo/src/main/java/com/lzy/demo/okgo/CacheActivity.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.demo.okgo;\n\nimport android.app.Activity;\nimport android.app.AlertDialog;\nimport android.os.Bundle;\nimport android.view.View;\n\nimport com.lzy.demo.R;\nimport com.lzy.demo.base.BaseDetailActivity;\nimport com.lzy.demo.callback.DialogCallback;\nimport com.lzy.demo.model.LzyResponse;\nimport com.lzy.demo.model.ServerModel;\nimport com.lzy.demo.utils.Urls;\nimport com.lzy.okgo.OkGo;\nimport com.lzy.okgo.cache.CacheEntity;\nimport com.lzy.okgo.cache.CacheMode;\nimport com.lzy.okgo.db.CacheManager;\nimport com.lzy.okgo.model.Response;\n\nimport java.util.List;\n\nimport butterknife.ButterKnife;\nimport butterknife.OnClick;\nimport okhttp3.Call;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：16/9/11\n * 描    述：\n * 修订历史：\n * ================================================\n */\npublic class CacheActivity extends BaseDetailActivity {\n\n    @Override\n    protected void onActivityCreate(Bundle savedInstanceState) {\n        setContentView(R.layout.activity_cache);\n        ButterKnife.bind(this);\n        setTitle(\"网络缓存基本用法\");\n    }\n\n    @Override\n    protected void onDestroy() {\n        super.onDestroy();\n        //Activity销毁时，取消网络请求\n        OkGo.getInstance().cancelTag(this);\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    @OnClick(R.id.getAll)\n    public void getAll(View view) {\n        // 获取所有的缓存，但是一般每个缓存的泛型都不一样，所以缓存的泛型使用 ？\n        List<CacheEntity<?>> all = CacheManager.getInstance().getAll();\n        StringBuilder sb = new StringBuilder();\n        sb.append(\"共\" + all.size() + \"条缓存：\").append(\"\\n\\n\");\n        for (int i = 0; i < all.size(); i++) {\n            CacheEntity<?> cacheEntity = all.get(i);\n            sb.append(\"第\" + (i + 1) + \"条缓存：\").append(\"\\n\").append(cacheEntity).append(\"\\n\\n\");\n        }\n        AlertDialog.Builder builder = new AlertDialog.Builder(this);\n        builder.setTitle(\"所有缓存显示\").setMessage(sb.toString()).show();\n    }\n\n    @OnClick(R.id.clear)\n    public void clear(View view) {\n        boolean clear = CacheManager.getInstance().clear();\n        AlertDialog.Builder builder = new AlertDialog.Builder(this);\n        builder.setTitle(\"清除缓存\").setMessage(\"是否清除成功：\" + clear).show();\n    }\n\n    @OnClick(R.id.no_cache)\n    public void no_cache(View view) {\n        OkGo.<LzyResponse<ServerModel>>get(Urls.URL_CACHE)//\n                .tag(this)//\n                .cacheMode(CacheMode.NO_CACHE)//\n                .cacheKey(\"no_cache\")   //对于无缓存模式,该参数无效\n                .cacheTime(5000)        //对于无缓存模式,该时间无效\n                .headers(\"header1\", \"headerValue1\")//\n                .params(\"param1\", \"paramValue1\")//\n                .execute(new CacheCallBack(this));\n    }\n\n    @OnClick(R.id.cache_default)\n    public void cache_default(View view) {\n        OkGo.<LzyResponse<ServerModel>>get(Urls.URL_CACHE)//\n                .tag(this)//\n                .cacheMode(CacheMode.DEFAULT)//\n                .cacheKey(\"cache_default\")//\n                .cacheTime(5000)//对于默认的缓存模式,该时间无效,依靠的是服务端对304缓存的控制\n                .headers(\"header1\", \"headerValue1\")//\n                .params(\"param1\", \"paramValue1\")//\n                .execute(new CacheCallBack(this));\n    }\n\n    @OnClick(R.id.request_failed_read_cache)\n    public void request_failed_read_cache(View view) {\n        OkGo.<LzyResponse<ServerModel>>get(Urls.URL_CACHE)//\n                .tag(this)//\n                .cacheMode(CacheMode.REQUEST_FAILED_READ_CACHE)//\n                .cacheKey(\"request_failed_read_cache\")//\n                .cacheTime(5000)            // 单位毫秒.5秒后过期\n                .headers(\"header1\", \"headerValue1\")//\n                .params(\"param1\", \"paramValue1\")//\n                .execute(new CacheCallBack(this));\n    }\n\n    @OnClick(R.id.if_none_cache_request)\n    public void if_none_cache_request(View view) {\n        OkGo.<LzyResponse<ServerModel>>get(Urls.URL_CACHE)//\n                .tag(this)//\n                .cacheMode(CacheMode.IF_NONE_CACHE_REQUEST)//\n                .cacheKey(\"if_none_cache_request\")//\n                .cacheTime(5000)            // 单位毫秒.5秒后过期\n                .headers(\"header1\", \"headerValue1\")//\n                .params(\"param1\", \"paramValue1\")//\n                .execute(new CacheCallBack(this));\n    }\n\n    @OnClick(R.id.first_cache_then_request)\n    public void first_cache_then_request(View view) {\n        OkGo.<LzyResponse<ServerModel>>get(Urls.URL_CACHE)//\n                .tag(this)//\n                .cacheMode(CacheMode.FIRST_CACHE_THEN_REQUEST)//\n                .cacheKey(\"first_cache_then_request\")//\n                .cacheTime(5000)            // 单位毫秒.5秒后过期\n                .headers(\"header1\", \"headerValue1\")//\n                .params(\"param1\", \"paramValue1\")//\n                .execute(new CacheCallBack(this));\n    }\n\n    private class CacheCallBack extends DialogCallback<LzyResponse<ServerModel>> {\n\n        CacheCallBack(Activity activity) {\n            super(activity);\n        }\n\n        @Override\n        public void onSuccess(Response<LzyResponse<ServerModel>> response) {\n            handleResponse(response);\n            Call call = response.getRawCall();\n            requestState.setText(\"请求成功  是否来自缓存：false  请求方式：\" + call.request().method() + \"\\n\" + \"url：\" + call.request().url());\n        }\n\n        @Override\n        public void onCacheSuccess(Response<LzyResponse<ServerModel>> response) {\n            handleResponse(response);\n            Call call = response.getRawCall();\n            requestState.setText(\"请求成功  是否来自缓存：true  请求方式：\" + call.request().method() + \"\\n\" + \"url：\" + call.request().url());\n        }\n\n        @Override\n        public void onError(Response<LzyResponse<ServerModel>> response) {\n            handleError(response);\n            Call call = response.getRawCall();\n            requestState.setText(\"请求失败  是否来自缓存：false  请求方式：\" + call.request().method() + \"\\n\" + \"url：\" + call.request().url());\n        }\n    }\n}\n"
  },
  {
    "path": "demo/src/main/java/com/lzy/demo/okgo/CommonActivity.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.demo.okgo;\n\nimport android.content.Intent;\nimport android.os.Bundle;\nimport android.support.v7.widget.DefaultItemAnimator;\nimport android.support.v7.widget.LinearLayoutManager;\nimport android.support.v7.widget.RecyclerView;\nimport android.support.v7.widget.Toolbar;\nimport android.view.View;\n\nimport com.chad.library.adapter.base.BaseQuickAdapter;\nimport com.chad.library.adapter.base.BaseViewHolder;\nimport com.lzy.demo.R;\nimport com.lzy.demo.base.BaseActivity;\nimport com.lzy.demo.base.DividerItemDecoration;\nimport com.lzy.demo.model.ItemModel;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport butterknife.Bind;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：16/9/11\n * 描    述：\n * 修订历史：\n * ================================================\n */\npublic class CommonActivity extends BaseActivity {\n\n    @Bind(R.id.toolbar) Toolbar toolbar;\n    @Bind(R.id.recyclerView) RecyclerView recyclerView;\n    private List<ItemModel> data;\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.activity_recycler);\n        initToolBar(toolbar, true, \"OkGo功能介绍\");\n\n        initData();\n\n        recyclerView.setLayoutManager(new LinearLayoutManager(this));\n        recyclerView.setItemAnimator(new DefaultItemAnimator());\n        recyclerView.addItemDecoration(new DividerItemDecoration(this, LinearLayoutManager.VERTICAL));\n        recyclerView.setAdapter(new MainAdapter(data));\n    }\n\n    private void initData() {\n        data = new ArrayList<>();\n        data.add(new ItemModel(\"请求方法演示\", \"目前支持 GET，HEAD，OPTIONS，POST，PUT，DELETE, PATCH, TRACE\"));\n        data.add(new ItemModel(\"请求图片\", \"请求服务器返回bitmap对象\"));\n        data.add(new ItemModel(\"普通上传数据\", \"可以向服务器上传任意类型的文本数据，包括 String，JSONObject，JSONArray，byte[]，文件等\"));\n        data.add(new ItemModel(\"网络缓存基本用法\", \"默认提供了四种缓存模式，根据需要选择使用\"));\n        data.add(new ItemModel(\"支持https请求\", \"支持 cer,bks 证书，支持双向认证\"));\n        data.add(new ItemModel(\"cookie管理与session保持\", \"支持cookie的自动管理，也支持自己手动管理cookie，自动session保持\"));\n        data.add(new ItemModel(\"同步请求\", \"允许直接返回Response对象，会阻塞主线程，需要自行开启子线程\"));\n        data.add(new ItemModel(\"301重定向\", \"支持301重定向请求\"));\n        data.add(new ItemModel(\"测试页面\", \"用于测试特殊情况下的网络连接,可忽略\"));\n    }\n\n    private class MainAdapter extends BaseQuickAdapter<ItemModel> {\n\n        MainAdapter(List<ItemModel> data) {\n            super(R.layout.item_main_list, data);\n        }\n\n        @Override\n        protected void convert(final BaseViewHolder baseViewHolder, ItemModel itemModel) {\n            baseViewHolder.setText(R.id.title, itemModel.title);\n            baseViewHolder.setText(R.id.des, itemModel.des);\n            baseViewHolder.getConvertView().setOnClickListener(new View.OnClickListener() {\n                @Override\n                public void onClick(View v) {\n                    int position = baseViewHolder.getAdapterPosition();\n                    if (position == 0) startActivity(new Intent(CommonActivity.this, MethodActivity.class));\n                    if (position == 1) startActivity(new Intent(CommonActivity.this, BitmapRequestActivity.class));\n                    if (position == 2) startActivity(new Intent(CommonActivity.this, UpActivity.class));\n                    if (position == 3) startActivity(new Intent(CommonActivity.this, CacheActivity.class));\n                    if (position == 4) startActivity(new Intent(CommonActivity.this, HttpsActivity.class));\n                    if (position == 5) startActivity(new Intent(CommonActivity.this, CookieActivity.class));\n                    if (position == 6) startActivity(new Intent(CommonActivity.this, SyncActivity.class));\n                    if (position == 7) startActivity(new Intent(CommonActivity.this, RedirectActivity.class));\n                    if (position == 8) startActivity(new Intent(CommonActivity.this, TestActivity.class));\n                }\n            });\n        }\n    }\n}\n"
  },
  {
    "path": "demo/src/main/java/com/lzy/demo/okgo/CookieActivity.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.demo.okgo;\n\nimport android.os.Bundle;\nimport android.view.View;\n\nimport com.lzy.demo.R;\nimport com.lzy.demo.base.BaseDetailActivity;\nimport com.lzy.demo.callback.StringDialogCallback;\nimport com.lzy.demo.utils.Urls;\nimport com.lzy.okgo.OkGo;\nimport com.lzy.okgo.cookie.store.CookieStore;\nimport com.lzy.okgo.model.Response;\n\nimport java.util.List;\n\nimport butterknife.ButterKnife;\nimport butterknife.OnClick;\nimport okhttp3.Cookie;\nimport okhttp3.HttpUrl;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：16/9/11\n * 描    述：\n * 修订历史：\n * ================================================\n */\npublic class CookieActivity extends BaseDetailActivity {\n\n    @Override\n    protected void onActivityCreate(Bundle savedInstanceState) {\n        setContentView(R.layout.activity_cookie);\n        ButterKnife.bind(this);\n        setTitle(\"cookie管理与session保持\");\n    }\n\n    @Override\n    protected void onDestroy() {\n        super.onDestroy();\n        //Activity销毁时，取消网络请求\n        OkGo.getInstance().cancelTag(this);\n    }\n\n    @OnClick(R.id.getCookie)\n    public void getCookie(View view) {\n        //一般手动取出cookie的目的只是交给 webview 等等，非必要情况不要自己操作\n        CookieStore cookieStore = OkGo.getInstance().getCookieJar().getCookieStore();\n        HttpUrl httpUrl = HttpUrl.parse(Urls.URL_METHOD);\n        List<Cookie> cookies = cookieStore.getCookie(httpUrl);\n        showToast(httpUrl.host() + \"对应的cookie如下：\" + cookies.toString());\n    }\n\n    @OnClick(R.id.getAllCookie)\n    public void getAllCookie(View view) {\n        //一般手动取出cookie的目的只是交给 webview 等等，非必要情况不要自己操作\n        CookieStore cookieStore = OkGo.getInstance().getCookieJar().getCookieStore();\n        List<Cookie> allCookie = cookieStore.getAllCookie();\n        showToast(\"所有cookie如下：\" + allCookie.toString());\n    }\n\n    @OnClick(R.id.addCookie)\n    public void addCookie(View view) {\n\n        HttpUrl httpUrl = HttpUrl.parse(Urls.URL_METHOD);\n        Cookie.Builder builder = new Cookie.Builder();\n        Cookie cookie = builder.name(\"myCookieKey1\").value(\"myCookieValue1\").domain(httpUrl.host()).build();\n        CookieStore cookieStore = OkGo.getInstance().getCookieJar().getCookieStore();\n        cookieStore.saveCookie(httpUrl, cookie);\n\n        showToast(\"详细添加cookie的代码，请看demo的代码\");\n\n        OkGo.<String>post(Urls.URL_TEXT_UPLOAD)//\n                .tag(this)//\n                .execute(new StringDialogCallback(this) {\n                    @Override\n                    public void onSuccess(Response<String> response) {\n                        handleResponse(response);\n                    }\n\n                    @Override\n                    public void onError(Response<String> response) {\n                        handleError(response);\n                    }\n                });\n    }\n\n    @OnClick(R.id.removeCookie)\n    public void removeCookie(View view) {\n        HttpUrl httpUrl = HttpUrl.parse(Urls.URL_METHOD);\n        CookieStore cookieStore = OkGo.getInstance().getCookieJar().getCookieStore();\n        cookieStore.removeCookie(httpUrl);\n\n        showToast(\"详细移除cookie的代码，请看demo的代码\");\n    }\n\n    @OnClick(R.id.updateCookie)\n    public void updateCookie(View view) {\n        showToast(\"暂时未实现，可以先移除再添加，效果一样\");\n    }\n}\n"
  },
  {
    "path": "demo/src/main/java/com/lzy/demo/okgo/FormUploadActivity.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.demo.okgo;\n\nimport android.content.Intent;\nimport android.os.Bundle;\nimport android.text.format.Formatter;\nimport android.view.View;\nimport android.widget.Button;\nimport android.widget.TextView;\nimport android.widget.Toast;\n\nimport com.lzy.demo.R;\nimport com.lzy.demo.base.BaseDetailActivity;\nimport com.lzy.demo.callback.JsonCallback;\nimport com.lzy.demo.model.LzyResponse;\nimport com.lzy.demo.model.ServerModel;\nimport com.lzy.demo.ui.NumberProgressBar;\nimport com.lzy.demo.utils.GlideImageLoader;\nimport com.lzy.demo.utils.Urls;\nimport com.lzy.imagepicker.ImagePicker;\nimport com.lzy.imagepicker.bean.ImageItem;\nimport com.lzy.imagepicker.ui.ImageGridActivity;\nimport com.lzy.okgo.OkGo;\nimport com.lzy.okgo.model.Progress;\nimport com.lzy.okgo.model.Response;\nimport com.lzy.okgo.request.base.Request;\n\nimport java.io.File;\nimport java.text.NumberFormat;\nimport java.util.ArrayList;\n\nimport butterknife.Bind;\nimport butterknife.ButterKnife;\nimport butterknife.OnClick;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：16/9/11\n * 描    述：\n * 修订历史：\n * ================================================\n */\npublic class FormUploadActivity extends BaseDetailActivity {\n\n    @Bind(R.id.formUpload) Button btnFormUpload;\n    @Bind(R.id.downloadSize) TextView tvDownloadSize;\n    @Bind(R.id.tvProgress) TextView tvProgress;\n    @Bind(R.id.netSpeed) TextView tvNetSpeed;\n    @Bind(R.id.pbProgress) NumberProgressBar pbProgress;\n    @Bind(R.id.images) TextView tvImages;\n\n    private ArrayList<ImageItem> imageItems;\n    private NumberFormat numberFormat;\n\n    @Override\n    protected void onActivityCreate(Bundle savedInstanceState) {\n        setContentView(R.layout.activity_form_upload);\n        ButterKnife.bind(this);\n        setTitle(\"文件上传\");\n\n        numberFormat = NumberFormat.getPercentInstance();\n        numberFormat.setMinimumFractionDigits(2);\n    }\n\n    @Override\n    protected void onDestroy() {\n        super.onDestroy();\n        //Activity销毁时，取消网络请求\n        OkGo.getInstance().cancelTag(this);\n    }\n\n    @OnClick(R.id.selectImage)\n    public void selectImage(View view) {\n        ImagePicker imagePicker = ImagePicker.getInstance();\n        imagePicker.setImageLoader(new GlideImageLoader());\n        imagePicker.setMultiMode(true);   //多选\n        imagePicker.setShowCamera(true);  //显示拍照按钮\n        imagePicker.setSelectLimit(9);    //最多选择9张\n        imagePicker.setCrop(false);       //不进行裁剪\n        Intent intent = new Intent(this, ImageGridActivity.class);\n        startActivityForResult(intent, 100);\n    }\n\n    @Override\n    public void onActivityResult(int requestCode, int resultCode, Intent data) {\n        super.onActivityResult(requestCode, resultCode, data);\n        if (resultCode == ImagePicker.RESULT_CODE_ITEMS) {\n            if (data != null && requestCode == 100) {\n                imageItems = (ArrayList<ImageItem>) data.getSerializableExtra(ImagePicker.EXTRA_RESULT_ITEMS);\n                if (imageItems != null && imageItems.size() > 0) {\n                    StringBuilder sb = new StringBuilder();\n                    for (int i = 0; i < imageItems.size(); i++) {\n                        if (i == imageItems.size() - 1) sb.append(\"图片\").append(i + 1).append(\" ： \").append(imageItems.get(i).path);\n                        else sb.append(\"图片\").append(i + 1).append(\" ： \").append(imageItems.get(i).path).append(\"\\n\");\n                    }\n                    tvImages.setText(sb.toString());\n                } else {\n                    tvImages.setText(\"--\");\n                }\n            } else {\n                Toast.makeText(this, \"没有选择图片\", Toast.LENGTH_SHORT).show();\n                tvImages.setText(\"--\");\n            }\n        }\n    }\n\n    @OnClick(R.id.formUpload)\n    public void formUpload(View view) {\n        ArrayList<File> files = new ArrayList<>();\n        if (imageItems != null && imageItems.size() > 0) {\n            for (int i = 0; i < imageItems.size(); i++) {\n                files.add(new File(imageItems.get(i).path));\n            }\n        }\n        //拼接参数\n        OkGo.<LzyResponse<ServerModel>>post(Urls.URL_FORM_UPLOAD)//\n                .tag(this)//\n                .headers(\"header1\", \"headerValue1\")//\n                .headers(\"header2\", \"headerValue2\")//\n                .params(\"param1\", \"paramValue1\")//\n                .params(\"param2\", \"paramValue2\")//\n//                .params(\"file1\",new File(\"文件路径\"))   //这种方式为一个key，对应一个文件\n//                .params(\"file2\",new File(\"文件路径\"))\n//                .params(\"file3\",new File(\"文件路径\"))\n                .addFileParams(\"file\", files)           // 这种方式为同一个key，上传多个文件\n                .execute(new JsonCallback<LzyResponse<ServerModel>>() {\n                    @Override\n                    public void onStart(Request<LzyResponse<ServerModel>, ? extends Request> request) {\n                        btnFormUpload.setText(\"正在上传中...\");\n                    }\n\n                    @Override\n                    public void onSuccess(Response<LzyResponse<ServerModel>> response) {\n                        handleResponse(response);\n                        btnFormUpload.setText(\"上传完成\");\n                    }\n\n                    @Override\n                    public void onError(Response<LzyResponse<ServerModel>> response) {\n                        handleError(response);\n                        btnFormUpload.setText(\"上传出错\");\n                    }\n\n                    @Override\n                    public void uploadProgress(Progress progress) {\n                        System.out.println(\"uploadProgress: \" + progress);\n\n                        String downloadLength = Formatter.formatFileSize(getApplicationContext(), progress.currentSize);\n                        String totalLength = Formatter.formatFileSize(getApplicationContext(), progress.totalSize);\n                        tvDownloadSize.setText(downloadLength + \"/\" + totalLength);\n                        String speed = Formatter.formatFileSize(getApplicationContext(), progress.speed);\n                        tvNetSpeed.setText(String.format(\"%s/s\", speed));\n                        tvProgress.setText(numberFormat.format(progress.fraction));\n                        pbProgress.setMax(10000);\n                        pbProgress.setProgress((int) (progress.fraction * 10000));\n                    }\n                });\n    }\n}\n"
  },
  {
    "path": "demo/src/main/java/com/lzy/demo/okgo/HttpsActivity.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.demo.okgo;\n\nimport android.os.Bundle;\nimport android.view.View;\n\nimport com.lzy.demo.R;\nimport com.lzy.demo.base.BaseDetailActivity;\nimport com.lzy.demo.callback.StringDialogCallback;\nimport com.lzy.okgo.OkGo;\nimport com.lzy.okgo.model.Response;\n\nimport butterknife.ButterKnife;\nimport butterknife.OnClick;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：16/9/11\n * 描    述：\n * 修订历史：\n * ================================================\n */\npublic class HttpsActivity extends BaseDetailActivity {\n\n    private static final String CER_12306 = \"-----BEGIN CERTIFICATE-----\\n\" +                                                  //\n                                            \"MIICmjCCAgOgAwIBAgIIbyZr5/jKH6QwDQYJKoZIhvcNAQEFBQAwRzELMAkGA1UEBhMCQ04xKTAn\\n\" + //\n                                            \"BgNVBAoTIFNpbm9yYWlsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MQ0wCwYDVQQDEwRTUkNBMB4X\\n\" + //\n                                            \"DTA5MDUyNTA2NTYwMFoXDTI5MDUyMDA2NTYwMFowRzELMAkGA1UEBhMCQ04xKTAnBgNVBAoTIFNp\\n\" + //\n                                            \"bm9yYWlsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MQ0wCwYDVQQDEwRTUkNBMIGfMA0GCSqGSIb3\\n\" + //\n                                            \"DQEBAQUAA4GNADCBiQKBgQDMpbNeb34p0GvLkZ6t72/OOba4mX2K/eZRWFfnuk8e5jKDH+9BgCb2\\n\" + //\n                                            \"9bSotqPqTbxXWPxIOz8EjyUO3bfR5pQ8ovNTOlks2rS5BdMhoi4sUjCKi5ELiqtyww/XgY5iFqv6\\n\" + //\n                                            \"D4Pw9QvOUcdRVSbPWo1DwMmH75It6pk/rARIFHEjWwIDAQABo4GOMIGLMB8GA1UdIwQYMBaAFHle\\n\" + //\n                                            \"tne34lKDQ+3HUYhMY4UsAENYMAwGA1UdEwQFMAMBAf8wLgYDVR0fBCcwJTAjoCGgH4YdaHR0cDov\\n\" + //\n                                            \"LzE5Mi4xNjguOS4xNDkvY3JsMS5jcmwwCwYDVR0PBAQDAgH+MB0GA1UdDgQWBBR5XrZ3t+JSg0Pt\\n\" + //\n                                            \"x1GITGOFLABDWDANBgkqhkiG9w0BAQUFAAOBgQDGrAm2U/of1LbOnG2bnnQtgcVaBXiVJF8LKPaV\\n\" + //\n                                            \"23XQ96HU8xfgSZMJS6U00WHAI7zp0q208RSUft9wDq9ee///VOhzR6Tebg9QfyPSohkBrhXQenvQ\\n\" + //\n                                            \"og555S+C3eJAAVeNCTeMS3N/M5hzBRJAoffn3qoYdAO1Q8bTguOi+2849A==\\n\" +                 //\n                                            \"-----END CERTIFICATE-----\";\n\n    @Override\n    protected void onActivityCreate(Bundle savedInstanceState) {\n        setContentView(R.layout.activity_https);\n        ButterKnife.bind(this);\n        setTitle(\"支持https请求\");\n    }\n\n    @Override\n    protected void onDestroy() {\n        super.onDestroy();\n        //Activity销毁时，取消网络请求\n        OkGo.getInstance().cancelTag(this);\n    }\n\n    @OnClick(R.id.btn_none_https_request)\n    public void btn_none_https_request(View view) {\n        //CA 认证的证书不需要任何设置，和http请求一样\n        OkGo.<String>get(\"https://github.com/jeasonlzy\")//\n                .tag(this)//\n                .headers(\"header1\", \"headerValue1\")//\n                .params(\"param1\", \"paramValue1\")//\n                .execute(new StringDialogCallback(this) {\n\n                    @Override\n                    public void onError(Response<String> response) {\n                        handleError(response);\n                    }\n\n                    @Override\n                    public void onSuccess(Response<String> response) {\n                        handleResponse(response);\n                    }\n                });\n    }\n\n    @OnClick(R.id.btn_https_request)\n    public void btn_https_request(View view) {\n        //自签名的证书需要在全局初始化的时候设置，详细看初始化的代码\n        OkGo.<String>get(\"https://kyfw.12306.cn/otn\")//\n                .tag(this)//\n                .headers(\"Connection\", \"close\")           //如果对于部分自签名的https访问不成功，需要加上该控制头\n                .headers(\"header1\", \"headerValue1\")//\n                .params(\"param1\", \"paramValue1\")//\n                .execute(new StringDialogCallback(this) {\n                    @Override\n                    public void onError(Response<String> response) {\n                        handleError(response);\n                    }\n\n                    @Override\n                    public void onSuccess(Response<String> response) {\n                        handleResponse(response);\n                    }\n                });\n    }\n}\n"
  },
  {
    "path": "demo/src/main/java/com/lzy/demo/okgo/JsonActivity.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.demo.okgo;\n\nimport android.os.Bundle;\nimport android.view.View;\n\nimport com.lzy.demo.R;\nimport com.lzy.demo.base.BaseDetailActivity;\nimport com.lzy.demo.callback.DialogCallback;\nimport com.lzy.demo.model.LzyResponse;\nimport com.lzy.demo.model.ServerModel;\nimport com.lzy.demo.utils.Urls;\nimport com.lzy.okgo.OkGo;\nimport com.lzy.okgo.model.Response;\n\nimport java.util.List;\n\nimport butterknife.ButterKnife;\nimport butterknife.OnClick;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：16/9/11\n * 描    述：\n * 修订历史：\n * ================================================\n */\npublic class JsonActivity extends BaseDetailActivity {\n\n    @Override\n    protected void onActivityCreate(Bundle savedInstanceState) {\n        setContentView(R.layout.activity_custom_request);\n        ButterKnife.bind(this);\n        actionBar.setTitle(\"自动解析JSON对象\");\n    }\n\n    @Override\n    protected void onDestroy() {\n        super.onDestroy();\n        //Activity销毁时，取消网络请求\n        OkGo.getInstance().cancelTag(this);\n    }\n\n    /**\n     * 解析javabean对象\n     */\n    @OnClick(R.id.requestJson)\n    public void requestJson(View view) {\n        OkGo.<LzyResponse<ServerModel>>get(Urls.URL_JSONOBJECT)//\n                .tag(this)//\n                .headers(\"header1\", \"headerValue1\")//\n                .params(\"param1\", \"paramValue1\")//\n                .execute(new DialogCallback<LzyResponse<ServerModel>>(this) {\n\n                    @Override\n                    public void onSuccess(Response<LzyResponse<ServerModel>> response) {\n                        handleResponse(response);\n                    }\n\n                    @Override\n                    public void onError(Response<LzyResponse<ServerModel>> response) {\n                        handleError(response);\n                    }\n                });\n    }\n\n    /**\n     * 解析集合对象\n     */\n    @OnClick(R.id.requestJsonArray)\n    public void requestJsonArray(View view) {\n        OkGo.<LzyResponse<List<ServerModel>>>get(Urls.URL_JSONARRAY)//\n                .tag(this)//\n                .headers(\"header1\", \"headerValue1\")//\n                .params(\"param1\", \"paramValue1\")//\n                .execute(new DialogCallback<LzyResponse<List<ServerModel>>>(this) {\n                    @Override\n                    public void onSuccess(Response<LzyResponse<List<ServerModel>>> response) {\n                        handleResponse(response);\n                    }\n\n                    @Override\n                    public void onError(Response<LzyResponse<List<ServerModel>>> response) {\n                        handleError(response);\n                    }\n                });\n    }\n}\n"
  },
  {
    "path": "demo/src/main/java/com/lzy/demo/okgo/MethodActivity.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.demo.okgo;\n\nimport android.graphics.Color;\nimport android.os.Bundle;\nimport android.view.Gravity;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.AdapterView;\nimport android.widget.BaseAdapter;\nimport android.widget.GridView;\nimport android.widget.TextView;\n\nimport com.lzy.demo.R;\nimport com.lzy.demo.base.BaseDetailActivity;\nimport com.lzy.demo.callback.DialogCallback;\nimport com.lzy.demo.callback.StringDialogCallback;\nimport com.lzy.demo.model.LzyResponse;\nimport com.lzy.demo.model.ServerModel;\nimport com.lzy.demo.utils.ColorUtils;\nimport com.lzy.demo.utils.Urls;\nimport com.lzy.okgo.OkGo;\nimport com.lzy.okgo.model.Response;\n\nimport butterknife.Bind;\nimport butterknife.ButterKnife;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：16/9/11\n * 描    述：\n * 修订历史：\n * ================================================\n */\npublic class MethodActivity extends BaseDetailActivity implements AdapterView.OnItemClickListener {\n\n    @Bind(R.id.gridView) GridView gridView;\n\n    private String[] methods = {\"GET\", \"HEAD\", \"OPTIONS\", \"POST\", \"PUT\", \"DELETE\", \"PATCH\", \"TRACE\"};\n\n    @Override\n    protected void onActivityCreate(Bundle savedInstanceState) {\n        setContentView(R.layout.activity_method);\n        ButterKnife.bind(this);\n\n        setTitle(\"请求方法演示\");\n        gridView.setAdapter(new MyAdapter());\n        gridView.setOnItemClickListener(this);\n    }\n\n    @Override\n    protected void onDestroy() {\n        super.onDestroy();\n        //Activity销毁时，取消网络请求\n        OkGo.getInstance().cancelTag(this);\n    }\n\n    @Override\n    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {\n        switch (position) {\n            case 0:\n                OkGo.<LzyResponse<ServerModel>>get(Urls.URL_METHOD)//\n                        .tag(this)//\n                        .headers(\"header1\", \"headerValue1\")//\n                        .params(\"param1\", \"paramValue1\")//\n                        .execute(new DialogCallback<LzyResponse<ServerModel>>(this) {\n                            @Override\n                            public void onSuccess(Response<LzyResponse<ServerModel>> response) {\n                                handleResponse(response);\n                            }\n\n                            @Override\n                            public void onError(Response<LzyResponse<ServerModel>> response) {\n                                handleError(response);\n                            }\n                        });\n                break;\n            case 1:\n                OkGo.<String>head(Urls.URL_METHOD)//\n                        .tag(this)//\n                        .headers(\"header1\", \"headerValue1\")//\n                        .params(\"param1\", \"paramValue1\")//\n                        .execute(new StringDialogCallback(this) {\n                            @Override\n                            public void onSuccess(Response<String> response) {\n                                handleResponse(response);\n                            }\n\n                            @Override\n                            public void onError(Response<String> response) {\n                                handleError(response);\n                            }\n                        });\n                break;\n            case 2:\n                OkGo.<LzyResponse<ServerModel>>options(Urls.URL_METHOD)//\n                        .tag(this)//\n                        .headers(\"header1\", \"headerValue1\")//\n                        .params(\"param1\", \"paramValue1\")//\n                        .execute(new DialogCallback<LzyResponse<ServerModel>>(this) {\n                            @Override\n                            public void onSuccess(Response<LzyResponse<ServerModel>> response) {\n                                handleResponse(response);\n                            }\n\n                            @Override\n                            public void onError(Response<LzyResponse<ServerModel>> response) {\n                                handleError(response);\n                            }\n                        });\n                break;\n            case 3:\n                OkGo.<LzyResponse<ServerModel>>post(Urls.URL_METHOD)//\n                        .tag(this)//\n                        .headers(\"header1\", \"headerValue1\")//\n                        .params(\"param1\", \"paramValue1\")//\n                        .params(\"param2\", \"paramValue2\")//\n                        .params(\"param3\", \"paramValue3\")//\n                        .isMultipart(true)         //强制使用 multipart/form-data 表单上传（只是演示，不需要的话不要设置。默认就是false）\n                        .execute(new DialogCallback<LzyResponse<ServerModel>>(this) {\n                            @Override\n                            public void onSuccess(Response<LzyResponse<ServerModel>> response) {\n                                handleResponse(response);\n                            }\n\n                            @Override\n                            public void onError(Response<LzyResponse<ServerModel>> response) {\n                                handleError(response);\n                            }\n                        });\n                break;\n            case 4:\n                OkGo.<LzyResponse<ServerModel>>put(Urls.URL_METHOD)//\n                        .tag(this)//\n                        .headers(\"header1\", \"headerValue1\")//\n                        .params(\"param1\", \"paramValue1\")//\n                        .execute(new DialogCallback<LzyResponse<ServerModel>>(this) {\n                            @Override\n                            public void onSuccess(Response<LzyResponse<ServerModel>> response) {\n                                handleResponse(response);\n                            }\n\n                            @Override\n                            public void onError(Response<LzyResponse<ServerModel>> response) {\n                                handleError(response);\n                            }\n                        });\n                break;\n            case 5:\n                OkGo.<LzyResponse<ServerModel>>delete(Urls.URL_METHOD)//\n                        .tag(this)//\n                        .headers(\"header1\", \"headerValue1\")//\n                        .upString(\"这是要上传的数据\")//\n                        .execute(new DialogCallback<LzyResponse<ServerModel>>(this) {\n                            @Override\n                            public void onSuccess(Response<LzyResponse<ServerModel>> response) {\n                                handleResponse(response);\n                            }\n\n                            @Override\n                            public void onError(Response<LzyResponse<ServerModel>> response) {\n                                handleError(response);\n                            }\n                        });\n                break;\n            case 6:\n                OkGo.<LzyResponse<ServerModel>>patch(Urls.URL_METHOD)//\n                        .tag(this)//\n                        .headers(\"header1\", \"headerValue1\")//\n                        .upString(\"这是要上传的数据\")//\n                        .execute(new DialogCallback<LzyResponse<ServerModel>>(this) {\n                            @Override\n                            public void onSuccess(Response<LzyResponse<ServerModel>> response) {\n                                handleResponse(response);\n                            }\n\n                            @Override\n                            public void onError(Response<LzyResponse<ServerModel>> response) {\n                                handleError(response);\n                            }\n                        });\n                break;\n            case 7:\n                OkGo.<LzyResponse<ServerModel>>trace(Urls.URL_METHOD)//\n                        .tag(this)//\n                        .headers(\"header1\", \"headerValue1\")//\n                        .params(\"param1\", \"paramValue1\")//\n                        .execute(new DialogCallback<LzyResponse<ServerModel>>(this) {\n                            @Override\n                            public void onSuccess(Response<LzyResponse<ServerModel>> response) {\n                                handleResponse(response);\n                            }\n\n                            @Override\n                            public void onError(Response<LzyResponse<ServerModel>> response) {\n                                handleError(response);\n                            }\n                        });\n                break;\n        }\n    }\n\n    private class MyAdapter extends BaseAdapter {\n        @Override\n        public int getCount() {\n            return methods.length;\n        }\n\n        @Override\n        public String getItem(int position) {\n            return methods[position];\n        }\n\n        @Override\n        public long getItemId(int position) {\n            return position;\n        }\n\n        @Override\n        public View getView(int position, View convertView, ViewGroup parent) {\n            if (convertView == null) {\n                convertView = new TextView(getApplicationContext());\n            }\n            TextView textView = (TextView) convertView;\n            textView.setGravity(Gravity.CENTER);\n            textView.setHeight(200);\n            textView.setText(getItem(position));\n            textView.setTextColor(Color.WHITE);\n            textView.setTextSize(16);\n            textView.setBackgroundColor(ColorUtils.randomColor());\n            return textView;\n        }\n    }\n}\n"
  },
  {
    "path": "demo/src/main/java/com/lzy/demo/okgo/OkGoFragment.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.demo.okgo;\n\nimport android.content.Intent;\n\nimport com.lzy.demo.base.MainFragment;\nimport com.lzy.demo.model.ItemModel;\nimport com.lzy.demo.supercache.SuperCacheActivity;\n\nimport java.util.List;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：2017/6/9\n * 描    述：\n * 修订历史：\n * ================================================\n */\npublic class OkGoFragment extends MainFragment {\n\n    @Override\n    public void fillData(List<ItemModel> items) {\n\n        items.add(new ItemModel(\"强大的缓存示例 -- 先联网获取数据,然后断开网络再进试试\",//\n                                \"1.OkGo的强大的缓存功能,让你代码无需关心数据来源,专注于业务逻辑的实现\\n\" +//\n                                \"2.内置五种缓存模式满足你各种使用场景\\n\" +//\n                                \"3.支持自定义缓存策略，可以按照自己的需求改写缓存逻辑\\n\" +//\n                                \"4.支持自定义缓存过期时间\"));\n\n        items.add(new ItemModel(\"基本功能\",//\n                                \"1.GET，HEAD，OPTIONS，POST，PUT，DELETE, PATCH, TRACE 请求方法演示\\n\" +//\n                                \"2.请求服务器返回bitmap对象\\n\" +//\n                                \"3.支持https请求\\n\" +//\n                                \"4.支持同步请求\\n\" +//\n                                \"5.支持301重定向\"));\n\n        items.add(new ItemModel(\"自动解析JSON对象\",//\n                                \"1.自动解析JSONObject对象\\n\" + //\n                                \"2.自动解析JSONArray对象\"));\n\n        items.add(new ItemModel(\"文件下载\",//\n                                \"1.支持大文件或小文件下载，无论多大文件都不会发生OOM\\n\" +//\n                                \"2.支持监听下载进度和下载网速\\n\" +//\n                                \"3.支持自定义下载目录和下载文件名\"));\n\n        items.add(new ItemModel(\"文件上传\",//\n                                \"1.支持上传单个文件\\n\" +//\n                                \"2.支持同时上传多个文件\\n\" +//\n                                \"3.支持多个文件多个参数同时上传\\n\" +//\n                                \"4.支持大文件上传,无论多大都不会发生OOM\\n\" +//\n                                \"5.支持监听上传进度和上传网速\"));\n    }\n\n    @Override\n    public void onItemClick(int position) {\n        if (position == 0) startActivity(new Intent(context, SuperCacheActivity.class));\n        if (position == 1) startActivity(new Intent(context, CommonActivity.class));\n        if (position == 2) startActivity(new Intent(context, JsonActivity.class));\n        if (position == 3) startActivity(new Intent(context, SimpleDownloadActivity.class));\n        if (position == 4) startActivity(new Intent(context, FormUploadActivity.class));\n    }\n}\n"
  },
  {
    "path": "demo/src/main/java/com/lzy/demo/okgo/RedirectActivity.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.demo.okgo;\n\nimport android.os.Bundle;\nimport android.view.View;\n\nimport com.lzy.demo.R;\nimport com.lzy.demo.base.BaseDetailActivity;\nimport com.lzy.demo.callback.StringDialogCallback;\nimport com.lzy.demo.utils.Urls;\nimport com.lzy.okgo.OkGo;\nimport com.lzy.okgo.model.Response;\n\nimport butterknife.ButterKnife;\nimport butterknife.OnClick;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：16/9/11\n * 描    述：\n * 修订历史：\n * ================================================\n */\npublic class RedirectActivity extends BaseDetailActivity {\n\n    @Override\n    protected void onActivityCreate(Bundle savedInstanceState) {\n        setContentView(R.layout.activity_redirect);\n        ButterKnife.bind(this);\n        setTitle(\"301重定向\");\n    }\n\n    @Override\n    protected void onDestroy() {\n        super.onDestroy();\n        //Activity销毁时，取消网络请求\n        OkGo.getInstance().cancelTag(this);\n    }\n\n    @OnClick(R.id.redirect)\n    public void redirect(View view) {\n        OkGo.<String>get(Urls.URL_REDIRECT)//\n                .tag(this)//\n                .headers(\"header1\", \"headerValue1\")//\n                .params(\"param1\", \"paramValue1\")//\n                .execute(new StringDialogCallback(this) {\n                    @Override\n                    public void onSuccess(Response<String> response) {\n                        handleResponse(response);\n                        responseData.setText(\"注意看请求头的url和响应头的url是不一样的！\\n这代表了在请求过程中发生了重定向，\" +//\n                                             \"okhttp默认将重定向封装在了请求内部，只有最后一次请求的数据会被真正的请求下来触发回调，中间过程\" +//\n                                             \"是默认实现的，不会触发回调！\");\n                    }\n\n                    @Override\n                    public void onError(Response<String> response) {\n                        handleError(response);\n                    }\n                });\n    }\n}\n"
  },
  {
    "path": "demo/src/main/java/com/lzy/demo/okgo/SimpleDownloadActivity.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.demo.okgo;\n\nimport android.Manifest;\nimport android.content.pm.PackageManager;\nimport android.os.Bundle;\nimport android.support.annotation.NonNull;\nimport android.support.v4.app.ActivityCompat;\nimport android.text.format.Formatter;\nimport android.view.View;\nimport android.widget.Button;\nimport android.widget.TextView;\n\nimport com.lzy.demo.R;\nimport com.lzy.demo.base.BaseDetailActivity;\nimport com.lzy.demo.ui.NumberProgressBar;\nimport com.lzy.demo.utils.Urls;\nimport com.lzy.okgo.OkGo;\nimport com.lzy.okgo.callback.FileCallback;\nimport com.lzy.okgo.model.Progress;\nimport com.lzy.okgo.model.Response;\nimport com.lzy.okgo.request.base.Request;\n\nimport java.io.File;\nimport java.text.NumberFormat;\n\nimport butterknife.Bind;\nimport butterknife.ButterKnife;\nimport butterknife.OnClick;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：16/9/11\n * 描    述：\n * 修订历史：\n * ================================================\n */\npublic class SimpleDownloadActivity extends BaseDetailActivity {\n\n    private static final int REQUEST_PERMISSION_STORAGE = 0x01;\n\n    @Bind(R.id.fileDownload) Button btnFileDownload;\n    @Bind(R.id.downloadSize) TextView tvDownloadSize;\n    @Bind(R.id.tvProgress) TextView tvProgress;\n    @Bind(R.id.netSpeed) TextView tvNetSpeed;\n    @Bind(R.id.pbProgress) NumberProgressBar pbProgress;\n    private NumberFormat numberFormat;\n\n    @Override\n    protected void onActivityCreate(Bundle savedInstanceState) {\n        setContentView(R.layout.activity_file_download);\n        ButterKnife.bind(this);\n        setTitle(\"简单文件下载\");\n\n        numberFormat = NumberFormat.getPercentInstance();\n        numberFormat.setMinimumFractionDigits(2);\n\n        checkSDCardPermission();\n    }\n\n    /** 检查SD卡权限 */\n    protected void checkSDCardPermission() {\n        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {\n            ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_PERMISSION_STORAGE);\n        }\n    }\n\n    @Override\n    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {\n        super.onRequestPermissionsResult(requestCode, permissions, grantResults);\n        if (requestCode == REQUEST_PERMISSION_STORAGE) {\n            if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {\n                //获取权限\n            } else {\n                showToast(\"权限被禁止，无法下载文件！\");\n            }\n        }\n    }\n\n    @Override\n    protected void onDestroy() {\n        super.onDestroy();\n        //Activity销毁时，取消网络请求\n        OkGo.getInstance().cancelTag(this);\n    }\n\n    @OnClick(R.id.fileDownload)\n    public void fileDownload(View view) {\n        OkGo.<File>get(Urls.URL_DOWNLOAD)//\n                .tag(this)//\n                .headers(\"header1\", \"headerValue1\")//\n                .params(\"param1\", \"paramValue1\")//\n                .execute(new FileCallback(\"OkGo.apk\") {\n\n                    @Override\n                    public void onStart(Request<File, ? extends Request> request) {\n                        btnFileDownload.setText(\"正在下载中\");\n                    }\n\n                    @Override\n                    public void onSuccess(Response<File> response) {\n                        handleResponse(response);\n                        btnFileDownload.setText(\"下载完成\");\n                    }\n\n                    @Override\n                    public void onError(Response<File> response) {\n                        handleError(response);\n                        btnFileDownload.setText(\"下载出错\");\n                    }\n\n                    @Override\n                    public void downloadProgress(Progress progress) {\n                        System.out.println(progress);\n\n                        String downloadLength = Formatter.formatFileSize(getApplicationContext(), progress.currentSize);\n                        String totalLength = Formatter.formatFileSize(getApplicationContext(), progress.totalSize);\n                        tvDownloadSize.setText(downloadLength + \"/\" + totalLength);\n                        String speed = Formatter.formatFileSize(getApplicationContext(), progress.speed);\n                        tvNetSpeed.setText(String.format(\"%s/s\", speed));\n                        tvProgress.setText(numberFormat.format(progress.fraction));\n                        pbProgress.setMax(10000);\n                        pbProgress.setProgress((int) (progress.fraction * 10000));\n                    }\n                });\n    }\n}\n"
  },
  {
    "path": "demo/src/main/java/com/lzy/demo/okgo/SyncActivity.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.demo.okgo;\n\nimport android.os.Bundle;\nimport android.os.Handler;\nimport android.os.Message;\nimport android.view.View;\nimport android.widget.Toast;\n\nimport com.lzy.demo.R;\nimport com.lzy.demo.base.BaseDetailActivity;\nimport com.lzy.demo.utils.Urls;\nimport com.lzy.okgo.OkGo;\nimport com.lzy.okgo.adapter.Call;\nimport com.lzy.okgo.convert.StringConvert;\nimport com.lzy.okgo.model.Response;\n\nimport butterknife.ButterKnife;\nimport butterknife.OnClick;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：16/9/11\n * 描    述：\n * 修订历史：\n * ================================================\n */\npublic class SyncActivity extends BaseDetailActivity {\n\n    private Handler handler = new InnerHandler();\n\n    private class InnerHandler extends Handler {\n        @Override\n        public void handleMessage(Message msg) {\n            String data = (String) msg.obj;\n            System.out.println(\"同步请求的数据：\" + data);\n            Toast.makeText(getApplicationContext(), \"同步请求成功\" + data, Toast.LENGTH_SHORT).show();\n        }\n    }\n\n    @Override\n    protected void onActivityCreate(Bundle savedInstanceState) {\n        setContentView(R.layout.activity_sync);\n        ButterKnife.bind(this);\n        setTitle(\"同步请求\");\n    }\n\n    @Override\n    protected void onDestroy() {\n        super.onDestroy();\n        //Activity销毁时，取消网络请求\n        OkGo.getInstance().cancelTag(this);\n    }\n\n    @OnClick(R.id.sync)\n    public void sync(View view) {\n        new Thread(new Runnable() {\n            @Override\n            public void run() {\n                try {\n//                    //同步会阻塞主线程，必须开线程\n//                    Response response = OkGo.get(Urls.URL_JSONOBJECT)//\n//                            .tag(this)//\n//                            .headers(\"header1\", \"headerValue1\")//\n//                            .params(\"param1\", \"paramValue1\")//\n//                            .execute();  //不传callback即为同步请求\n\n                    Call<String> call = OkGo.<String>get(Urls.URL_JSONOBJECT)//\n                            .tag(this)//\n                            .headers(\"header1\", \"headerValue1\")//\n                            .params(\"param1\", \"paramValue1\")//\n                            .converter(new StringConvert())//\n                            .adapt();\n                    Response<String> response = call.execute();\n\n                    Message message = Message.obtain();\n                    message.obj = response.body();\n                    handler.sendMessage(message);\n                } catch (Exception e) {\n                    e.printStackTrace();\n                }\n            }\n        }).start();\n    }\n}\n"
  },
  {
    "path": "demo/src/main/java/com/lzy/demo/okgo/TestActivity.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.demo.okgo;\n\nimport android.os.Bundle;\nimport android.view.View;\nimport android.widget.EditText;\nimport android.widget.ImageView;\n\nimport com.lzy.demo.R;\nimport com.lzy.demo.base.BaseActivity;\nimport com.lzy.demo.callback.JsonCallback;\nimport com.lzy.demo.utils.Urls;\nimport com.lzy.okgo.OkGo;\nimport com.lzy.okgo.adapter.Call;\nimport com.lzy.okgo.callback.StringCallback;\nimport com.lzy.okgo.model.HttpHeaders;\nimport com.lzy.okgo.model.Response;\n\nimport org.json.JSONObject;\n\nimport butterknife.Bind;\nimport butterknife.OnClick;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：16/9/11\n * 描    述：\n * 修订历史：\n * ================================================\n */\npublic class TestActivity extends BaseActivity {\n\n    @Bind(R.id.image) ImageView imageView;\n    @Bind(R.id.edit) EditText editText;\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.activity_test);\n        setTitle(\"测试页面\");\n    }\n\n    @Override\n    protected void onDestroy() {\n        super.onDestroy();\n        //Activity销毁时，取消网络请求\n        OkGo.getInstance().cancelTag(this);\n    }\n\n    @OnClick(R.id.btn1)\n    public void btn1(View view) {\n        OkGo.<JSONObject>get(Urls.URL_JSONOBJECT)//\n                .execute(new JsonCallback<JSONObject>() {\n                    @Override\n                    public void onSuccess(Response<JSONObject> response) {\n                        System.out.println(response.body());\n                    }\n\n                    @Override\n                    public void onError(Response<JSONObject> response) {\n                        response.getException().printStackTrace();\n                    }\n                });\n    }\n\n    @OnClick(R.id.btn2)\n    public void btn2(View view) {\n        new Thread(new Runnable() {\n            @Override\n            public void run() {\n                try {\n                    Call<JSONObject> adapt = OkGo.<JSONObject>get(Urls.URL_JSONOBJECT).adapt();\n                    Response<JSONObject> response = adapt.execute();\n                    System.out.println(\"body \" + response.body());\n                    Throwable exception = response.getException();\n                    if (exception != null) exception.printStackTrace();\n                } catch (Exception e) {\n                    e.printStackTrace();\n                }\n            }\n        }).start();\n    }\n\n    @OnClick(R.id.btn3)\n    public void btn3(View view) {\n        OkGo.<String>get(\"asdfasf\")//\n                .tag(this)//\n                .headers(HttpHeaders.HEAD_KEY_USER_AGENT, \"abcd\")//\n                .execute(new StringCallback() {\n                    @Override\n                    public void onSuccess(Response<String> response) {\n\n                    }\n                });\n    }\n}\n"
  },
  {
    "path": "demo/src/main/java/com/lzy/demo/okgo/UpActivity.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.demo.okgo;\n\nimport android.content.Intent;\nimport android.os.Bundle;\nimport android.view.View;\nimport android.widget.TextView;\nimport android.widget.Toast;\n\nimport com.lzy.demo.R;\nimport com.lzy.demo.base.BaseDetailActivity;\nimport com.lzy.demo.callback.DialogCallback;\nimport com.lzy.demo.model.LzyResponse;\nimport com.lzy.demo.model.ServerModel;\nimport com.lzy.demo.utils.GlideImageLoader;\nimport com.lzy.demo.utils.Urls;\nimport com.lzy.imagepicker.ImagePicker;\nimport com.lzy.imagepicker.bean.ImageItem;\nimport com.lzy.imagepicker.ui.ImageGridActivity;\nimport com.lzy.okgo.OkGo;\nimport com.lzy.okgo.model.Response;\n\nimport org.json.JSONObject;\n\nimport java.io.File;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\n\nimport butterknife.Bind;\nimport butterknife.ButterKnife;\nimport butterknife.OnClick;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：16/9/11\n * 描    述：\n * 修订历史：\n * ================================================\n */\npublic class UpActivity extends BaseDetailActivity {\n\n    @Bind(R.id.images) TextView tvImages;\n\n    private ImageItem imageItem;\n\n    @Override\n    protected void onActivityCreate(Bundle savedInstanceState) {\n        setContentView(R.layout.activity_up_text);\n        ButterKnife.bind(this);\n        setTitle(\"普通上传数据\");\n    }\n\n    @Override\n    protected void onDestroy() {\n        super.onDestroy();\n        //Activity销毁时，取消网络请求\n        OkGo.getInstance().cancelTag(this);\n    }\n\n    @OnClick(R.id.selectImage)\n    public void selectImage(View view) {\n        ImagePicker imagePicker = ImagePicker.getInstance();\n        imagePicker.setImageLoader(new GlideImageLoader());\n        imagePicker.setMultiMode(false);   //单选\n        imagePicker.setShowCamera(true);  //显示拍照按钮\n        imagePicker.setSelectLimit(9);    //最多选择9张\n        imagePicker.setCrop(false);       //不进行裁剪\n        Intent intent = new Intent(this, ImageGridActivity.class);\n        startActivityForResult(intent, 100);\n    }\n\n    @Override\n    public void onActivityResult(int requestCode, int resultCode, Intent data) {\n        super.onActivityResult(requestCode, resultCode, data);\n        if (resultCode == ImagePicker.RESULT_CODE_ITEMS) {\n            if (data != null && requestCode == 100) {\n                //noinspection unchecked\n                List<ImageItem> imageItems = (ArrayList<ImageItem>) data.getSerializableExtra(ImagePicker.EXTRA_RESULT_ITEMS);\n                if (imageItems != null && imageItems.size() > 0) {\n                    imageItem = imageItems.get(0);\n                    tvImages.setText(imageItem.path);\n                } else {\n                    tvImages.setText(\"--\");\n                }\n            } else {\n                Toast.makeText(this, \"没有选择图片\", Toast.LENGTH_SHORT).show();\n                tvImages.setText(\"--\");\n            }\n        }\n    }\n\n    @OnClick(R.id.upJson)\n    public void upJson(View view) {\n\n        HashMap<String, String> params = new HashMap<>();\n        params.put(\"key1\", \"value1\");\n        params.put(\"key2\", \"这里是需要提交的json格式数据\");\n        params.put(\"key3\", \"也可以使用三方工具将对象转成json字符串\");\n        params.put(\"key4\", \"其实你怎么高兴怎么写都行\");\n        JSONObject jsonObject = new JSONObject(params);\n\n        OkGo.<LzyResponse<ServerModel>>post(Urls.URL_TEXT_UPLOAD)//\n                .tag(this)//\n                .headers(\"header1\", \"headerValue1\")//\n//                .params(\"param1\", \"paramValue1\")//  这里不要使用params，upJson 与 params 是互斥的，只有 upJson 的数据会被上传\n                .upJson(jsonObject)//\n                .execute(new DialogCallback<LzyResponse<ServerModel>>(this) {\n                    @Override\n                    public void onSuccess(Response<LzyResponse<ServerModel>> response) {\n                        handleResponse(response);\n                    }\n\n                    @Override\n                    public void onError(Response<LzyResponse<ServerModel>> response) {\n                        handleError(response);\n                    }\n                });\n    }\n\n    @OnClick(R.id.upString)\n    public void upString(View view) {\n        OkGo.<LzyResponse<ServerModel>>post(Urls.URL_TEXT_UPLOAD)//\n                .tag(this)//\n                .headers(\"header1\", \"headerValue1\")//\n//                .params(\"param1\", \"paramValue1\")// 这里不要使用params，upString 与 params 是互斥的，只有 upString 的数据会被上传\n                .upString(\"这是要上传的长文本数据！\")//\n//                .upString(\"这是要上传的长文本数据！\", MediaType.parse(\"application/xml\"))// 比如上传xml数据，这里就可以自己指定请求头\n                .execute(new DialogCallback<LzyResponse<ServerModel>>(this) {\n                    @Override\n                    public void onSuccess(Response<LzyResponse<ServerModel>> response) {\n                        handleResponse(response);\n                    }\n\n                    @Override\n                    public void onError(Response<LzyResponse<ServerModel>> response) {\n                        handleError(response);\n                    }\n                });\n    }\n\n    @OnClick(R.id.upBytes)\n    public void upBytes(View view) {\n        OkGo.<LzyResponse<ServerModel>>post(Urls.URL_TEXT_UPLOAD)//\n                .tag(this)//\n                .headers(\"header1\", \"headerValue1\")//\n//                .params(\"param1\", \"paramValue1\")// 这里不要使用params，upBytes 与 params 是互斥的，只有 upBytes 的数据会被上传\n                .upBytes(\"这是字节数据\".getBytes())//\n                .execute(new DialogCallback<LzyResponse<ServerModel>>(this) {\n                    @Override\n                    public void onSuccess(Response<LzyResponse<ServerModel>> response) {\n                        handleResponse(response);\n                    }\n\n                    @Override\n                    public void onError(Response<LzyResponse<ServerModel>> response) {\n                        handleError(response);\n                    }\n                });\n    }\n\n    @OnClick(R.id.upFile)\n    public void upFile(View view) {\n        if (imageItem == null) {\n            showToast(\"请先选择文件！\");\n            return;\n        }\n        OkGo.<LzyResponse<ServerModel>>post(Urls.URL_TEXT_UPLOAD)//\n                .tag(this)//\n                .headers(\"header1\", \"headerValue1\")//\n//                .params(\"param1\", \"paramValue1\")// 这里不要使用params，upBytes 与 params 是互斥的，只有 upBytes 的数据会被上传\n                .upFile(new File(imageItem.path))//\n                .execute(new DialogCallback<LzyResponse<ServerModel>>(this) {\n                    @Override\n                    public void onSuccess(Response<LzyResponse<ServerModel>> response) {\n                        handleResponse(response);\n                    }\n\n                    @Override\n                    public void onError(Response<LzyResponse<ServerModel>> response) {\n                        handleError(response);\n                    }\n                });\n    }\n}\n"
  },
  {
    "path": "demo/src/main/java/com/lzy/demo/okrx2/OkRx2Fragment.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.demo.okrx2;\n\nimport android.content.Intent;\n\nimport com.lzy.demo.base.MainFragment;\nimport com.lzy.demo.model.ItemModel;\n\nimport java.util.List;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：2017/6/9\n * 描    述：\n * 修订历史：\n * ================================================\n */\npublic class OkRx2Fragment extends MainFragment {\n\n    @Override\n    public void fillData(List<ItemModel> items) {\n        items.add(new ItemModel(\"基本请求\", //\n                                \"1.支持GET，HEAD，OPTIONS，POST，PUT，DELETE, PATCH, TRACE 8种请求方式\\n\" +//\n                                \"2.自动解析JSONObject对象\\n\" +//\n                                \"3.自动解析JSONArray对象\\n\" +//\n                                \"4.上传string文本\\n\" +//\n                                \"5.上传json数据\"));\n        items.add(new ItemModel(\"rx使用缓存\", \"okrx的缓存与okgo的缓存一模一样，详细看okrx的文档介绍\"));\n        items.add(new ItemModel(\"统一管理请求\", \"如果你熟悉Retrofit，那么和Retrofit一样，可以使用一个Api类管理所有的请求\"));\n        items.add(new ItemModel(\"请求图片\", \"请求服务器返回bitmap对象\"));\n        items.add(new ItemModel(\"文件上传\", \"支持参数和文件一起上传,并回调上传进度\"));\n        items.add(new ItemModel(\"文件下载\", \"支持下载进度回调\"));\n    }\n\n    @Override\n    public void onItemClick(int position) {\n        if (position == 0) startActivity(new Intent(context, RxCommonActivity.class));\n        if (position == 1) startActivity(new Intent(context, RxCacheActivity.class));\n        if (position == 2) startActivity(new Intent(context, RxRetrofitActivity.class));\n        if (position == 3) startActivity(new Intent(context, RxBitmapActivity.class));\n        if (position == 4) startActivity(new Intent(context, RxFormUploadActivity.class));\n        if (position == 5) startActivity(new Intent(context, RxFileDownloadActivity.class));\n    }\n}\n"
  },
  {
    "path": "demo/src/main/java/com/lzy/demo/okrx2/OkRxFragment.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.demo.okrx2;\n\nimport com.lzy.demo.base.MainFragment;\nimport com.lzy.demo.model.ItemModel;\n\nimport java.util.List;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：2017/6/9\n * 描    述：\n * 修订历史：\n * ================================================\n */\npublic class OkRxFragment extends MainFragment {\n\n    @Override\n    public void fillData(List<ItemModel> items) {\n        items.add(new ItemModel(\"OkRx是OkGo结合RxJava的扩展项目\\n\" +//\n                                \"OkRx2是OkGo结合RxJava2的扩展项目\\n\" +//\n                                \"他们的使用方法完全一样，在此不做演示，详细请看OkRx2的使用介绍\",  //\n                                \"1.完美结合RxJava\\n\" +//\n                                \"2.比Retrofit更简单方便\\n\" +//\n                                \"3.网络请求和RxJava调用,一条链点到底\\n\" +//\n                                \"4.支持JSON数据的自动解析转换\"));\n    }\n\n    @Override\n    public void onItemClick(int position) {\n    }\n}\n"
  },
  {
    "path": "demo/src/main/java/com/lzy/demo/okrx2/RxBitmapActivity.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.demo.okrx2;\n\nimport android.graphics.Bitmap;\nimport android.os.Bundle;\nimport android.view.View;\nimport android.widget.ImageView;\n\nimport com.lzy.demo.R;\nimport com.lzy.demo.base.BaseRxDetailActivity;\nimport com.lzy.okgo.model.Response;\n\nimport butterknife.Bind;\nimport butterknife.ButterKnife;\nimport butterknife.OnClick;\nimport io.reactivex.Observer;\nimport io.reactivex.android.schedulers.AndroidSchedulers;\nimport io.reactivex.annotations.NonNull;\nimport io.reactivex.disposables.Disposable;\nimport io.reactivex.functions.Consumer;\nimport io.reactivex.schedulers.Schedulers;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：16/9/11\n * 描    述：\n * 修订历史：\n * ================================================\n */\npublic class RxBitmapActivity extends BaseRxDetailActivity {\n\n    @Bind(R.id.imageView) ImageView imageView;\n\n    @Override\n    protected void onActivityCreate(Bundle savedInstanceState) {\n        setContentView(R.layout.activity_bitmap_request);\n        ButterKnife.bind(this);\n        setTitle(\"请求图片\");\n    }\n\n    @Override\n    protected void onDestroy() {\n        super.onDestroy();\n        //Activity销毁时，取消网络请求\n        dispose();\n    }\n\n    @OnClick(R.id.requestImage)\n    public void requestImage(View view) {\n        ServerApi.getBitmap(\"aaa\", \"bbb\")//\n                .subscribeOn(Schedulers.io())//\n                .doOnSubscribe(new Consumer<Disposable>() {\n                    @Override\n                    public void accept(@NonNull Disposable disposable) throws Exception {\n                        showLoading();\n                    }\n                })//\n                .observeOn(AndroidSchedulers.mainThread())//\n                .subscribe(new Observer<Response<Bitmap>>() {\n                    @Override\n                    public void onSubscribe(@NonNull Disposable d) {\n                        addDisposable(d);\n                    }\n\n                    @Override\n                    public void onNext(@NonNull Response<Bitmap> response) {\n                        handleResponse(response);\n                        imageView.setImageBitmap(response.body());\n                    }\n\n                    @Override\n                    public void onError(@NonNull Throwable e) {\n                        e.printStackTrace();            //请求失败\n                        handleError(null);\n                        showToast(\"请求失败\");\n                    }\n\n                    @Override\n                    public void onComplete() {\n                        dismissLoading();\n                    }\n                });\n    }\n}\n"
  },
  {
    "path": "demo/src/main/java/com/lzy/demo/okrx2/RxCacheActivity.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.demo.okrx2;\n\nimport android.os.Bundle;\nimport android.view.View;\n\nimport com.lzy.demo.R;\nimport com.lzy.demo.base.BaseRxDetailActivity;\nimport com.lzy.demo.utils.Urls;\nimport com.lzy.okgo.OkGo;\nimport com.lzy.okgo.cache.CacheMode;\nimport com.lzy.okgo.convert.StringConvert;\nimport com.lzy.okgo.model.Response;\nimport com.lzy.okrx2.adapter.ObservableResponse;\n\nimport butterknife.ButterKnife;\nimport butterknife.OnClick;\nimport io.reactivex.Observer;\nimport io.reactivex.android.schedulers.AndroidSchedulers;\nimport io.reactivex.annotations.NonNull;\nimport io.reactivex.disposables.Disposable;\nimport io.reactivex.functions.Consumer;\nimport io.reactivex.schedulers.Schedulers;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：16/9/11\n * 描    述：\n * 修订历史：\n * ================================================\n */\npublic class RxCacheActivity extends BaseRxDetailActivity {\n\n    @Override\n    protected void onActivityCreate(Bundle savedInstanceState) {\n        setContentView(R.layout.activity_rx_cache);\n        ButterKnife.bind(this);\n        setTitle(\"使用缓存\");\n    }\n\n    @Override\n    protected void onDestroy() {\n        super.onDestroy();\n        //Activity销毁时，取消网络请求\n        dispose();\n    }\n\n    @OnClick(R.id.cache)\n    public void cache(View view) {\n\n        // 详细看文档： https://github.com/jeasonlzy/okhttp-OkGo/wiki/OkRx\n\n        OkGo.<String>post(Urls.URL_METHOD)//\n                .headers(\"aaa\", \"111\")//\n                .params(\"bbb\", \"222\")//\n                .cacheKey(\"rx_cache\")              //这里完全同okgo的配置一样\n                .cacheMode(CacheMode.FIRST_CACHE_THEN_REQUEST)  //这里完全同okgo的配置一样\n                .converter(new StringConvert())//\n                .adapt(new ObservableResponse<String>())//\n                .subscribeOn(Schedulers.io())//\n                .doOnSubscribe(new Consumer<Disposable>() {\n                    @Override\n                    public void accept(@NonNull Disposable disposable) throws Exception {\n                        showLoading();\n                    }\n                })//\n                .observeOn(AndroidSchedulers.mainThread())//\n                .subscribe(new Observer<Response<String>>() {\n                    @Override\n                    public void onSubscribe(@NonNull Disposable d) {\n                        addDisposable(d);\n                    }\n\n                    @Override\n                    public void onNext(@NonNull Response<String> response) {\n                        handleResponse(response);\n                    }\n\n                    @Override\n                    public void onError(@NonNull Throwable e) {\n                        e.printStackTrace();\n                        showToast(\"请求失败\");\n                        handleError(null);\n                    }\n\n                    @Override\n                    public void onComplete() {\n                        dismissLoading();\n                    }\n                });\n    }\n}\n"
  },
  {
    "path": "demo/src/main/java/com/lzy/demo/okrx2/RxCommonActivity.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.demo.okrx2;\n\nimport android.os.Bundle;\nimport android.view.View;\n\nimport com.lzy.demo.R;\nimport com.lzy.demo.base.BaseRxDetailActivity;\nimport com.lzy.demo.callback.JsonConvert;\nimport com.lzy.demo.model.LzyResponse;\nimport com.lzy.demo.model.ServerModel;\nimport com.lzy.demo.utils.Urls;\nimport com.lzy.okgo.OkGo;\nimport com.lzy.okgo.convert.StringConvert;\nimport com.lzy.okgo.model.Response;\nimport com.lzy.okrx2.adapter.ObservableBody;\nimport com.lzy.okrx2.adapter.ObservableResponse;\n\nimport org.json.JSONObject;\n\nimport java.util.HashMap;\nimport java.util.List;\n\nimport butterknife.ButterKnife;\nimport butterknife.OnClick;\nimport io.reactivex.Observer;\nimport io.reactivex.android.schedulers.AndroidSchedulers;\nimport io.reactivex.annotations.NonNull;\nimport io.reactivex.disposables.Disposable;\nimport io.reactivex.functions.Consumer;\nimport io.reactivex.functions.Function;\nimport io.reactivex.schedulers.Schedulers;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：16/9/11\n * 描    述：\n * 修订历史：\n * ================================================\n */\npublic class RxCommonActivity extends BaseRxDetailActivity {\n\n    @Override\n    protected void onActivityCreate(Bundle savedInstanceState) {\n        setContentView(R.layout.activity_rx_common);\n        ButterKnife.bind(this);\n        setTitle(\"OkRx基本请求\");\n    }\n\n    @Override\n    protected void onDestroy() {\n        super.onDestroy();\n        //Activity销毁时，取消网络请求\n        dispose();\n    }\n\n    @OnClick(R.id.commonRequest)\n    public void commonRequest(View view) {\n        OkGo.<String>post(Urls.URL_METHOD)//\n                .headers(\"aaa\", \"111\")//\n                .params(\"bbb\", \"222\")//\n                .converter(new StringConvert())//\n                .adapt(new ObservableResponse<String>())//\n                .subscribeOn(Schedulers.io())//\n                .doOnSubscribe(new Consumer<Disposable>() {\n                    @Override\n                    public void accept(@NonNull Disposable disposable) throws Exception {\n                        showLoading();\n                    }\n                })//\n                .observeOn(AndroidSchedulers.mainThread())//\n                .subscribe(new Observer<Response<String>>() {\n                    @Override\n                    public void onSubscribe(@NonNull Disposable d) {\n                        addDisposable(d);\n                    }\n\n                    @Override\n                    public void onNext(@NonNull Response<String> response) {\n                        handleResponse(response);\n                    }\n\n                    @Override\n                    public void onError(@NonNull Throwable e) {\n                        e.printStackTrace();\n                        showToast(\"请求失败\");\n                        handleError(null);\n                    }\n\n                    @Override\n                    public void onComplete() {\n                        dismissLoading();\n                    }\n                });\n    }\n\n    @OnClick(R.id.jsonRequest)\n    public void jsonRequest(View view) {\n        OkGo.<LzyResponse<ServerModel>>get(Urls.URL_JSONOBJECT)//\n                .headers(\"aaa\", \"111\")//\n                .params(\"bbb\", \"222\")//\n                .converter(new JsonConvert<LzyResponse<ServerModel>>() {})//\n                .adapt(new ObservableBody<LzyResponse<ServerModel>>())//\n                .subscribeOn(Schedulers.io())//\n                .doOnSubscribe(new Consumer<Disposable>() {\n                    @Override\n                    public void accept(@NonNull Disposable disposable) throws Exception {\n                        showLoading();\n                    }\n                })//\n                .map(new Function<LzyResponse<ServerModel>, ServerModel>() {\n                    @Override\n                    public ServerModel apply(@NonNull LzyResponse<ServerModel> response) throws Exception {\n                        return response.data;\n                    }\n                })//\n                .observeOn(AndroidSchedulers.mainThread())//\n                .subscribe(new Observer<ServerModel>() {\n                    @Override\n                    public void onSubscribe(@NonNull Disposable d) {\n                        addDisposable(d);\n                    }\n\n                    @Override\n                    public void onNext(@NonNull ServerModel serverModel) {\n                        handleResponse(serverModel);\n                    }\n\n                    @Override\n                    public void onError(@NonNull Throwable e) {\n                        e.printStackTrace();            //请求失败\n                        showToast(\"请求失败\");\n                        handleError(null);\n                    }\n\n                    @Override\n                    public void onComplete() {\n                        dismissLoading();\n                    }\n                });\n    }\n\n    @OnClick(R.id.jsonArrayRequest)\n    public void jsonArrayRequest(View view) {\n        OkGo.<LzyResponse<List<ServerModel>>>get(Urls.URL_JSONARRAY)//\n                .headers(\"aaa\", \"111\")//\n                .params(\"bbb\", \"222\")//\n                .converter(new JsonConvert<LzyResponse<List<ServerModel>>>() {})//\n                .adapt(new ObservableBody<LzyResponse<List<ServerModel>>>())//\n                .doOnSubscribe(new Consumer<Disposable>() {\n                    @Override\n                    public void accept(@NonNull Disposable disposable) throws Exception {\n                        showLoading();\n                    }\n                })//\n                .map(new Function<LzyResponse<List<ServerModel>>, List<ServerModel>>() {\n                    @Override\n                    public List<ServerModel> apply(@NonNull LzyResponse<List<ServerModel>> response) throws Exception {\n                        return response.data;\n                    }\n                })//\n                .observeOn(AndroidSchedulers.mainThread())//\n                .subscribe(new Observer<List<ServerModel>>() {\n                    @Override\n                    public void onSubscribe(@NonNull Disposable d) {\n                        addDisposable(d);\n                    }\n\n                    @Override\n                    public void onNext(@NonNull List<ServerModel> response) {\n                        handleResponse(response);\n                    }\n\n                    @Override\n                    public void onError(@NonNull Throwable e) {\n                        e.printStackTrace();            //请求失败\n                        showToast(\"请求失败\");\n                        handleError(null);\n                    }\n\n                    @Override\n                    public void onComplete() {\n                        dismissLoading();\n                    }\n                });\n    }\n\n    @OnClick(R.id.upString)\n    public void upString(View view) {\n        OkGo.<String>post(Urls.URL_TEXT_UPLOAD)//\n                .headers(\"aaa\", \"111\")//\n                .upString(\"上传的文本。。。\")//\n                .converter(new StringConvert())//\n                .adapt(new ObservableResponse<String>())//\n                .subscribeOn(Schedulers.io())//\n                .doOnSubscribe(new Consumer<Disposable>() {\n                    @Override\n                    public void accept(@NonNull Disposable disposable) throws Exception {\n                        showLoading();\n                    }\n                })//\n                .observeOn(AndroidSchedulers.mainThread())//\n                .subscribe(new Observer<Response<String>>() {\n                    @Override\n                    public void onSubscribe(@NonNull Disposable d) {\n                        addDisposable(d);\n                    }\n\n                    @Override\n                    public void onNext(@NonNull Response<String> response) {\n                        handleResponse(response);\n                    }\n\n                    @Override\n                    public void onError(@NonNull Throwable e) {\n                        e.printStackTrace();\n                        showToast(\"请求失败\");\n                        handleError(null);\n                    }\n\n                    @Override\n                    public void onComplete() {\n                        dismissLoading();\n                    }\n                });\n    }\n\n    @OnClick(R.id.upJson)\n    public void upJson(View view) {\n        HashMap<String, String> params = new HashMap<>();\n        params.put(\"key1\", \"value1\");\n        params.put(\"key2\", \"这里是需要提交的json格式数据\");\n        params.put(\"key3\", \"也可以使用三方工具将对象转成json字符串\");\n        params.put(\"key4\", \"其实你怎么高兴怎么写都行\");\n        JSONObject jsonObject = new JSONObject(params);\n\n        OkGo.<String>post(Urls.URL_TEXT_UPLOAD)//\n                .headers(\"aaa\", \"111\")//\n                .upJson(jsonObject)//\n                .converter(new StringConvert())//\n                .adapt(new ObservableResponse<String>())//\n                .subscribeOn(Schedulers.io())//\n                .doOnSubscribe(new Consumer<Disposable>() {\n                    @Override\n                    public void accept(@NonNull Disposable disposable) throws Exception {\n                        showLoading();\n                    }\n                })//\n                .observeOn(AndroidSchedulers.mainThread())//\n                .subscribe(new Observer<Response<String>>() {\n                    @Override\n                    public void onSubscribe(@NonNull Disposable d) {\n                        addDisposable(d);\n                    }\n\n                    @Override\n                    public void onNext(@NonNull Response<String> response) {\n                        handleResponse(response);\n                    }\n\n                    @Override\n                    public void onError(@NonNull Throwable e) {\n                        e.printStackTrace();\n                        showToast(\"请求失败\");\n                        handleError(null);\n                    }\n\n                    @Override\n                    public void onComplete() {\n                        dismissLoading();\n                    }\n                });\n    }\n}\n"
  },
  {
    "path": "demo/src/main/java/com/lzy/demo/okrx2/RxFileDownloadActivity.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.demo.okrx2;\n\nimport android.Manifest;\nimport android.content.pm.PackageManager;\nimport android.os.Bundle;\nimport android.support.v4.app.ActivityCompat;\nimport android.text.TextUtils;\nimport android.text.format.Formatter;\nimport android.view.View;\nimport android.widget.Button;\nimport android.widget.EditText;\nimport android.widget.TextView;\n\nimport com.lzy.demo.R;\nimport com.lzy.demo.base.BaseRxDetailActivity;\nimport com.lzy.demo.ui.NumberProgressBar;\nimport com.lzy.demo.utils.Urls;\nimport com.lzy.okgo.OkGo;\nimport com.lzy.okgo.callback.FileCallback;\nimport com.lzy.okgo.convert.FileConvert;\nimport com.lzy.okgo.model.Progress;\nimport com.lzy.okgo.model.Response;\nimport com.lzy.okrx2.adapter.ObservableResponse;\n\nimport java.io.File;\nimport java.text.NumberFormat;\n\nimport butterknife.Bind;\nimport butterknife.ButterKnife;\nimport butterknife.OnClick;\nimport io.reactivex.Observable;\nimport io.reactivex.ObservableEmitter;\nimport io.reactivex.ObservableOnSubscribe;\nimport io.reactivex.Observer;\nimport io.reactivex.android.schedulers.AndroidSchedulers;\nimport io.reactivex.annotations.NonNull;\nimport io.reactivex.disposables.Disposable;\nimport io.reactivex.functions.Consumer;\nimport io.reactivex.schedulers.Schedulers;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：16/9/11\n * 描    述：\n * 修订历史：\n * ================================================\n */\npublic class RxFileDownloadActivity extends BaseRxDetailActivity {\n\n    private static final int REQUEST_PERMISSION_STORAGE = 0x01;\n\n    @Bind(R.id.et_url) EditText etUrl;\n    @Bind(R.id.fileDownload1) Button btnFileDownload1;\n    @Bind(R.id.fileDownload2) Button btnFileDownload2;\n    @Bind(R.id.downloadSize) TextView tvDownloadSize;\n    @Bind(R.id.tvProgress) TextView tvProgress;\n    @Bind(R.id.netSpeed) TextView tvNetSpeed;\n    @Bind(R.id.pbProgress) NumberProgressBar pbProgress;\n    private NumberFormat numberFormat;\n\n    @Override\n    protected void onActivityCreate(Bundle savedInstanceState) {\n        setContentView(R.layout.activity_rx_file_download);\n        ButterKnife.bind(this);\n        setTitle(\"文件下载\");\n\n        numberFormat = NumberFormat.getPercentInstance();\n        numberFormat.setMinimumFractionDigits(2);\n\n        checkSDCardPermission();\n    }\n\n    /** 检查SD卡权限 */\n    protected void checkSDCardPermission() {\n        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {\n            ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_PERMISSION_STORAGE);\n        }\n    }\n\n    @Override\n    public void onRequestPermissionsResult(int requestCode, @android.support.annotation.NonNull String[] permissions, @android.support.annotation.NonNull int[] grantResults) {\n        super.onRequestPermissionsResult(requestCode, permissions, grantResults);\n        if (requestCode == REQUEST_PERMISSION_STORAGE) {\n            if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {\n                //获取权限\n            } else {\n                showToast(\"权限被禁止，无法下载文件！\");\n            }\n        }\n    }\n\n    @Override\n    protected void onDestroy() {\n        super.onDestroy();\n        //Activity销毁时，取消网络请求\n        dispose();\n    }\n\n    @OnClick(R.id.fileDownload1)\n    public void fileDownload1(View view) {\n        //使用okrx直接下，下载进度封装比较麻烦,推荐使用回调方式\n        String etString = etUrl.getText().toString();\n        String url = TextUtils.isEmpty(etString) ? Urls.URL_DOWNLOAD : etString;\n        OkGo.<File>get(url)//\n                .headers(\"aaa\", \"111\")//\n                .params(\"bbb\", \"222\")//\n                .converter(new FileConvert())//\n                .adapt(new ObservableResponse<File>()).subscribeOn(Schedulers.io())//\n                .doOnSubscribe(new Consumer<Disposable>() {\n                    @Override\n                    public void accept(@NonNull Disposable disposable) throws Exception {\n                        btnFileDownload1.setText(\"正在下载中...\\n使用Rx方式做进度监听稍显麻烦,推荐使用方式2\");\n                    }\n                })//\n                .observeOn(AndroidSchedulers.mainThread())//\n                .subscribe(new Observer<Response<File>>() {\n                    @Override\n                    public void onSubscribe(@NonNull Disposable d) {\n                        addDisposable(d);\n                    }\n\n                    @Override\n                    public void onNext(@NonNull Response<File> response) {\n                        btnFileDownload1.setText(\"下载完成\");\n                        handleResponse(response);\n                    }\n\n                    @Override\n                    public void onError(@NonNull Throwable e) {\n                        e.printStackTrace();\n                        btnFileDownload1.setText(\"下载出错\");\n                        showToast(e.getMessage());\n                        handleError(null);\n                    }\n\n                    @Override\n                    public void onComplete() {\n\n                    }\n                });\n    }\n\n    @OnClick(R.id.fileDownload2)\n    public void fileDownload2(View view) {\n        Observable.create(new ObservableOnSubscribe<Progress>() {\n            @Override\n            public void subscribe(@NonNull final ObservableEmitter<Progress> e) throws Exception {\n                String etString = etUrl.getText().toString();\n                String url = TextUtils.isEmpty(etString) ? Urls.URL_DOWNLOAD : etString;\n                OkGo.<File>get(url)//\n                        .headers(\"aaa\", \"111\")//\n                        .params(\"bbb\", \"222\")//\n                        .execute(new FileCallback() {\n                            @Override\n                            public void onSuccess(Response<File> response) {\n                                e.onComplete();\n                            }\n\n                            @Override\n                            public void onError(Response<File> response) {\n                                e.onError(response.getException());\n                            }\n\n                            @Override\n                            public void downloadProgress(Progress progress) {\n                                e.onNext(progress);\n                            }\n                        });\n            }\n        })//\n                .doOnSubscribe(new Consumer<Disposable>() {\n                    @Override\n                    public void accept(@NonNull Disposable disposable) throws Exception {\n                        btnFileDownload2.setText(\"正在下载中...\");\n                    }\n                })//\n                .observeOn(AndroidSchedulers.mainThread())//\n                .subscribe(new Observer<Progress>() {\n                    @Override\n                    public void onSubscribe(@NonNull Disposable d) {\n                        addDisposable(d);\n                    }\n\n                    @Override\n                    public void onNext(@NonNull Progress progress) {\n                        String downloadLength = Formatter.formatFileSize(getApplicationContext(), progress.currentSize);\n                        String totalLength = Formatter.formatFileSize(getApplicationContext(), progress.totalSize);\n                        tvDownloadSize.setText(downloadLength + \"/\" + totalLength);\n                        String speed = Formatter.formatFileSize(getApplicationContext(), progress.speed);\n                        tvNetSpeed.setText(String.format(\"%s/s\", speed));\n                        tvProgress.setText(numberFormat.format(progress.fraction));\n                        pbProgress.setMax(10000);\n                        pbProgress.setProgress((int) (progress.fraction * 10000));\n                    }\n\n                    @Override\n                    public void onError(@NonNull Throwable e) {\n                        e.printStackTrace();\n                        btnFileDownload2.setText(\"下载出错\");\n                        showToast(e.getMessage());\n                    }\n\n                    @Override\n                    public void onComplete() {\n                        btnFileDownload2.setText(\"下载完成\");\n                    }\n                });\n    }\n}\n"
  },
  {
    "path": "demo/src/main/java/com/lzy/demo/okrx2/RxFormUploadActivity.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.demo.okrx2;\n\nimport android.content.Intent;\nimport android.os.Bundle;\nimport android.text.format.Formatter;\nimport android.view.View;\nimport android.widget.Button;\nimport android.widget.TextView;\nimport android.widget.Toast;\n\nimport com.lzy.demo.R;\nimport com.lzy.demo.base.BaseRxDetailActivity;\nimport com.lzy.demo.ui.NumberProgressBar;\nimport com.lzy.demo.utils.GlideImageLoader;\nimport com.lzy.demo.utils.Urls;\nimport com.lzy.imagepicker.ImagePicker;\nimport com.lzy.imagepicker.bean.ImageItem;\nimport com.lzy.imagepicker.ui.ImageGridActivity;\nimport com.lzy.okgo.OkGo;\nimport com.lzy.okgo.callback.StringCallback;\nimport com.lzy.okgo.convert.StringConvert;\nimport com.lzy.okgo.model.Progress;\nimport com.lzy.okgo.model.Response;\nimport com.lzy.okrx2.adapter.ObservableResponse;\n\nimport java.io.File;\nimport java.text.NumberFormat;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport butterknife.Bind;\nimport butterknife.ButterKnife;\nimport butterknife.OnClick;\nimport io.reactivex.Observable;\nimport io.reactivex.ObservableEmitter;\nimport io.reactivex.ObservableOnSubscribe;\nimport io.reactivex.Observer;\nimport io.reactivex.android.schedulers.AndroidSchedulers;\nimport io.reactivex.annotations.NonNull;\nimport io.reactivex.disposables.Disposable;\nimport io.reactivex.functions.Consumer;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：16/9/11\n * 描    述：\n * 修订历史：\n * ================================================\n */\npublic class RxFormUploadActivity extends BaseRxDetailActivity {\n\n    @Bind(R.id.formUpload1) Button btnFormUpload1;\n    @Bind(R.id.formUpload2) Button btnFormUpload2;\n    @Bind(R.id.downloadSize) TextView tvDownloadSize;\n    @Bind(R.id.tvProgress) TextView tvProgress;\n    @Bind(R.id.netSpeed) TextView tvNetSpeed;\n    @Bind(R.id.pbProgress) NumberProgressBar pbProgress;\n    @Bind(R.id.images) TextView tvImages;\n\n    private List<ImageItem> imageItems;\n    private NumberFormat numberFormat;\n\n    @Override\n    protected void onActivityCreate(Bundle savedInstanceState) {\n        setContentView(R.layout.activity_rx_form_upload);\n        ButterKnife.bind(this);\n        setTitle(\"文件上传\");\n\n        numberFormat = NumberFormat.getPercentInstance();\n        numberFormat.setMinimumFractionDigits(2);\n    }\n\n    @Override\n    protected void onDestroy() {\n        super.onDestroy();\n        //Activity销毁时，取消网络请求\n        dispose();\n    }\n\n    @OnClick(R.id.selectImage)\n    public void selectImage(View view) {\n        ImagePicker imagePicker = ImagePicker.getInstance();\n        imagePicker.setImageLoader(new GlideImageLoader());\n        imagePicker.setMultiMode(true);   //多选\n        imagePicker.setShowCamera(true);  //显示拍照按钮\n        imagePicker.setSelectLimit(9);    //最多选择9张\n        imagePicker.setCrop(false);       //不进行裁剪\n        Intent intent = new Intent(this, ImageGridActivity.class);\n        startActivityForResult(intent, 100);\n    }\n\n    @Override\n    public void onActivityResult(int requestCode, int resultCode, Intent data) {\n        super.onActivityResult(requestCode, resultCode, data);\n        if (resultCode == ImagePicker.RESULT_CODE_ITEMS) {\n            if (data != null && requestCode == 100) {\n                //noinspection unchecked\n                imageItems = (ArrayList<ImageItem>) data.getSerializableExtra(ImagePicker.EXTRA_RESULT_ITEMS);\n                if (imageItems != null && imageItems.size() > 0) {\n                    StringBuilder sb = new StringBuilder();\n                    for (int i = 0; i < imageItems.size(); i++) {\n                        if (i == imageItems.size() - 1) sb.append(\"图片\").append(i + 1).append(\" ： \").append(imageItems.get(i).path);\n                        else sb.append(\"图片\").append(i + 1).append(\" ： \").append(imageItems.get(i).path).append(\"\\n\");\n                    }\n                    tvImages.setText(sb.toString());\n                } else {\n                    tvImages.setText(\"--\");\n                }\n            } else {\n                Toast.makeText(this, \"没有选择图片\", Toast.LENGTH_SHORT).show();\n                tvImages.setText(\"--\");\n            }\n        }\n    }\n\n    @OnClick(R.id.formUpload1)\n    public void formUpload1(View view) {\n        ArrayList<File> files = new ArrayList<>();\n        if (imageItems != null && imageItems.size() > 0) {\n            for (int i = 0; i < imageItems.size(); i++) {\n                files.add(new File(imageItems.get(i).path));\n            }\n        }\n        //拼接参数\n        OkGo.<String>post(Urls.URL_FORM_UPLOAD)//\n                .tag(this)//\n                .headers(\"header1\", \"headerValue1\")//\n                .headers(\"header2\", \"headerValue2\")//\n                .params(\"param1\", \"paramValue1\")//\n                .params(\"param2\", \"paramValue2\")//\n//                .params(\"file1\",new File(\"文件路径\"))\n//                .params(\"file2\",new File(\"文件路径\"))\n//                .params(\"file3\",new File(\"文件路径\"))\n                .addFileParams(\"file\", files)//\n                .converter(new StringConvert())//\n                .adapt(new ObservableResponse<String>())//\n                .doOnSubscribe(new Consumer<Disposable>() {\n                    @Override\n                    public void accept(@NonNull Disposable disposable) throws Exception {\n                        btnFormUpload1.setText(\"正在上传中...\\n使用Rx方式做进度监听稍显麻烦,推荐使用方式2\");\n                    }\n                })//\n                .observeOn(AndroidSchedulers.mainThread())//\n                .subscribe(new Observer<Response<String>>() {\n                    @Override\n                    public void onSubscribe(@NonNull Disposable d) {\n                        addDisposable(d);\n                    }\n\n                    @Override\n                    public void onNext(@NonNull Response<String> response) {\n                        btnFormUpload1.setText(\"上传完成\");\n                        handleResponse(response);\n                    }\n\n                    @Override\n                    public void onError(@NonNull Throwable e) {\n                        e.printStackTrace();\n                        btnFormUpload1.setText(\"上传出错\");\n                        showToast(e.getMessage());\n                        handleError(null);\n                    }\n\n                    @Override\n                    public void onComplete() {\n\n                    }\n                });\n    }\n\n    @OnClick(R.id.formUpload2)\n    public void formUpload2(View view) {\n        final ArrayList<File> files = new ArrayList<>();\n        if (imageItems != null && imageItems.size() > 0) {\n            for (int i = 0; i < imageItems.size(); i++) {\n                files.add(new File(imageItems.get(i).path));\n            }\n        }\n\n        Observable.create(new ObservableOnSubscribe<Progress>() {\n            @Override\n            public void subscribe(@NonNull final ObservableEmitter<Progress> e) throws Exception {\n                OkGo.<String>post(Urls.URL_FORM_UPLOAD)//\n                        .tag(this)//\n                        .headers(\"header1\", \"headerValue1\")//\n                        .headers(\"header2\", \"headerValue2\")//\n                        .params(\"param1\", \"paramValue1\")//\n                        .params(\"param2\", \"paramValue2\")//\n                        //.params(\"file1\",new File(\"文件路径\"))\n                        //.params(\"file2\",new File(\"文件路径\"))\n                        //.params(\"file3\",new File(\"文件路径\"))\n                        .addFileParams(\"file\", files)//\n                        .execute(new StringCallback() {\n                            @Override\n                            public void onSuccess(Response<String> response) {\n                                e.onComplete();\n                            }\n\n                            @Override\n                            public void onError(Response<String> response) {\n                                e.onError(response.getException());\n                            }\n\n                            @Override\n                            public void uploadProgress(Progress progress) {\n                                e.onNext(progress);\n                            }\n                        });\n            }\n        })//\n                .doOnSubscribe(new Consumer<Disposable>() {\n                    @Override\n                    public void accept(@NonNull Disposable disposable) throws Exception {\n                        btnFormUpload2.setText(\"正在上传中...\");\n                    }\n                })//\n                .observeOn(AndroidSchedulers.mainThread())//\n                .subscribe(new Observer<Progress>() {\n                    @Override\n                    public void onSubscribe(@NonNull Disposable d) {\n                        addDisposable(d);\n                    }\n\n                    @Override\n                    public void onNext(@NonNull Progress progress) {\n                        System.out.println(\"uploadProgress: \" + progress);\n\n                        String downloadLength = Formatter.formatFileSize(getApplicationContext(), progress.currentSize);\n                        String totalLength = Formatter.formatFileSize(getApplicationContext(), progress.totalSize);\n                        tvDownloadSize.setText(downloadLength + \"/\" + totalLength);\n                        String speed = Formatter.formatFileSize(getApplicationContext(), progress.speed);\n                        tvNetSpeed.setText(String.format(\"%s/s\", speed));\n                        tvProgress.setText(numberFormat.format(progress.fraction));\n                        pbProgress.setMax(10000);\n                        pbProgress.setProgress((int) (progress.fraction * 10000));\n                    }\n\n                    @Override\n                    public void onError(@NonNull Throwable e) {\n                        e.printStackTrace();\n                        btnFormUpload2.setText(\"上传出错\");\n                        showToast(e.getMessage());\n                    }\n\n                    @Override\n                    public void onComplete() {\n                        btnFormUpload2.setText(\"上传完成\");\n                    }\n                });\n    }\n}\n"
  },
  {
    "path": "demo/src/main/java/com/lzy/demo/okrx2/RxRetrofitActivity.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.demo.okrx2;\n\nimport android.os.Bundle;\nimport android.view.View;\n\nimport com.google.gson.reflect.TypeToken;\nimport com.lzy.demo.R;\nimport com.lzy.demo.base.BaseRxDetailActivity;\nimport com.lzy.demo.model.LzyResponse;\nimport com.lzy.demo.model.ServerModel;\nimport com.lzy.demo.utils.Urls;\n\nimport java.lang.reflect.Type;\nimport java.util.List;\n\nimport butterknife.ButterKnife;\nimport butterknife.OnClick;\nimport io.reactivex.Observer;\nimport io.reactivex.android.schedulers.AndroidSchedulers;\nimport io.reactivex.annotations.NonNull;\nimport io.reactivex.disposables.Disposable;\nimport io.reactivex.functions.Consumer;\nimport io.reactivex.functions.Function;\nimport io.reactivex.schedulers.Schedulers;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：16/9/11\n * 描    述：\n * 修订历史：\n * ================================================\n */\npublic class RxRetrofitActivity extends BaseRxDetailActivity {\n\n    @Override\n    protected void onActivityCreate(Bundle savedInstanceState) {\n        setContentView(R.layout.activity_rx_retrofit);\n        ButterKnife.bind(this);\n        setTitle(\"统一管理请求\");\n    }\n\n    @Override\n    protected void onDestroy() {\n        super.onDestroy();\n        //Activity销毁时，取消网络请求\n        dispose();\n    }\n\n    @OnClick(R.id.retrofitRequest)\n    public void retrofitRequest(View view) {\n        ServerApi.getString(\"aaa\", \"bbb\")//\n                .subscribeOn(Schedulers.io())//\n                .doOnSubscribe(new Consumer<Disposable>() {\n                    @Override\n                    public void accept(@NonNull Disposable disposable) throws Exception {\n                        showLoading();\n                    }\n                })//\n                .observeOn(AndroidSchedulers.mainThread())  //\n                .subscribe(new Observer<String>() {\n                    @Override\n                    public void onSubscribe(@NonNull Disposable d) {\n                        addDisposable(d);\n                    }\n\n                    @Override\n                    public void onNext(@NonNull String s) {\n                        handleResponse(s);\n                    }\n\n                    @Override\n                    public void onError(@NonNull Throwable e) {\n                        e.printStackTrace();            //请求失败\n                        showToast(\"请求失败\");\n                        handleError(null);\n                    }\n\n                    @Override\n                    public void onComplete() {\n                        dismissLoading();\n                    }\n                });\n    }\n\n    @OnClick(R.id.jsonRequest)\n    public void jsonRequest(View view) {\n        Type type = new TypeToken<LzyResponse<ServerModel>>() {}.getType();\n        ServerApi.<LzyResponse<ServerModel>>getData(type, Urls.URL_JSONOBJECT, \"aaa\", \"bbb\")//\n                .subscribeOn(Schedulers.io())//\n                .doOnSubscribe(new Consumer<Disposable>() {\n                    @Override\n                    public void accept(@NonNull Disposable disposable) throws Exception {\n                        showLoading();\n                    }\n                })//\n                .map(new Function<LzyResponse<ServerModel>, ServerModel>() {\n                    @Override\n                    public ServerModel apply(@NonNull LzyResponse<ServerModel> response) throws Exception {\n                        return response.data;\n                    }\n                })//\n                .observeOn(AndroidSchedulers.mainThread())  //\n                .subscribe(new Observer<ServerModel>() {\n                    @Override\n                    public void onSubscribe(@NonNull Disposable d) {\n                        addDisposable(d);\n                    }\n\n                    @Override\n                    public void onNext(@NonNull ServerModel response) {\n                        handleResponse(response);\n                    }\n\n                    @Override\n                    public void onError(@NonNull Throwable e) {\n                        e.printStackTrace();            //请求失败\n                        showToast(\"请求失败\");\n                        handleError(null);\n                    }\n\n                    @Override\n                    public void onComplete() {\n                        dismissLoading();\n                    }\n                });\n    }\n\n    @OnClick(R.id.jsonArrayRequest)\n    public void jsonArrayRequest(View view) {\n        Type type = new TypeToken<LzyResponse<List<ServerModel>>>() {}.getType();\n        ServerApi.<LzyResponse<List<ServerModel>>>getData(type, Urls.URL_JSONARRAY, \"aaa\", \"bbb\")//\n                .doOnSubscribe(new Consumer<Disposable>() {\n                    @Override\n                    public void accept(@NonNull Disposable disposable) throws Exception {\n                        showLoading();\n                    }\n                })//\n                .map(new Function<LzyResponse<List<ServerModel>>, List<ServerModel>>() {\n                    @Override\n                    public List<ServerModel> apply(@NonNull LzyResponse<List<ServerModel>> response) throws Exception {\n                        return response.data;\n                    }\n                })//\n                .observeOn(AndroidSchedulers.mainThread())//\n                .subscribe(new Observer<List<ServerModel>>() {\n                    @Override\n                    public void onSubscribe(@NonNull Disposable d) {\n                        addDisposable(d);\n                    }\n\n                    @Override\n                    public void onNext(@NonNull List<ServerModel> response) {\n                        handleResponse(response);\n                    }\n\n                    @Override\n                    public void onError(@NonNull Throwable e) {\n                        e.printStackTrace();            //请求失败\n                        showToast(\"请求失败\");\n                        handleError(null);\n                    }\n\n                    @Override\n                    public void onComplete() {\n                        dismissLoading();\n                    }\n                });\n    }\n}\n"
  },
  {
    "path": "demo/src/main/java/com/lzy/demo/okrx2/RxUtils.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.demo.okrx2;\n\nimport com.lzy.demo.callback.JsonConvert;\nimport com.lzy.okgo.OkGo;\nimport com.lzy.okgo.model.HttpHeaders;\nimport com.lzy.okgo.model.HttpMethod;\nimport com.lzy.okgo.model.HttpParams;\nimport com.lzy.okgo.request.base.Request;\nimport com.lzy.okrx2.adapter.ObservableBody;\n\nimport java.lang.reflect.Type;\n\nimport io.reactivex.Observable;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：2017/5/28\n * 描    述：\n * 修订历史：\n * ================================================\n */\npublic class RxUtils {\n\n    public static <T> Observable<T> request(HttpMethod method, String url, Type type) {\n        return request(method, url, type, null);\n    }\n\n    public static <T> Observable<T> request(HttpMethod method, String url, Type type, HttpParams params) {\n        return request(method, url, type, params, null);\n    }\n\n    public static <T> Observable<T> request(HttpMethod method, String url, Type type, HttpParams params, HttpHeaders headers) {\n        return request(method, url, type, null, params, headers);\n    }\n\n    public static <T> Observable<T> request(HttpMethod method, String url, Class<T> clazz) {\n        return request(method, url, clazz, null);\n    }\n\n    public static <T> Observable<T> request(HttpMethod method, String url, Class<T> clazz, HttpParams params) {\n        return request(method, url, clazz, params, null);\n    }\n\n    public static <T> Observable<T> request(HttpMethod method, String url, Class<T> clazz, HttpParams params, HttpHeaders headers) {\n        return request(method, url, null, clazz, params, headers);\n    }\n\n    /**\n     * 这个封装其实没有必要，只是有些人喜欢这么干，我就多此一举写出来了。。\n     * 这个封装其实没有必要，只是有些人喜欢这么干，我就多此一举写出来了。。\n     * 这个封装其实没有必要，只是有些人喜欢这么干，我就多此一举写出来了。。\n     */\n    public static <T> Observable<T> request(HttpMethod method, String url, Type type, Class<T> clazz, HttpParams params, HttpHeaders headers) {\n        Request<T, ? extends Request> request;\n        if (method == HttpMethod.GET) request = OkGo.get(url);\n        else if (method == HttpMethod.POST) request = OkGo.post(url);\n        else if (method == HttpMethod.PUT) request = OkGo.put(url);\n        else if (method == HttpMethod.DELETE) request = OkGo.delete(url);\n        else if (method == HttpMethod.HEAD) request = OkGo.head(url);\n        else if (method == HttpMethod.PATCH) request = OkGo.patch(url);\n        else if (method == HttpMethod.OPTIONS) request = OkGo.options(url);\n        else if (method == HttpMethod.TRACE) request = OkGo.trace(url);\n        else request = OkGo.get(url);\n\n        request.headers(headers);\n        request.params(params);\n        if (type != null) {\n            request.converter(new JsonConvert<T>(type));\n        } else if (clazz != null) {\n            request.converter(new JsonConvert<T>(clazz));\n        } else {\n            request.converter(new JsonConvert<T>());\n        }\n        return request.adapt(new ObservableBody<T>());\n    }\n}\n"
  },
  {
    "path": "demo/src/main/java/com/lzy/demo/okrx2/ServerApi.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.demo.okrx2;\n\nimport android.graphics.Bitmap;\n\nimport com.lzy.demo.utils.Urls;\nimport com.lzy.okgo.OkGo;\nimport com.lzy.okgo.convert.BitmapConvert;\nimport com.lzy.okgo.convert.FileConvert;\nimport com.lzy.okgo.model.HttpHeaders;\nimport com.lzy.okgo.model.HttpMethod;\nimport com.lzy.okgo.model.HttpParams;\nimport com.lzy.okgo.model.Response;\nimport com.lzy.okrx2.adapter.ObservableResponse;\n\nimport java.io.File;\nimport java.lang.reflect.Type;\n\nimport io.reactivex.Observable;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：16/9/30\n * 描    述：\n * 修订历史：\n * ================================================\n */\npublic class ServerApi {\n\n    public static Observable<String> getString(String header, String param) {\n        HttpHeaders headers = new HttpHeaders();\n        headers.put(\"aaa\", header);\n        HttpParams params = new HttpParams();\n        params.put(\"bbb\", param);\n        //这个RxUtils的封装其实没有必要，只是有些人喜欢这么干，我就多此一举写出来了。。\n        //这个RxUtils的封装其实没有必要，只是有些人喜欢这么干，我就多此一举写出来了。。\n        //这个RxUtils的封装其实没有必要，只是有些人喜欢这么干，我就多此一举写出来了。。\n        return RxUtils.request(HttpMethod.GET, Urls.URL_METHOD, String.class, params, headers);\n    }\n\n    public static <T> Observable<T> getData(Type type, String url, String header, String param) {\n        HttpHeaders headers = new HttpHeaders();\n        headers.put(\"aaa\", header);\n        HttpParams params = new HttpParams();\n        params.put(\"bbb\", param);\n        //这个RxUtils的封装其实没有必要，只是有些人喜欢这么干，我就多此一举写出来了。。\n        //这个RxUtils的封装其实没有必要，只是有些人喜欢这么干，我就多此一举写出来了。。\n        //这个RxUtils的封装其实没有必要，只是有些人喜欢这么干，我就多此一举写出来了。。\n        return RxUtils.request(HttpMethod.POST, url, type, params, headers);\n    }\n\n    public static Observable<Response<Bitmap>> getBitmap(String header, String param) {\n        return OkGo.<Bitmap>post(Urls.URL_IMAGE)//\n                .headers(\"aaa\", header)//\n                .params(\"bbb\", param)//\n                .converter(new BitmapConvert())//\n                .adapt(new ObservableResponse<Bitmap>());\n    }\n\n    public static Observable<Response<File>> getFile(String header, String param) {\n        return OkGo.<File>get(Urls.URL_DOWNLOAD)//\n                .headers(\"aaa\", header)//\n                .params(\"bbb\", param)//\n                .converter(new FileConvert())//\n                .adapt(new ObservableResponse<File>());\n    }\n}\n"
  },
  {
    "path": "demo/src/main/java/com/lzy/demo/okupload/LogUploadListener.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.demo.okupload;\n\nimport com.lzy.okgo.model.Progress;\nimport com.lzy.okserver.upload.UploadListener;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：2017/6/7\n * 描    述：\n * 修订历史：\n * ================================================\n */\npublic class LogUploadListener<T> extends UploadListener<T> {\n\n    public LogUploadListener() {\n        super(\"LogUploadListener\");\n    }\n\n    @Override\n    public void onStart(Progress progress) {\n        System.out.println(\"onStart: \" + progress);\n    }\n\n    @Override\n    public void onProgress(Progress progress) {\n        System.out.println(\"onProgress: \" + progress);\n    }\n\n    @Override\n    public void onError(Progress progress) {\n        System.out.println(\"onError: \" + progress);\n        progress.exception.printStackTrace();\n    }\n\n    @Override\n    public void onFinish(T t, Progress progress) {\n        System.out.println(\"onFinish: \" + progress);\n    }\n\n    @Override\n    public void onRemove(Progress progress) {\n        System.out.println(\"onRemove: \" + progress);\n    }\n}\n"
  },
  {
    "path": "demo/src/main/java/com/lzy/demo/okupload/OkUploadFragment.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.demo.okupload;\n\nimport android.content.Intent;\n\nimport com.lzy.demo.base.MainFragment;\nimport com.lzy.demo.model.ItemModel;\n\nimport java.util.List;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：2017/6/9\n * 描    述：\n * 修订历史：\n * ================================================\n */\npublic class OkUploadFragment extends MainFragment {\n\n    @Override\n    public void fillData(List<ItemModel> items) {\n\n        items.add(new ItemModel(\"开始上传\",//\n                                \"1. 这个属于OkServer依赖中的功能,并不属于OkGo\\n\" +//\n                                \"2. 只是简单上传管理,不支持断点上传或者分片上传\\n\" +//\n                                \"3. 支持自定义上传任务优先级\\n\" +//\n                                \"4. 支持链试调用\\n\" +//\n                                \"5. 最多支持扩展3个额外数据\"));\n\n        items.add(new ItemModel(\"所有任务\",//\n                                \"1. 每个任务支持停止，重新上传，删除等操作\\n\" +//\n                                \"2. 支持全部停止，全部开始，全部删除\\n\" +//\n                                \"3. 支持全局上传任务监听\\n\" +//\n                                \"4. 支持一个任务多个监听\\n\" +//\n                                \"5. 支持按上传中列表和上传完成列表筛选\"));\n\n        items.add(new ItemModel(\"上传中任务\",//\n                                \"1. 每个任务支持停止，重新上传，删除等操作\\n\" +//\n                                \"2. 支持全部停止，全部开始，全部删除\\n\" +//\n                                \"3. 支持全局上传任务监听\\n\" +//\n                                \"4. 支持一个任务多个监听\\n\" +//\n                                \"5. 支持按上传中列表和上传完成列表筛选\"));\n\n        items.add(new ItemModel(\"已完成任务\",//\n                                \"1. 每个任务支持停止，重新上传，删除等操作\\n\" +//\n                                \"2. 支持全部停止，全部开始，全部删除\\n\" +//\n                                \"3. 支持全局上传任务监听\\n\" +//\n                                \"4. 支持一个任务多个监听\\n\" +//\n                                \"5. 支持按上传中列表和上传完成列表筛选\"));\n    }\n\n    @Override\n    public void onItemClick(int position) {\n        if (position == 0) startActivity(new Intent(context, UploadListActivity.class));\n        if (position == 1) startActivity(new Intent(context, UploadAllActivity.class));\n        if (position == 2) startActivity(new Intent(context, UploadingActivity.class));\n        if (position == 3) startActivity(new Intent(context, UploadFinishActivity.class));\n    }\n}\n"
  },
  {
    "path": "demo/src/main/java/com/lzy/demo/okupload/UploadAdapter.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.demo.okupload;\n\nimport android.content.Context;\nimport android.support.v7.widget.RecyclerView;\nimport android.text.format.Formatter;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.Button;\nimport android.widget.ImageView;\nimport android.widget.TextView;\nimport android.widget.Toast;\n\nimport com.bumptech.glide.Glide;\nimport com.lzy.demo.R;\nimport com.lzy.demo.ui.NumberProgressBar;\nimport com.lzy.demo.utils.Urls;\nimport com.lzy.imagepicker.bean.ImageItem;\nimport com.lzy.okgo.OkGo;\nimport com.lzy.okgo.convert.StringConvert;\nimport com.lzy.okgo.db.UploadManager;\nimport com.lzy.okgo.model.Progress;\nimport com.lzy.okgo.request.PostRequest;\nimport com.lzy.okgo.request.base.Request;\nimport com.lzy.okserver.OkUpload;\nimport com.lzy.okserver.upload.UploadListener;\nimport com.lzy.okserver.upload.UploadTask;\n\nimport java.io.File;\nimport java.text.NumberFormat;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Random;\n\nimport butterknife.Bind;\nimport butterknife.ButterKnife;\nimport butterknife.OnClick;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：2017/6/5\n * 描    述：\n * 修订历史：\n * ================================================\n */\npublic class UploadAdapter extends RecyclerView.Adapter<UploadAdapter.ViewHolder> {\n\n    public static final int TYPE_ALL = 0;\n    public static final int TYPE_FINISH = 1;\n    public static final int TYPE_ING = 2;\n\n    private List<UploadTask<?>> values;\n    private List<ImageItem> images;\n    private NumberFormat numberFormat;\n    private LayoutInflater inflater;\n    private Context context;\n    private int type = -1;\n\n    public UploadAdapter(Context context) {\n        this.context = context;\n        numberFormat = NumberFormat.getPercentInstance();\n        numberFormat.setMinimumFractionDigits(2);\n        inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);\n    }\n\n    public void updateData(int type) {\n        //这里是将数据库的数据恢复\n        this.type = type;\n        if (type == TYPE_ALL) values = OkUpload.restore(UploadManager.getInstance().getAll());\n        if (type == TYPE_FINISH) values = OkUpload.restore(UploadManager.getInstance().getFinished());\n        if (type == TYPE_ING) values = OkUpload.restore(UploadManager.getInstance().getUploading());\n\n        //由于Converter是无法保存下来的，所以这里恢复任务的时候，需要额外传入Converter，否则就没法解析数据\n        //至于数据类型，统一就行，不一定非要是String\n        for (UploadTask<?> task : values) {\n            //noinspection unchecked\n            Request<String, ? extends Request> request = (Request<String, ? extends Request>) task.progress.request;\n            request.converter(new StringConvert());\n        }\n\n        notifyDataSetChanged();\n    }\n\n    public List<UploadTask<?>> updateData(List<ImageItem> images) {\n        this.type = -1;\n        this.images = images;\n        values = new ArrayList<>();\n        if (images != null) {\n            Random random = new Random();\n            for (int i = 0; i < images.size(); i++) {\n                ImageItem imageItem = images.get(i);\n                //这里是演示可以传递任何数据\n                PostRequest<String> postRequest = OkGo.<String>post(Urls.URL_FORM_UPLOAD)//\n                        .headers(\"aaa\", \"111\")//\n                        .params(\"bbb\", \"222\")//\n                        .params(\"fileKey\" + i, new File(imageItem.path))//\n                        .converter(new StringConvert());\n\n                UploadTask<String> task = OkUpload.request(imageItem.path, postRequest)//\n                        .priority(random.nextInt(100))//\n                        .extra1(imageItem)//\n                        .save();\n                values.add(task);\n            }\n        }\n        notifyDataSetChanged();\n        return values;\n    }\n\n    @Override\n    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {\n        View view = inflater.inflate(R.layout.item_upload_manager, parent, false);\n        return new ViewHolder(view);\n    }\n\n    @Override\n    public void onBindViewHolder(ViewHolder holder, int position) {\n        //noinspection unchecked\n        UploadTask<String> task = (UploadTask<String>) values.get(position);\n        String tag = createTag(task);\n        task.register(new ListUploadListener(tag, holder))//\n                .register(new LogUploadListener<String>());\n        holder.setTag(tag);\n        holder.setTask(task);\n        holder.bind();\n        holder.refresh(task.progress);\n    }\n\n    public void unRegister() {\n        Map<String, UploadTask<?>> taskMap = OkUpload.getInstance().getTaskMap();\n        for (UploadTask<?> task : taskMap.values()) {\n            task.unRegister(createTag(task));\n        }\n    }\n\n    private String createTag(UploadTask task) {\n        return type + \"_\" + task.progress.tag;\n    }\n\n    @Override\n    public int getItemCount() {\n        return values == null ? 0 : values.size();\n    }\n\n    public class ViewHolder extends RecyclerView.ViewHolder {\n\n        @Bind(R.id.icon) ImageView icon;\n        @Bind(R.id.name) TextView name;\n        @Bind(R.id.priority) TextView priority;\n        @Bind(R.id.downloadSize) TextView downloadSize;\n        @Bind(R.id.tvProgress) TextView tvProgress;\n        @Bind(R.id.netSpeed) TextView netSpeed;\n        @Bind(R.id.pbProgress) NumberProgressBar pbProgress;\n        @Bind(R.id.upload) Button upload;\n        private UploadTask<?> task;\n        private String tag;\n\n        public ViewHolder(View itemView) {\n            super(itemView);\n            ButterKnife.bind(this, itemView);\n        }\n\n        public void setTask(UploadTask<?> task) {\n            this.task = task;\n        }\n\n        public void bind() {\n            Progress progress = task.progress;\n            ImageItem item = (ImageItem) progress.extra1;\n            Glide.with(context).load(item.path).error(R.mipmap.ic_launcher).into(icon);\n            name.setText(item.name);\n            priority.setText(String.format(\"优先级：%s\", progress.priority));\n        }\n\n        public void refresh(Progress progress) {\n            String currentSize = Formatter.formatFileSize(context, progress.currentSize);\n            String totalSize = Formatter.formatFileSize(context, progress.totalSize);\n            downloadSize.setText(currentSize + \"/\" + totalSize);\n            priority.setText(String.format(\"优先级：%s\", progress.priority));\n            switch (progress.status) {\n                case Progress.NONE:\n                    netSpeed.setText(\"停止\");\n                    upload.setText(\"上传\");\n                    break;\n                case Progress.PAUSE:\n                    netSpeed.setText(\"暂停中\");\n                    upload.setText(\"继续\");\n                    break;\n                case Progress.ERROR:\n                    netSpeed.setText(\"上传出错\");\n                    upload.setText(\"出错\");\n                    break;\n                case Progress.WAITING:\n                    netSpeed.setText(\"等待中\");\n                    upload.setText(\"等待\");\n                    break;\n                case Progress.FINISH:\n                    upload.setText(\"完成\");\n                    netSpeed.setText(\"上传成功\");\n                    break;\n                case Progress.LOADING:\n                    String speed = Formatter.formatFileSize(context, progress.speed);\n                    netSpeed.setText(String.format(\"%s/s\", speed));\n                    upload.setText(\"停止\");\n                    break;\n            }\n            tvProgress.setText(numberFormat.format(progress.fraction));\n            pbProgress.setMax(10000);\n            pbProgress.setProgress((int) (progress.fraction * 10000));\n        }\n\n        @OnClick(R.id.upload)\n        public void upload() {\n            Progress progress = task.progress;\n            switch (progress.status) {\n                case Progress.PAUSE:\n                case Progress.NONE:\n                case Progress.ERROR:\n                    task.start();\n                    break;\n                case Progress.LOADING:\n                    task.pause();\n                    break;\n                case Progress.FINISH:\n                    break;\n            }\n            refresh(progress);\n        }\n\n        @OnClick(R.id.remove)\n        public void remove() {\n            task.remove();\n            if (type == -1) {\n                int removeIndex = -1;\n                for (int i = 0; i < images.size(); i++) {\n                    if (images.get(i).path.equals(task.progress.tag)) {\n                        removeIndex = i;\n                        break;\n                    }\n                }\n                if (removeIndex != -1) {\n                    images.remove(removeIndex);\n                }\n                updateData(images);\n            } else {\n                updateData(type);\n            }\n        }\n\n        @OnClick(R.id.restart)\n        public void restart() {\n            task.restart();\n        }\n\n        public void setTag(String tag) {\n            this.tag = tag;\n        }\n\n        public String getTag() {\n            return tag;\n        }\n    }\n\n    private class ListUploadListener extends UploadListener<String> {\n\n        private ViewHolder holder;\n\n        ListUploadListener(Object tag, ViewHolder holder) {\n            super(tag);\n            this.holder = holder;\n        }\n\n        @Override\n        public void onStart(Progress progress) {\n        }\n\n        @Override\n        public void onProgress(Progress progress) {\n            if (tag == holder.getTag()) {\n                holder.refresh(progress);\n            }\n        }\n\n        @Override\n        public void onError(Progress progress) {\n            Throwable throwable = progress.exception;\n            if (throwable != null) throwable.printStackTrace();\n        }\n\n        @Override\n        public void onFinish(String s, Progress progress) {\n            Toast.makeText(context, \"上传完成\", Toast.LENGTH_SHORT).show();\n            if (type != -1) updateData(type);\n        }\n\n        @Override\n        public void onRemove(Progress progress) {\n        }\n    }\n}\n"
  },
  {
    "path": "demo/src/main/java/com/lzy/demo/okupload/UploadAllActivity.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.demo.okupload;\n\nimport android.os.Bundle;\nimport android.support.v7.widget.LinearLayoutManager;\nimport android.support.v7.widget.RecyclerView;\nimport android.support.v7.widget.Toolbar;\nimport android.view.View;\nimport android.widget.Button;\n\nimport com.lzy.demo.R;\nimport com.lzy.demo.base.BaseActivity;\nimport com.lzy.okserver.OkUpload;\nimport com.lzy.okserver.task.XExecutor;\n\nimport butterknife.Bind;\nimport butterknife.OnClick;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：16/9/11\n * 描    述：\n * 修订历史：\n * ================================================\n */\npublic class UploadAllActivity extends BaseActivity implements XExecutor.OnAllTaskEndListener {\n\n    @Bind(R.id.toolbar) Toolbar toolbar;\n    @Bind(R.id.recyclerView) RecyclerView recyclerView;\n    @Bind(R.id.select) Button select;\n    @Bind(R.id.upload) Button upload;\n    @Bind(R.id.deleteAll) Button deleteAll;\n\n    private OkUpload okUpload;\n    private UploadAdapter adapter;\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.activity_upload_list);\n        initToolBar(toolbar, true, \"所有任务\");\n\n        select.setVisibility(View.GONE);\n        upload.setVisibility(View.GONE);\n        deleteAll.setVisibility(View.VISIBLE);\n\n        okUpload = OkUpload.getInstance();\n        okUpload.getThreadPool().setCorePoolSize(1);\n\n        adapter = new UploadAdapter(this);\n        adapter.updateData(UploadAdapter.TYPE_ALL);\n        recyclerView.setLayoutManager(new LinearLayoutManager(this));\n        recyclerView.setAdapter(adapter);\n\n        okUpload.addOnAllTaskEndListener(this);\n    }\n\n    @Override\n    protected void onDestroy() {\n        super.onDestroy();\n        okUpload.removeOnAllTaskEndListener(this);\n        adapter.unRegister();\n    }\n\n    @Override\n    public void onAllTaskEnd() {\n        showToast(\"所有上传任务已结束\");\n    }\n\n    @OnClick(R.id.deleteAll)\n    public void deleteAll(View view) {\n        OkUpload.getInstance().removeAll();\n        adapter.updateData(UploadAdapter.TYPE_ALL);\n        adapter.notifyDataSetChanged();\n    }\n}\n"
  },
  {
    "path": "demo/src/main/java/com/lzy/demo/okupload/UploadFinishActivity.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.demo.okupload;\n\nimport android.os.Bundle;\nimport android.support.v7.widget.LinearLayoutManager;\nimport android.support.v7.widget.RecyclerView;\nimport android.support.v7.widget.Toolbar;\nimport android.view.View;\nimport android.widget.Button;\n\nimport com.lzy.demo.R;\nimport com.lzy.demo.base.BaseActivity;\nimport com.lzy.okserver.OkUpload;\nimport com.lzy.okserver.task.XExecutor;\n\nimport butterknife.Bind;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：16/9/11\n * 描    述：\n * 修订历史：\n * ================================================\n */\npublic class UploadFinishActivity extends BaseActivity implements XExecutor.OnAllTaskEndListener {\n\n    @Bind(R.id.toolbar) Toolbar toolbar;\n    @Bind(R.id.recyclerView) RecyclerView recyclerView;\n    @Bind(R.id.select) Button select;\n    @Bind(R.id.upload) Button upload;\n\n    private OkUpload okUpload;\n    private UploadAdapter adapter;\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.activity_upload_list);\n        initToolBar(toolbar, true, \"已完成任务\");\n\n        select.setVisibility(View.GONE);\n        upload.setVisibility(View.GONE);\n\n        okUpload = OkUpload.getInstance();\n        okUpload.getThreadPool().setCorePoolSize(1);\n\n        adapter = new UploadAdapter(this);\n        adapter.updateData(UploadAdapter.TYPE_FINISH);\n        recyclerView.setLayoutManager(new LinearLayoutManager(this));\n        recyclerView.setAdapter(adapter);\n\n        okUpload.addOnAllTaskEndListener(this);\n    }\n\n    @Override\n    protected void onDestroy() {\n        super.onDestroy();\n        okUpload.removeOnAllTaskEndListener(this);\n        adapter.unRegister();\n    }\n\n    @Override\n    public void onAllTaskEnd() {\n        showToast(\"所有上传任务已结束\");\n    }\n}\n"
  },
  {
    "path": "demo/src/main/java/com/lzy/demo/okupload/UploadListActivity.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.demo.okupload;\n\nimport android.content.Intent;\nimport android.os.Bundle;\nimport android.support.v7.widget.LinearLayoutManager;\nimport android.support.v7.widget.RecyclerView;\nimport android.support.v7.widget.Toolbar;\nimport android.view.View;\n\nimport com.lzy.demo.R;\nimport com.lzy.demo.base.BaseActivity;\nimport com.lzy.demo.utils.GlideImageLoader;\nimport com.lzy.imagepicker.ImagePicker;\nimport com.lzy.imagepicker.bean.ImageItem;\nimport com.lzy.imagepicker.ui.ImageGridActivity;\nimport com.lzy.okserver.OkUpload;\nimport com.lzy.okserver.task.XExecutor;\nimport com.lzy.okserver.upload.UploadTask;\n\nimport java.util.List;\n\nimport butterknife.Bind;\nimport butterknife.OnClick;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：16/9/11\n * 描    述：\n * 修订历史：\n * ================================================\n */\npublic class UploadListActivity extends BaseActivity implements XExecutor.OnAllTaskEndListener {\n\n    @Bind(R.id.toolbar) Toolbar toolbar;\n    @Bind(R.id.recyclerView) RecyclerView recyclerView;\n\n    private UploadAdapter adapter;\n    private OkUpload okUpload;\n    private List<UploadTask<?>> tasks;\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.activity_upload_list);\n        initToolBar(toolbar, true, \"开始上传\");\n\n        okUpload = OkUpload.getInstance();\n        okUpload.getThreadPool().setCorePoolSize(1);\n\n        adapter = new UploadAdapter(this);\n        recyclerView.setLayoutManager(new LinearLayoutManager(this));\n        recyclerView.setAdapter(adapter);\n\n        okUpload.addOnAllTaskEndListener(this);\n    }\n\n    @Override\n    protected void onDestroy() {\n        super.onDestroy();\n        okUpload.removeOnAllTaskEndListener(this);\n        adapter.unRegister();\n    }\n\n    @Override\n    public void onAllTaskEnd() {\n        showToast(\"所有上传任务已结束\");\n    }\n\n    @OnClick(R.id.select)\n    public void select(View view) {\n        ImagePicker imagePicker = ImagePicker.getInstance();\n        imagePicker.setImageLoader(new GlideImageLoader());\n        imagePicker.setShowCamera(true);\n        imagePicker.setSelectLimit(9);\n        imagePicker.setCrop(false);\n        Intent intent = new Intent(getApplicationContext(), ImageGridActivity.class);\n        startActivityForResult(intent, 100);\n    }\n\n    @OnClick(R.id.upload)\n    public void upload(View view) {\n        if (tasks == null) {\n            showToast(\"请先选择图片\");\n            return;\n        }\n        for (UploadTask<?> task : tasks) {\n            task.start();\n        }\n    }\n\n    @Override\n    public void onActivityResult(int requestCode, int resultCode, Intent data) {\n        super.onActivityResult(requestCode, resultCode, data);\n        if (resultCode == ImagePicker.RESULT_CODE_ITEMS) {\n            if (data != null && requestCode == 100) {\n                //noinspection unchecked\n                List<ImageItem> images = (List<ImageItem>) data.getSerializableExtra(ImagePicker.EXTRA_RESULT_ITEMS);\n                tasks = adapter.updateData(images);\n            } else {\n                showToast(\"没有数据\");\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "demo/src/main/java/com/lzy/demo/okupload/UploadingActivity.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.demo.okupload;\n\nimport android.os.Bundle;\nimport android.support.v7.widget.LinearLayoutManager;\nimport android.support.v7.widget.RecyclerView;\nimport android.support.v7.widget.Toolbar;\nimport android.view.View;\nimport android.widget.Button;\n\nimport com.lzy.demo.R;\nimport com.lzy.demo.base.BaseActivity;\nimport com.lzy.okserver.OkUpload;\nimport com.lzy.okserver.task.XExecutor;\n\nimport butterknife.Bind;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：16/9/11\n * 描    述：\n * 修订历史：\n * ================================================\n */\npublic class UploadingActivity extends BaseActivity implements XExecutor.OnAllTaskEndListener {\n\n    @Bind(R.id.toolbar) Toolbar toolbar;\n    @Bind(R.id.recyclerView) RecyclerView recyclerView;\n    @Bind(R.id.select) Button select;\n    @Bind(R.id.upload) Button upload;\n\n    private OkUpload okUpload;\n    private UploadAdapter adapter;\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.activity_upload_list);\n        initToolBar(toolbar, true, \"上传中任务\");\n\n        select.setVisibility(View.GONE);\n        upload.setVisibility(View.GONE);\n\n        okUpload = OkUpload.getInstance();\n        okUpload.getThreadPool().setCorePoolSize(1);\n\n        adapter = new UploadAdapter(this);\n        adapter.updateData(UploadAdapter.TYPE_ING);\n        recyclerView.setLayoutManager(new LinearLayoutManager(this));\n        recyclerView.setAdapter(adapter);\n\n        okUpload.addOnAllTaskEndListener(this);\n    }\n\n    @Override\n    protected void onDestroy() {\n        super.onDestroy();\n        okUpload.removeOnAllTaskEndListener(this);\n        adapter.unRegister();\n    }\n\n    @Override\n    public void onAllTaskEnd() {\n        showToast(\"所有上传任务已结束\");\n    }\n}\n"
  },
  {
    "path": "demo/src/main/java/com/lzy/demo/supercache/NewsAdapter.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.demo.supercache;\n\nimport android.view.View;\n\nimport com.chad.library.adapter.base.BaseQuickAdapter;\nimport com.chad.library.adapter.base.BaseViewHolder;\nimport com.lzy.demo.R;\nimport com.lzy.demo.WebActivity;\nimport com.lzy.demo.model.GankModel;\nimport com.lzy.ninegrid.ImageInfo;\nimport com.lzy.ninegrid.NineGridView;\nimport com.lzy.ninegrid.preview.NineGridViewClickAdapter;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：16/8/17\n * 描    述：\n * 修订历史：\n * ================================================\n */\npublic class NewsAdapter extends BaseQuickAdapter<GankModel> {\n\n    public NewsAdapter(List<GankModel> data) {\n        super(R.layout.item_news, data);\n    }\n\n    @Override\n    protected void convert(BaseViewHolder baseViewHolder, final GankModel model) {\n        baseViewHolder.setText(R.id.title, model.desc)//\n                .setText(R.id.desc, model.desc)//\n                .setText(R.id.pubDate, model.publishedAt.toString())//\n                .setText(R.id.source, model.source);\n\n        View view = baseViewHolder.getConvertView();\n        view.setOnClickListener(new View.OnClickListener() {\n            @Override\n            public void onClick(View v) {\n                WebActivity.runActivity(mContext, model.desc, model.url);\n            }\n        });\n\n        NineGridView nineGrid = baseViewHolder.getView(R.id.nineGrid);\n        ArrayList<ImageInfo> imageInfo = new ArrayList<>();\n        if (model.images != null) {\n            for (String image : model.images) {\n                ImageInfo info = new ImageInfo();\n                info.setThumbnailUrl(image);\n                info.setBigImageUrl(image);\n                imageInfo.add(info);\n            }\n        }\n        nineGrid.setAdapter(new NineGridViewClickAdapter(mContext, imageInfo));\n    }\n}\n"
  },
  {
    "path": "demo/src/main/java/com/lzy/demo/supercache/NewsCallback.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.demo.supercache;\n\nimport com.google.gson.stream.JsonReader;\nimport com.lzy.demo.model.GankResponse;\nimport com.lzy.demo.utils.Convert;\nimport com.lzy.okgo.callback.AbsCallback;\n\nimport java.lang.reflect.ParameterizedType;\nimport java.lang.reflect.Type;\n\nimport okhttp3.Response;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：16/9/1\n * 描    述：\n * 修订历史：\n * ================================================\n */\npublic abstract class NewsCallback<T> extends AbsCallback<T> {\n\n    /**\n     * 这里的数据解析是根据 http://gank.io/api/data/Android/10/1 返回的数据来写的\n     * 实际使用中,自己服务器返回的数据格式和上面网站肯定不一样,所以以下是参考代码,根据实际情况自己改写\n     */\n    @Override\n    public T convertResponse(Response response) throws Throwable {\n        //以下代码是通过泛型解析实际参数,泛型必须传\n        Type genType = getClass().getGenericSuperclass();\n        Type[] params = ((ParameterizedType) genType).getActualTypeArguments();\n        Type type = params[0];\n        if (!(type instanceof ParameterizedType)) throw new IllegalStateException(\"没有填写泛型参数\");\n\n        JsonReader jsonReader = new JsonReader(response.body().charStream());\n        Type rawType = ((ParameterizedType) type).getRawType();\n        if (rawType == GankResponse.class) {\n            GankResponse gankResponse = Convert.fromJson(jsonReader, type);\n            if (!gankResponse.error) {\n                response.close();\n                //noinspection unchecked\n                return (T) gankResponse;\n            } else {\n                response.close();\n                throw new IllegalStateException(\"服务端接口错误\");\n            }\n        } else {\n            response.close();\n            throw new IllegalStateException(\"基类错误无法解析!\");\n        }\n    }\n}\n"
  },
  {
    "path": "demo/src/main/java/com/lzy/demo/supercache/NewsTabFragment.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.demo.supercache;\n\nimport android.content.Context;\nimport android.graphics.Color;\nimport android.os.Bundle;\nimport android.support.design.widget.Snackbar;\nimport android.support.v4.widget.SwipeRefreshLayout;\nimport android.support.v7.widget.DefaultItemAnimator;\nimport android.support.v7.widget.LinearLayoutManager;\nimport android.support.v7.widget.RecyclerView;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\n\nimport com.chad.library.adapter.base.BaseQuickAdapter;\nimport com.lzy.demo.R;\nimport com.lzy.demo.base.BaseFragment;\nimport com.lzy.demo.model.GankModel;\nimport com.lzy.demo.model.GankResponse;\nimport com.lzy.demo.utils.Urls;\nimport com.lzy.okgo.OkGo;\nimport com.lzy.okgo.cache.CacheMode;\nimport com.lzy.okgo.model.Response;\n\nimport java.util.List;\n\nimport butterknife.Bind;\nimport butterknife.ButterKnife;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：16/9/11\n * 描    述：\n * 修订历史：\n * ================================================\n */\npublic class NewsTabFragment extends BaseFragment implements SwipeRefreshLayout.OnRefreshListener, BaseQuickAdapter.RequestLoadMoreListener {\n\n    private static final int PAGE_SIZE = 20;\n\n    @Bind(R.id.recyclerView) RecyclerView recyclerView;\n    @Bind(R.id.refreshLayout) SwipeRefreshLayout refreshLayout;\n\n    private Context context;\n    private int currentPage = 2;\n    private NewsAdapter newsAdapter;\n    private String url;\n    private boolean isInitCache = false;\n\n    public static NewsTabFragment newInstance() {\n        return new NewsTabFragment();\n    }\n\n    @Override\n    public void onAttach(Context context) {\n        this.context = context;\n        super.onAttach(context);\n    }\n\n    @Override\n    protected View initView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {\n        View view = inflater.inflate(R.layout.item_refresh, container, false);\n        ButterKnife.bind(this, view);\n        return view;\n    }\n\n    @Override\n    protected void initData() {\n        url = Urls.URL_GANK_BASE + fragmentTitle + \"/\" + PAGE_SIZE + \"/\";\n        recyclerView.setItemAnimator(new DefaultItemAnimator());\n        recyclerView.setLayoutManager(new LinearLayoutManager(context));\n        newsAdapter = new NewsAdapter(null);\n        newsAdapter.openLoadAnimation(BaseQuickAdapter.SCALEIN);\n        newsAdapter.isFirstOnly(false);\n        recyclerView.setAdapter(newsAdapter);\n\n        refreshLayout.setColorSchemeColors(Color.RED, Color.BLUE, Color.GREEN);\n        refreshLayout.setOnRefreshListener(this);\n        newsAdapter.setOnLoadMoreListener(this);\n\n        //开启loading,获取数据\n        setRefreshing(true);\n        onRefresh();\n    }\n\n    /** 下拉刷新 */\n    @Override\n    public void onRefresh() {\n        OkGo.<GankResponse<List<GankModel>>>get(url + \"1\")//\n                .cacheKey(\"TabFragment_\" + fragmentTitle)       //由于该fragment会被复用,必须保证key唯一,否则数据会发生覆盖\n                .cacheMode(CacheMode.FIRST_CACHE_THEN_REQUEST)  //缓存模式先使用缓存,然后使用网络数据\n                .execute(new NewsCallback<GankResponse<List<GankModel>>>() {\n                    @Override\n                    public void onSuccess(Response<GankResponse<List<GankModel>>> response) {\n                        List<GankModel> results = response.body().results;\n                        if (results != null) {\n                            currentPage = 2;\n                            newsAdapter.setNewData(results);\n                        }\n                    }\n\n                    @Override\n                    public void onCacheSuccess(Response<GankResponse<List<GankModel>>> response) {\n                        //一般来说,只需呀第一次初始化界面的时候需要使用缓存刷新界面,以后不需要,所以用一个变量标识\n                        if (!isInitCache) {\n                            //一般来说,缓存回调成功和网络回调成功做的事情是一样的,所以这里直接回调onSuccess\n                            onSuccess(response);\n                            isInitCache = true;\n                        }\n                    }\n\n                    @Override\n                    public void onError(Response<GankResponse<List<GankModel>>> response) {\n                        //网络请求失败的回调,一般会弹个Toast\n                        showToast(response.getException().getMessage());\n                    }\n\n                    @Override\n                    public void onFinish() {\n                        //可能需要移除之前添加的布局\n                        newsAdapter.removeAllFooterView();\n                        //最后调用结束刷新的方法\n                        setRefreshing(false);\n                    }\n                });\n    }\n\n    /** 上拉加载 */\n    @Override\n    public void onLoadMoreRequested() {\n        OkGo.<GankResponse<List<GankModel>>>get(url + currentPage)//\n                .cacheMode(CacheMode.NO_CACHE)       //上拉不需要缓存\n                .execute(new NewsCallback<GankResponse<List<GankModel>>>() {\n                    @Override\n                    public void onSuccess(Response<GankResponse<List<GankModel>>> response) {\n                        List<GankModel> results = response.body().results;\n                        if (results != null && results.size() > 0) {\n                            currentPage++;\n                            newsAdapter.addData(results);\n                        } else {\n                            //显示没有更多数据\n                            newsAdapter.loadComplete();\n                            View noDataView = inflater.inflate(R.layout.item_no_data, (ViewGroup) recyclerView.getParent(), false);\n                            newsAdapter.addFooterView(noDataView);\n                        }\n                    }\n\n                    @Override\n                    public void onError(Response<GankResponse<List<GankModel>>> response) {\n                        //显示数据加载失败,点击重试\n                        newsAdapter.showLoadMoreFailedView();\n                        //网络请求失败的回调,一般会弹个Toast\n                        showToast(response.getException().getMessage());\n                    }\n                });\n    }\n\n    public void showToast(String msg) {\n        Snackbar.make(recyclerView, msg, Snackbar.LENGTH_SHORT).show();\n    }\n\n    public void setRefreshing(final boolean refreshing) {\n        refreshLayout.post(new Runnable() {\n            @Override\n            public void run() {\n                refreshLayout.setRefreshing(refreshing);\n            }\n        });\n    }\n}\n"
  },
  {
    "path": "demo/src/main/java/com/lzy/demo/supercache/SuperCacheActivity.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.demo.supercache;\n\nimport android.os.Bundle;\nimport android.support.design.widget.TabLayout;\nimport android.support.v4.app.Fragment;\nimport android.support.v4.app.FragmentManager;\nimport android.support.v4.app.FragmentPagerAdapter;\nimport android.support.v4.view.ViewPager;\nimport android.support.v7.widget.Toolbar;\nimport android.view.View;\n\nimport com.lzy.demo.R;\nimport com.lzy.demo.WebActivity;\nimport com.lzy.demo.base.BaseActivity;\nimport com.lzy.demo.utils.GlideImageLoader;\nimport com.lzy.ninegrid.NineGridView;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport butterknife.Bind;\nimport butterknife.OnClick;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：16/9/11\n * 描    述：\n * 修订历史：\n * ================================================\n */\npublic class SuperCacheActivity extends BaseActivity {\n\n    @Bind(R.id.toolbar) Toolbar toolbar;\n    @Bind(R.id.viewPager) ViewPager viewPager;\n    @Bind(R.id.tab) TabLayout tab;\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.activity_super_cache);\n        initToolBar(toolbar, true, \"强大的缓存\");\n\n        NineGridView.setImageLoader(new GlideImageLoader());\n\n        ArrayList<NewsTabFragment> fragments = new ArrayList<>();\n        NewsTabFragment fragment1 = NewsTabFragment.newInstance();\n        fragment1.setTitle(\"Android\");\n        fragments.add(fragment1);\n        NewsTabFragment fragment2 = NewsTabFragment.newInstance();\n        fragment2.setTitle(\"iOS\");\n        fragments.add(fragment2);\n        NewsTabFragment fragment3 = NewsTabFragment.newInstance();\n        fragment3.setTitle(\"前端\");\n        fragments.add(fragment3);\n        MyPagerAdapter adapter = new MyPagerAdapter(getSupportFragmentManager(), fragments);\n        viewPager.setAdapter(adapter);\n        viewPager.setOffscreenPageLimit(fragments.size());\n        tab.setupWithViewPager(viewPager);\n    }\n\n    @OnClick(R.id.fab)\n    public void fab(View view) {\n        WebActivity.runActivity(this, \"我的Github,欢迎star\", \"https://github.com/jeasonlzy\");\n    }\n\n    public class MyPagerAdapter extends FragmentPagerAdapter {\n\n        private List<NewsTabFragment> fragments;\n\n        public MyPagerAdapter(FragmentManager fm, List<NewsTabFragment> fragments) {\n            super(fm);\n            this.fragments = fragments;\n        }\n\n        @Override\n        public CharSequence getPageTitle(int position) {\n            return fragments.get(position).getTitle();\n        }\n\n        @Override\n        public Fragment getItem(int position) {\n            return fragments.get(position);\n        }\n\n        @Override\n        public int getCount() {\n            return fragments.size();\n        }\n    }\n}\n"
  },
  {
    "path": "demo/src/main/java/com/lzy/demo/ui/NumberProgressBar.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.demo.ui;\n\nimport android.content.Context;\nimport android.content.res.TypedArray;\nimport android.graphics.Canvas;\nimport android.graphics.Color;\nimport android.graphics.Paint;\nimport android.graphics.RectF;\nimport android.os.Bundle;\nimport android.os.Parcelable;\nimport android.util.AttributeSet;\nimport android.view.View;\n\nimport com.lzy.demo.R;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：16/9/11\n * 描    述：\n * 修订历史：\n * ================================================\n */\npublic class NumberProgressBar extends View {\n\n    public interface OnProgressBarListener {\n\n        void onProgressChange(int current, int max);\n    }\n\n    private int mMaxProgress = 100;\n\n    /**\n     * Current progress, can not exceed the max progress.\n     */\n    private int mCurrentProgress = 0;\n\n    /**\n     * The progress area bar color.\n     */\n    private int mReachedBarColor;\n\n    /**\n     * The bar unreached area color.\n     */\n    private int mUnreachedBarColor;\n\n    /**\n     * The progress text color.\n     */\n    private int mTextColor;\n\n    /**\n     * The progress text size.\n     */\n    private float mTextSize;\n\n    /**\n     * The height of the reached area.\n     */\n    private float mReachedBarHeight;\n\n    /**\n     * The height of the unreached area.\n     */\n    private float mUnreachedBarHeight;\n\n    /**\n     * The suffix of the number.\n     */\n    private String mSuffix = \"%\";\n\n    /**\n     * The prefix.\n     */\n    private String mPrefix = \"\";\n\n    private final int default_text_color = Color.rgb(66, 145, 241);\n    private final int default_reached_color = Color.rgb(66, 145, 241);\n    private final int default_unreached_color = Color.rgb(204, 204, 204);\n    private final float default_progress_text_offset;\n    private final float default_text_size;\n    private final float default_reached_bar_height;\n    private final float default_unreached_bar_height;\n\n    /**\n     * For save and restore instance of progressbar.\n     */\n    private static final String INSTANCE_STATE = \"saved_instance\";\n    private static final String INSTANCE_TEXT_COLOR = \"text_color\";\n    private static final String INSTANCE_TEXT_SIZE = \"text_size\";\n    private static final String INSTANCE_REACHED_BAR_HEIGHT = \"reached_bar_height\";\n    private static final String INSTANCE_REACHED_BAR_COLOR = \"reached_bar_color\";\n    private static final String INSTANCE_UNREACHED_BAR_HEIGHT = \"unreached_bar_height\";\n    private static final String INSTANCE_UNREACHED_BAR_COLOR = \"unreached_bar_color\";\n    private static final String INSTANCE_MAX = \"max\";\n    private static final String INSTANCE_PROGRESS = \"progress\";\n    private static final String INSTANCE_SUFFIX = \"suffix\";\n    private static final String INSTANCE_PREFIX = \"prefix\";\n    private static final String INSTANCE_TEXT_VISIBILITY = \"text_visibility\";\n\n    private static final int PROGRESS_TEXT_VISIBLE = 0;\n\n    /**\n     * The width of the text that to be drawn.\n     */\n    private float mDrawTextWidth;\n\n    /**\n     * The drawn text start.\n     */\n    private float mDrawTextStart;\n\n    /**\n     * The drawn text end.\n     */\n    private float mDrawTextEnd;\n\n    /**\n     * The text that to be drawn in onDraw().\n     */\n    private String mCurrentDrawText;\n\n    /**\n     * The Paint of the reached area.\n     */\n    private Paint mReachedBarPaint;\n    /**\n     * The Paint of the unreached area.\n     */\n    private Paint mUnreachedBarPaint;\n    /**\n     * The Paint of the progress text.\n     */\n    private Paint mTextPaint;\n\n    /**\n     * Unreached bar area to draw rect.\n     */\n    private RectF mUnreachedRectF = new RectF(0, 0, 0, 0);\n    /**\n     * Reached bar area rect.\n     */\n    private RectF mReachedRectF = new RectF(0, 0, 0, 0);\n\n    /**\n     * The progress text offset.\n     */\n    private float mOffset;\n\n    /**\n     * Determine if need to draw unreached area.\n     */\n    private boolean mDrawUnreachedBar = true;\n\n    private boolean mDrawReachedBar = true;\n\n    private boolean mIfDrawText = true;\n\n    /**\n     * Listener\n     */\n    private OnProgressBarListener mListener;\n\n    public enum ProgressTextVisibility {\n        Visible, Invisible\n    }\n\n    public NumberProgressBar(Context context) {\n        this(context, null);\n    }\n\n    public NumberProgressBar(Context context, AttributeSet attrs) {\n        this(context, attrs, 0);\n    }\n\n    public NumberProgressBar(Context context, AttributeSet attrs, int defStyleAttr) {\n        super(context, attrs, defStyleAttr);\n\n        default_reached_bar_height = dp2px(1.5f);\n        default_unreached_bar_height = dp2px(1.0f);\n        default_text_size = sp2px(10);\n        default_progress_text_offset = dp2px(3.0f);\n\n        //load styled attributes.\n        final TypedArray attributes = context.getTheme().obtainStyledAttributes(attrs, R.styleable.NumberProgressBar, defStyleAttr, 0);\n\n        mReachedBarColor = attributes.getColor(R.styleable.NumberProgressBar_progress_reached_color, default_reached_color);\n        mUnreachedBarColor = attributes.getColor(R.styleable.NumberProgressBar_progress_unreached_color, default_unreached_color);\n        mTextColor = attributes.getColor(R.styleable.NumberProgressBar_progress_text_color, default_text_color);\n        mTextSize = attributes.getDimension(R.styleable.NumberProgressBar_progress_text_size, default_text_size);\n\n        mReachedBarHeight = attributes.getDimension(R.styleable.NumberProgressBar_progress_reached_bar_height, default_reached_bar_height);\n        mUnreachedBarHeight = attributes.getDimension(R.styleable.NumberProgressBar_progress_unreached_bar_height, default_unreached_bar_height);\n        mOffset = attributes.getDimension(R.styleable.NumberProgressBar_progress_text_offset, default_progress_text_offset);\n\n        int textVisible = attributes.getInt(R.styleable.NumberProgressBar_progress_text_visibility, PROGRESS_TEXT_VISIBLE);\n        if (textVisible != PROGRESS_TEXT_VISIBLE) {\n            mIfDrawText = false;\n        }\n\n        setProgress(attributes.getInt(R.styleable.NumberProgressBar_progress_current, 0));\n        setMax(attributes.getInt(R.styleable.NumberProgressBar_progress_max, 100));\n\n        attributes.recycle();\n        initializePainters();\n    }\n\n    @Override\n    protected int getSuggestedMinimumWidth() {\n        return (int) mTextSize;\n    }\n\n    @Override\n    protected int getSuggestedMinimumHeight() {\n        return Math.max((int) mTextSize, Math.max((int) mReachedBarHeight, (int) mUnreachedBarHeight));\n    }\n\n    @Override\n    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {\n        setMeasuredDimension(measure(widthMeasureSpec, true), measure(heightMeasureSpec, false));\n    }\n\n    private int measure(int measureSpec, boolean isWidth) {\n        int result;\n        int mode = MeasureSpec.getMode(measureSpec);\n        int size = MeasureSpec.getSize(measureSpec);\n        int padding = isWidth ? getPaddingLeft() + getPaddingRight() : getPaddingTop() + getPaddingBottom();\n        if (mode == MeasureSpec.EXACTLY) {\n            result = size;\n        } else {\n            result = isWidth ? getSuggestedMinimumWidth() : getSuggestedMinimumHeight();\n            result += padding;\n            if (mode == MeasureSpec.AT_MOST) {\n                if (isWidth) {\n                    result = Math.max(result, size);\n                } else {\n                    result = Math.min(result, size);\n                }\n            }\n        }\n        return result;\n    }\n\n    @Override\n    protected void onDraw(Canvas canvas) {\n        if (mIfDrawText) {\n            calculateDrawRectF();\n        } else {\n            calculateDrawRectFWithoutProgressText();\n        }\n\n        if (mDrawReachedBar) {\n            canvas.drawRect(mReachedRectF, mReachedBarPaint);\n        }\n\n        if (mDrawUnreachedBar) {\n            canvas.drawRect(mUnreachedRectF, mUnreachedBarPaint);\n        }\n\n        if (mIfDrawText) canvas.drawText(mCurrentDrawText, mDrawTextStart, mDrawTextEnd, mTextPaint);\n    }\n\n    private void initializePainters() {\n        mReachedBarPaint = new Paint(Paint.ANTI_ALIAS_FLAG);\n        mReachedBarPaint.setColor(mReachedBarColor);\n\n        mUnreachedBarPaint = new Paint(Paint.ANTI_ALIAS_FLAG);\n        mUnreachedBarPaint.setColor(mUnreachedBarColor);\n\n        mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);\n        mTextPaint.setColor(mTextColor);\n        mTextPaint.setTextSize(mTextSize);\n    }\n\n    private void calculateDrawRectFWithoutProgressText() {\n        mReachedRectF.left = getPaddingLeft();\n        mReachedRectF.top = getHeight() / 2.0f - mReachedBarHeight / 2.0f;\n        mReachedRectF.right = (getWidth() - getPaddingLeft() - getPaddingRight()) / (getMax() * 1.0f) * getProgress() + getPaddingLeft();\n        mReachedRectF.bottom = getHeight() / 2.0f + mReachedBarHeight / 2.0f;\n\n        mUnreachedRectF.left = mReachedRectF.right;\n        mUnreachedRectF.right = getWidth() - getPaddingRight();\n        mUnreachedRectF.top = getHeight() / 2.0f + -mUnreachedBarHeight / 2.0f;\n        mUnreachedRectF.bottom = getHeight() / 2.0f + mUnreachedBarHeight / 2.0f;\n    }\n\n    private void calculateDrawRectF() {\n\n        mCurrentDrawText = String.format(\"%d\", getProgress() * 100 / getMax());\n        mCurrentDrawText = mPrefix + mCurrentDrawText + mSuffix;\n        mDrawTextWidth = mTextPaint.measureText(mCurrentDrawText);\n\n        if (getProgress() == 0) {\n            mDrawReachedBar = false;\n            mDrawTextStart = getPaddingLeft();\n        } else {\n            mDrawReachedBar = true;\n            mReachedRectF.left = getPaddingLeft();\n            mReachedRectF.top = getHeight() / 2.0f - mReachedBarHeight / 2.0f;\n            mReachedRectF.right = (getWidth() - getPaddingLeft() - getPaddingRight()) / (getMax() * 1.0f) * getProgress() - mOffset + getPaddingLeft();\n            mReachedRectF.bottom = getHeight() / 2.0f + mReachedBarHeight / 2.0f;\n            mDrawTextStart = (mReachedRectF.right + mOffset);\n        }\n\n        mDrawTextEnd = (int) ((getHeight() / 2.0f) - ((mTextPaint.descent() + mTextPaint.ascent()) / 2.0f));\n\n        if ((mDrawTextStart + mDrawTextWidth) >= getWidth() - getPaddingRight()) {\n            mDrawTextStart = getWidth() - getPaddingRight() - mDrawTextWidth;\n            mReachedRectF.right = mDrawTextStart - mOffset;\n        }\n\n        float unreachedBarStart = mDrawTextStart + mDrawTextWidth + mOffset;\n        if (unreachedBarStart >= getWidth() - getPaddingRight()) {\n            mDrawUnreachedBar = false;\n        } else {\n            mDrawUnreachedBar = true;\n            mUnreachedRectF.left = unreachedBarStart;\n            mUnreachedRectF.right = getWidth() - getPaddingRight();\n            mUnreachedRectF.top = getHeight() / 2.0f + -mUnreachedBarHeight / 2.0f;\n            mUnreachedRectF.bottom = getHeight() / 2.0f + mUnreachedBarHeight / 2.0f;\n        }\n    }\n\n    /**\n     * Get progress text color.\n     *\n     * @return progress text color.\n     */\n    public int getTextColor() {\n        return mTextColor;\n    }\n\n    /**\n     * Get progress text size.\n     *\n     * @return progress text size.\n     */\n    public float getProgressTextSize() {\n        return mTextSize;\n    }\n\n    public int getUnreachedBarColor() {\n        return mUnreachedBarColor;\n    }\n\n    public int getReachedBarColor() {\n        return mReachedBarColor;\n    }\n\n    public int getProgress() {\n        return mCurrentProgress;\n    }\n\n    public int getMax() {\n        return mMaxProgress;\n    }\n\n    public float getReachedBarHeight() {\n        return mReachedBarHeight;\n    }\n\n    public float getUnreachedBarHeight() {\n        return mUnreachedBarHeight;\n    }\n\n    public void setProgressTextSize(float textSize) {\n        this.mTextSize = textSize;\n        mTextPaint.setTextSize(mTextSize);\n        invalidate();\n    }\n\n    public void setProgressTextColor(int textColor) {\n        this.mTextColor = textColor;\n        mTextPaint.setColor(mTextColor);\n        invalidate();\n    }\n\n    public void setUnreachedBarColor(int barColor) {\n        this.mUnreachedBarColor = barColor;\n        mUnreachedBarPaint.setColor(mUnreachedBarColor);\n        invalidate();\n    }\n\n    public void setReachedBarColor(int progressColor) {\n        this.mReachedBarColor = progressColor;\n        mReachedBarPaint.setColor(mReachedBarColor);\n        invalidate();\n    }\n\n    public void setReachedBarHeight(float height) {\n        mReachedBarHeight = height;\n    }\n\n    public void setUnreachedBarHeight(float height) {\n        mUnreachedBarHeight = height;\n    }\n\n    public void setMax(int maxProgress) {\n        if (maxProgress > 0) {\n            this.mMaxProgress = maxProgress;\n            invalidate();\n        }\n    }\n\n    public void setSuffix(String suffix) {\n        if (suffix == null) {\n            mSuffix = \"\";\n        } else {\n            mSuffix = suffix;\n        }\n    }\n\n    public String getSuffix() {\n        return mSuffix;\n    }\n\n    public void setPrefix(String prefix) {\n        if (prefix == null) mPrefix = \"\";\n        else {\n            mPrefix = prefix;\n        }\n    }\n\n    public String getPrefix() {\n        return mPrefix;\n    }\n\n    public void incrementProgressBy(int by) {\n        if (by > 0) {\n            setProgress(getProgress() + by);\n        }\n\n        if (mListener != null) {\n            mListener.onProgressChange(getProgress(), getMax());\n        }\n    }\n\n    public void setProgress(int progress) {\n        if (progress <= getMax() && progress >= 0) {\n            this.mCurrentProgress = progress;\n            invalidate();\n        }\n    }\n\n    @Override\n    protected Parcelable onSaveInstanceState() {\n        final Bundle bundle = new Bundle();\n        bundle.putParcelable(INSTANCE_STATE, super.onSaveInstanceState());\n        bundle.putInt(INSTANCE_TEXT_COLOR, getTextColor());\n        bundle.putFloat(INSTANCE_TEXT_SIZE, getProgressTextSize());\n        bundle.putFloat(INSTANCE_REACHED_BAR_HEIGHT, getReachedBarHeight());\n        bundle.putFloat(INSTANCE_UNREACHED_BAR_HEIGHT, getUnreachedBarHeight());\n        bundle.putInt(INSTANCE_REACHED_BAR_COLOR, getReachedBarColor());\n        bundle.putInt(INSTANCE_UNREACHED_BAR_COLOR, getUnreachedBarColor());\n        bundle.putInt(INSTANCE_MAX, getMax());\n        bundle.putInt(INSTANCE_PROGRESS, getProgress());\n        bundle.putString(INSTANCE_SUFFIX, getSuffix());\n        bundle.putString(INSTANCE_PREFIX, getPrefix());\n        bundle.putBoolean(INSTANCE_TEXT_VISIBILITY, getProgressTextVisibility());\n        return bundle;\n    }\n\n    @Override\n    protected void onRestoreInstanceState(Parcelable state) {\n        if (state instanceof Bundle) {\n            final Bundle bundle = (Bundle) state;\n            mTextColor = bundle.getInt(INSTANCE_TEXT_COLOR);\n            mTextSize = bundle.getFloat(INSTANCE_TEXT_SIZE);\n            mReachedBarHeight = bundle.getFloat(INSTANCE_REACHED_BAR_HEIGHT);\n            mUnreachedBarHeight = bundle.getFloat(INSTANCE_UNREACHED_BAR_HEIGHT);\n            mReachedBarColor = bundle.getInt(INSTANCE_REACHED_BAR_COLOR);\n            mUnreachedBarColor = bundle.getInt(INSTANCE_UNREACHED_BAR_COLOR);\n            initializePainters();\n            setMax(bundle.getInt(INSTANCE_MAX));\n            setProgress(bundle.getInt(INSTANCE_PROGRESS));\n            setPrefix(bundle.getString(INSTANCE_PREFIX));\n            setSuffix(bundle.getString(INSTANCE_SUFFIX));\n            setProgressTextVisibility(bundle.getBoolean(INSTANCE_TEXT_VISIBILITY) ? ProgressTextVisibility.Visible : ProgressTextVisibility.Invisible);\n            super.onRestoreInstanceState(bundle.getParcelable(INSTANCE_STATE));\n            return;\n        }\n        super.onRestoreInstanceState(state);\n    }\n\n    public float dp2px(float dp) {\n        final float scale = getResources().getDisplayMetrics().density;\n        return dp * scale + 0.5f;\n    }\n\n    public float sp2px(float sp) {\n        final float scale = getResources().getDisplayMetrics().scaledDensity;\n        return sp * scale;\n    }\n\n    public void setProgressTextVisibility(ProgressTextVisibility visibility) {\n        mIfDrawText = visibility == ProgressTextVisibility.Visible;\n        invalidate();\n    }\n\n    public boolean getProgressTextVisibility() {\n        return mIfDrawText;\n    }\n\n    public void setOnProgressBarListener(OnProgressBarListener listener) {\n        mListener = listener;\n    }\n}\n"
  },
  {
    "path": "demo/src/main/java/com/lzy/demo/ui/ProgressPieView.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.demo.ui;\n\nimport android.content.Context;\nimport android.content.res.AssetManager;\nimport android.content.res.Resources;\nimport android.content.res.TypedArray;\nimport android.graphics.Canvas;\nimport android.graphics.Color;\nimport android.graphics.Paint;\nimport android.graphics.Rect;\nimport android.graphics.RectF;\nimport android.graphics.Typeface;\nimport android.graphics.drawable.Drawable;\nimport android.os.Handler;\nimport android.os.Message;\nimport android.support.v4.util.LruCache;\nimport android.text.TextUtils;\nimport android.util.AttributeSet;\nimport android.util.DisplayMetrics;\nimport android.view.View;\n\nimport com.lzy.demo.R;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：16/9/11\n * 描    述：\n * 修订历史：\n * ================================================\n */\npublic class ProgressPieView extends View {\n\n    public interface OnProgressListener {\n        public void onProgressChanged(int progress, int max);\n\n        public void onProgressCompleted();\n    }\n\n    /**\n     * Fills the progress radially in a clockwise direction.\n     */\n    public static final int FILL_TYPE_RADIAL = 0;\n    /**\n     * Fills the progress expanding from the center of the view.\n     */\n    public static final int FILL_TYPE_CENTER = 1;\n\n    public static final int SLOW_ANIMATION_SPEED = 50;\n    public static final int MEDIUM_ANIMATION_SPEED = 25;\n    public static final int FAST_ANIMATION_SPEED = 1;\n\n    private static final int DEFAULT_MAX = 100;\n    private static final int DEFAULT_PROGRESS = 0;\n    private static final int DEFAULT_START_ANGLE = -90;\n    private static final float DEFAULT_STROKE_WIDTH = 3f;\n    private static final float DEFAULT_TEXT_SIZE = 14f;\n    private static final int DEFAULT_VIEW_SIZE = 96;\n\n    private static LruCache<String, Typeface> sTypefaceCache = new LruCache<String, Typeface>(8);\n\n    private OnProgressListener mListener;\n    private DisplayMetrics mDisplayMetrics;\n    private int mMax = DEFAULT_MAX;\n    private int mProgress = DEFAULT_PROGRESS;\n    private int mStartAngle = DEFAULT_START_ANGLE;\n    private boolean mInverted = false;\n    private boolean mCounterclockwise = false;\n    private boolean mShowStroke = true;\n    private float mStrokeWidth = DEFAULT_STROKE_WIDTH;\n    private boolean mShowText = true;\n    private float mTextSize = DEFAULT_TEXT_SIZE;\n    private String mText;\n    private String mTypeface;\n    private boolean mShowImage = true;\n    private Drawable mImage;\n    private Rect mImageRect;\n    private Paint mStrokePaint;\n    private Paint mTextPaint;\n    private Paint mProgressPaint;\n    private Paint mBackgroundPaint;\n    private RectF mInnerRectF;\n    private int mProgressFillType = FILL_TYPE_RADIAL;\n\n    private int mAnimationSpeed = MEDIUM_ANIMATION_SPEED;\n    private AnimationHandler mAnimationHandler = new AnimationHandler();\n\n    private int mViewSize;\n\n    public ProgressPieView(Context context) {\n        this(context, null);\n    }\n\n    public ProgressPieView(Context context, AttributeSet attrs) {\n        this(context, attrs, 0);\n    }\n\n    public ProgressPieView(Context context, AttributeSet attrs, int defStyleAttr) {\n        super(context, attrs, defStyleAttr);\n        init(context, attrs);\n    }\n\n    private void init(Context context, AttributeSet attrs) {\n        mDisplayMetrics = context.getResources().getDisplayMetrics();\n\n        mStrokeWidth = mStrokeWidth * mDisplayMetrics.density;\n        mTextSize = mTextSize * mDisplayMetrics.scaledDensity;\n\n        final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ProgressPieView);\n        final Resources res = getResources();\n\n        mMax = a.getInteger(R.styleable.ProgressPieView_ppvMax, mMax);\n        mProgress = a.getInteger(R.styleable.ProgressPieView_ppvProgress, mProgress);\n        mStartAngle = a.getInt(R.styleable.ProgressPieView_ppvStartAngle, mStartAngle);\n        mInverted = a.getBoolean(R.styleable.ProgressPieView_ppvInverted, mInverted);\n        mCounterclockwise = a.getBoolean(R.styleable.ProgressPieView_ppvCounterclockwise, mCounterclockwise);\n        mStrokeWidth = a.getDimension(R.styleable.ProgressPieView_ppvStrokeWidth, mStrokeWidth);\n        mTypeface = a.getString(R.styleable.ProgressPieView_ppvTypeface);\n        mTextSize = a.getDimension(R.styleable.ProgressPieView_android_textSize, mTextSize);\n        mText = a.getString(R.styleable.ProgressPieView_android_text);\n\n        mShowStroke = a.getBoolean(R.styleable.ProgressPieView_ppvShowStroke, mShowStroke);\n        mShowText = a.getBoolean(R.styleable.ProgressPieView_ppvShowText, mShowText);\n        mImage = a.getDrawable(R.styleable.ProgressPieView_ppvImage);\n\n        int backgroundColor = Color.parseColor(\"#00000000\");\n        backgroundColor = a.getColor(R.styleable.ProgressPieView_ppvBackgroundColor, backgroundColor);\n        int progressColor = Color.parseColor(\"#33b5e5\");\n        progressColor = a.getColor(R.styleable.ProgressPieView_ppvProgressColor, progressColor);\n        int strokeColor = Color.parseColor(\"#33b5e5\");\n        strokeColor = a.getColor(R.styleable.ProgressPieView_ppvStrokeColor, strokeColor);\n        int textColor = Color.parseColor(\"#333333\");\n        textColor = a.getColor(R.styleable.ProgressPieView_android_textColor, textColor);\n\n        mProgressFillType = a.getInteger(R.styleable.ProgressPieView_ppvProgressFillType, mProgressFillType);\n\n        a.recycle();\n\n        mBackgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG);\n        mBackgroundPaint.setColor(backgroundColor);\n        mBackgroundPaint.setStyle(Paint.Style.FILL);\n\n        mProgressPaint = new Paint(Paint.ANTI_ALIAS_FLAG);\n        mProgressPaint.setColor(progressColor);\n        mProgressPaint.setStyle(Paint.Style.FILL);\n\n        mStrokePaint = new Paint(Paint.ANTI_ALIAS_FLAG);\n        mStrokePaint.setColor(strokeColor);\n        mStrokePaint.setStyle(Paint.Style.STROKE);\n        mStrokePaint.setStrokeWidth(mStrokeWidth);\n\n        mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);\n        mTextPaint.setColor(textColor);\n        mTextPaint.setTextSize(mTextSize);\n        mTextPaint.setTextAlign(Paint.Align.CENTER);\n\n        mInnerRectF = new RectF();\n        mImageRect = new Rect();\n    }\n\n    @Override\n    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {\n        super.onMeasure(widthMeasureSpec, heightMeasureSpec);\n\n        int width = resolveSize(DEFAULT_VIEW_SIZE, widthMeasureSpec);\n        int height = resolveSize(DEFAULT_VIEW_SIZE, heightMeasureSpec);\n        mViewSize = Math.min(width, height);\n\n        setMeasuredDimension(width, height);\n    }\n\n    @Override\n    protected void onDraw(Canvas canvas) {\n        super.onDraw(canvas);\n        mInnerRectF.set(0, 0, mViewSize, mViewSize);\n        mInnerRectF.offset((getWidth() - mViewSize) / 2, (getHeight() - mViewSize) / 2);\n        if (mShowStroke) {\n            final int halfBorder = (int) (mStrokePaint.getStrokeWidth() / 2f + 0.5f);\n            mInnerRectF.inset(halfBorder, halfBorder);\n        }\n        float centerX = mInnerRectF.centerX();\n        float centerY = mInnerRectF.centerY();\n\n        canvas.drawArc(mInnerRectF, 0, 360, true, mBackgroundPaint);\n\n        switch (mProgressFillType) {\n            case FILL_TYPE_RADIAL:\n                float sweepAngle = 360 * mProgress / mMax;\n                if (mInverted) {\n                    sweepAngle = sweepAngle - 360;\n                }\n                if (mCounterclockwise) {\n                    sweepAngle = -sweepAngle;\n                }\n                canvas.drawArc(mInnerRectF, mStartAngle, sweepAngle, true, mProgressPaint);\n                break;\n            case FILL_TYPE_CENTER:\n                float radius = (mViewSize / 2) * ((float) mProgress / mMax);\n                if (mShowStroke) {\n                    radius = radius + 0.5f - mStrokePaint.getStrokeWidth();\n                }\n                canvas.drawCircle(centerX, centerY, radius, mProgressPaint);\n                break;\n            default:\n                throw new IllegalArgumentException(\"Invalid Progress Fill = \" + mProgressFillType);\n        }\n\n        if (!TextUtils.isEmpty(mText) && mShowText) {\n            if (!TextUtils.isEmpty(mTypeface)) {\n                Typeface typeface = sTypefaceCache.get(mTypeface);\n                if (null == typeface && null != getResources()) {\n                    AssetManager assets = getResources().getAssets();\n                    if (null != assets) {\n                        typeface = Typeface.createFromAsset(assets, mTypeface);\n                        sTypefaceCache.put(mTypeface, typeface);\n                    }\n                }\n                mTextPaint.setTypeface(typeface);\n            }\n            int xPos = (int) centerX;\n            int yPos = (int) (centerY - (mTextPaint.descent() + mTextPaint.ascent()) / 2);\n            canvas.drawText(mText, xPos, yPos, mTextPaint);\n        }\n\n        if (null != mImage && mShowImage) {\n            int drawableSize = mImage.getIntrinsicWidth();\n            mImageRect.set(0, 0, drawableSize, drawableSize);\n            mImageRect.offset((getWidth() - drawableSize) / 2, (getHeight() - drawableSize) / 2);\n            mImage.setBounds(mImageRect);\n            mImage.draw(canvas);\n        }\n\n        if (mShowStroke) {\n            canvas.drawOval(mInnerRectF, mStrokePaint);\n        }\n\n    }\n\n    /**\n     * Gets the maximum progress value.\n     */\n    public int getMax() {\n        return mMax;\n    }\n\n    /**\n     * Sets the maximum progress value. Defaults to 100.\n     */\n    public void setMax(int max) {\n        if (max <= 0 || max < mProgress) {\n            throw new IllegalArgumentException(String.format(\"Max (%d) must be > 0 and >= %d\", max, mProgress));\n        }\n        mMax = max;\n        invalidate();\n    }\n\n    /**\n     * Sets the animation speed used in the animateProgressFill method.\n     */\n    public void setAnimationSpeed(int animationSpeed) {\n        this.mAnimationSpeed = animationSpeed;\n    }\n\n    /**\n     * Returns the current animation speed used in animateProgressFill method.\n     */\n    public int getAnimationSpeed() {\n        return this.mAnimationSpeed;\n    }\n\n    /**\n     * Animates a progress fill of the view, using a Handler.\n     */\n    public void animateProgressFill() {\n        mAnimationHandler.removeMessages(0);\n        mAnimationHandler.setAnimateTo(mMax);\n        mAnimationHandler.sendEmptyMessage(0);\n        invalidate();\n    }\n\n    /**\n     * Animates a progress fill of the view, using a Handler.\n     *\n     * @param animateTo - the progress value the animation should stop at (0 - MAX)\n     */\n    public void animateProgressFill(int animateTo) {\n        mAnimationHandler.removeMessages(0);\n        if (animateTo > mMax || animateTo < 0) {\n            throw new IllegalArgumentException(String.format(\"Animation progress (%d) is greater than the max progress (%d) or lower than 0 \", animateTo, mMax));\n        }\n        mAnimationHandler.setAnimateTo(animateTo);\n        mAnimationHandler.sendEmptyMessage(0);\n        invalidate();\n    }\n\n    /**\n     * Stops the views animation.\n     */\n    public void stopAnimating() {\n        mAnimationHandler.removeMessages(0);\n        mAnimationHandler.setAnimateTo(mProgress);\n        invalidate();\n    }\n\n    /**\n     * Gets the current progress from 0 to max.\n     */\n    public int getProgress() {\n        return mProgress;\n    }\n\n    /**\n     * Sets the current progress (must be between 0 and max).\n     */\n    public void setProgress(int progress) {\n        if (progress > mMax || progress < 0) {\n            throw new IllegalArgumentException(String.format(\"Progress (%d) must be between %d and %d\", progress, 0, mMax));\n        }\n        mProgress = progress;\n        if (null != mListener) {\n            if (mProgress == mMax) {\n                mListener.onProgressCompleted();\n            } else {\n                mListener.onProgressChanged(mProgress, mMax);\n            }\n        }\n        invalidate();\n    }\n\n    /**\n     * Gets the start angle the {@link #FILL_TYPE_RADIAL} uses.\n     */\n    public int getStartAngle() {\n        return mStartAngle;\n    }\n\n    /**\n     * Sets the start angle the {@link #FILL_TYPE_RADIAL} uses.\n     *\n     * @param startAngle start angle in degrees\n     */\n    public void setStartAngle(int startAngle) {\n        mStartAngle = startAngle;\n    }\n\n    /**\n     * Gets the inverted state.\n     */\n    public boolean isInverted() {\n        return mInverted;\n    }\n\n    /**\n     * Sets the inverted state.\n     *\n     * @param inverted draw the progress inverted or not\n     */\n    public void setInverted(boolean inverted) {\n        mInverted = inverted;\n    }\n\n    /**\n     * Gets the counterclockwise state.\n     */\n    public boolean isCounterclockwise() {\n        return mCounterclockwise;\n    }\n\n    /**\n     * Sets the counterclockwise state.\n     *\n     * @param counterclockwise draw the progress counterclockwise or not\n     */\n    public void setCounterclockwise(boolean counterclockwise) {\n        mCounterclockwise = counterclockwise;\n    }\n\n    /**\n     * Gets the color used to display the progress of the view.\n     */\n    public int getProgressColor() {\n        return mProgressPaint.getColor();\n    }\n\n    /**\n     * Sets the color used to display the progress of the view.\n     *\n     * @param color - color of the progress part of the view\n     */\n    public void setProgressColor(int color) {\n        mProgressPaint.setColor(color);\n        invalidate();\n    }\n\n    /**\n     * Gets the color used to display the background of the view.\n     */\n    public int getBackgroundColor() {\n        return mBackgroundPaint.getColor();\n    }\n\n    /**\n     * Sets the color used to display the background of the view.\n     *\n     * @param color - color of the background part of the view\n     */\n    public void setBackgroundColor(int color) {\n        mBackgroundPaint.setColor(color);\n        invalidate();\n    }\n\n    /**\n     * Gets the color used to display the text of the view.\n     */\n    public int getTextColor() {\n        return mTextPaint.getColor();\n    }\n\n    /**\n     * Sets the color used to display the text of the view.\n     *\n     * @param color - color of the text part of the view\n     */\n    public void setTextColor(int color) {\n        mTextPaint.setColor(color);\n        invalidate();\n    }\n\n    /**\n     * Gets the text size in sp.\n     */\n    public float getTextSize() {\n        return mTextSize;\n    }\n\n    /**\n     * Sets the text size.\n     *\n     * @param sizeSp in sp for the text\n     */\n    public void setTextSize(int sizeSp) {\n        mTextSize = sizeSp * mDisplayMetrics.scaledDensity;\n        mTextPaint.setTextSize(mTextSize);\n        invalidate();\n    }\n\n    /**\n     * Gets the text of the view.\n     */\n    public String getText() {\n        return mText;\n    }\n\n    /**\n     * Sets the text of the view.\n     *\n     * @param text to be displayed in the view\n     */\n    public void setText(String text) {\n        mText = text;\n        invalidate();\n    }\n\n    /**\n     * Gets the typeface of the text.\n     */\n    public String getTypeface() {\n        return mTypeface;\n    }\n\n    /**\n     * Sets the text typeface.\n     * - i.printStackTrace. fonts/Roboto/Roboto-Regular.ttf\n     *\n     * @param typeface that the text is displayed in\n     */\n    public void setTypeface(String typeface) {\n        mTypeface = typeface;\n        invalidate();\n    }\n\n    /**\n     * Gets the show text state.\n     */\n    public boolean isTextShowing() {\n        return mShowText;\n    }\n\n    /**\n     * Sets the show text state.\n     *\n     * @param showText show or hide text\n     */\n    public void setShowText(boolean showText) {\n        mShowText = showText;\n        invalidate();\n    }\n\n    /**\n     * Get the color used to display the stroke of the view.\n     */\n    public int getStrokeColor() {\n        return mStrokePaint.getColor();\n    }\n\n    /**\n     * Sets the color used to display the stroke of the view.\n     *\n     * @param color - color of the stroke part of the view\n     */\n    public void setStrokeColor(int color) {\n        mStrokePaint.setColor(color);\n        invalidate();\n    }\n\n    /**\n     * Gets the stroke width in dp.\n     */\n    public float getStrokeWidth() {\n        return mStrokeWidth;\n    }\n\n    /**\n     * Set the stroke width.\n     *\n     * @param widthDp in dp for the pie border\n     */\n    public void setStrokeWidth(int widthDp) {\n        mStrokeWidth = widthDp * mDisplayMetrics.density;\n        mStrokePaint.setStrokeWidth(mStrokeWidth);\n        invalidate();\n    }\n\n    /**\n     * Gets the show stroke state.\n     */\n    public boolean isStrokeShowing() {\n        return mShowStroke;\n    }\n\n    /**\n     * Sets the show stroke state.\n     *\n     * @param showStroke show or hide stroke\n     */\n    public void setShowStroke(boolean showStroke) {\n        mShowStroke = showStroke;\n        invalidate();\n    }\n\n    /**\n     * Gets the drawable of the view.\n     */\n    public Drawable getImageDrawable() {\n        return mImage;\n    }\n\n    /**\n     * Sets the drawable of the view.\n     *\n     * @param image drawable of the view\n     */\n    public void setImageDrawable(Drawable image) {\n        mImage = image;\n        invalidate();\n    }\n\n    /**\n     * Sets the drawable of the view.\n     *\n     * @param resId resource id of the view's drawable\n     */\n    public void setImageResource(int resId) {\n        if (null != getResources()) {\n            mImage = getResources().getDrawable(resId);\n            invalidate();\n        }\n    }\n\n    /**\n     * Gets the show image state.\n     */\n    public boolean isImageShowing() {\n        return mShowImage;\n    }\n\n    /**\n     * Sets the show image state.\n     *\n     * @param showImage show or hide image\n     */\n    public void setShowImage(boolean showImage) {\n        mShowImage = showImage;\n        invalidate();\n    }\n\n    /**\n     * Gets the progress fill type.\n     */\n    public int getProgressFillType() {\n        return mProgressFillType;\n    }\n\n    /**\n     * Sets the progress fill type.\n     *\n     * @param fillType one of {@link #FILL_TYPE_CENTER}, {@link #FILL_TYPE_RADIAL}\n     */\n    public void setProgressFillType(int fillType) {\n        mProgressFillType = fillType;\n    }\n\n    /**\n     * Sets the progress listner.\n     *\n     * @param listener progress listener\n     */\n    public void setOnProgressListener(OnProgressListener listener) {\n        mListener = listener;\n    }\n\n    /**\n     * Handler used to perform the fill animation.\n     */\n    private class AnimationHandler extends Handler {\n\n        private int mAnimateTo;\n\n        public void setAnimateTo(int animateTo) {\n            mAnimateTo = animateTo;\n        }\n\n        @Override\n        public void handleMessage(Message msg) {\n            if (mProgress > mAnimateTo) {\n                setProgress(mProgress - 1);\n                sendEmptyMessageDelayed(0, mAnimationSpeed);\n            } else if (mProgress < mAnimateTo) {\n                setProgress(mProgress + 1);\n                sendEmptyMessageDelayed(0, mAnimationSpeed);\n            } else {\n                removeMessages(0);\n            }\n        }\n    }\n\n}\n"
  },
  {
    "path": "demo/src/main/java/com/lzy/demo/ui/SimpleViewBehavior.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.demo.ui;\n\nimport android.content.Context;\nimport android.content.res.TypedArray;\nimport android.graphics.drawable.ColorDrawable;\nimport android.os.Build;\nimport android.support.design.widget.AppBarLayout;\nimport android.support.design.widget.CoordinatorLayout;\nimport android.util.AttributeSet;\nimport android.view.View;\nimport android.view.animation.Animation;\nimport android.view.animation.AnimationUtils;\nimport android.view.animation.Transformation;\n\nimport com.lzy.demo.R;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：16/9/11\n * 描    述：\n * 修订历史：\n * ================================================\n */\n@SuppressWarnings(\"unused\")\npublic class SimpleViewBehavior extends CoordinatorLayout.Behavior<View> {\n\n    private static final int UNSPECIFIED_INT = Integer.MAX_VALUE;\n    private static final float UNSPECIFIED_FLOAT = Float.MAX_VALUE;\n\n    private static final int DEPEND_TYPE_HEIGHT = 0;\n    private static final int DEPEND_TYPE_WIDTH = 1;\n    private static final int DEPEND_TYPE_X = 2;\n    private static final int DEPEND_TYPE_Y = 3;\n\n    private int mDependViewId = 0;              //默认没有依赖对象\n    private int mDependType = DEPEND_TYPE_Y;    //默认按照y方向变化\n    private int mDependTargetX;                 //X方向的允许最大距离(影响动画percent)\n    private int mDependTargetY;                 //Y方向的允许最大距离(影响动画percent)\n    private int mDependTargetWidth;             //依赖控件起始最大宽度(影响动画percent)\n    private int mDependTargetHeight;            //依赖控件起始最大高度(影响动画percent)\n    private int targetX;\n    private int targetY;\n    private int targetWidth;\n    private int targetHeight;\n    private int targetBackgroundColor;\n    private float targetAlpha;\n    private float targetRotateX;\n    private float targetRotateY;\n    private int mAnimationId = 0;               //自定义动画id(xml文件定义动画)\n\n    private int mDependStartX;\n    private int mDependStartY;\n    private int mDependStartWidth;\n    private int mDependStartHeight;\n    private int mStartX;\n    private int mStartY;\n    private int mStartWidth;\n    private int mStartHeight;\n    private int mStartBackgroundColor;\n    private float mStartAlpha;\n    private float mStartRotateX;\n    private float mStartRotateY;\n\n    private Animation mAnimation;\n    private boolean isPrepared;\n\n    public SimpleViewBehavior(Context context, AttributeSet attrs) {\n        super(context, attrs);\n        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.SimpleViewBehavior);\n        mDependViewId = a.getResourceId(R.styleable.SimpleViewBehavior_svb_dependOn, mDependViewId);\n        mDependType = a.getInt(R.styleable.SimpleViewBehavior_svb_dependType, mDependType);\n        mDependTargetX = a.getDimensionPixelOffset(R.styleable.SimpleViewBehavior_svb_dependTargetX, UNSPECIFIED_INT);\n        mDependTargetY = a.getDimensionPixelOffset(R.styleable.SimpleViewBehavior_svb_dependTargetY, UNSPECIFIED_INT);\n        mDependTargetWidth = a.getDimensionPixelOffset(R.styleable.SimpleViewBehavior_svb_dependTargetWidth, UNSPECIFIED_INT);\n        mDependTargetHeight = a.getDimensionPixelOffset(R.styleable.SimpleViewBehavior_svb_dependTargetHeight, UNSPECIFIED_INT);\n        targetX = a.getDimensionPixelOffset(R.styleable.SimpleViewBehavior_svb_targetX, UNSPECIFIED_INT);\n        targetY = a.getDimensionPixelOffset(R.styleable.SimpleViewBehavior_svb_targetY, UNSPECIFIED_INT);\n        targetWidth = a.getDimensionPixelOffset(R.styleable.SimpleViewBehavior_svb_targetWidth, UNSPECIFIED_INT);\n        targetHeight = a.getDimensionPixelOffset(R.styleable.SimpleViewBehavior_svb_targetHeight, UNSPECIFIED_INT);\n        targetBackgroundColor = a.getColor(R.styleable.SimpleViewBehavior_svb_targetBackgroundColor, UNSPECIFIED_INT);\n        targetAlpha = a.getFloat(R.styleable.SimpleViewBehavior_svb_targetAlpha, UNSPECIFIED_FLOAT);\n        targetRotateX = a.getFloat(R.styleable.SimpleViewBehavior_svb_targetRotateX, UNSPECIFIED_FLOAT);\n        targetRotateY = a.getFloat(R.styleable.SimpleViewBehavior_svb_targetRotateY, UNSPECIFIED_FLOAT);\n        mAnimationId = a.getResourceId(R.styleable.SimpleViewBehavior_svb_animation, mAnimationId);\n        a.recycle();\n    }\n\n    /** 初始化数据 */\n    private void prepare(CoordinatorLayout parent, View child, View dependency) {\n        mDependStartX = (int) dependency.getX();\n        mDependStartY = (int) dependency.getY();\n        mDependStartWidth = dependency.getWidth();\n        mDependStartHeight = dependency.getHeight();\n        mStartX = (int) child.getX();\n        mStartY = (int) child.getY();\n        mStartWidth = child.getWidth();\n        mStartHeight = child.getHeight();\n        mStartAlpha = child.getAlpha();\n        mStartRotateX = child.getRotationX();\n        mStartRotateY = child.getRotationY();\n\n        //特殊处理y方向变化\n        if (mDependTargetY == UNSPECIFIED_INT && dependency instanceof AppBarLayout) {\n            mDependTargetY = ((AppBarLayout) dependency).getTotalScrollRange();\n        }\n        // 背景颜色渐变\n        if (child.getBackground() instanceof ColorDrawable) mStartBackgroundColor = ((ColorDrawable) child.getBackground()).getColor();\n        // 自定义动画\n        if (mAnimationId != 0) {\n            mAnimation = AnimationUtils.loadAnimation(child.getContext(), mAnimationId);\n            mAnimation.initialize(child.getWidth(), child.getHeight(), parent.getWidth(), parent.getHeight());\n        }\n        // 兼容5.0以上的沉浸模式\n        if (Build.VERSION.SDK_INT > 16 && parent.getFitsSystemWindows() && targetY != UNSPECIFIED_INT) {\n            targetY += getStatusBarHeight(parent.getContext());\n        }\n        isPrepared = true;\n    }\n\n    /**\n     * child 是指应用behavior的View ，dependency 担任触发behavior的角色，并与child进行互动。\n     * layoutDependsOn方法在每次layout发生变化时都会调用，我们需要在dependency控件发生变化时返回True，\n     * 在我们的例子中是用户在屏幕上滑动时（因为AppBarLayout发生了移动），然后我们需要让child做出相应的反应。\n     */\n    @Override\n    public boolean layoutDependsOn(CoordinatorLayout parent, View child, View dependency) {\n        return dependency.getId() == mDependViewId;\n    }\n\n    @Override\n    public boolean onDependentViewChanged(CoordinatorLayout parent, View child, View dependency) {\n        // 该方法会在滑动的时候一直回调,但只需要初始化一次\n        if (!isPrepared) prepare(parent, child, dependency);\n        updateView(child, dependency);\n        return false;\n    }\n\n    /**\n     * 这个是CoordinatorLayout在进行measure的过程中，利用Behavior对象对子view进行大小测量的一个方法。\n     * 在这个方法内，我们可以通过parent.getDependencies(child);这个方法，获取到这个child依赖的view，然后通过获取这个child依赖的view的大小来决定自身的大小。\n     */\n    @Override\n    public boolean onMeasureChild(CoordinatorLayout parent, View child, int parentWidthMeasureSpec, int widthUsed, int parentHeightMeasureSpec, int heightUsed) {\n        return super.onMeasureChild(parent, child, parentWidthMeasureSpec, widthUsed, parentHeightMeasureSpec, heightUsed);\n    }\n\n    /**\n     * 这个方法是用来子view用来布局自身使用，如果依赖其他view，那么系统会首先调用\n     * public boolean onDependentViewChanged(CoordinatorLayout parent, View child, View dependency)\n     * 这个方法，可以在这个回调中记录dependency的一些位置信息，在onLayoutChild中利用保存下来的信息进行计算，然后得到自身的具体位置。\n     */\n    @Override\n    public boolean onLayoutChild(CoordinatorLayout parent, View child, int layoutDirection) {\n        boolean bool = super.onLayoutChild(parent, child, layoutDirection);\n        if (isPrepared) updateView(child, parent.getDependencies(child).get(0));\n        return bool;\n    }\n\n    public void updateView(View child, View dependency) {\n        float percent = 0;\n        float start = 0;\n        float current = 0;\n        float end = UNSPECIFIED_INT;\n        switch (mDependType) {\n            case DEPEND_TYPE_WIDTH:\n                start = mDependStartWidth;\n                current = dependency.getWidth();\n                end = mDependTargetWidth;\n                break;\n            case DEPEND_TYPE_HEIGHT:\n                start = mDependStartHeight;\n                current = dependency.getHeight();\n                end = mDependTargetHeight;\n                break;\n            case DEPEND_TYPE_X:\n                start = mDependStartX;\n                current = dependency.getX();\n                end = mDependTargetX;\n                break;\n            case DEPEND_TYPE_Y:\n                start = mDependStartY;\n                current = dependency.getY();\n                end = mDependTargetY;\n                break;\n        }\n        if (end != UNSPECIFIED_INT) {\n            percent = Math.abs(current - start) / Math.abs(end - start);\n        }\n        updateViewWithPercent(child, percent > 1 ? 1 : percent);\n    }\n\n    /** 更新View */\n    public void updateViewWithPercent(View child, float percent) {\n        if (mAnimation == null) {\n            //如果没有自定义动画,那么使用属性动画\n            float newX = targetX == UNSPECIFIED_INT ? 0 : (targetX - mStartX) * percent;\n            float newY = targetY == UNSPECIFIED_INT ? 0 : (targetY - mStartY) * percent;\n            //缩放动画\n            if (targetWidth != UNSPECIFIED_INT || targetHeight != UNSPECIFIED_INT) {\n                child.setScaleX(scaleEvaluator(mStartWidth, targetWidth, percent));\n                child.setScaleY(scaleEvaluator(mStartHeight, targetHeight, percent));\n                float newWidth = floatEvaluator(mStartWidth, targetWidth, percent);\n                float newHeight = floatEvaluator(mStartWidth, targetWidth, percent);\n                newX -= (mStartWidth - newWidth) / 2;\n                newY -= (mStartHeight - newHeight) / 2;\n            }\n            //平移动画\n            child.setTranslationX(newX);\n            child.setTranslationY(newY);\n            //透明度变化\n            if (targetAlpha != UNSPECIFIED_FLOAT) child.setAlpha(floatEvaluator(mStartAlpha, targetAlpha, percent));\n            //背景渐变\n            if (targetBackgroundColor != UNSPECIFIED_INT && mStartBackgroundColor != 0) {\n                child.setBackgroundColor(argbEvaluator(mStartBackgroundColor, targetBackgroundColor, percent));\n            }\n            //旋转动画\n            if (targetRotateX != UNSPECIFIED_FLOAT) child.setRotationX(floatEvaluator(mStartRotateX, targetRotateX, percent));\n            if (targetRotateY != UNSPECIFIED_FLOAT) child.setRotationY(floatEvaluator(mStartRotateY, targetRotateY, percent));\n        } else {\n            mAnimation.setStartTime(0);\n            mAnimation.restrictDuration(100);\n            Transformation transformation = new Transformation();\n            mAnimation.getTransformation((long) (percent * 100), transformation);\n            BehaviorAnimation animation = new BehaviorAnimation(transformation);\n            child.startAnimation(animation);\n        }\n        child.requestLayout();\n    }\n\n    private static class BehaviorAnimation extends Animation {\n\n        private Transformation mTransformation;\n\n        public BehaviorAnimation(Transformation transformation) {\n            mTransformation = transformation;\n            setDuration(0);\n            setFillAfter(true);\n        }\n\n        @Override\n        protected void applyTransformation(float interpolatedTime, Transformation t) {\n            t.compose(mTransformation);\n            super.applyTransformation(interpolatedTime, t);\n        }\n    }\n\n    public static float floatEvaluator(float originalSize, float finalSize, float percent) {\n        return (finalSize - originalSize) * percent + originalSize;\n    }\n\n    public static float scaleEvaluator(float originalSize, float finalSize, float percent) {\n        float calcSize = (finalSize - originalSize) * percent + originalSize;\n        return calcSize / originalSize;\n    }\n\n    public static int argbEvaluator(int startColor, int endColor, float percent) {\n        int startA = (startColor >> 24) & 0xff;\n        int startR = (startColor >> 16) & 0xff;\n        int startG = (startColor >> 8) & 0xff;\n        int startB = startColor & 0xff;\n\n        int endA = (endColor >> 24) & 0xff;\n        int endR = (endColor >> 16) & 0xff;\n        int endG = (endColor >> 8) & 0xff;\n        int endB = endColor & 0xff;\n\n        return ((startA + (int) (percent * (endA - startA))) << 24) |//\n               ((startR + (int) (percent * (endR - startR))) << 16) |//\n               ((startG + (int) (percent * (endG - startG))) << 8) |//\n               ((startB + (int) (percent * (endB - startB))));\n    }\n\n    /** 获取状态栏的高度 */\n    private static int getStatusBarHeight(Context context) {\n        int result = 0;\n        int resourceId = context.getResources().getIdentifier(\"status_bar_height\", \"dimen\", \"android\");\n        if (resourceId > 0) {\n            result = context.getResources().getDimensionPixelSize(resourceId);\n        }\n        return result;\n    }\n}\n"
  },
  {
    "path": "demo/src/main/java/com/lzy/demo/ui/TranslateUpDownBehavior.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.demo.ui;\n\nimport android.content.Context;\nimport android.support.design.widget.CoordinatorLayout;\nimport android.support.design.widget.FloatingActionButton;\nimport android.support.v4.view.ViewCompat;\nimport android.support.v4.view.ViewPropertyAnimatorListener;\nimport android.util.AttributeSet;\nimport android.view.View;\nimport android.view.ViewGroup;\n\nimport com.lzy.demo.utils.AnimHelper;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：16/8/17\n * 描    述：\n * 修订历史：\n * ================================================\n */\n@SuppressWarnings(\"unused\")\npublic class TranslateUpDownBehavior extends FloatingActionButton.Behavior {\n\n    private boolean isAnimating = false;\n    private OnStateChangeListener listener;\n\n    public TranslateUpDownBehavior(Context context, AttributeSet attrs) {\n        super();\n    }\n\n    public static TranslateUpDownBehavior form(View view) {\n        ViewGroup.LayoutParams params = view.getLayoutParams();\n        if (params == null || !(params instanceof CoordinatorLayout.LayoutParams)) {\n            throw new IllegalArgumentException(\"parent must be CoordinatorLayout\");\n        }\n        CoordinatorLayout.Behavior behavior = ((CoordinatorLayout.LayoutParams) params).getBehavior();\n        if (!(behavior instanceof TranslateUpDownBehavior)) {\n            throw new IllegalArgumentException(\"the behavior must be TranslateUpDownBehavior\");\n        }\n        return (TranslateUpDownBehavior) behavior;\n    }\n\n    @Override\n    public boolean onStartNestedScroll(CoordinatorLayout coordinatorLayout, FloatingActionButton child, View directTargetChild, View target, int nestedScrollAxes) {\n        return nestedScrollAxes == ViewCompat.SCROLL_AXIS_VERTICAL;\n    }\n\n    @Override\n    public void onNestedScroll(CoordinatorLayout coordinatorLayout, FloatingActionButton child, View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed) {\n        if (((dyConsumed > 0 && dyUnconsumed == 0) || (dyConsumed == 0 && dyUnconsumed > 0)) && !isAnimating && child.getVisibility() == View.VISIBLE) {\n            if (listener != null) listener.onChange(true);\n            AnimHelper.translateDown(child, new MyViewPropertyAnimatorListener() {\n                @Override\n                public void onAnimationEnd(View view) {\n                    super.onAnimationEnd(view);\n                    view.setVisibility(View.INVISIBLE);\n                }\n            });\n        } else if ((dyConsumed < 0 && dyUnconsumed == 0) || (dyConsumed == 0 && dyUnconsumed < 0) && !isAnimating && child.getVisibility() == View.INVISIBLE) {\n            if (listener != null) listener.onChange(false);\n            child.setVisibility(View.VISIBLE);\n            AnimHelper.translateUp(child, null);\n        }\n    }\n\n    private class MyViewPropertyAnimatorListener implements ViewPropertyAnimatorListener {\n\n        @Override\n        public void onAnimationStart(View view) {\n            isAnimating = true;\n        }\n\n        @Override\n        public void onAnimationEnd(View view) {\n            isAnimating = false;\n        }\n\n        @Override\n        public void onAnimationCancel(View view) {\n            isAnimating = false;\n        }\n    }\n\n    public void setOnStateChangeListener(OnStateChangeListener listener) {\n        this.listener = listener;\n    }\n\n    public interface OnStateChangeListener {\n        void onChange(boolean isUp);\n    }\n}\n"
  },
  {
    "path": "demo/src/main/java/com/lzy/demo/utils/AnimHelper.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.demo.utils;\n\nimport android.content.Context;\nimport android.support.v4.view.ViewCompat;\nimport android.support.v4.view.ViewPropertyAnimatorListener;\nimport android.support.v4.view.animation.FastOutSlowInInterpolator;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.view.animation.Interpolator;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：16/8/17\n * 描    述：\n * 修订历史：\n * ================================================\n */\npublic class AnimHelper {\n\n    private AnimHelper() {\n        throw new RuntimeException(\"AnimHelper cannot be initialized!\");\n    }\n\n    public static final Interpolator INTERPOLATOR = new FastOutSlowInInterpolator();\n    public static final int DURATION = 300;\n\n    public static void scaleShow(View view, ViewPropertyAnimatorListener listener) {\n        ViewCompat.animate(view).scaleX(1.0f).scaleY(1.0f).alpha(1.0f).setDuration(DURATION).setListener(listener).setInterpolator(INTERPOLATOR).withLayer().start();\n    }\n\n    public static void scaleHide(View view, ViewPropertyAnimatorListener listener) {\n        ViewCompat.animate(view).scaleX(0f).scaleY(0f).alpha(0f).setDuration(DURATION).setListener(listener).setInterpolator(INTERPOLATOR).withLayer().start();\n    }\n\n    public static void alphaShow(View view, ViewPropertyAnimatorListener listener) {\n        ViewCompat.animate(view).alpha(1.0f).setDuration(DURATION).setListener(listener).setInterpolator(INTERPOLATOR).withLayer().start();\n    }\n\n    public static void alphaHide(View view, ViewPropertyAnimatorListener listener) {\n        ViewCompat.animate(view).alpha(0f).setDuration(DURATION).setListener(listener).setInterpolator(INTERPOLATOR).withLayer().start();\n    }\n\n    public static void translateUp(View view, ViewPropertyAnimatorListener listener) {\n        ViewCompat.animate(view).translationY(0).setDuration(DURATION).setListener(listener).setInterpolator(INTERPOLATOR).withLayer().start();\n    }\n\n    public static void translateDown(View view, ViewPropertyAnimatorListener listener) {\n        int height = view.getHeight();\n        ViewGroup.LayoutParams params = view.getLayoutParams();\n        ViewGroup.MarginLayoutParams layoutParams = params instanceof ViewGroup.MarginLayoutParams ? ((ViewGroup.MarginLayoutParams) params) : null;\n        if (layoutParams != null) height += layoutParams.bottomMargin;\n        ViewCompat.animate(view).translationY(height).setDuration(DURATION).setListener(listener).setInterpolator(INTERPOLATOR).withLayer().start();\n    }\n\n    public static float floatEvaluator(float originalSize, float finalSize, float percent) {\n        return (finalSize - originalSize) * percent + originalSize;\n    }\n\n    public static int argbEvaluator(int startColor, int endColor, float percent) {\n        int startA = (startColor >> 24) & 0xff;\n        int startR = (startColor >> 16) & 0xff;\n        int startG = (startColor >> 8) & 0xff;\n        int startB = startColor & 0xff;\n\n        int endA = (endColor >> 24) & 0xff;\n        int endR = (endColor >> 16) & 0xff;\n        int endG = (endColor >> 8) & 0xff;\n        int endB = endColor & 0xff;\n\n        return ((startA + (int) (percent * (endA - startA))) << 24) |\n                ((startR + (int) (percent * (endR - startR))) << 16) |\n                ((startG + (int) (percent * (endG - startG))) << 8) |\n                ((startB + (int) (percent * (endB - startB))));\n    }\n\n    public static float scaleEvaluator(float originalSize, float finalSize, float percent) {\n        float calcSize = (finalSize - originalSize) * percent + originalSize;\n        return calcSize / originalSize;\n    }\n\n    /** 获得状态栏的高度 */\n    public static int getStatusBarHeight(Context context) {\n        int statusHeight = -1;\n        try {\n            Class<?> clazz = Class.forName(\"com.android.internal.R$dimen\");\n            Object object = clazz.newInstance();\n            int height = Integer.parseInt(clazz.getField(\"status_bar_height\").get(object).toString());\n            statusHeight = context.getResources().getDimensionPixelSize(height);\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n        return statusHeight;\n    }\n}\n"
  },
  {
    "path": "demo/src/main/java/com/lzy/demo/utils/ApkUtils.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.demo.utils;\n\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.pm.ApplicationInfo;\nimport android.content.pm.PackageInfo;\nimport android.content.pm.PackageManager;\nimport android.net.Uri;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.Enumeration;\nimport java.util.List;\nimport java.util.zip.ZipEntry;\nimport java.util.zip.ZipFile;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：2016/1/25\n * 描    述：\n * 修订历史：\n * ================================================\n */\npublic class ApkUtils {\n\n    /** 安装一个apk文件 */\n    public static void install(Context context, File uriFile) {\n        Intent intent = new Intent(Intent.ACTION_VIEW);\n        intent.setDataAndType(Uri.fromFile(uriFile), \"application/vnd.android.package-archive\");\n        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);\n        context.startActivity(intent);\n    }\n\n    /** 卸载一个app */\n    public static void uninstall(Context context, String packageName) {\n        //通过程序的包名创建URI\n        Uri packageURI = Uri.parse(\"package:\" + packageName);\n        //创建Intent意图\n        Intent intent = new Intent(Intent.ACTION_DELETE, packageURI);\n        //执行卸载程序\n        context.startActivity(intent);\n    }\n\n    /** 检查手机上是否安装了指定的软件 */\n    public static boolean isAvailable(Context context, String packageName) {\n        // 获取packagemanager\n        final PackageManager packageManager = context.getPackageManager();\n        // 获取所有已安装程序的包信息\n        List<PackageInfo> packageInfos = packageManager.getInstalledPackages(0);\n        // 用于存储所有已安装程序的包名\n        List<String> packageNames = new ArrayList<>();\n        // 从pinfo中将包名字逐一取出，压入pName list中\n        if (packageInfos != null) {\n            for (int i = 0; i < packageInfos.size(); i++) {\n                String packName = packageInfos.get(i).packageName;\n                packageNames.add(packName);\n            }\n        }\n        // 判断packageNames中是否有目标程序的包名，有TRUE，没有FALSE\n        return packageNames.contains(packageName);\n    }\n\n    /** 检查手机上是否安装了指定的软件 */\n    public static boolean isAvailable(Context context, File file) {\n        return isAvailable(context, getPackageName(context, file.getAbsolutePath()));\n    }\n\n    /** 根据文件路径获取包名 */\n    public static String getPackageName(Context context, String filePath) {\n        PackageManager packageManager = context.getPackageManager();\n        PackageInfo info = packageManager.getPackageArchiveInfo(filePath, PackageManager.GET_ACTIVITIES);\n        if (info != null) {\n            ApplicationInfo appInfo = info.applicationInfo;\n            return appInfo.packageName;  //得到安装包名称\n        }\n        return null;\n    }\n\n    /** 从apk中获取版本信息 */\n    public static String getChannelFromApk(Context context, String channelPrefix) {\n        //从apk包中获取\n        ApplicationInfo appinfo = context.getApplicationInfo();\n        String sourceDir = appinfo.sourceDir;\n        //默认放在meta-inf/里， 所以需要再拼接一下\n        String key = \"META-INF/\" + channelPrefix;\n        String ret = \"\";\n        ZipFile zipfile = null;\n        try {\n            zipfile = new ZipFile(sourceDir);\n            Enumeration<?> entries = zipfile.entries();\n            while (entries.hasMoreElements()) {\n                ZipEntry entry = ((ZipEntry) entries.nextElement());\n                String entryName = entry.getName();\n                if (entryName.startsWith(key)) {\n                    ret = entryName;\n                    break;\n                }\n            }\n        } catch (IOException e) {\n            e.printStackTrace();\n        } finally {\n            if (zipfile != null) {\n                try {\n                    zipfile.close();\n                } catch (IOException e) {\n                    e.printStackTrace();\n                }\n            }\n        }\n        String[] split = ret.split(channelPrefix);\n        String channel = \"\";\n        if (split.length >= 2) {\n            channel = ret.substring(key.length());\n        }\n        return channel;\n    }\n}\n"
  },
  {
    "path": "demo/src/main/java/com/lzy/demo/utils/ColorUtils.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.demo.utils;/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：2015/8/4\n * 描    述：\n * 修订历史：\n * ================================================\n */\n\nimport android.graphics.Color;\n\nimport java.util.Random;\n\npublic class ColorUtils {\n\n    public static int randomColor() {\n        Random random = new Random();\n        int red = random.nextInt(150) + 50;\n        int green = random.nextInt(150) + 50;\n        int blue = random.nextInt(150) + 50;\n        return Color.rgb(red, green, blue);\n    }\n}\n"
  },
  {
    "path": "demo/src/main/java/com/lzy/demo/utils/Convert.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.demo.utils;\n\nimport com.google.gson.Gson;\nimport com.google.gson.JsonElement;\nimport com.google.gson.JsonIOException;\nimport com.google.gson.JsonParser;\nimport com.google.gson.JsonSyntaxException;\nimport com.google.gson.stream.JsonReader;\nimport com.readystatesoftware.chuck.internal.support.JsonConvertor;\n\nimport java.io.Reader;\nimport java.lang.reflect.Type;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：16/9/28\n * 描    述：\n * 修订历史：\n * ================================================\n */\npublic class Convert {\n\n    private static Gson create() {\n        return Convert.GsonHolder.gson;\n    }\n\n    private static class GsonHolder {\n        private static Gson gson = new Gson();\n    }\n\n    public static <T> T fromJson(String json, Class<T> type) throws JsonIOException, JsonSyntaxException {\n        return create().fromJson(json, type);\n    }\n\n    public static <T> T fromJson(String json, Type type) {\n        return create().fromJson(json, type);\n    }\n\n    public static <T> T fromJson(JsonReader reader, Type typeOfT) throws JsonIOException, JsonSyntaxException {\n        return create().fromJson(reader, typeOfT);\n    }\n\n    public static <T> T fromJson(Reader json, Class<T> classOfT) throws JsonSyntaxException, JsonIOException {\n        return create().fromJson(json, classOfT);\n    }\n\n    public static <T> T fromJson(Reader json, Type typeOfT) throws JsonIOException, JsonSyntaxException {\n        return create().fromJson(json, typeOfT);\n    }\n\n    public static String toJson(Object src) {\n        return create().toJson(src);\n    }\n\n    public static String toJson(Object src, Type typeOfSrc) {\n        return create().toJson(src, typeOfSrc);\n    }\n\n    public static String formatJson(String json) {\n        try {\n            JsonParser jp = new JsonParser();\n            JsonElement je = jp.parse(json);\n            return JsonConvertor.getInstance().toJson(je);\n        } catch (Exception e) {\n            return json;\n        }\n    }\n\n    public static String formatJson(Object src) {\n        try {\n            JsonParser jp = new JsonParser();\n            JsonElement je = jp.parse(toJson(src));\n            return JsonConvertor.getInstance().toJson(je);\n        } catch (Exception e) {\n            return e.getMessage();\n        }\n    }\n}\n"
  },
  {
    "path": "demo/src/main/java/com/lzy/demo/utils/GlideImageLoader.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.demo.utils;\n\nimport android.app.Activity;\nimport android.content.Context;\nimport android.graphics.Bitmap;\nimport android.widget.ImageView;\n\nimport com.bumptech.glide.Glide;\nimport com.bumptech.glide.load.engine.DiskCacheStrategy;\nimport com.lzy.demo.R;\nimport com.lzy.imagepicker.loader.ImageLoader;\nimport com.lzy.ninegrid.NineGridView;\n\nimport java.io.File;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：16/9/5\n * 描    述：\n * 修订历史：\n * ================================================\n */\npublic class GlideImageLoader implements ImageLoader, NineGridView.ImageLoader {\n    @Override\n    public void onDisplayImage(Context context, ImageView imageView, String url) {\n        Glide.with(context).load(url)//\n                .placeholder(R.drawable.ic_default_color)// 这行貌似是glide的bug,在部分机型上会导致第一次图片不在中间\n                .error(R.drawable.ic_default_color)//\n                .diskCacheStrategy(DiskCacheStrategy.SOURCE)//\n                .into(imageView);\n    }\n\n    @Override\n    public Bitmap getCacheImage(String url) {\n        return null;\n    }\n\n    @Override\n    public void displayImage(Activity activity, String path, ImageView imageView, int width, int height) {\n        Glide.with(activity).load(new File(path))//\n                .placeholder(R.drawable.ic_default_color)//\n                .error(R.drawable.ic_default_color)//\n                .diskCacheStrategy(DiskCacheStrategy.SOURCE)//\n                .into(imageView);\n    }\n\n    @Override\n    public void clearMemoryCache() {\n    }\n}\n"
  },
  {
    "path": "demo/src/main/java/com/lzy/demo/utils/MD5Utils.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.demo.utils;\n\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.security.DigestInputStream;\nimport java.security.MessageDigest;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：2015/10/11\n * 描    述：MD5加密工具类\n * 修订历史：\n * ================================================\n */\npublic class MD5Utils {\n\n    private MD5Utils() {\n    }\n\n    /**\n     * 获取字符串的 MD5\n     */\n    public static String encode(String str) {\n        try {\n            MessageDigest md5 = MessageDigest.getInstance(\"MD5\");\n            md5.update(str.getBytes(\"UTF-8\"));\n            byte messageDigest[] = md5.digest();\n            StringBuilder hexString = new StringBuilder();\n            for (byte b : messageDigest) {\n                hexString.append(String.format(\"%02X\", b));\n            }\n            return hexString.toString().toLowerCase();\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n        return \"\";\n    }\n\n    /**\n     * 获取文件的 MD5\n     */\n    public static String encode(File file) {\n        try {\n            MessageDigest messageDigest = MessageDigest.getInstance(\"MD5\");\n            FileInputStream inputStream = new FileInputStream(file);\n            DigestInputStream digestInputStream = new DigestInputStream(inputStream, messageDigest);\n            //必须把文件读取完毕才能拿到md5\n            byte[] buffer = new byte[4096];\n            while (digestInputStream.read(buffer) > -1) {\n            }\n            MessageDigest digest = digestInputStream.getMessageDigest();\n            digestInputStream.close();\n            byte[] md5 = digest.digest();\n            StringBuilder sb = new StringBuilder();\n            for (byte b : md5) {\n                sb.append(String.format(\"%02X\", b));\n            }\n            return sb.toString().toLowerCase();\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n        return null;\n    }\n}\n"
  },
  {
    "path": "demo/src/main/java/com/lzy/demo/utils/PicassoImageLoader.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.demo.utils;\n\nimport android.app.Activity;\nimport android.content.Context;\nimport android.graphics.Bitmap;\nimport android.net.Uri;\nimport android.widget.ImageView;\n\nimport com.lzy.imagepicker.loader.ImageLoader;\nimport com.lzy.ninegrid.NineGridView;\nimport com.lzy.demo.R;\nimport com.squareup.picasso.Picasso;\n\nimport java.io.File;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：16/9/1\n * 描    述：\n * 修订历史：\n * ================================================\n */\npublic class PicassoImageLoader implements ImageLoader, NineGridView.ImageLoader {\n\n    @Override\n    public void displayImage(Activity activity, String path, ImageView imageView, int width, int height) {\n        Picasso.with(activity)                                  //配置上下文\n                .load(Uri.fromFile(new File(path)))             //设置图片路径(fix #8,文件名包含%符号 无法识别和显示)\n                .error(R.drawable.ic_default_color)             //设置错误图片\n                .placeholder(R.drawable.ic_default_color)       //设置占位图片\n                .into(imageView);\n    }\n\n    @Override\n    public void clearMemoryCache() {\n    }\n\n    @Override\n    public void onDisplayImage(Context context, ImageView imageView, String url) {\n        Picasso.with(context).load(url)//\n                .placeholder(R.drawable.ic_default_color)//\n                .error(R.drawable.ic_default_color)//\n                .into(imageView);\n    }\n\n    @Override\n    public Bitmap getCacheImage(String url) {\n        return null;\n    }\n}\n"
  },
  {
    "path": "demo/src/main/java/com/lzy/demo/utils/Urls.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.demo.utils;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）\n * 版    本：1.0\n * 创建日期：2016/4/6\n * 描    述：我的Github地址  https://github.com/jeasonlzy\n * 修订历史：\n * ================================================\n */\npublic class Urls {\n    public static final String SERVER = \"http://server.jeasonlzy.com/OkHttpUtils/\";\n    //    public static final String SERVER = \"http://192.168.1.121:8080/OkHttpUtils/\";\n    public static final String URL_METHOD = SERVER + \"method\";\n    public static final String URL_CACHE = SERVER + \"cache\";\n    public static final String URL_IMAGE = SERVER + \"image\";\n    public static final String URL_JSONOBJECT = SERVER + \"jsonObject\";\n    public static final String URL_JSONARRAY = SERVER + \"jsonArray\";\n    public static final String URL_FORM_UPLOAD = SERVER + \"upload\";\n    public static final String URL_TEXT_UPLOAD = SERVER + \"uploadString\";\n    public static final String URL_DOWNLOAD = SERVER + \"download\";\n    public static final String URL_REDIRECT = SERVER + \"redirect\";\n\n    public static final String URL_GANK_BASE = \"http://gank.io/api/data/\";\n}\n"
  },
  {
    "path": "demo/src/main/res/drawable/progress_bar_states.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n    Copyright 2016 jeasonlzy(廖子尧)\n    \n    Licensed under the Apache License, Version 2.0 (the \"License\");\n    you may not use this file except in compliance with the License.\n    You may obtain a copy of the License at\n    \n       http://www.apache.org/licenses/LICENSE-2.0\n       \n    Unless required by applicable law or agreed to in writing, software\n    distributed under the License is distributed on an \"AS IS\" BASIS,\n    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n    See the License for the specific language governing permissions and\n    limitations under the License.\n-->\n<layer-list xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <item android:id=\"@android:id/background\">\n        <shape>\n            <gradient\n                android:angle=\"270\"\n                android:centerColor=\"#ff5a5d5a\"\n                android:centerY=\"0.75\"\n                android:endColor=\"#ff747674\"\n                android:startColor=\"#ff9d9e9d\"/>\n        </shape>\n    </item>\n\n    <item android:id=\"@android:id/secondaryProgress\">\n        <clip>\n            <shape>\n                <gradient\n                    android:angle=\"270\"\n                    android:centerColor=\"#a046801b\"\n                    android:centerY=\"0.75\"\n                    android:endColor=\"#a046c01b\"\n                    android:startColor=\"#a046c01b\"/>\n            </shape>\n        </clip>\n    </item>\n\n    <item android:id=\"@android:id/progress\">\n        <clip>\n            <shape>\n                <gradient\n                    android:angle=\"270\"\n                    android:centerColor=\"#46bb1b\"\n                    android:centerY=\"0.75\"\n                    android:endColor=\"#46cc1b\"\n                    android:startColor=\"#46cc1b\"/>\n            </shape>\n        </clip>\n    </item>\n</layer-list>\n"
  },
  {
    "path": "demo/src/main/res/layout/activity_base.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n    Copyright 2016 jeasonlzy(廖子尧)\n    \n    Licensed under the Apache License, Version 2.0 (the \"License\");\n    you may not use this file except in compliance with the License.\n    You may obtain a copy of the License at\n    \n       http://www.apache.org/licenses/LICENSE-2.0\n       \n    Unless required by applicable law or agreed to in writing, software\n    distributed under the License is distributed on an \"AS IS\" BASIS,\n    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n    See the License for the specific language governing permissions and\n    limitations under the License.\n-->\n<ScrollView\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\">\n\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:orientation=\"vertical\"\n        android:padding=\"10dp\">\n\n        <FrameLayout\n            android:id=\"@+id/content\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"/>\n\n        <include layout=\"@layout/include_data\"/>\n\n    </LinearLayout>\n\n</ScrollView>\n"
  },
  {
    "path": "demo/src/main/res/layout/activity_bitmap_request.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n    Copyright 2016 jeasonlzy(廖子尧)\n    \n    Licensed under the Apache License, Version 2.0 (the \"License\");\n    you may not use this file except in compliance with the License.\n    You may obtain a copy of the License at\n    \n       http://www.apache.org/licenses/LICENSE-2.0\n       \n    Unless required by applicable law or agreed to in writing, software\n    distributed under the License is distributed on an \"AS IS\" BASIS,\n    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n    See the License for the specific language governing permissions and\n    limitations under the License.\n-->\n<LinearLayout\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:orientation=\"vertical\">\n\n    <Button\n        android:id=\"@+id/requestImage\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:text=\"请求图片\"\n        android:textAllCaps=\"false\"/>\n\n    <ImageView\n        android:id=\"@+id/imageView\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"/>\n\n</LinearLayout>\n"
  },
  {
    "path": "demo/src/main/res/layout/activity_cache.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n    Copyright 2016 jeasonlzy(廖子尧)\n    \n    Licensed under the Apache License, Version 2.0 (the \"License\");\n    you may not use this file except in compliance with the License.\n    You may obtain a copy of the License at\n    \n       http://www.apache.org/licenses/LICENSE-2.0\n       \n    Unless required by applicable law or agreed to in writing, software\n    distributed under the License is distributed on an \"AS IS\" BASIS,\n    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n    See the License for the specific language governing permissions and\n    limitations under the License.\n-->\n<LinearLayout\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:orientation=\"vertical\">\n\n    <Button\n        android:id=\"@+id/no_cache\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:gravity=\"left|center_vertical\"\n        android:text=\"0. 不使用缓存\"\n        android:textAllCaps=\"false\"/>\n\n    <Button\n        android:id=\"@+id/cache_default\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:gravity=\"left|center_vertical\"\n        android:text=\"1. Http标准的缓存协议(304缓存头)\"\n        android:textAllCaps=\"false\"/>\n\n    <Button\n        android:id=\"@+id/request_failed_read_cache\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:gravity=\"left|center_vertical\"\n        android:text=\"2. 先请求网络，如果失败，则返回上次的缓存\"\n        android:textAllCaps=\"false\"/>\n\n    <Button\n        android:id=\"@+id/if_none_cache_request\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:gravity=\"left|center_vertical\"\n        android:text=\"3. 先读取缓存，如果缓存不存在，才请求网络，\\n如果网络请求也失败，则请求失败\"\n        android:textAllCaps=\"false\"/>\n\n    <Button\n        android:id=\"@+id/first_cache_then_request\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:gravity=\"left|center_vertical\"\n        android:text=\"4. 先读取缓存，无论缓存是否存在，都请求网络，\\n如果网络请求失败，则仍然使用缓存\"\n        android:textAllCaps=\"false\"/>\n\n    <Button\n        android:id=\"@+id/getAll\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:text=\"显示所有缓存\"\n        android:textAllCaps=\"false\"/>\n\n    <Button\n        android:id=\"@+id/clear\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:text=\"清除所有缓存\"\n        android:textAllCaps=\"false\"/>\n\n</LinearLayout>\n"
  },
  {
    "path": "demo/src/main/res/layout/activity_cookie.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n    Copyright 2016 jeasonlzy(廖子尧)\n    \n    Licensed under the Apache License, Version 2.0 (the \"License\");\n    you may not use this file except in compliance with the License.\n    You may obtain a copy of the License at\n    \n       http://www.apache.org/licenses/LICENSE-2.0\n       \n    Unless required by applicable law or agreed to in writing, software\n    distributed under the License is distributed on an \"AS IS\" BASIS,\n    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n    See the License for the specific language governing permissions and\n    limitations under the License.\n-->\n<LinearLayout\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:orientation=\"vertical\">\n\n    <Button\n        android:id=\"@+id/getCookie\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:text=\"获取指定url对应的cookie\"\n        android:textAllCaps=\"false\"/>\n\n    <Button\n        android:id=\"@+id/getAllCookie\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:text=\"获取所有的cookie\"\n        android:textAllCaps=\"false\"/>\n\n    <Button\n        android:id=\"@+id/addCookie\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:text=\"添加自定义cookie\"\n        android:textAllCaps=\"false\"/>\n\n    <Button\n        android:id=\"@+id/removeCookie\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:text=\"手动移除cookie\"\n        android:textAllCaps=\"false\"/>\n\n    <Button\n        android:id=\"@+id/updateCookie\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:text=\"手动修改cookie\"\n        android:textAllCaps=\"false\"/>\n\n</LinearLayout>\n"
  },
  {
    "path": "demo/src/main/res/layout/activity_custom_request.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n    Copyright 2016 jeasonlzy(廖子尧)\n    \n    Licensed under the Apache License, Version 2.0 (the \"License\");\n    you may not use this file except in compliance with the License.\n    You may obtain a copy of the License at\n    \n       http://www.apache.org/licenses/LICENSE-2.0\n       \n    Unless required by applicable law or agreed to in writing, software\n    distributed under the License is distributed on an \"AS IS\" BASIS,\n    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n    See the License for the specific language governing permissions and\n    limitations under the License.\n-->\n<LinearLayout\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:orientation=\"vertical\">\n\n    <Button\n        android:id=\"@+id/requestJson\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:text=\"解析JSONObject数据\"\n        android:textAllCaps=\"false\"/>\n\n    <Button\n        android:id=\"@+id/requestJsonArray\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:text=\"解析JSONArray数据\"\n        android:textAllCaps=\"false\"/>\n\n</LinearLayout>\n"
  },
  {
    "path": "demo/src/main/res/layout/activity_download_all.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n    Copyright 2016 jeasonlzy(廖子尧)\n    \n    Licensed under the Apache License, Version 2.0 (the \"License\");\n    you may not use this file except in compliance with the License.\n    You may obtain a copy of the License at\n    \n       http://www.apache.org/licenses/LICENSE-2.0\n       \n    Unless required by applicable law or agreed to in writing, software\n    distributed under the License is distributed on an \"AS IS\" BASIS,\n    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n    See the License for the specific language governing permissions and\n    limitations under the License.\n-->\n<LinearLayout\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:orientation=\"vertical\">\n\n    <android.support.design.widget.AppBarLayout\n        android:id=\"@+id/appbar\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        app:theme=\"@style/AppTheme.AppBarOverlay\">\n\n        <android.support.v7.widget.Toolbar\n            android:id=\"@+id/toolbar\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"?attr/actionBarSize\"\n            app:popupTheme=\"@style/AppTheme.PopupOverlay\"/>\n    </android.support.design.widget.AppBarLayout>\n\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:orientation=\"horizontal\">\n\n        <Button\n            android:id=\"@+id/removeAll\"\n            android:layout_width=\"0dp\"\n            android:layout_height=\"wrap_content\"\n            android:layout_weight=\"1\"\n            android:text=\"删除所有\"/>\n\n        <Button\n            android:id=\"@+id/pauseAll\"\n            android:layout_width=\"0dp\"\n            android:layout_height=\"wrap_content\"\n            android:layout_weight=\"1\"\n            android:text=\"暂停所有\"/>\n\n        <Button\n            android:id=\"@+id/startAll\"\n            android:layout_width=\"0dp\"\n            android:layout_height=\"wrap_content\"\n            android:layout_weight=\"1\"\n            android:text=\"开始所有\"/>\n    </LinearLayout>\n\n    <android.support.v7.widget.RecyclerView\n        android:id=\"@+id/recyclerView\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        tools:listitem=\"@layout/item_download_manager\"/>\n\n</LinearLayout>\n"
  },
  {
    "path": "demo/src/main/res/layout/activity_download_details.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n    Copyright 2016 jeasonlzy(廖子尧)\n    \n    Licensed under the Apache License, Version 2.0 (the \"License\");\n    you may not use this file except in compliance with the License.\n    You may obtain a copy of the License at\n    \n       http://www.apache.org/licenses/LICENSE-2.0\n       \n    Unless required by applicable law or agreed to in writing, software\n    distributed under the License is distributed on an \"AS IS\" BASIS,\n    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n    See the License for the specific language governing permissions and\n    limitations under the License.\n-->\n<LinearLayout\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:orientation=\"vertical\">\n\n    <android.support.design.widget.AppBarLayout\n        android:id=\"@+id/appbar\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        app:theme=\"@style/AppTheme.AppBarOverlay\">\n\n        <android.support.v7.widget.Toolbar\n            android:id=\"@+id/toolbar\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"?attr/actionBarSize\"\n            app:popupTheme=\"@style/AppTheme.PopupOverlay\"/>\n    </android.support.design.widget.AppBarLayout>\n\n    <ImageView\n        android:id=\"@+id/icon\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"0dp\"\n        android:layout_weight=\"1\"\n        android:paddingTop=\"10dp\"\n        android:src=\"@mipmap/ic_launcher\"/>\n\n    <TextView\n        android:id=\"@+id/name\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"0dp\"\n        android:layout_weight=\"1\"\n        android:gravity=\"center\"\n        android:text=\"标题\"/>\n\n\n    <RelativeLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginTop=\"10dp\"\n        android:padding=\"5dp\">\n\n        <TextView\n            android:id=\"@+id/downloadSize\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:text=\"--M/--M\"\n            android:textSize=\"12sp\"/>\n\n        <TextView\n            android:id=\"@+id/tvProgress\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_centerHorizontal=\"true\"\n            android:text=\"--.--%\"\n            android:textSize=\"12sp\"/>\n\n        <TextView\n            android:id=\"@+id/netSpeed\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_alignParentRight=\"true\"\n            android:layout_marginRight=\"10dp\"\n            android:text=\"---K/s\"\n            android:textSize=\"12sp\"/>\n    </RelativeLayout>\n\n    <ProgressBar\n        android:id=\"@+id/pbProgress\"\n        style=\"@style/Widget.AppCompat.ProgressBar.Horizontal\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:padding=\"5dp\"/>\n\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"50dp\">\n\n        <Button\n            android:id=\"@+id/start\"\n            android:layout_width=\"0dp\"\n            android:layout_height=\"match_parent\"\n            android:layout_gravity=\"center\"\n            android:layout_weight=\"1\"\n            android:background=\"#E30\"\n            android:padding=\"5dp\"\n            android:text=\"下载\"\n            android:textColor=\"#FFF\"/>\n\n        <Button\n            android:id=\"@+id/remove\"\n            android:layout_width=\"0dp\"\n            android:layout_height=\"match_parent\"\n            android:layout_gravity=\"center\"\n            android:layout_weight=\"1\"\n            android:background=\"#3E0\"\n            android:padding=\"5dp\"\n            android:text=\"删除\"\n            android:textColor=\"#FFF\"/>\n\n        <Button\n            android:id=\"@+id/restart\"\n            android:layout_width=\"0dp\"\n            android:layout_height=\"match_parent\"\n            android:layout_gravity=\"center\"\n            android:layout_weight=\"1\"\n            android:background=\"#03E\"\n            android:padding=\"5dp\"\n            android:text=\"重新下载\"\n            android:textColor=\"#FFF\"/>\n    </LinearLayout>\n\n</LinearLayout>\n"
  },
  {
    "path": "demo/src/main/res/layout/activity_download_list.xml",
    "content": "<!--\n    Copyright 2016 jeasonlzy(廖子尧)\n    \n    Licensed under the Apache License, Version 2.0 (the \"License\");\n    you may not use this file except in compliance with the License.\n    You may obtain a copy of the License at\n    \n       http://www.apache.org/licenses/LICENSE-2.0\n       \n    Unless required by applicable law or agreed to in writing, software\n    distributed under the License is distributed on an \"AS IS\" BASIS,\n    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n    See the License for the specific language governing permissions and\n    limitations under the License.\n-->\n<LinearLayout\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:orientation=\"vertical\">\n\n    <android.support.design.widget.AppBarLayout\n        android:id=\"@+id/appbar\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        app:theme=\"@style/AppTheme.AppBarOverlay\">\n\n        <android.support.v7.widget.Toolbar\n            android:id=\"@+id/toolbar\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"?attr/actionBarSize\"\n            app:popupTheme=\"@style/AppTheme.PopupOverlay\"/>\n    </android.support.design.widget.AppBarLayout>\n\n    <TextView\n        android:id=\"@+id/targetFolder\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:padding=\"5dp\"\n        android:text=\"下载路径文件夹:\"/>\n\n    <Button\n        android:id=\"@+id/startAll\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:text=\"全部下载\"/>\n\n    <android.support.v7.widget.RecyclerView\n        android:id=\"@+id/recyclerView\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        app:layout_behavior=\"@string/appbar_scrolling_view_behavior\"\n        tools:listitem=\"@layout/item_download_list\"/>\n\n</LinearLayout>\n"
  },
  {
    "path": "demo/src/main/res/layout/activity_file_download.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n    Copyright 2016 jeasonlzy(廖子尧)\n    \n    Licensed under the Apache License, Version 2.0 (the \"License\");\n    you may not use this file except in compliance with the License.\n    You may obtain a copy of the License at\n    \n       http://www.apache.org/licenses/LICENSE-2.0\n       \n    Unless required by applicable law or agreed to in writing, software\n    distributed under the License is distributed on an \"AS IS\" BASIS,\n    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n    See the License for the specific language governing permissions and\n    limitations under the License.\n-->\n<LinearLayout\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:orientation=\"vertical\">\n\n    <Button\n        android:id=\"@+id/fileDownload\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:text=\"开始下载\"\n        android:textAllCaps=\"false\"/>\n\n    <RelativeLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"20dp\"\n        android:layout_marginTop=\"10dp\">\n\n        <TextView\n            android:id=\"@+id/downloadSize\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_centerVertical=\"true\"\n            android:text=\"--M/--M\"\n            android:textSize=\"10sp\"/>\n\n        <TextView\n            android:id=\"@+id/netSpeed\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_alignParentRight=\"true\"\n            android:layout_centerVertical=\"true\"\n            android:layout_marginRight=\"10dp\"\n            android:text=\"---K/s\"\n            android:textSize=\"10sp\"/>\n\n        <TextView\n            android:id=\"@+id/tvProgress\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_centerHorizontal=\"true\"\n            android:layout_centerVertical=\"true\"\n            android:text=\"--.--%\"\n            android:textSize=\"10sp\"/>\n\n    </RelativeLayout>\n\n    <com.lzy.demo.ui.NumberProgressBar\n        android:id=\"@+id/pbProgress\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        app:progress_reached_bar_height=\"1.5dp\"\n        app:progress_reached_color=\"#3498DB\"\n        app:progress_text_color=\"#3498DB\"\n        app:progress_text_size=\"10sp\"\n        app:progress_unreached_bar_height=\"0.75dp\"\n        app:progress_unreached_color=\"#CCCCCC\"/>\n\n</LinearLayout>\n"
  },
  {
    "path": "demo/src/main/res/layout/activity_form_upload.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n    Copyright 2016 jeasonlzy(廖子尧)\n    \n    Licensed under the Apache License, Version 2.0 (the \"License\");\n    you may not use this file except in compliance with the License.\n    You may obtain a copy of the License at\n    \n       http://www.apache.org/licenses/LICENSE-2.0\n       \n    Unless required by applicable law or agreed to in writing, software\n    distributed under the License is distributed on an \"AS IS\" BASIS,\n    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n    See the License for the specific language governing permissions and\n    limitations under the License.\n-->\n<LinearLayout\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:orientation=\"vertical\">\n\n    <Button\n        android:id=\"@+id/selectImage\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:text=\"选择图片（可多选）\"\n        android:textAllCaps=\"false\"/>\n\n    <Button\n        android:id=\"@+id/formUpload\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:text=\"上传\"\n        android:textAllCaps=\"false\"/>\n\n    <RelativeLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"20dp\"\n        android:layout_marginTop=\"10dp\">\n\n        <TextView\n            android:id=\"@+id/downloadSize\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_centerVertical=\"true\"\n            android:text=\"--M/--M\"\n            android:textSize=\"10sp\"/>\n\n        <TextView\n            android:id=\"@+id/netSpeed\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_alignParentRight=\"true\"\n            android:layout_centerVertical=\"true\"\n            android:layout_marginRight=\"10dp\"\n            android:text=\"---K/s\"\n            android:textSize=\"10sp\"/>\n\n        <TextView\n            android:id=\"@+id/tvProgress\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_centerHorizontal=\"true\"\n            android:layout_centerVertical=\"true\"\n            android:text=\"--.--%\"\n            android:textSize=\"10sp\"/>\n\n    </RelativeLayout>\n\n    <com.lzy.demo.ui.NumberProgressBar\n        android:id=\"@+id/pbProgress\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        app:progress_reached_bar_height=\"1.5dp\"\n        app:progress_reached_color=\"#3498DB\"\n        app:progress_text_color=\"#3498DB\"\n        app:progress_text_size=\"10sp\"\n        app:progress_unreached_bar_height=\"0.75dp\"\n        app:progress_unreached_color=\"#CCCCCC\"/>\n\n    <TextView\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginTop=\"10dp\"\n        android:background=\"#888\"\n        android:text=\"选择的图片路径\"\n        android:textColor=\"#FFF\"/>\n\n    <TextView\n        android:id=\"@+id/images\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:text=\"--\"/>\n\n</LinearLayout>\n"
  },
  {
    "path": "demo/src/main/res/layout/activity_https.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n    Copyright 2016 jeasonlzy(廖子尧)\n    \n    Licensed under the Apache License, Version 2.0 (the \"License\");\n    you may not use this file except in compliance with the License.\n    You may obtain a copy of the License at\n    \n       http://www.apache.org/licenses/LICENSE-2.0\n       \n    Unless required by applicable law or agreed to in writing, software\n    distributed under the License is distributed on an \"AS IS\" BASIS,\n    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n    See the License for the specific language governing permissions and\n    limitations under the License.\n-->\n<LinearLayout\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:orientation=\"vertical\">\n\n    <Button\n        android:id=\"@+id/btn_none_https_request\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:text=\"访问可信Https网站(免证书)\"\n        android:textAllCaps=\"false\"/>\n\n    <Button\n        android:id=\"@+id/btn_https_request\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:text=\"访问自签名Https网站(需要自签名证书)\"\n        android:textAllCaps=\"false\"/>\n\n</LinearLayout>\n"
  },
  {
    "path": "demo/src/main/res/layout/activity_main.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n    Copyright 2016 jeasonlzy(廖子尧)\n    \n    Licensed under the Apache License, Version 2.0 (the \"License\");\n    you may not use this file except in compliance with the License.\n    You may obtain a copy of the License at\n    \n       http://www.apache.org/licenses/LICENSE-2.0\n       \n    Unless required by applicable law or agreed to in writing, software\n    distributed under the License is distributed on an \"AS IS\" BASIS,\n    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n    See the License for the specific language governing permissions and\n    limitations under the License.\n-->\n<android.support.design.widget.CoordinatorLayout\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:fitsSystemWindows=\"true\">\n\n    <android.support.design.widget.AppBarLayout\n        android:id=\"@+id/appbar\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:fitsSystemWindows=\"true\"\n        app:theme=\"@style/AppTheme.AppBarOverlay\">\n\n        <android.support.design.widget.CollapsingToolbarLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"200dp\"\n            app:contentScrim=\"@color/colorPrimary\"\n            app:expandedTitleMarginStart=\"100dp\"\n            app:layout_scrollFlags=\"scroll|exitUntilCollapsed|snap\"\n            app:statusBarScrim=\"@android:color/transparent\"\n            app:titleEnabled=\"false\">\n\n            <ImageView\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"match_parent\"\n                android:fitsSystemWindows=\"true\"\n                android:scaleType=\"centerCrop\"\n                android:src=\"@mipmap/logo\"\n                app:layout_collapseMode=\"parallax\"\n                app:layout_collapseParallaxMultiplier=\"0.6\"/>\n\n            <android.support.v7.widget.Toolbar\n                android:id=\"@+id/toolbar\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"?attr/actionBarSize\"\n                app:layout_collapseMode=\"pin\"\n                app:popupTheme=\"@style/AppTheme.PopupOverlay\"\n                app:title=\"\"/>\n        </android.support.design.widget.CollapsingToolbarLayout>\n\n        <android.support.design.widget.TabLayout\n            android:id=\"@+id/tab\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:background=\"@color/colorPrimary\"\n            app:tabMode=\"scrollable\"\n            app:tabTextAppearance=\"@style/TabLayoutTextStyle\"/>\n    </android.support.design.widget.AppBarLayout>\n\n    <android.support.v4.view.ViewPager\n        android:id=\"@+id/viewPager\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        app:layout_behavior=\"@string/appbar_scrolling_view_behavior\"/>\n\n    <TextView\n        android:id=\"@+id/toolbar_title\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"?attr/actionBarSize\"\n        android:layout_marginLeft=\"16dp\"\n        android:layout_marginTop=\"-100dp\"\n        android:alpha=\"0\"\n        android:elevation=\"10dp\"\n        android:gravity=\"center_vertical\"\n        android:text=\"OkGo-让网络请求更简单\"\n        android:textColor=\"@android:color/white\"\n        android:textSize=\"20sp\"\n        android:textStyle=\"bold\"\n        app:layout_behavior=\"@string/simple_view_behavior\"\n        app:svb_dependOn=\"@id/appbar\"\n        app:svb_dependType=\"y\"\n        app:svb_targetAlpha=\"1\"\n        app:svb_targetY=\"0dp\"/>\n\n    <android.support.design.widget.FloatingActionButton\n        android:id=\"@+id/fab\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_gravity=\"right|bottom\"\n        android:layout_margin=\"16dp\"\n        android:layout_marginBottom=\"32dp\"\n        android:layout_marginRight=\"16dp\"\n        android:src=\"@mipmap/ic_start\"\n        app:layout_behavior=\"@string/translate_up_down_behavior\"\n        app:layout_scrollFlags=\"scroll|enterAlways|snap\"/>\n</android.support.design.widget.CoordinatorLayout>\n"
  },
  {
    "path": "demo/src/main/res/layout/activity_method.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n    Copyright 2016 jeasonlzy(廖子尧)\n    \n    Licensed under the Apache License, Version 2.0 (the \"License\");\n    you may not use this file except in compliance with the License.\n    You may obtain a copy of the License at\n    \n       http://www.apache.org/licenses/LICENSE-2.0\n       \n    Unless required by applicable law or agreed to in writing, software\n    distributed under the License is distributed on an \"AS IS\" BASIS,\n    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n    See the License for the specific language governing permissions and\n    limitations under the License.\n-->\n<LinearLayout\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\">\n\n    <com.lzy.widget.ExpandGridView\n        android:id=\"@+id/gridView\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:horizontalSpacing=\"10dp\"\n        android:numColumns=\"3\"\n        android:verticalSpacing=\"10dp\"/>\n\n</LinearLayout>\n"
  },
  {
    "path": "demo/src/main/res/layout/activity_recycler.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n    Copyright 2016 jeasonlzy(廖子尧)\n    \n    Licensed under the Apache License, Version 2.0 (the \"License\");\n    you may not use this file except in compliance with the License.\n    You may obtain a copy of the License at\n    \n       http://www.apache.org/licenses/LICENSE-2.0\n       \n    Unless required by applicable law or agreed to in writing, software\n    distributed under the License is distributed on an \"AS IS\" BASIS,\n    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n    See the License for the specific language governing permissions and\n    limitations under the License.\n-->\n<android.support.design.widget.CoordinatorLayout\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\">\n\n    <android.support.design.widget.AppBarLayout\n        android:id=\"@+id/appbar\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        app:theme=\"@style/AppTheme.AppBarOverlay\">\n\n        <android.support.v7.widget.Toolbar\n            android:id=\"@+id/toolbar\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"?attr/actionBarSize\"\n            app:popupTheme=\"@style/AppTheme.PopupOverlay\"/>\n    </android.support.design.widget.AppBarLayout>\n\n    <android.support.v7.widget.RecyclerView\n        android:id=\"@+id/recyclerView\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        app:layout_behavior=\"@string/appbar_scrolling_view_behavior\"\n        tools:listitem=\"@layout/item_main_list\"/>\n</android.support.design.widget.CoordinatorLayout>\n"
  },
  {
    "path": "demo/src/main/res/layout/activity_redirect.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n    Copyright 2016 jeasonlzy(廖子尧)\n    \n    Licensed under the Apache License, Version 2.0 (the \"License\");\n    you may not use this file except in compliance with the License.\n    You may obtain a copy of the License at\n    \n       http://www.apache.org/licenses/LICENSE-2.0\n       \n    Unless required by applicable law or agreed to in writing, software\n    distributed under the License is distributed on an \"AS IS\" BASIS,\n    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n    See the License for the specific language governing permissions and\n    limitations under the License.\n-->\n<RelativeLayout\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\">\n\n    <Button\n        android:id=\"@+id/redirect\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:text=\"301重定向请求\"\n        android:textAllCaps=\"false\"/>\n\n</RelativeLayout>\n"
  },
  {
    "path": "demo/src/main/res/layout/activity_rx_cache.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n    Copyright 2016 jeasonlzy(廖子尧)\n    \n    Licensed under the Apache License, Version 2.0 (the \"License\");\n    you may not use this file except in compliance with the License.\n    You may obtain a copy of the License at\n    \n       http://www.apache.org/licenses/LICENSE-2.0\n       \n    Unless required by applicable law or agreed to in writing, software\n    distributed under the License is distributed on an \"AS IS\" BASIS,\n    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n    See the License for the specific language governing permissions and\n    limitations under the License.\n-->\n\n<LinearLayout\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    android:orientation=\"vertical\">\n\n    <Button\n        android:id=\"@+id/cache\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:gravity=\"start|center_vertical\"\n        android:text=\"rx使用缓存\"\n        android:textAllCaps=\"false\"/>\n\n</LinearLayout>\n"
  },
  {
    "path": "demo/src/main/res/layout/activity_rx_common.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n    Copyright 2016 jeasonlzy(廖子尧)\n    \n    Licensed under the Apache License, Version 2.0 (the \"License\");\n    you may not use this file except in compliance with the License.\n    You may obtain a copy of the License at\n    \n       http://www.apache.org/licenses/LICENSE-2.0\n       \n    Unless required by applicable law or agreed to in writing, software\n    distributed under the License is distributed on an \"AS IS\" BASIS,\n    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n    See the License for the specific language governing permissions and\n    limitations under the License.\n-->\n\n<LinearLayout\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    android:orientation=\"vertical\">\n\n    <Button\n        android:id=\"@+id/commonRequest\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:gravity=\"start|center_vertical\"\n        android:text=\"1. 基本请求方式\"\n        android:textAllCaps=\"false\"/>\n\n    <Button\n        android:id=\"@+id/jsonRequest\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:gravity=\"start|center_vertical\"\n        android:text=\"2. 请求JSONObject对象\"\n        android:textAllCaps=\"false\"/>\n\n    <Button\n        android:id=\"@+id/jsonArrayRequest\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:gravity=\"start|center_vertical\"\n        android:text=\"3. 请求JSONArray对象\"\n        android:textAllCaps=\"false\"/>\n\n    <Button\n        android:id=\"@+id/upString\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:gravity=\"start|center_vertical\"\n        android:text=\"4. 上传string文本\"\n        android:textAllCaps=\"false\"/>\n\n    <Button\n        android:id=\"@+id/upJson\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:gravity=\"start|center_vertical\"\n        android:text=\"5. 上传json数据\"\n        android:textAllCaps=\"false\"/>\n\n</LinearLayout>\n"
  },
  {
    "path": "demo/src/main/res/layout/activity_rx_file_download.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n    Copyright 2016 jeasonlzy(廖子尧)\n    \n    Licensed under the Apache License, Version 2.0 (the \"License\");\n    you may not use this file except in compliance with the License.\n    You may obtain a copy of the License at\n    \n       http://www.apache.org/licenses/LICENSE-2.0\n       \n    Unless required by applicable law or agreed to in writing, software\n    distributed under the License is distributed on an \"AS IS\" BASIS,\n    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n    See the License for the specific language governing permissions and\n    limitations under the License.\n-->\n<LinearLayout\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:orientation=\"vertical\">\n\n    <EditText\n        android:id=\"@+id/et_url\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:hint=\"下载链接\"/>\n\n    <Button\n        android:id=\"@+id/fileDownload1\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:text=\"下载方式1，无进度回调\"\n        android:textAllCaps=\"false\"/>\n\n    <Button\n        android:id=\"@+id/fileDownload2\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:text=\"下载方式2，无进度回调\"\n        android:textAllCaps=\"false\"/>\n\n    <RelativeLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"20dp\"\n        android:layout_marginTop=\"10dp\">\n\n        <TextView\n            android:id=\"@+id/downloadSize\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_centerVertical=\"true\"\n            android:text=\"--M/--M\"\n            android:textSize=\"10sp\"/>\n\n        <TextView\n            android:id=\"@+id/netSpeed\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_alignParentRight=\"true\"\n            android:layout_centerVertical=\"true\"\n            android:layout_marginRight=\"10dp\"\n            android:text=\"---K/s\"\n            android:textSize=\"10sp\"/>\n\n        <TextView\n            android:id=\"@+id/tvProgress\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_centerHorizontal=\"true\"\n            android:layout_centerVertical=\"true\"\n            android:text=\"--.--%\"\n            android:textSize=\"10sp\"/>\n\n    </RelativeLayout>\n\n    <com.lzy.demo.ui.NumberProgressBar\n        android:id=\"@+id/pbProgress\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        app:progress_reached_bar_height=\"1.5dp\"\n        app:progress_reached_color=\"#3498DB\"\n        app:progress_text_color=\"#3498DB\"\n        app:progress_text_size=\"10sp\"\n        app:progress_unreached_bar_height=\"0.75dp\"\n        app:progress_unreached_color=\"#CCCCCC\"/>\n\n</LinearLayout>\n"
  },
  {
    "path": "demo/src/main/res/layout/activity_rx_form_upload.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n    Copyright 2016 jeasonlzy(廖子尧)\n    \n    Licensed under the Apache License, Version 2.0 (the \"License\");\n    you may not use this file except in compliance with the License.\n    You may obtain a copy of the License at\n    \n       http://www.apache.org/licenses/LICENSE-2.0\n       \n    Unless required by applicable law or agreed to in writing, software\n    distributed under the License is distributed on an \"AS IS\" BASIS,\n    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n    See the License for the specific language governing permissions and\n    limitations under the License.\n-->\n<LinearLayout\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:orientation=\"vertical\">\n\n    <Button\n        android:id=\"@+id/selectImage\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:text=\"选择图片（可多选）\"\n        android:textAllCaps=\"false\"/>\n\n    <Button\n        android:id=\"@+id/formUpload1\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:text=\"上传方式1：无进度回调\"\n        android:textAllCaps=\"false\"/>\n\n    <Button\n        android:id=\"@+id/formUpload2\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:text=\"上传方式2：有进度回调\"\n        android:textAllCaps=\"false\"/>\n\n    <RelativeLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"20dp\"\n        android:layout_marginTop=\"10dp\">\n\n        <TextView\n            android:id=\"@+id/downloadSize\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_centerVertical=\"true\"\n            android:text=\"--M/--M\"\n            android:textSize=\"10sp\"/>\n\n        <TextView\n            android:id=\"@+id/netSpeed\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_alignParentRight=\"true\"\n            android:layout_centerVertical=\"true\"\n            android:layout_marginRight=\"10dp\"\n            android:text=\"---K/s\"\n            android:textSize=\"10sp\"/>\n\n        <TextView\n            android:id=\"@+id/tvProgress\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_centerHorizontal=\"true\"\n            android:layout_centerVertical=\"true\"\n            android:text=\"--.--%\"\n            android:textSize=\"10sp\"/>\n\n    </RelativeLayout>\n\n    <com.lzy.demo.ui.NumberProgressBar\n        android:id=\"@+id/pbProgress\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        app:progress_reached_bar_height=\"1.5dp\"\n        app:progress_reached_color=\"#3498DB\"\n        app:progress_text_color=\"#3498DB\"\n        app:progress_text_size=\"10sp\"\n        app:progress_unreached_bar_height=\"0.75dp\"\n        app:progress_unreached_color=\"#CCCCCC\"/>\n\n    <TextView\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginTop=\"10dp\"\n        android:background=\"#888\"\n        android:text=\"选择的图片路径\"\n        android:textColor=\"#FFF\"/>\n\n    <TextView\n        android:id=\"@+id/images\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:text=\"--\"/>\n\n</LinearLayout>\n"
  },
  {
    "path": "demo/src/main/res/layout/activity_rx_retrofit.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n    Copyright 2016 jeasonlzy(廖子尧)\n    \n    Licensed under the Apache License, Version 2.0 (the \"License\");\n    you may not use this file except in compliance with the License.\n    You may obtain a copy of the License at\n    \n       http://www.apache.org/licenses/LICENSE-2.0\n       \n    Unless required by applicable law or agreed to in writing, software\n    distributed under the License is distributed on an \"AS IS\" BASIS,\n    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n    See the License for the specific language governing permissions and\n    limitations under the License.\n-->\n\n<LinearLayout\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    android:orientation=\"vertical\">\n\n    <Button\n        android:id=\"@+id/retrofitRequest\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:gravity=\"start|center_vertical\"\n        android:text=\"1. 请求普通String数据\"\n        android:textAllCaps=\"false\"/>\n\n    <Button\n        android:id=\"@+id/jsonRequest\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:gravity=\"start|center_vertical\"\n        android:text=\"2. 请求JSONObject对象\"\n        android:textAllCaps=\"false\"/>\n\n    <Button\n        android:id=\"@+id/jsonArrayRequest\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:gravity=\"start|center_vertical\"\n        android:text=\"3. 请求JSONArray对象\"\n        android:textAllCaps=\"false\"/>\n\n</LinearLayout>\n"
  },
  {
    "path": "demo/src/main/res/layout/activity_super_cache.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n    Copyright 2016 jeasonlzy(廖子尧)\n    \n    Licensed under the Apache License, Version 2.0 (the \"License\");\n    you may not use this file except in compliance with the License.\n    You may obtain a copy of the License at\n    \n       http://www.apache.org/licenses/LICENSE-2.0\n       \n    Unless required by applicable law or agreed to in writing, software\n    distributed under the License is distributed on an \"AS IS\" BASIS,\n    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n    See the License for the specific language governing permissions and\n    limitations under the License.\n-->\n<android.support.design.widget.CoordinatorLayout\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\">\n\n    <android.support.design.widget.AppBarLayout\n        android:id=\"@+id/appbar\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        app:theme=\"@style/AppTheme.AppBarOverlay\">\n\n        <android.support.v7.widget.Toolbar\n            android:id=\"@+id/toolbar\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"?attr/actionBarSize\"\n            app:layout_scrollFlags=\"scroll|enterAlways|snap\"\n            app:popupTheme=\"@style/AppTheme.PopupOverlay\"/>\n\n        <android.support.design.widget.TabLayout\n            android:id=\"@+id/tab\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:background=\"@color/colorPrimary\"\n            app:tabMode=\"fixed\"/>\n    </android.support.design.widget.AppBarLayout>\n\n    <android.support.v4.view.ViewPager\n        android:id=\"@+id/viewPager\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        app:layout_behavior=\"@string/appbar_scrolling_view_behavior\"/>\n\n    <android.support.design.widget.FloatingActionButton\n        android:id=\"@+id/fab\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_gravity=\"right|bottom\"\n        android:layout_marginBottom=\"32dp\"\n        android:layout_marginRight=\"16dp\"\n        android:src=\"@mipmap/ic_start\"\n        app:layout_behavior=\"@string/translate_up_down_behavior\"\n        app:layout_scrollFlags=\"scroll|enterAlways|snap\"/>\n\n</android.support.design.widget.CoordinatorLayout>\n"
  },
  {
    "path": "demo/src/main/res/layout/activity_sync.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n    Copyright 2016 jeasonlzy(廖子尧)\n    \n    Licensed under the Apache License, Version 2.0 (the \"License\");\n    you may not use this file except in compliance with the License.\n    You may obtain a copy of the License at\n    \n       http://www.apache.org/licenses/LICENSE-2.0\n       \n    Unless required by applicable law or agreed to in writing, software\n    distributed under the License is distributed on an \"AS IS\" BASIS,\n    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n    See the License for the specific language governing permissions and\n    limitations under the License.\n-->\n<RelativeLayout\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\">\n\n    <Button\n        android:id=\"@+id/sync\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:text=\"同步请求\"\n        android:textAllCaps=\"false\"/>\n\n</RelativeLayout>\n"
  },
  {
    "path": "demo/src/main/res/layout/activity_test.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n    Copyright 2016 jeasonlzy(廖子尧)\n    \n    Licensed under the Apache License, Version 2.0 (the \"License\");\n    you may not use this file except in compliance with the License.\n    You may obtain a copy of the License at\n    \n       http://www.apache.org/licenses/LICENSE-2.0\n       \n    Unless required by applicable law or agreed to in writing, software\n    distributed under the License is distributed on an \"AS IS\" BASIS,\n    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n    See the License for the specific language governing permissions and\n    limitations under the License.\n-->\n<LinearLayout\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:orientation=\"vertical\">\n\n    <Button\n        android:id=\"@+id/btn1\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:text=\"btn1\"/>\n\n    <Button\n        android:id=\"@+id/btn2\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:text=\"btn2\"/>\n\n    <Button\n        android:id=\"@+id/btn3\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:text=\"btn3\"/>\n\n    <ImageView\n        android:id=\"@+id/image\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"50dp\"/>\n\n    <EditText\n        android:id=\"@+id/edit\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"/>\n</LinearLayout>\n"
  },
  {
    "path": "demo/src/main/res/layout/activity_up_text.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n    Copyright 2016 jeasonlzy(廖子尧)\n    \n    Licensed under the Apache License, Version 2.0 (the \"License\");\n    you may not use this file except in compliance with the License.\n    You may obtain a copy of the License at\n    \n       http://www.apache.org/licenses/LICENSE-2.0\n       \n    Unless required by applicable law or agreed to in writing, software\n    distributed under the License is distributed on an \"AS IS\" BASIS,\n    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n    See the License for the specific language governing permissions and\n    limitations under the License.\n-->\n<LinearLayout\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:orientation=\"vertical\">\n\n    <Button\n        android:id=\"@+id/upJson\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:text=\"上传Json数据\"\n        android:textAllCaps=\"false\"/>\n\n    <Button\n        android:id=\"@+id/upString\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:text=\"上传String字符串\"\n        android:textAllCaps=\"false\"/>\n\n    <Button\n        android:id=\"@+id/upBytes\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:text=\"上传byte[]字节数组\"\n        android:textAllCaps=\"false\"/>\n\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:orientation=\"horizontal\">\n\n        <Button\n            android:id=\"@+id/upFile\"\n            android:layout_width=\"0dp\"\n            android:layout_height=\"wrap_content\"\n            android:layout_weight=\"1\"\n            android:text=\"上传单个文件\"\n            android:textAllCaps=\"false\"/>\n\n        <Button\n            android:id=\"@+id/selectImage\"\n            android:layout_width=\"0dp\"\n            android:layout_height=\"wrap_content\"\n            android:layout_weight=\"1\"\n            android:text=\"选择图片（单选）\"\n            android:textAllCaps=\"false\"/>\n    </LinearLayout>\n\n\n    <TextView\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginTop=\"10dp\"\n        android:background=\"#888\"\n        android:text=\"选择的图片路径\"\n        android:textColor=\"#FFF\"/>\n\n    <TextView\n        android:id=\"@+id/images\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:text=\"--\"/>\n\n</LinearLayout>\n"
  },
  {
    "path": "demo/src/main/res/layout/activity_upload_list.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n    Copyright 2016 jeasonlzy(廖子尧)\n    \n    Licensed under the Apache License, Version 2.0 (the \"License\");\n    you may not use this file except in compliance with the License.\n    You may obtain a copy of the License at\n    \n       http://www.apache.org/licenses/LICENSE-2.0\n       \n    Unless required by applicable law or agreed to in writing, software\n    distributed under the License is distributed on an \"AS IS\" BASIS,\n    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n    See the License for the specific language governing permissions and\n    limitations under the License.\n-->\n<LinearLayout\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:orientation=\"vertical\">\n\n    <android.support.design.widget.AppBarLayout\n        android:id=\"@+id/appbar\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        app:theme=\"@style/AppTheme.AppBarOverlay\">\n\n        <android.support.v7.widget.Toolbar\n            android:id=\"@+id/toolbar\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"?attr/actionBarSize\"\n            app:popupTheme=\"@style/AppTheme.PopupOverlay\"/>\n    </android.support.design.widget.AppBarLayout>\n\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:orientation=\"horizontal\"\n        app:layout_behavior=\"@string/appbar_scrolling_view_behavior\">\n\n        <Button\n            android:id=\"@+id/select\"\n            android:layout_width=\"0dp\"\n            android:layout_height=\"wrap_content\"\n            android:layout_weight=\"1\"\n            android:text=\"选择图片\"/>\n\n        <Button\n            android:id=\"@+id/upload\"\n            android:layout_width=\"0dp\"\n            android:layout_height=\"wrap_content\"\n            android:layout_weight=\"1\"\n            android:text=\"开始上传\"/>\n\n        <Button\n            android:id=\"@+id/deleteAll\"\n            android:layout_width=\"0dp\"\n            android:layout_height=\"wrap_content\"\n            android:layout_weight=\"1\"\n            android:text=\"删除全部\"\n            android:visibility=\"gone\"\n            tools:visibility=\"visible\"/>\n    </LinearLayout>\n\n    <android.support.v7.widget.RecyclerView\n        android:id=\"@+id/recyclerView\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        app:layout_behavior=\"@string/appbar_scrolling_view_behavior\"\n        tools:listitem=\"@layout/item_upload_manager\"/>\n\n</LinearLayout>\n"
  },
  {
    "path": "demo/src/main/res/layout/activity_web.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n    Copyright 2016 jeasonlzy(廖子尧)\n    \n    Licensed under the Apache License, Version 2.0 (the \"License\");\n    you may not use this file except in compliance with the License.\n    You may obtain a copy of the License at\n    \n       http://www.apache.org/licenses/LICENSE-2.0\n       \n    Unless required by applicable law or agreed to in writing, software\n    distributed under the License is distributed on an \"AS IS\" BASIS,\n    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n    See the License for the specific language governing permissions and\n    limitations under the License.\n-->\n<LinearLayout\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:orientation=\"vertical\">\n\n    <android.support.design.widget.AppBarLayout\n        android:id=\"@+id/appbar\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        app:theme=\"@style/AppTheme.AppBarOverlay\">\n\n        <android.support.v7.widget.Toolbar\n            android:id=\"@+id/toolbar\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"?attr/actionBarSize\"\n            app:popupTheme=\"@style/AppTheme.PopupOverlay\"/>\n    </android.support.design.widget.AppBarLayout>\n\n    <ProgressBar\n        android:id=\"@+id/pb\"\n        style=\"@style/Widget.AppCompat.ProgressBar.Horizontal\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:indeterminate=\"false\"\n        android:minHeight=\"3dp\"\n        android:progressDrawable=\"@drawable/progress_bar_states\"/>\n\n    <WebView\n        android:id=\"@+id/webView\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"/>\n</LinearLayout>\n"
  },
  {
    "path": "demo/src/main/res/layout/fragment_pay.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n    Copyright 2016 jeasonlzy(廖子尧)\n    \n    Licensed under the Apache License, Version 2.0 (the \"License\");\n    you may not use this file except in compliance with the License.\n    You may obtain a copy of the License at\n    \n       http://www.apache.org/licenses/LICENSE-2.0\n       \n    Unless required by applicable law or agreed to in writing, software\n    distributed under the License is distributed on an \"AS IS\" BASIS,\n    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n    See the License for the specific language governing permissions and\n    limitations under the License.\n-->\n<android.support.v4.widget.NestedScrollView\n    android:id=\"@+id/refreshLayout\"\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\">\n\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:orientation=\"vertical\">\n\n        <TextView\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:background=\"@color/colorPrimary\"\n            android:padding=\"10dp\"\n            android:text=\"如果你觉得好，对你有过帮助，请给我一点打赏鼓励吧，一分也是爱呀！\"\n            android:textColor=\"#FFF\"\n            android:textSize=\"16sp\"/>\n\n        <ImageView\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:src=\"@mipmap/pay\"/>\n    </LinearLayout>\n</android.support.v4.widget.NestedScrollView>\n\n"
  },
  {
    "path": "demo/src/main/res/layout/include_data.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n    Copyright 2016 jeasonlzy(廖子尧)\n    \n    Licensed under the Apache License, Version 2.0 (the \"License\");\n    you may not use this file except in compliance with the License.\n    You may obtain a copy of the License at\n    \n       http://www.apache.org/licenses/LICENSE-2.0\n       \n    Unless required by applicable law or agreed to in writing, software\n    distributed under the License is distributed on an \"AS IS\" BASIS,\n    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n    See the License for the specific language governing permissions and\n    limitations under the License.\n-->\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n              android:layout_width=\"match_parent\"\n              android:layout_height=\"match_parent\"\n              android:orientation=\"vertical\">\n\n    <TextView\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginTop=\"10dp\"\n        android:background=\"#888\"\n        android:text=\"请求状态\"\n        android:textColor=\"#FFF\"/>\n\n    <TextView\n        android:id=\"@+id/requestState\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginBottom=\"10dp\"\n        android:text=\"--\"/>\n\n    <TextView\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:background=\"#888\"\n        android:text=\"请求头\"\n        android:textColor=\"#FFF\"/>\n\n    <TextView\n        android:id=\"@+id/requestHeaders\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginBottom=\"10dp\"\n        android:text=\"--\"/>\n\n    <TextView\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:background=\"#888\"\n        android:text=\"响应数据\"\n        android:textColor=\"#FFF\"/>\n\n    <TextView\n        android:id=\"@+id/responseData\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginBottom=\"10dp\"\n        android:text=\"--\"/>\n\n    <TextView\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:background=\"#888\"\n        android:text=\"响应头\"\n        android:textColor=\"#FFF\"/>\n\n    <TextView\n        android:id=\"@+id/responseHeader\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginBottom=\"10dp\"\n        android:text=\"--\"/>\n</LinearLayout>\n"
  },
  {
    "path": "demo/src/main/res/layout/item_download_list.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n    Copyright 2016 jeasonlzy(廖子尧)\n    \n    Licensed under the Apache License, Version 2.0 (the \"License\");\n    you may not use this file except in compliance with the License.\n    You may obtain a copy of the License at\n    \n       http://www.apache.org/licenses/LICENSE-2.0\n       \n    Unless required by applicable law or agreed to in writing, software\n    distributed under the License is distributed on an \"AS IS\" BASIS,\n    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n    See the License for the specific language governing permissions and\n    limitations under the License.\n-->\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n              android:layout_width=\"match_parent\"\n              android:layout_height=\"wrap_content\"\n              android:gravity=\"center\"\n              android:orientation=\"horizontal\"\n              android:padding=\"10dp\">\n\n\n    <ImageView\n        android:id=\"@+id/icon\"\n        android:layout_width=\"80dp\"\n        android:layout_height=\"80dp\"\n        android:src=\"@mipmap/ic_launcher\"/>\n\n    <LinearLayout\n        android:layout_width=\"0dp\"\n        android:layout_height=\"wrap_content\"\n        android:layout_weight=\"1\"\n        android:orientation=\"vertical\">\n\n        <TextView\n            android:id=\"@+id/priority\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:gravity=\"center\"\n            android:text=\"priority\"/>\n\n        <TextView\n            android:id=\"@+id/name\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginTop=\"5dp\"\n            android:gravity=\"center\"\n            android:text=\"appName\"/>\n\n    </LinearLayout>\n\n    <Button\n        android:id=\"@+id/download\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_gravity=\"center\"\n        android:focusable=\"false\"\n        android:text=\"下载\"/>\n\n</LinearLayout>\n"
  },
  {
    "path": "demo/src/main/res/layout/item_download_manager.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n    Copyright 2016 jeasonlzy(廖子尧)\n    \n    Licensed under the Apache License, Version 2.0 (the \"License\");\n    you may not use this file except in compliance with the License.\n    You may obtain a copy of the License at\n    \n       http://www.apache.org/licenses/LICENSE-2.0\n       \n    Unless required by applicable law or agreed to in writing, software\n    distributed under the License is distributed on an \"AS IS\" BASIS,\n    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n    See the License for the specific language governing permissions and\n    limitations under the License.\n-->\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n              xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n              android:layout_width=\"match_parent\"\n              android:layout_height=\"wrap_content\"\n              android:gravity=\"center\"\n              android:orientation=\"horizontal\"\n              android:paddingBottom=\"10dp\"\n              android:paddingTop=\"10dp\">\n\n    <ImageView\n        android:id=\"@+id/icon\"\n        android:layout_width=\"80dp\"\n        android:layout_height=\"80dp\"\n        android:padding=\"5dp\"\n        android:src=\"@mipmap/ic_launcher\"/>\n\n    <LinearLayout\n        android:layout_width=\"0dp\"\n        android:layout_height=\"wrap_content\"\n        android:layout_gravity=\"center\"\n        android:layout_marginRight=\"5dp\"\n        android:layout_weight=\"1\"\n        android:orientation=\"vertical\">\n\n        <TextView\n            android:id=\"@+id/name\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:maxLines=\"1\"\n            android:text=\"应用名字\"\n            android:textColor=\"#000\"\n            android:textSize=\"14sp\"/>\n\n        <TextView\n            android:id=\"@+id/priority\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:gravity=\"center\"\n            android:text=\"priority\"/>\n\n        <RelativeLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"25dp\"\n            android:layout_marginTop=\"10dp\">\n\n            <TextView\n                android:id=\"@+id/downloadSize\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_alignParentBottom=\"true\"\n                android:text=\"--M/--M\"\n                android:textSize=\"10sp\"/>\n\n            <TextView\n                android:id=\"@+id/netSpeed\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_alignParentBottom=\"true\"\n                android:layout_alignParentRight=\"true\"\n                android:layout_marginRight=\"10dp\"\n                android:text=\"---K/s\"\n                android:textSize=\"10sp\"/>\n\n            <TextView\n                android:id=\"@+id/tvProgress\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_above=\"@+id/netSpeed\"\n                android:text=\"--.--%\"\n                android:textSize=\"10sp\"/>\n\n        </RelativeLayout>\n\n        <com.lzy.demo.ui.NumberProgressBar\n            android:id=\"@+id/pbProgress\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            app:progress_reached_bar_height=\"1.5dp\"\n            app:progress_reached_color=\"#3498DB\"\n            app:progress_text_color=\"#3498DB\"\n            app:progress_text_size=\"10sp\"\n            app:progress_unreached_bar_height=\"0.75dp\"\n            app:progress_unreached_color=\"#CCCCCC\"/>\n    </LinearLayout>\n\n    <Button\n        android:id=\"@+id/start\"\n        android:layout_width=\"40dp\"\n        android:layout_height=\"match_parent\"\n        android:layout_gravity=\"center\"\n        android:background=\"#E30\"\n        android:padding=\"5dp\"\n        android:text=\"下载\"\n        android:textColor=\"#FFF\"/>\n\n    <Button\n        android:id=\"@+id/remove\"\n        android:layout_width=\"40dp\"\n        android:layout_height=\"match_parent\"\n        android:layout_gravity=\"center\"\n        android:background=\"#3E0\"\n        android:padding=\"5dp\"\n        android:text=\"删除\"\n        android:textColor=\"#FFF\"/>\n\n    <Button\n        android:id=\"@+id/restart\"\n        android:layout_width=\"40dp\"\n        android:layout_height=\"match_parent\"\n        android:layout_gravity=\"center\"\n        android:background=\"#03E\"\n        android:padding=\"5dp\"\n        android:text=\"重新\\n下载\"\n        android:textColor=\"#FFF\"/>\n</LinearLayout>\n"
  },
  {
    "path": "demo/src/main/res/layout/item_main_list.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n    Copyright 2016 jeasonlzy(廖子尧)\n    \n    Licensed under the Apache License, Version 2.0 (the \"License\");\n    you may not use this file except in compliance with the License.\n    You may obtain a copy of the License at\n    \n       http://www.apache.org/licenses/LICENSE-2.0\n       \n    Unless required by applicable law or agreed to in writing, software\n    distributed under the License is distributed on an \"AS IS\" BASIS,\n    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n    See the License for the specific language governing permissions and\n    limitations under the License.\n-->\n<LinearLayout\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    android:orientation=\"vertical\"\n    android:padding=\"5dp\">\n\n    <TextView\n        android:id=\"@+id/title\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:textColor=\"#000\"\n        android:textSize=\"18sp\"/>\n\n    <TextView\n        android:id=\"@+id/des\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginTop=\"5dp\"\n        android:textColor=\"#888\"\n        android:textSize=\"14sp\"/>\n\n</LinearLayout>\n"
  },
  {
    "path": "demo/src/main/res/layout/item_main_type.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n    Copyright 2016 jeasonlzy(廖子尧)\n    \n    Licensed under the Apache License, Version 2.0 (the \"License\");\n    you may not use this file except in compliance with the License.\n    You may obtain a copy of the License at\n    \n       http://www.apache.org/licenses/LICENSE-2.0\n       \n    Unless required by applicable law or agreed to in writing, software\n    distributed under the License is distributed on an \"AS IS\" BASIS,\n    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n    See the License for the specific language governing permissions and\n    limitations under the License.\n-->\n<LinearLayout\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    android:orientation=\"vertical\">\n\n    <TextView\n        android:id=\"@+id/divider\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:background=\"#D888\"\n        android:gravity=\"center\"\n        android:padding=\"20dp\"\n        android:text=\"测试\"\n        android:textColor=\"#FFF\"\n        android:textSize=\"16sp\"/>\n\n</LinearLayout>\n"
  },
  {
    "path": "demo/src/main/res/layout/item_news.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n    Copyright 2016 jeasonlzy(廖子尧)\n    \n    Licensed under the Apache License, Version 2.0 (the \"License\");\n    you may not use this file except in compliance with the License.\n    You may obtain a copy of the License at\n    \n       http://www.apache.org/licenses/LICENSE-2.0\n       \n    Unless required by applicable law or agreed to in writing, software\n    distributed under the License is distributed on an \"AS IS\" BASIS,\n    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n    See the License for the specific language governing permissions and\n    limitations under the License.\n-->\n<android.support.v7.widget.CardView\n    android:id=\"@+id/cardView\"\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    android:layout_margin=\"5dp\"\n    android:foreground=\"?android:attr/selectableItemBackground\"\n    app:cardCornerRadius=\"10dp\"\n    app:contentPadding=\"10dp\">\n\n    <LinearLayout\n        android:id=\"@+id/container\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:background=\"#FFF\"\n        android:orientation=\"vertical\">\n\n        <TextView\n            android:id=\"@+id/title\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginBottom=\"8dp\"\n            android:textColor=\"#333333\"\n            android:textSize=\"16sp\"\n            tools:text=\"标题标题标题标题标题标题标题\"/>\n\n        <TextView\n            android:id=\"@+id/desc\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginBottom=\"8dp\"\n            android:textColor=\"#88333333\"\n            android:textSize=\"12sp\"\n            tools:text=\"描述描述描述描述描述描述描述描述\"/>\n\n        <com.lzy.ninegrid.NineGridView\n            android:id=\"@+id/nineGrid\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginBottom=\"8dp\"\n            app:ngv_gridSpacing=\"3dp\"\n            app:ngv_maxSize=\"9\"\n            app:ngv_mode=\"grid\"\n            app:ngv_singleImageRatio=\"1\"\n            app:ngv_singleImageSize=\"250dp\"/>\n\n        <RelativeLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\">\n\n            <TextView\n                android:id=\"@+id/pubDate\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:textColor=\"#88333333\"\n                android:textSize=\"12sp\"\n                tools:text=\"2015-07-06 16:30:00\"/>\n\n            <TextView\n                android:id=\"@+id/source\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_alignParentRight=\"true\"\n                android:textColor=\"#88333333\"\n                android:textSize=\"12sp\"\n                tools:text=\"新华网\"/>\n        </RelativeLayout>\n    </LinearLayout>\n</android.support.v7.widget.CardView>\n"
  },
  {
    "path": "demo/src/main/res/layout/item_no_data.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n    Copyright 2016 jeasonlzy(廖子尧)\n    \n    Licensed under the Apache License, Version 2.0 (the \"License\");\n    you may not use this file except in compliance with the License.\n    You may obtain a copy of the License at\n    \n       http://www.apache.org/licenses/LICENSE-2.0\n       \n    Unless required by applicable law or agreed to in writing, software\n    distributed under the License is distributed on an \"AS IS\" BASIS,\n    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n    See the License for the specific language governing permissions and\n    limitations under the License.\n-->\n<LinearLayout\n    android:id=\"@+id/loading_view\"\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"@dimen/dp_36\"\n    android:gravity=\"center\"\n    android:orientation=\"horizontal\">\n\n    <TextView\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"30dp\"\n        android:gravity=\"center\"\n        android:text=\"-- 没有更多数据了 --\"\n        android:textColor=\"@android:color/darker_gray\"/>\n</LinearLayout>\n"
  },
  {
    "path": "demo/src/main/res/layout/item_refresh.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n    Copyright 2016 jeasonlzy(廖子尧)\n    \n    Licensed under the Apache License, Version 2.0 (the \"License\");\n    you may not use this file except in compliance with the License.\n    You may obtain a copy of the License at\n    \n       http://www.apache.org/licenses/LICENSE-2.0\n       \n    Unless required by applicable law or agreed to in writing, software\n    distributed under the License is distributed on an \"AS IS\" BASIS,\n    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n    See the License for the specific language governing permissions and\n    limitations under the License.\n-->\n<android.support.v4.widget.SwipeRefreshLayout\n    android:id=\"@+id/refreshLayout\"\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\">\n\n    <android.support.v7.widget.RecyclerView\n        android:id=\"@+id/recyclerView\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        app:layout_behavior=\"@string/appbar_scrolling_view_behavior\"\n        tools:listitem=\"@layout/item_main_list\"/>\n</android.support.v4.widget.SwipeRefreshLayout>\n\n"
  },
  {
    "path": "demo/src/main/res/layout/item_upload_manager.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n    Copyright 2016 jeasonlzy(廖子尧)\n    \n    Licensed under the Apache License, Version 2.0 (the \"License\");\n    you may not use this file except in compliance with the License.\n    You may obtain a copy of the License at\n    \n       http://www.apache.org/licenses/LICENSE-2.0\n       \n    Unless required by applicable law or agreed to in writing, software\n    distributed under the License is distributed on an \"AS IS\" BASIS,\n    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n    See the License for the specific language governing permissions and\n    limitations under the License.\n-->\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n              xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n              android:layout_width=\"match_parent\"\n              android:layout_height=\"wrap_content\"\n              android:gravity=\"center\"\n              android:orientation=\"horizontal\"\n              android:paddingBottom=\"10dp\"\n              android:paddingTop=\"10dp\">\n\n    <ImageView\n        android:id=\"@+id/icon\"\n        android:layout_width=\"80dp\"\n        android:layout_height=\"80dp\"\n        android:padding=\"5dp\"\n        android:src=\"@mipmap/ic_launcher\"/>\n\n    <LinearLayout\n        android:layout_width=\"0dp\"\n        android:layout_height=\"wrap_content\"\n        android:layout_gravity=\"center\"\n        android:layout_marginRight=\"5dp\"\n        android:layout_weight=\"1\"\n        android:orientation=\"vertical\">\n\n        <TextView\n            android:id=\"@+id/name\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:text=\"应用名字\"\n            android:textColor=\"#000\"\n            android:textSize=\"14sp\"/>\n\n        <TextView\n            android:id=\"@+id/priority\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:gravity=\"center\"\n            android:text=\"priority\"/>\n\n        <RelativeLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"25dp\"\n            android:layout_marginTop=\"10dp\">\n\n            <TextView\n                android:id=\"@+id/downloadSize\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_alignParentBottom=\"true\"\n                android:text=\"--M/--M\"\n                android:textSize=\"10sp\"/>\n\n            <TextView\n                android:id=\"@+id/netSpeed\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_alignParentBottom=\"true\"\n                android:layout_alignParentRight=\"true\"\n                android:layout_marginRight=\"10dp\"\n                android:text=\"---K/s\"\n                android:textSize=\"10sp\"/>\n\n            <TextView\n                android:id=\"@+id/tvProgress\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_above=\"@+id/netSpeed\"\n                android:text=\"--.--%\"\n                android:textSize=\"10sp\"/>\n\n        </RelativeLayout>\n\n        <com.lzy.demo.ui.NumberProgressBar\n            android:id=\"@+id/pbProgress\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            app:progress_reached_bar_height=\"1.5dp\"\n            app:progress_reached_color=\"#3498DB\"\n            app:progress_text_color=\"#3498DB\"\n            app:progress_text_size=\"10sp\"\n            app:progress_unreached_bar_height=\"0.75dp\"\n            app:progress_unreached_color=\"#CCCCCC\"/>\n    </LinearLayout>\n\n    <Button\n        android:id=\"@+id/upload\"\n        android:layout_width=\"40dp\"\n        android:layout_height=\"match_parent\"\n        android:layout_gravity=\"center\"\n        android:background=\"#E30\"\n        android:padding=\"5dp\"\n        android:text=\"上传\"\n        android:textColor=\"#FFF\"/>\n\n    <Button\n        android:id=\"@+id/remove\"\n        android:layout_width=\"40dp\"\n        android:layout_height=\"match_parent\"\n        android:layout_gravity=\"center\"\n        android:background=\"#3E0\"\n        android:padding=\"5dp\"\n        android:text=\"删除\"\n        android:textColor=\"#FFF\"/>\n\n    <Button\n        android:id=\"@+id/restart\"\n        android:layout_width=\"40dp\"\n        android:layout_height=\"match_parent\"\n        android:layout_gravity=\"center\"\n        android:background=\"#03E\"\n        android:padding=\"5dp\"\n        android:text=\"重新\\n上传\"\n        android:textColor=\"#FFF\"/>\n</LinearLayout>\n"
  },
  {
    "path": "demo/src/main/res/values/attrs.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n    Copyright 2016 jeasonlzy(廖子尧)\n    \n    Licensed under the Apache License, Version 2.0 (the \"License\");\n    you may not use this file except in compliance with the License.\n    You may obtain a copy of the License at\n    \n       http://www.apache.org/licenses/LICENSE-2.0\n       \n    Unless required by applicable law or agreed to in writing, software\n    distributed under the License is distributed on an \"AS IS\" BASIS,\n    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n    See the License for the specific language governing permissions and\n    limitations under the License.\n-->\n<resources>\n\n    <declare-styleable name=\"NumberProgressBar\">\n        <attr name=\"progress_current\" format=\"integer\"/>\n        <attr name=\"progress_max\" format=\"integer\"/>\n        <attr name=\"progress_unreached_color\" format=\"color\"/>\n        <attr name=\"progress_reached_color\" format=\"color\"/>\n        <attr name=\"progress_reached_bar_height\" format=\"dimension\"/>\n        <attr name=\"progress_unreached_bar_height\" format=\"dimension\"/>\n        <attr name=\"progress_text_size\" format=\"dimension\"/>\n        <attr name=\"progress_text_color\" format=\"color\"/>\n        <attr name=\"progress_text_offset\" format=\"dimension\"/>\n        <attr name=\"progress_text_visibility\" format=\"enum\">\n            <enum name=\"visible\" value=\"0\"/>\n            <enum name=\"invisible\" value=\"1\"/>\n        </attr>\n    </declare-styleable>\n\n    <declare-styleable name=\"ProgressPieView\">\n        <attr name=\"android:text\"/>\n        <attr name=\"android:textSize\"/>\n        <attr name=\"android:textColor\"/>\n        <attr name=\"ppvProgress\" format=\"integer\"/>\n        <attr name=\"ppvMax\" format=\"integer\"/>\n        <attr name=\"ppvStartAngle\" format=\"integer\"/>\n        <attr name=\"ppvInverted\" format=\"boolean\"/>\n        <attr name=\"ppvCounterclockwise\" format=\"boolean\"/>\n        <attr name=\"ppvStrokeWidth\" format=\"dimension\"/>\n        <attr name=\"ppvBackgroundColor\" format=\"reference|color\"/>\n        <attr name=\"ppvProgressColor\" format=\"reference|color\"/>\n        <attr name=\"ppvStrokeColor\" format=\"reference|color\"/>\n        <attr name=\"ppvShowStroke\" format=\"boolean\"/>\n        <attr name=\"ppvShowText\" format=\"boolean\"/>\n        <attr name=\"ppvTypeface\" format=\"string\"/>\n        <attr name=\"ppvImage\" format=\"reference\"/>\n        <attr name=\"ppvProgressFillType\" format=\"enum\">\n            <enum name=\"radial\" value=\"0\"/>\n            <enum name=\"center\" value=\"1\"/>\n        </attr>\n    </declare-styleable>\n\n    <declare-styleable name=\"SimpleViewBehavior\">\n        <attr name=\"svb_dependOn\" format=\"reference\"/>\n        <attr name=\"svb_dependType\">\n            <enum name=\"height\" value=\"0\"/>\n            <enum name=\"width\" value=\"1\"/>\n            <enum name=\"x\" value=\"2\"/>\n            <enum name=\"y\" value=\"3\"/>\n        </attr>\n        <attr name=\"svb_dependTargetX\" format=\"reference|dimension\"/>\n        <attr name=\"svb_dependTargetY\" format=\"reference|dimension\"/>\n        <attr name=\"svb_dependTargetWidth\" format=\"reference|dimension\"/>\n        <attr name=\"svb_dependTargetHeight\" format=\"reference|dimension\"/>\n        <attr name=\"svb_targetX\" format=\"reference|dimension\"/>\n        <attr name=\"svb_targetY\" format=\"reference|dimension\"/>\n        <attr name=\"svb_targetWidth\" format=\"reference|dimension\"/>\n        <attr name=\"svb_targetHeight\" format=\"reference|dimension\"/>\n        <attr name=\"svb_targetBackgroundColor\" format=\"reference|color\"/>\n        <attr name=\"svb_targetAlpha\" format=\"float\"/>\n        <attr name=\"svb_targetRotateX\" format=\"float\"/>\n        <attr name=\"svb_targetRotateY\" format=\"float\"/>\n        <attr name=\"svb_animation\" format=\"reference\"/>\n    </declare-styleable>\n</resources>\n"
  },
  {
    "path": "demo/src/main/res/values/colors.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n    Copyright 2016 jeasonlzy(廖子尧)\n    \n    Licensed under the Apache License, Version 2.0 (the \"License\");\n    you may not use this file except in compliance with the License.\n    You may obtain a copy of the License at\n    \n       http://www.apache.org/licenses/LICENSE-2.0\n       \n    Unless required by applicable law or agreed to in writing, software\n    distributed under the License is distributed on an \"AS IS\" BASIS,\n    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n    See the License for the specific language governing permissions and\n    limitations under the License.\n-->\n<resources>\n    <color name=\"colorPrimary\">#FB7E00</color>\n    <color name=\"colorPrimaryDark\">#FB7E00</color>\n    <color name=\"colorAccent\">#FF4081</color>\n</resources>\n"
  },
  {
    "path": "demo/src/main/res/values/dimens.xml",
    "content": "<!--\n    Copyright 2016 jeasonlzy(廖子尧)\n    \n    Licensed under the Apache License, Version 2.0 (the \"License\");\n    you may not use this file except in compliance with the License.\n    You may obtain a copy of the License at\n    \n       http://www.apache.org/licenses/LICENSE-2.0\n       \n    Unless required by applicable law or agreed to in writing, software\n    distributed under the License is distributed on an \"AS IS\" BASIS,\n    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n    See the License for the specific language governing permissions and\n    limitations under the License.\n-->\n<resources>\n    <!-- Default screen margins, per the Android Design guidelines. -->\n    <dimen name=\"activity_horizontal_margin\">16dp</dimen>\n    <dimen name=\"activity_vertical_margin\">16dp</dimen>\n</resources>\n"
  },
  {
    "path": "demo/src/main/res/values/strings.xml",
    "content": "<!--\n    Copyright 2016 jeasonlzy(廖子尧)\n    \n    Licensed under the Apache License, Version 2.0 (the \"License\");\n    you may not use this file except in compliance with the License.\n    You may obtain a copy of the License at\n    \n       http://www.apache.org/licenses/LICENSE-2.0\n       \n    Unless required by applicable law or agreed to in writing, software\n    distributed under the License is distributed on an \"AS IS\" BASIS,\n    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n    See the License for the specific language governing permissions and\n    limitations under the License.\n-->\n<resources>\n    <string name=\"app_name\">OkGo</string>\n\n    <string name=\"simple_view_behavior\">com.lzy.demo.ui.SimpleViewBehavior</string>\n    <string name=\"translate_up_down_behavior\">com.lzy.demo.ui.TranslateUpDownBehavior</string>\n</resources>\n"
  },
  {
    "path": "demo/src/main/res/values/styles.xml",
    "content": "<!--\n    Copyright 2016 jeasonlzy(廖子尧)\n    \n    Licensed under the Apache License, Version 2.0 (the \"License\");\n    you may not use this file except in compliance with the License.\n    You may obtain a copy of the License at\n    \n       http://www.apache.org/licenses/LICENSE-2.0\n       \n    Unless required by applicable law or agreed to in writing, software\n    distributed under the License is distributed on an \"AS IS\" BASIS,\n    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n    See the License for the specific language governing permissions and\n    limitations under the License.\n-->\n<resources>\n\n    <style name=\"AppTheme\" parent=\"Theme.AppCompat.Light.DarkActionBar\">\n        <item name=\"colorPrimary\">@color/colorPrimary</item>\n        <item name=\"colorPrimaryDark\">@color/colorPrimaryDark</item>\n        <item name=\"colorAccent\">@color/colorAccent</item>\n    </style>\n\n    <!--toolbar替代actionbar后必须设置主题为NoActionBar-->\n    <style name=\"AppTheme.NoActionBar\">\n        <item name=\"windowActionBar\">false</item>\n        <item name=\"windowNoTitle\">true</item>\n    </style>\n\n    <!--控制头部据appbar的样式-->\n    <style name=\"AppTheme.AppBarOverlay\" parent=\"ThemeOverlay.AppCompat.Dark.ActionBar\"/>\n\n    <!--用于控制toolbar溢出菜单的样式-->\n    <style name=\"AppTheme.PopupOverlay\" parent=\"ThemeOverlay.AppCompat.Light\"/>\n\n    <style name=\"TabLayoutTextStyle\" parent=\"TextAppearance.Design.Tab\">\n        <item name=\"textAllCaps\">false</item>\n    </style>\n\n</resources>\n"
  },
  {
    "path": "gradle/wrapper/gradle-wrapper.properties",
    "content": "#Thu Apr 20 14:50:29 CST 2017\ndistributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\nzipStoreBase=GRADLE_USER_HOME\nzipStorePath=wrapper/dists\ndistributionUrl=https\\://services.gradle.org/distributions/gradle-3.3-all.zip\n"
  },
  {
    "path": "gradle.properties",
    "content": "# Project-wide Gradle settings.\n\n# IDE (e.g. Android Studio) users:\n# Gradle settings configured through the IDE *will override*\n# any settings specified in this file.\n\n# For more details on how to configure your build environment visit\n# http://www.gradle.org/docs/current/userguide/build_environment.html\n\n# Specifies the JVM arguments used for the daemon process.\n# The setting is particularly useful for tweaking memory settings.\n# Default value: -Xmx10248m -XX:MaxPermSize=256m\n# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8\n\n# When configured, Gradle will run in incubating parallel mode.\n# This option should only be used with decoupled projects. More details, visit\n# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects\n# org.gradle.parallel=true"
  },
  {
    "path": "gradlew",
    "content": "#!/usr/bin/env bash\n\n##############################################################################\n##\n##  Gradle start up script for UN*X\n##\n##############################################################################\n\n# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\nDEFAULT_JVM_OPTS=\"\"\n\nAPP_NAME=\"Gradle\"\nAPP_BASE_NAME=`basename \"$0\"`\n\n# Use the maximum available, or set MAX_FD != -1 to use that value.\nMAX_FD=\"maximum\"\n\nwarn ( ) {\n    echo \"$*\"\n}\n\ndie ( ) {\n    echo\n    echo \"$*\"\n    echo\n    exit 1\n}\n\n# OS specific support (must be 'true' or 'false').\ncygwin=false\nmsys=false\ndarwin=false\ncase \"`uname`\" in\n  CYGWIN* )\n    cygwin=true\n    ;;\n  Darwin* )\n    darwin=true\n    ;;\n  MINGW* )\n    msys=true\n    ;;\nesac\n\n# Attempt to set APP_HOME\n# Resolve links: $0 may be a link\nPRG=\"$0\"\n# Need this for relative symlinks.\nwhile [ -h \"$PRG\" ] ; do\n    ls=`ls -ld \"$PRG\"`\n    link=`expr \"$ls\" : '.*-> \\(.*\\)$'`\n    if expr \"$link\" : '/.*' > /dev/null; then\n        PRG=\"$link\"\n    else\n        PRG=`dirname \"$PRG\"`\"/$link\"\n    fi\ndone\nSAVED=\"`pwd`\"\ncd \"`dirname \\\"$PRG\\\"`/\" >/dev/null\nAPP_HOME=\"`pwd -P`\"\ncd \"$SAVED\" >/dev/null\n\nCLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar\n\n# Determine the Java command to use to start the JVM.\nif [ -n \"$JAVA_HOME\" ] ; then\n    if [ -x \"$JAVA_HOME/jre/sh/java\" ] ; then\n        # IBM's JDK on AIX uses strange locations for the executables\n        JAVACMD=\"$JAVA_HOME/jre/sh/java\"\n    else\n        JAVACMD=\"$JAVA_HOME/bin/java\"\n    fi\n    if [ ! -x \"$JAVACMD\" ] ; then\n        die \"ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\n    fi\nelse\n    JAVACMD=\"java\"\n    which java >/dev/null 2>&1 || die \"ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\nfi\n\n# Increase the maximum file descriptors if we can.\nif [ \"$cygwin\" = \"false\" -a \"$darwin\" = \"false\" ] ; then\n    MAX_FD_LIMIT=`ulimit -H -n`\n    if [ $? -eq 0 ] ; then\n        if [ \"$MAX_FD\" = \"maximum\" -o \"$MAX_FD\" = \"max\" ] ; then\n            MAX_FD=\"$MAX_FD_LIMIT\"\n        fi\n        ulimit -n $MAX_FD\n        if [ $? -ne 0 ] ; then\n            warn \"Could not set maximum file descriptor limit: $MAX_FD\"\n        fi\n    else\n        warn \"Could not query maximum file descriptor limit: $MAX_FD_LIMIT\"\n    fi\nfi\n\n# For Darwin, add options to specify how the application appears in the dock\nif $darwin; then\n    GRADLE_OPTS=\"$GRADLE_OPTS \\\"-Xdock:name=$APP_NAME\\\" \\\"-Xdock:icon=$APP_HOME/media/gradle.icns\\\"\"\nfi\n\n# For Cygwin, switch paths to Windows format before running java\nif $cygwin ; then\n    APP_HOME=`cygpath --path --mixed \"$APP_HOME\"`\n    CLASSPATH=`cygpath --path --mixed \"$CLASSPATH\"`\n    JAVACMD=`cygpath --unix \"$JAVACMD\"`\n\n    # We build the pattern for arguments to be converted via cygpath\n    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`\n    SEP=\"\"\n    for dir in $ROOTDIRSRAW ; do\n        ROOTDIRS=\"$ROOTDIRS$SEP$dir\"\n        SEP=\"|\"\n    done\n    OURCYGPATTERN=\"(^($ROOTDIRS))\"\n    # Add a user-defined pattern to the cygpath arguments\n    if [ \"$GRADLE_CYGPATTERN\" != \"\" ] ; then\n        OURCYGPATTERN=\"$OURCYGPATTERN|($GRADLE_CYGPATTERN)\"\n    fi\n    # Now convert the arguments - kludge to limit ourselves to /bin/sh\n    i=0\n    for arg in \"$@\" ; do\n        CHECK=`echo \"$arg\"|egrep -c \"$OURCYGPATTERN\" -`\n        CHECK2=`echo \"$arg\"|egrep -c \"^-\"`                                 ### Determine if an option\n\n        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition\n            eval `echo args$i`=`cygpath --path --ignore --mixed \"$arg\"`\n        else\n            eval `echo args$i`=\"\\\"$arg\\\"\"\n        fi\n        i=$((i+1))\n    done\n    case $i in\n        (0) set -- ;;\n        (1) set -- \"$args0\" ;;\n        (2) set -- \"$args0\" \"$args1\" ;;\n        (3) set -- \"$args0\" \"$args1\" \"$args2\" ;;\n        (4) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" ;;\n        (5) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" ;;\n        (6) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" ;;\n        (7) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" ;;\n        (8) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" ;;\n        (9) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" \"$args8\" ;;\n    esac\nfi\n\n# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules\nfunction splitJvmOpts() {\n    JVM_OPTS=(\"$@\")\n}\neval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS\nJVM_OPTS[${#JVM_OPTS[*]}]=\"-Dorg.gradle.appname=$APP_BASE_NAME\"\n\nexec \"$JAVACMD\" \"${JVM_OPTS[@]}\" -classpath \"$CLASSPATH\" org.gradle.wrapper.GradleWrapperMain \"$@\"\n"
  },
  {
    "path": "gradlew.bat",
    "content": "@if \"%DEBUG%\" == \"\" @echo off\n@rem ##########################################################################\n@rem\n@rem  Gradle startup script for Windows\n@rem\n@rem ##########################################################################\n\n@rem Set local scope for the variables with windows NT shell\nif \"%OS%\"==\"Windows_NT\" setlocal\n\n@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\nset DEFAULT_JVM_OPTS=\n\nset DIRNAME=%~dp0\nif \"%DIRNAME%\" == \"\" set DIRNAME=.\nset APP_BASE_NAME=%~n0\nset APP_HOME=%DIRNAME%\n\n@rem Find java.exe\nif defined JAVA_HOME goto findJavaFromJavaHome\n\nset JAVA_EXE=java.exe\n%JAVA_EXE% -version >NUL 2>&1\nif \"%ERRORLEVEL%\" == \"0\" goto init\n\necho.\necho ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\necho.\necho Please set the JAVA_HOME variable in your environment to match the\necho location of your Java installation.\n\ngoto fail\n\n:findJavaFromJavaHome\nset JAVA_HOME=%JAVA_HOME:\"=%\nset JAVA_EXE=%JAVA_HOME%/bin/java.exe\n\nif exist \"%JAVA_EXE%\" goto init\n\necho.\necho ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%\necho.\necho Please set the JAVA_HOME variable in your environment to match the\necho location of your Java installation.\n\ngoto fail\n\n:init\n@rem Get command-line arguments, handling Windowz variants\n\nif not \"%OS%\" == \"Windows_NT\" goto win9xME_args\nif \"%@eval[2+2]\" == \"4\" goto 4NT_args\n\n:win9xME_args\n@rem Slurp the command line arguments.\nset CMD_LINE_ARGS=\nset _SKIP=2\n\n:win9xME_args_slurp\nif \"x%~1\" == \"x\" goto execute\n\nset CMD_LINE_ARGS=%*\ngoto execute\n\n:4NT_args\n@rem Get arguments from the 4NT Shell from JP Software\nset CMD_LINE_ARGS=%$\n\n:execute\n@rem Setup the command line\n\nset CLASSPATH=%APP_HOME%\\gradle\\wrapper\\gradle-wrapper.jar\n\n@rem Execute Gradle\n\"%JAVA_EXE%\" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% \"-Dorg.gradle.appname=%APP_BASE_NAME%\" -classpath \"%CLASSPATH%\" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%\n\n:end\n@rem End local scope for the variables with windows NT shell\nif \"%ERRORLEVEL%\"==\"0\" goto mainEnd\n\n:fail\nrem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of\nrem the _cmd.exe /c_ return code!\nif  not \"\" == \"%GRADLE_EXIT_CONSOLE%\" exit 1\nexit /b 1\n\n:mainEnd\nif \"%OS%\"==\"Windows_NT\" endlocal\n\n:omega\n"
  },
  {
    "path": "okgo/.gitignore",
    "content": "/build\n"
  },
  {
    "path": "okgo/bintray.gradle",
    "content": "apply plugin: 'com.github.dcendents.android-maven'\napply plugin: 'com.jfrog.bintray'\n\nversion = rootProject.ext.versionName_okgo      // 数据仓库依赖第三部分\n\ndef siteUrl = 'https://github.com/jeasonlzy/OkGo'\ndef gitUrl = 'https://github.com/jeasonlzy/OkGo.git'\ngroup = \"com.lzy.net\"       // 数据仓库依赖第一部分\n\ninstall {\n    repositories.mavenInstaller {\n        pom {\n            project {\n                packaging 'aar'\n                name 'OkGo For Android'     // 项目描述\n                url siteUrl\n                licenses {\n                    license {\n                        name 'The Apache Software License, Version 2.0'\n                        url 'http://www.apache.org/licenses/LICENSE-2.0.txt'\n                    }\n                }\n                developers {\n                    developer {\n                        id 'jeasonlzy'                // 开发者信息\n                        name 'LiaoZiYao'              // 开发者信息\n                        email 'liaojeason@126.com'    // 开发者信息\n                    }\n                }\n                scm {\n                    connection gitUrl\n                    developerConnection gitUrl\n                    url siteUrl\n                }\n            }\n        }\n    }\n}\n\ntask sourcesJar(type: Jar) {\n    from android.sourceSets.main.java.srcDirs\n    classifier = 'sources'\n}\n\ntask javadoc(type: Javadoc) {\n    source = android.sourceSets.main.java.srcDirs\n    classpath += project.files(android.getBootClasspath().join(File.pathSeparator))\n}\n\ntask javadocJar(type: Jar, dependsOn: javadoc) {\n    classifier = 'javadoc'\n    from javadoc.destinationDir\n}\n\njavadoc {\n    options {\n        encoding \"UTF-8\"\n        charSet 'UTF-8'\n        author true\n        version true\n        links \"http://docs.oracle.com/javase/7/docs/api\"\n        title 'OkGo For Android'   // 文档标题\n    }\n}\n\nartifacts {\n//    archives javadocJar\n    archives sourcesJar\n}\n\n// 生成jar包\ntask releaseJar(type: Copy) {\n    from( 'build/intermediates/bundles/default')\n    into( '../jar')\n    include('classes.jar')\n    rename('classes.jar', 'okgo-' + version + '.jar')\n}\n\nProperties properties = new Properties()\nproperties.load(project.rootProject.file('local.properties').newDataInputStream())\nbintray {\n    user = properties.getProperty(\"bintray.user\")\n    key = properties.getProperty(\"bintray.apikey\")\n    configurations = ['archives']\n    pkg {\n        repo = \"maven\"\n        name = \"okgo\"             // 数据仓库依赖第二部分\n        websiteUrl = siteUrl\n        vcsUrl = gitUrl\n        licenses = [\"Apache-2.0\"]\n        publish = true\n    }\n}\n"
  },
  {
    "path": "okgo/build.gradle",
    "content": "apply plugin: 'com.android.library'\n\nandroid {\n    compileSdkVersion rootProject.ext.compileSdkVersion\n    buildToolsVersion rootProject.ext.buildToolsVersion\n\n    defaultConfig {\n        minSdkVersion rootProject.ext.libMinSdkVersion\n        targetSdkVersion rootProject.ext.targetSdkVersion\n        versionCode rootProject.ext.versionCode\n        versionName rootProject.ext.versionName_okgo\n    }\n}\n\ndependencies {\n    compile fileTree(include: ['*.jar'], dir: 'libs')\n    compile 'com.squareup.okhttp3:okhttp:3.8.1'\n}\n\n//apply from: 'bintray.gradle'"
  },
  {
    "path": "okgo/proguard-rules.pro",
    "content": "# Add project specific ProGuard rules here.\n# By default, the flags in this file are appended to flags specified\n# in E:\\Android\\SDK/tools/proguard/proguard-android.txt\n# You can edit the include path and order by changing the proguardFiles\n# directive in build.gradle.\n#\n# For more details, see\n#   http://developer.android.com/guide/developing/tools/proguard.html\n\n# Add any project specific keep options here:\n\n# If your project uses WebView with JS, uncomment the following\n# and specify the fully qualified class name to the JavaScript interface\n# class:\n#-keepclassmembers class fqcn.of.javascript.interface.for.webview {\n#   public *;\n#}\n"
  },
  {
    "path": "okgo/src/main/AndroidManifest.xml",
    "content": "<!--\n    Copyright 2016 jeasonlzy(廖子尧)\n    \n    Licensed under the Apache License, Version 2.0 (the \"License\");\n    you may not use this file except in compliance with the License.\n    You may obtain a copy of the License at\n    \n       http://www.apache.org/licenses/LICENSE-2.0\n       \n    Unless required by applicable law or agreed to in writing, software\n    distributed under the License is distributed on an \"AS IS\" BASIS,\n    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n    See the License for the specific language governing permissions and\n    limitations under the License.\n-->\n<manifest\n    package=\"com.lzy.okgo\"\n    xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <uses-permission android:name=\"android.permission.INTERNET\"/>\n    <uses-permission android:name=\"android.permission.READ_EXTERNAL_STORAGE\"/>\n    <uses-permission android:name=\"android.permission.WRITE_EXTERNAL_STORAGE\"/>\n    <uses-permission android:name=\"android.permission.MOUNT_UNMOUNT_FILESYSTEMS\"/>\n\n</manifest>\n"
  },
  {
    "path": "okgo/src/main/java/com/lzy/okgo/OkGo.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.okgo;\n\nimport android.app.Application;\nimport android.content.Context;\nimport android.os.Handler;\nimport android.os.Looper;\n\nimport com.lzy.okgo.cache.CacheEntity;\nimport com.lzy.okgo.cache.CacheMode;\nimport com.lzy.okgo.cookie.CookieJarImpl;\nimport com.lzy.okgo.https.HttpsUtils;\nimport com.lzy.okgo.interceptor.HttpLoggingInterceptor;\nimport com.lzy.okgo.model.HttpHeaders;\nimport com.lzy.okgo.model.HttpParams;\nimport com.lzy.okgo.request.DeleteRequest;\nimport com.lzy.okgo.request.GetRequest;\nimport com.lzy.okgo.request.HeadRequest;\nimport com.lzy.okgo.request.OptionsRequest;\nimport com.lzy.okgo.request.PatchRequest;\nimport com.lzy.okgo.request.PostRequest;\nimport com.lzy.okgo.request.PutRequest;\nimport com.lzy.okgo.request.TraceRequest;\nimport com.lzy.okgo.utils.HttpUtils;\n\nimport java.util.concurrent.TimeUnit;\nimport java.util.logging.Level;\n\nimport okhttp3.Call;\nimport okhttp3.OkHttpClient;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：2016/1/12\n * 描    述：网络请求的入口类\n * 修订历史：\n * ================================================\n */\npublic class OkGo {\n    public static final long DEFAULT_MILLISECONDS = 60000;      //默认的超时时间\n    public static long REFRESH_TIME = 300;                      //回调刷新时间（单位ms）\n\n    private Application context;            //全局上下文\n    private Handler mDelivery;              //用于在主线程执行的调度器\n    private OkHttpClient okHttpClient;      //ok请求的客户端\n    private HttpParams mCommonParams;       //全局公共请求参数\n    private HttpHeaders mCommonHeaders;     //全局公共请求头\n    private int mRetryCount;                //全局超时重试次数\n    private CacheMode mCacheMode;           //全局缓存模式\n    private long mCacheTime;                //全局缓存过期时间,默认永不过期\n\n    private OkGo() {\n        mDelivery = new Handler(Looper.getMainLooper());\n        mRetryCount = 3;\n        mCacheTime = CacheEntity.CACHE_NEVER_EXPIRE;\n        mCacheMode = CacheMode.NO_CACHE;\n\n        OkHttpClient.Builder builder = new OkHttpClient.Builder();\n        HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor(\"OkGo\");\n        loggingInterceptor.setPrintLevel(HttpLoggingInterceptor.Level.BODY);\n        loggingInterceptor.setColorLevel(Level.INFO);\n        builder.addInterceptor(loggingInterceptor);\n\n        builder.readTimeout(OkGo.DEFAULT_MILLISECONDS, TimeUnit.MILLISECONDS);\n        builder.writeTimeout(OkGo.DEFAULT_MILLISECONDS, TimeUnit.MILLISECONDS);\n        builder.connectTimeout(OkGo.DEFAULT_MILLISECONDS, TimeUnit.MILLISECONDS);\n\n        HttpsUtils.SSLParams sslParams = HttpsUtils.getSslSocketFactory();\n        builder.sslSocketFactory(sslParams.sSLSocketFactory, sslParams.trustManager);\n        builder.hostnameVerifier(HttpsUtils.UnSafeHostnameVerifier);\n        okHttpClient = builder.build();\n    }\n\n    public static OkGo getInstance() {\n        return OkGoHolder.holder;\n    }\n\n    private static class OkGoHolder {\n        private static OkGo holder = new OkGo();\n    }\n\n    /** get请求 */\n    public static <T> GetRequest<T> get(String url) {\n        return new GetRequest<>(url);\n    }\n\n    /** post请求 */\n    public static <T> PostRequest<T> post(String url) {\n        return new PostRequest<>(url);\n    }\n\n    /** put请求 */\n    public static <T> PutRequest<T> put(String url) {\n        return new PutRequest<>(url);\n    }\n\n    /** head请求 */\n    public static <T> HeadRequest<T> head(String url) {\n        return new HeadRequest<>(url);\n    }\n\n    /** delete请求 */\n    public static <T> DeleteRequest<T> delete(String url) {\n        return new DeleteRequest<>(url);\n    }\n\n    /** options请求 */\n    public static <T> OptionsRequest<T> options(String url) {\n        return new OptionsRequest<>(url);\n    }\n\n    /** patch请求 */\n    public static <T> PatchRequest<T> patch(String url) {\n        return new PatchRequest<>(url);\n    }\n\n    /** trace请求 */\n    public static <T> TraceRequest<T> trace(String url) {\n        return new TraceRequest<>(url);\n    }\n\n    /** 必须在全局Application先调用，获取context上下文，否则缓存无法使用 */\n    public OkGo init(Application app) {\n        context = app;\n        return this;\n    }\n\n    /** 获取全局上下文 */\n    public Context getContext() {\n        HttpUtils.checkNotNull(context, \"please call OkGo.getInstance().init() first in application!\");\n        return context;\n    }\n\n    public Handler getDelivery() {\n        return mDelivery;\n    }\n\n    public OkHttpClient getOkHttpClient() {\n        HttpUtils.checkNotNull(okHttpClient, \"please call OkGo.getInstance().setOkHttpClient() first in application!\");\n        return okHttpClient;\n    }\n\n    /** 必须设置 */\n    public OkGo setOkHttpClient(OkHttpClient okHttpClient) {\n        HttpUtils.checkNotNull(okHttpClient, \"okHttpClient == null\");\n        this.okHttpClient = okHttpClient;\n        return this;\n    }\n\n    /** 获取全局的cookie实例 */\n    public CookieJarImpl getCookieJar() {\n        return (CookieJarImpl) okHttpClient.cookieJar();\n    }\n\n    /** 超时重试次数 */\n    public OkGo setRetryCount(int retryCount) {\n        if (retryCount < 0) throw new IllegalArgumentException(\"retryCount must > 0\");\n        mRetryCount = retryCount;\n        return this;\n    }\n\n    /** 超时重试次数 */\n    public int getRetryCount() {\n        return mRetryCount;\n    }\n\n    /** 全局的缓存模式 */\n    public OkGo setCacheMode(CacheMode cacheMode) {\n        mCacheMode = cacheMode;\n        return this;\n    }\n\n    /** 获取全局的缓存模式 */\n    public CacheMode getCacheMode() {\n        return mCacheMode;\n    }\n\n    /** 全局的缓存过期时间 */\n    public OkGo setCacheTime(long cacheTime) {\n        if (cacheTime <= -1) cacheTime = CacheEntity.CACHE_NEVER_EXPIRE;\n        mCacheTime = cacheTime;\n        return this;\n    }\n\n    /** 获取全局的缓存过期时间 */\n    public long getCacheTime() {\n        return mCacheTime;\n    }\n\n    /** 获取全局公共请求参数 */\n    public HttpParams getCommonParams() {\n        return mCommonParams;\n    }\n\n    /** 添加全局公共请求参数 */\n    public OkGo addCommonParams(HttpParams commonParams) {\n        if (mCommonParams == null) mCommonParams = new HttpParams();\n        mCommonParams.put(commonParams);\n        return this;\n    }\n\n    /** 获取全局公共请求头 */\n    public HttpHeaders getCommonHeaders() {\n        return mCommonHeaders;\n    }\n\n    /** 添加全局公共请求参数 */\n    public OkGo addCommonHeaders(HttpHeaders commonHeaders) {\n        if (mCommonHeaders == null) mCommonHeaders = new HttpHeaders();\n        mCommonHeaders.put(commonHeaders);\n        return this;\n    }\n\n    /** 根据Tag取消请求 */\n    public void cancelTag(Object tag) {\n        if (tag == null) return;\n        for (Call call : getOkHttpClient().dispatcher().queuedCalls()) {\n            if (tag.equals(call.request().tag())) {\n                call.cancel();\n            }\n        }\n        for (Call call : getOkHttpClient().dispatcher().runningCalls()) {\n            if (tag.equals(call.request().tag())) {\n                call.cancel();\n            }\n        }\n    }\n\n    /** 根据Tag取消请求 */\n    public static void cancelTag(OkHttpClient client, Object tag) {\n        if (client == null || tag == null) return;\n        for (Call call : client.dispatcher().queuedCalls()) {\n            if (tag.equals(call.request().tag())) {\n                call.cancel();\n            }\n        }\n        for (Call call : client.dispatcher().runningCalls()) {\n            if (tag.equals(call.request().tag())) {\n                call.cancel();\n            }\n        }\n    }\n\n    /** 取消所有请求请求 */\n    public void cancelAll() {\n        for (Call call : getOkHttpClient().dispatcher().queuedCalls()) {\n            call.cancel();\n        }\n        for (Call call : getOkHttpClient().dispatcher().runningCalls()) {\n            call.cancel();\n        }\n    }\n\n    /** 取消所有请求请求 */\n    public static void cancelAll(OkHttpClient client) {\n        if (client == null) return;\n        for (Call call : client.dispatcher().queuedCalls()) {\n            call.cancel();\n        }\n        for (Call call : client.dispatcher().runningCalls()) {\n            call.cancel();\n        }\n    }\n}\n"
  },
  {
    "path": "okgo/src/main/java/com/lzy/okgo/adapter/AdapterParam.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.okgo.adapter;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：2017/5/26\n * 描    述：\n * 修订历史：\n * ================================================\n */\npublic class AdapterParam {\n    public boolean isAsync;\n\n    public AdapterParam() {\n        isAsync = true;\n    }\n}\n"
  },
  {
    "path": "okgo/src/main/java/com/lzy/okgo/adapter/CacheCall.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.okgo.adapter;\n\nimport com.lzy.okgo.cache.CacheEntity;\nimport com.lzy.okgo.cache.policy.CachePolicy;\nimport com.lzy.okgo.cache.policy.DefaultCachePolicy;\nimport com.lzy.okgo.cache.policy.FirstCacheRequestPolicy;\nimport com.lzy.okgo.cache.policy.NoCachePolicy;\nimport com.lzy.okgo.cache.policy.NoneCacheRequestPolicy;\nimport com.lzy.okgo.cache.policy.RequestFailedCachePolicy;\nimport com.lzy.okgo.callback.Callback;\nimport com.lzy.okgo.model.Response;\nimport com.lzy.okgo.request.base.Request;\nimport com.lzy.okgo.utils.HttpUtils;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：2016/9/11\n * 描    述：带缓存的请求\n * 修订历史：\n * ================================================\n */\npublic class CacheCall<T> implements Call<T> {\n\n    private CachePolicy<T> policy = null;\n    private Request<T, ? extends Request> request;\n\n    public CacheCall(Request<T, ? extends Request> request) {\n        this.request = request;\n        this.policy = preparePolicy();\n    }\n\n    @Override\n    public Response<T> execute() {\n        CacheEntity<T> cacheEntity = policy.prepareCache();\n        return policy.requestSync(cacheEntity);\n    }\n\n    @Override\n    public void execute(Callback<T> callback) {\n        HttpUtils.checkNotNull(callback, \"callback == null\");\n\n        CacheEntity<T> cacheEntity = policy.prepareCache();\n        policy.requestAsync(cacheEntity, callback);\n    }\n\n    private CachePolicy<T> preparePolicy() {\n        switch (request.getCacheMode()) {\n            case DEFAULT:\n                policy = new DefaultCachePolicy<>(request);\n                break;\n            case NO_CACHE:\n                policy = new NoCachePolicy<>(request);\n                break;\n            case IF_NONE_CACHE_REQUEST:\n                policy = new NoneCacheRequestPolicy<>(request);\n                break;\n            case FIRST_CACHE_THEN_REQUEST:\n                policy = new FirstCacheRequestPolicy<>(request);\n                break;\n            case REQUEST_FAILED_READ_CACHE:\n                policy = new RequestFailedCachePolicy<>(request);\n                break;\n        }\n        if (request.getCachePolicy() != null) {\n            policy = request.getCachePolicy();\n        }\n        HttpUtils.checkNotNull(policy, \"policy == null\");\n        return policy;\n    }\n\n    @Override\n    public boolean isExecuted() {\n        return policy.isExecuted();\n    }\n\n    @Override\n    public void cancel() {\n        policy.cancel();\n    }\n\n    @Override\n    public boolean isCanceled() {\n        return policy.isCanceled();\n    }\n\n    @SuppressWarnings(\"CloneDoesntCallSuperClone\")\n    @Override\n    public Call<T> clone() {\n        return new CacheCall<>(request);\n    }\n\n    public Request getRequest() {\n        return request;\n    }\n}\n"
  },
  {
    "path": "okgo/src/main/java/com/lzy/okgo/adapter/Call.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.okgo.adapter;\n\nimport com.lzy.okgo.callback.Callback;\nimport com.lzy.okgo.model.Response;\nimport com.lzy.okgo.request.base.Request;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：2016/9/11\n * 描    述：请求的包装类\n * 修订历史：\n * ================================================\n */\npublic interface Call<T> {\n    /** 同步执行 */\n    Response<T> execute() throws Exception;\n\n    /** 异步回调执行 */\n    void execute(Callback<T> callback);\n\n    /** 是否已经执行 */\n    boolean isExecuted();\n\n    /** 取消 */\n    void cancel();\n\n    /** 是否取消 */\n    boolean isCanceled();\n\n    Call<T> clone();\n\n    Request getRequest();\n}\n"
  },
  {
    "path": "okgo/src/main/java/com/lzy/okgo/adapter/CallAdapter.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.okgo.adapter;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：16/9/11\n * 描    述：返回值的适配器\n * 修订历史：\n * ================================================\n */\npublic interface CallAdapter<T, R> {\n\n    /** call执行的代理方法 */\n    R adapt(Call<T> call, AdapterParam param);\n}\n"
  },
  {
    "path": "okgo/src/main/java/com/lzy/okgo/adapter/DefaultCallAdapter.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.okgo.adapter;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：2016/9/11\n * 描    述：默认的工厂处理,不对返回值做任何操作\n * 修订历史：\n * ================================================\n */\npublic class DefaultCallAdapter<T> implements CallAdapter<T, Call<T>> {\n\n    @Override\n    public Call<T> adapt(Call<T> call, AdapterParam param) {\n        return call;\n    }\n}\n"
  },
  {
    "path": "okgo/src/main/java/com/lzy/okgo/cache/CacheEntity.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.okgo.cache;\n\nimport android.content.ContentValues;\nimport android.database.Cursor;\n\nimport com.lzy.okgo.model.HttpHeaders;\nimport com.lzy.okgo.utils.IOUtils;\n\nimport java.io.Serializable;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：16/9/11\n * 描    述：\n * 修订历史：\n * ================================================\n */\npublic class CacheEntity<T> implements Serializable {\n    private static final long serialVersionUID = -4337711009801627866L;\n\n    public static final long CACHE_NEVER_EXPIRE = -1;        //缓存永不过期\n\n    //表中的字段\n    public static final String KEY = \"key\";\n    public static final String LOCAL_EXPIRE = \"localExpire\";\n    public static final String HEAD = \"head\";\n    public static final String DATA = \"data\";\n\n    private String key;                    // 缓存key\n    private long localExpire;              // 缓存过期时间\n    private HttpHeaders responseHeaders;   // 缓存的响应头\n    private T data;                        // 缓存的实体数据\n    private boolean isExpire;   //缓存是否过期该变量不必保存到数据库，程序运行起来后会动态计算\n\n    public String getKey() {\n        return key;\n    }\n\n    public void setKey(String key) {\n        this.key = key;\n    }\n\n    public HttpHeaders getResponseHeaders() {\n        return responseHeaders;\n    }\n\n    public void setResponseHeaders(HttpHeaders responseHeaders) {\n        this.responseHeaders = responseHeaders;\n    }\n\n    public T getData() {\n        return data;\n    }\n\n    public void setData(T data) {\n        this.data = data;\n    }\n\n    public long getLocalExpire() {\n        return localExpire;\n    }\n\n    public void setLocalExpire(long localExpire) {\n        this.localExpire = localExpire;\n    }\n\n    public boolean isExpire() {\n        return isExpire;\n    }\n\n    public void setExpire(boolean expire) {\n        isExpire = expire;\n    }\n\n    /**\n     * @param cacheTime 允许的缓存时间\n     * @param baseTime  基准时间,小于当前时间视为过期\n     * @return 是否过期\n     */\n    public boolean checkExpire(CacheMode cacheMode, long cacheTime, long baseTime) {\n        //304的默认缓存模式,设置缓存时间无效,需要依靠服务端的响应头控制\n        if (cacheMode == CacheMode.DEFAULT) return getLocalExpire() < baseTime;\n        if (cacheTime == CACHE_NEVER_EXPIRE) return false;\n        return getLocalExpire() + cacheTime < baseTime;\n    }\n\n    public static <T> ContentValues getContentValues(CacheEntity<T> cacheEntity) {\n        ContentValues values = new ContentValues();\n        values.put(KEY, cacheEntity.getKey());\n        values.put(LOCAL_EXPIRE, cacheEntity.getLocalExpire());\n        values.put(HEAD, IOUtils.toByteArray(cacheEntity.getResponseHeaders()));\n        values.put(DATA, IOUtils.toByteArray(cacheEntity.getData()));\n        return values;\n    }\n\n    public static <T> CacheEntity<T> parseCursorToBean(Cursor cursor) {\n        CacheEntity<T> cacheEntity = new CacheEntity<>();\n        cacheEntity.setKey(cursor.getString(cursor.getColumnIndex(KEY)));\n        cacheEntity.setLocalExpire(cursor.getLong(cursor.getColumnIndex(LOCAL_EXPIRE)));\n        cacheEntity.setResponseHeaders((HttpHeaders) IOUtils.toObject(cursor.getBlob(cursor.getColumnIndex(HEAD))));\n        //noinspection unchecked\n        cacheEntity.setData((T) IOUtils.toObject(cursor.getBlob(cursor.getColumnIndex(DATA))));\n        return cacheEntity;\n    }\n\n    @Override\n    public String toString() {\n        return \"CacheEntity{key='\" + key + '\\'' + //\n               \", responseHeaders=\" + responseHeaders + //\n               \", data=\" + data + //\n               \", localExpire=\" + localExpire + //\n               '}';\n    }\n}\n"
  },
  {
    "path": "okgo/src/main/java/com/lzy/okgo/cache/CacheMode.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.okgo.cache;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：16/9/11\n * 描    述：\n * 修订历史：\n * ================================================\n */\npublic enum CacheMode {\n    /** 按照HTTP协议的默认缓存规则，例如有304响应头时缓存 */\n    DEFAULT,\n\n    /** 不使用缓存 */\n    NO_CACHE,\n\n    /** 请求网络失败后，读取缓存 */\n    REQUEST_FAILED_READ_CACHE,\n\n    /** 如果缓存不存在才请求网络，否则使用缓存 */\n    IF_NONE_CACHE_REQUEST,\n\n    /** 先使用缓存，不管是否存在，仍然请求网络 */\n    FIRST_CACHE_THEN_REQUEST,\n}\n"
  },
  {
    "path": "okgo/src/main/java/com/lzy/okgo/cache/policy/BaseCachePolicy.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.okgo.cache.policy;\n\nimport android.graphics.Bitmap;\n\nimport com.lzy.okgo.OkGo;\nimport com.lzy.okgo.cache.CacheEntity;\nimport com.lzy.okgo.cache.CacheMode;\nimport com.lzy.okgo.callback.Callback;\nimport com.lzy.okgo.db.CacheManager;\nimport com.lzy.okgo.exception.HttpException;\nimport com.lzy.okgo.model.Response;\nimport com.lzy.okgo.request.base.Request;\nimport com.lzy.okgo.utils.HeaderParser;\nimport com.lzy.okgo.utils.HttpUtils;\n\nimport java.io.IOException;\nimport java.net.SocketTimeoutException;\n\nimport okhttp3.Call;\nimport okhttp3.Headers;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：2017/5/25\n * 描    述：\n * 修订历史：\n * ================================================\n */\npublic abstract class BaseCachePolicy<T> implements CachePolicy<T> {\n\n    protected Request<T, ? extends Request> request;\n    protected volatile boolean canceled;\n    protected volatile int currentRetryCount = 0;\n    protected boolean executed;\n    protected okhttp3.Call rawCall;\n    protected Callback<T> mCallback;\n    protected CacheEntity<T> cacheEntity;\n\n    public BaseCachePolicy(Request<T, ? extends Request> request) {\n        this.request = request;\n    }\n\n    @Override\n    public boolean onAnalysisResponse(Call call, okhttp3.Response response) {\n        return false;\n    }\n\n    @Override\n    public CacheEntity<T> prepareCache() {\n        //check the config of cache\n        if (request.getCacheKey() == null) {\n            request.cacheKey(HttpUtils.createUrlFromParams(request.getBaseUrl(), request.getParams().urlParamsMap));\n        }\n        if (request.getCacheMode() == null) {\n            request.cacheMode(CacheMode.NO_CACHE);\n        }\n\n        CacheMode cacheMode = request.getCacheMode();\n        if (cacheMode != CacheMode.NO_CACHE) {\n            //noinspection unchecked\n            cacheEntity = (CacheEntity<T>) CacheManager.getInstance().get(request.getCacheKey());\n            HeaderParser.addCacheHeaders(request, cacheEntity, cacheMode);\n            if (cacheEntity != null && cacheEntity.checkExpire(cacheMode, request.getCacheTime(), System.currentTimeMillis())) {\n                cacheEntity.setExpire(true);\n            }\n        }\n\n        if (cacheEntity == null || cacheEntity.isExpire() || cacheEntity.getData() == null || cacheEntity.getResponseHeaders() == null) {\n            cacheEntity = null;\n        }\n        return cacheEntity;\n    }\n\n    @Override\n    public synchronized okhttp3.Call prepareRawCall() throws Throwable {\n        if (executed) throw HttpException.COMMON(\"Already executed!\");\n        executed = true;\n        rawCall = request.getRawCall();\n        if (canceled) rawCall.cancel();\n        return rawCall;\n    }\n\n    protected Response<T> requestNetworkSync() {\n        try {\n            okhttp3.Response response = rawCall.execute();\n            int responseCode = response.code();\n\n            //network error\n            if (responseCode == 404 || responseCode >= 500) {\n                return Response.error(false, rawCall, response, HttpException.NET_ERROR());\n            }\n\n            T body = request.getConverter().convertResponse(response);\n            //save cache when request is successful\n            saveCache(response.headers(), body);\n            return Response.success(false, body, rawCall, response);\n        } catch (Throwable throwable) {\n            if (throwable instanceof SocketTimeoutException && currentRetryCount < request.getRetryCount()) {\n                currentRetryCount++;\n                rawCall = request.getRawCall();\n                if (canceled) {\n                    rawCall.cancel();\n                } else {\n                    requestNetworkSync();\n                }\n            }\n            return Response.error(false, rawCall, null, throwable);\n        }\n    }\n\n    protected void requestNetworkAsync() {\n        rawCall.enqueue(new okhttp3.Callback() {\n            @Override\n            public void onFailure(okhttp3.Call call, IOException e) {\n                if (e instanceof SocketTimeoutException && currentRetryCount < request.getRetryCount()) {\n                    //retry when timeout\n                    currentRetryCount++;\n                    rawCall = request.getRawCall();\n                    if (canceled) {\n                        rawCall.cancel();\n                    } else {\n                        rawCall.enqueue(this);\n                    }\n                } else {\n                    if (!call.isCanceled()) {\n                        Response<T> error = Response.error(false, call, null, e);\n                        onError(error);\n                    }\n                }\n            }\n\n            @Override\n            public void onResponse(okhttp3.Call call, okhttp3.Response response) throws IOException {\n                int responseCode = response.code();\n\n                //network error\n                if (responseCode == 404 || responseCode >= 500) {\n                    Response<T> error = Response.error(false, call, response, HttpException.NET_ERROR());\n                    onError(error);\n                    return;\n                }\n\n                if (onAnalysisResponse(call, response)) return;\n\n                try {\n                    T body = request.getConverter().convertResponse(response);\n                    //save cache when request is successful\n                    saveCache(response.headers(), body);\n                    Response<T> success = Response.success(false, body, call, response);\n                    onSuccess(success);\n                } catch (Throwable throwable) {\n                    Response<T> error = Response.error(false, call, response, throwable);\n                    onError(error);\n                }\n            }\n        });\n    }\n\n    /**\n     * 请求成功后根据缓存模式，更新缓存数据\n     *\n     * @param headers 响应头\n     * @param data    响应数据\n     */\n    private void saveCache(Headers headers, T data) {\n        if (request.getCacheMode() == CacheMode.NO_CACHE) return;    //不需要缓存,直接返回\n        if (data instanceof Bitmap) return;             //Bitmap没有实现Serializable,不能缓存\n\n        CacheEntity<T> cache = HeaderParser.createCacheEntity(headers, data, request.getCacheMode(), request.getCacheKey());\n        if (cache == null) {\n            //服务器不需要缓存，移除本地缓存\n            CacheManager.getInstance().remove(request.getCacheKey());\n        } else {\n            //缓存命中，更新缓存\n            CacheManager.getInstance().replace(request.getCacheKey(), cache);\n        }\n    }\n\n    protected void runOnUiThread(Runnable run) {\n        OkGo.getInstance().getDelivery().post(run);\n    }\n\n    @Override\n    public boolean isExecuted() {\n        return executed;\n    }\n\n    @Override\n    public void cancel() {\n        canceled = true;\n        if (rawCall != null) {\n            rawCall.cancel();\n        }\n    }\n\n    @Override\n    public boolean isCanceled() {\n        if (canceled) return true;\n        synchronized (this) {\n            return rawCall != null && rawCall.isCanceled();\n        }\n    }\n}\n"
  },
  {
    "path": "okgo/src/main/java/com/lzy/okgo/cache/policy/CachePolicy.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.okgo.cache.policy;\n\nimport com.lzy.okgo.cache.CacheEntity;\nimport com.lzy.okgo.callback.Callback;\nimport com.lzy.okgo.model.Response;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：2017/5/25\n * 描    述：\n * 修订历史：\n * ================================================\n */\npublic interface CachePolicy<T> {\n\n    /**\n     * 获取数据成功的回调\n     *\n     * @param success 获取的数据，可是是缓存或者网络\n     */\n    void onSuccess(Response<T> success);\n\n    /**\n     * 获取数据失败的回调\n     *\n     * @param error 失败的信息，可是是缓存或者网络\n     */\n    void onError(Response<T> error);\n\n    /**\n     * 控制是否执行后续的回调动作\n     *\n     * @param call     请求的对象\n     * @param response 响应的对象\n     * @return true，不执行回调， false 执行回调\n     */\n    boolean onAnalysisResponse(okhttp3.Call call, okhttp3.Response response);\n\n    /**\n     * 构建缓存\n     *\n     * @return 获取的缓存\n     */\n    CacheEntity<T> prepareCache();\n\n    /**\n     * 构建请求对象\n     *\n     * @return 准备请求的对象\n     */\n    okhttp3.Call prepareRawCall() throws Throwable;\n\n    /**\n     * 同步请求获取数据\n     *\n     * @param cacheEntity 本地的缓存\n     * @return 从缓存或本地获取的数据\n     */\n    Response<T> requestSync(CacheEntity<T> cacheEntity);\n\n    /**\n     * 异步请求获取数据\n     *\n     * @param cacheEntity 本地的缓存\n     * @param callback    异步回调\n     */\n    void requestAsync(CacheEntity<T> cacheEntity, Callback<T> callback);\n\n    /**\n     * 当前请求是否已经执行\n     *\n     * @return true，已经执行， false，没有执行\n     */\n    boolean isExecuted();\n\n    /**\n     * 取消请求\n     */\n    void cancel();\n\n    /**\n     * 是否已经取消\n     *\n     * @return true，已经取消，false，没有取消\n     */\n    boolean isCanceled();\n}\n"
  },
  {
    "path": "okgo/src/main/java/com/lzy/okgo/cache/policy/DefaultCachePolicy.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.okgo.cache.policy;\n\nimport com.lzy.okgo.cache.CacheEntity;\nimport com.lzy.okgo.callback.Callback;\nimport com.lzy.okgo.exception.CacheException;\nimport com.lzy.okgo.model.Response;\nimport com.lzy.okgo.request.base.Request;\n\nimport okhttp3.Call;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：2017/5/25\n * 描    述：\n * 修订历史：\n * ================================================\n */\npublic class DefaultCachePolicy<T> extends BaseCachePolicy<T> {\n\n    public DefaultCachePolicy(Request<T, ? extends Request> request) {\n        super(request);\n    }\n\n    @Override\n    public void onSuccess(final Response<T> success) {\n        runOnUiThread(new Runnable() {\n            @Override\n            public void run() {\n                mCallback.onSuccess(success);\n                mCallback.onFinish();\n            }\n        });\n    }\n\n    @Override\n    public void onError(final Response<T> error) {\n        runOnUiThread(new Runnable() {\n            @Override\n            public void run() {\n                mCallback.onError(error);\n                mCallback.onFinish();\n            }\n        });\n    }\n\n    @Override\n    public boolean onAnalysisResponse(final Call call, final okhttp3.Response response) {\n        if (response.code() != 304) return false;\n\n        if (cacheEntity == null) {\n            final Response<T> error = Response.error(true, call, response, CacheException.NON_AND_304(request.getCacheKey()));\n            runOnUiThread(new Runnable() {\n                @Override\n                public void run() {\n                    mCallback.onError(error);\n                    mCallback.onFinish();\n                }\n            });\n        } else {\n            final Response<T> success = Response.success(true, cacheEntity.getData(), call, response);\n            runOnUiThread(new Runnable() {\n                @Override\n                public void run() {\n                    mCallback.onCacheSuccess(success);\n                    mCallback.onFinish();\n                }\n            });\n        }\n        return true;\n    }\n\n    @Override\n    public Response<T> requestSync(CacheEntity<T> cacheEntity) {\n        try {\n            prepareRawCall();\n        } catch (Throwable throwable) {\n            return Response.error(false, rawCall, null, throwable);\n        }\n        Response<T> response = requestNetworkSync();\n        //HTTP cache protocol\n        if (response.isSuccessful() && response.code() == 304) {\n            if (cacheEntity == null) {\n                response = Response.error(true, rawCall, response.getRawResponse(), CacheException.NON_AND_304(request.getCacheKey()));\n            } else {\n                response = Response.success(true, cacheEntity.getData(), rawCall, response.getRawResponse());\n            }\n        }\n        return response;\n    }\n\n    @Override\n    public void requestAsync(CacheEntity<T> cacheEntity, Callback<T> callback) {\n        mCallback = callback;\n        runOnUiThread(new Runnable() {\n            @Override\n            public void run() {\n                mCallback.onStart(request);\n\n                try {\n                    prepareRawCall();\n                } catch (Throwable throwable) {\n                    Response<T> error = Response.error(false, rawCall, null, throwable);\n                    mCallback.onError(error);\n                    return;\n                }\n                requestNetworkAsync();\n            }\n        });\n    }\n}\n"
  },
  {
    "path": "okgo/src/main/java/com/lzy/okgo/cache/policy/FirstCacheRequestPolicy.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.okgo.cache.policy;\n\nimport com.lzy.okgo.cache.CacheEntity;\nimport com.lzy.okgo.callback.Callback;\nimport com.lzy.okgo.model.Response;\nimport com.lzy.okgo.request.base.Request;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：2017/5/25\n * 描    述：\n * 修订历史：\n * ================================================\n */\npublic class FirstCacheRequestPolicy<T> extends BaseCachePolicy<T> {\n    public FirstCacheRequestPolicy(Request<T, ? extends Request> request) {\n        super(request);\n    }\n\n    @Override\n    public void onSuccess(final Response<T> success) {\n        runOnUiThread(new Runnable() {\n            @Override\n            public void run() {\n                mCallback.onSuccess(success);\n                mCallback.onFinish();\n            }\n        });\n    }\n\n    @Override\n    public void onError(final Response<T> error) {\n        runOnUiThread(new Runnable() {\n            @Override\n            public void run() {\n                mCallback.onError(error);\n                mCallback.onFinish();\n            }\n        });\n    }\n\n    @Override\n    public Response<T> requestSync(CacheEntity<T> cacheEntity) {\n        try {\n            prepareRawCall();\n        } catch (Throwable throwable) {\n            return Response.error(false, rawCall, null, throwable);\n        }\n        //同步请求，不能返回两次，只返回正确的数据\n        Response<T> response;\n        if (cacheEntity != null) {\n            response = Response.success(true, cacheEntity.getData(), rawCall, null);\n        }\n        response = requestNetworkSync();\n        if (!response.isSuccessful() && cacheEntity != null) {\n            response = Response.success(true, cacheEntity.getData(), rawCall, response.getRawResponse());\n        }\n        return response;\n    }\n\n    @Override\n    public void requestAsync(final CacheEntity<T> cacheEntity, Callback<T> callback) {\n        mCallback = callback;\n        runOnUiThread(new Runnable() {\n            @Override\n            public void run() {\n                mCallback.onStart(request);\n\n                try {\n                    prepareRawCall();\n                } catch (Throwable throwable) {\n                    Response<T> error = Response.error(false, rawCall, null, throwable);\n                    mCallback.onError(error);\n                    return;\n                }\n                if (cacheEntity != null) {\n                    Response<T> success = Response.success(true, cacheEntity.getData(), rawCall, null);\n                    mCallback.onCacheSuccess(success);\n                }\n                requestNetworkAsync();\n            }\n        });\n    }\n}\n"
  },
  {
    "path": "okgo/src/main/java/com/lzy/okgo/cache/policy/NoCachePolicy.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.okgo.cache.policy;\n\nimport com.lzy.okgo.cache.CacheEntity;\nimport com.lzy.okgo.callback.Callback;\nimport com.lzy.okgo.model.Response;\nimport com.lzy.okgo.request.base.Request;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：2017/5/25\n * 描    述：\n * 修订历史：\n * ================================================\n */\npublic class NoCachePolicy<T> extends BaseCachePolicy<T> {\n\n    public NoCachePolicy(Request<T, ? extends Request> request) {\n        super(request);\n    }\n\n    @Override\n    public void onSuccess(final Response<T> success) {\n        runOnUiThread(new Runnable() {\n            @Override\n            public void run() {\n                mCallback.onSuccess(success);\n                mCallback.onFinish();\n            }\n        });\n    }\n\n    @Override\n    public void onError(final Response<T> error) {\n        runOnUiThread(new Runnable() {\n            @Override\n            public void run() {\n                mCallback.onError(error);\n                mCallback.onFinish();\n            }\n        });\n    }\n\n    @Override\n    public Response<T> requestSync(CacheEntity<T> cacheEntity) {\n        try {\n            prepareRawCall();\n        } catch (Throwable throwable) {\n            return Response.error(false, rawCall, null, throwable);\n        }\n        return requestNetworkSync();\n    }\n\n    @Override\n    public void requestAsync(CacheEntity<T> cacheEntity, Callback<T> callback) {\n        mCallback = callback;\n        runOnUiThread(new Runnable() {\n            @Override\n            public void run() {\n                mCallback.onStart(request);\n\n                try {\n                    prepareRawCall();\n                } catch (Throwable throwable) {\n                    Response<T> error = Response.error(false, rawCall, null, throwable);\n                    mCallback.onError(error);\n                    return;\n                }\n                requestNetworkAsync();\n            }\n        });\n    }\n}\n"
  },
  {
    "path": "okgo/src/main/java/com/lzy/okgo/cache/policy/NoneCacheRequestPolicy.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.okgo.cache.policy;\n\nimport com.lzy.okgo.cache.CacheEntity;\nimport com.lzy.okgo.callback.Callback;\nimport com.lzy.okgo.model.Response;\nimport com.lzy.okgo.request.base.Request;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：2017/5/25\n * 描    述：\n * 修订历史：\n * ================================================\n */\npublic class NoneCacheRequestPolicy<T> extends BaseCachePolicy<T> {\n\n    public NoneCacheRequestPolicy(Request<T, ? extends Request> request) {\n        super(request);\n    }\n\n    @Override\n    public void onSuccess(final Response<T> success) {\n        runOnUiThread(new Runnable() {\n            @Override\n            public void run() {\n                mCallback.onSuccess(success);\n                mCallback.onFinish();\n            }\n        });\n    }\n\n    @Override\n    public void onError(final Response<T> error) {\n        runOnUiThread(new Runnable() {\n            @Override\n            public void run() {\n                mCallback.onError(error);\n                mCallback.onFinish();\n            }\n        });\n    }\n\n    @Override\n    public Response<T> requestSync(CacheEntity<T> cacheEntity) {\n        try {\n            prepareRawCall();\n        } catch (Throwable throwable) {\n            return Response.error(false, rawCall, null, throwable);\n        }\n        Response<T> response = null;\n        if (cacheEntity != null) {\n            response = Response.success(true, cacheEntity.getData(), rawCall, null);\n        }\n        if (response == null) {\n            response = requestNetworkSync();\n        }\n        return response;\n    }\n\n    @Override\n    public void requestAsync(final CacheEntity<T> cacheEntity, Callback<T> callback) {\n        mCallback = callback;\n        runOnUiThread(new Runnable() {\n            @Override\n            public void run() {\n                mCallback.onStart(request);\n\n                try {\n                    prepareRawCall();\n                } catch (Throwable throwable) {\n                    Response<T> error = Response.error(false, rawCall, null, throwable);\n                    mCallback.onError(error);\n                    return;\n                }\n                if (cacheEntity != null) {\n                    Response<T> success = Response.success(true, cacheEntity.getData(), rawCall, null);\n                    mCallback.onCacheSuccess(success);\n                    mCallback.onFinish();\n                    return;\n                }\n                requestNetworkAsync();\n            }\n        });\n    }\n}\n"
  },
  {
    "path": "okgo/src/main/java/com/lzy/okgo/cache/policy/RequestFailedCachePolicy.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.okgo.cache.policy;\n\nimport com.lzy.okgo.cache.CacheEntity;\nimport com.lzy.okgo.callback.Callback;\nimport com.lzy.okgo.model.Response;\nimport com.lzy.okgo.request.base.Request;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：2017/5/25\n * 描    述：\n * 修订历史：\n * ================================================\n */\npublic class RequestFailedCachePolicy<T> extends BaseCachePolicy<T> {\n\n    public RequestFailedCachePolicy(Request<T, ? extends Request> request) {\n        super(request);\n    }\n\n    @Override\n    public void onSuccess(final Response<T> success) {\n        runOnUiThread(new Runnable() {\n            @Override\n            public void run() {\n                mCallback.onSuccess(success);\n                mCallback.onFinish();\n            }\n        });\n    }\n\n    @Override\n    public void onError(final Response<T> error) {\n\n        if (cacheEntity != null) {\n            final Response<T> cacheSuccess = Response.success(true, cacheEntity.getData(), error.getRawCall(), error.getRawResponse());\n            runOnUiThread(new Runnable() {\n                @Override\n                public void run() {\n                    mCallback.onCacheSuccess(cacheSuccess);\n                    mCallback.onFinish();\n                }\n            });\n        } else {\n            runOnUiThread(new Runnable() {\n                @Override\n                public void run() {\n                    mCallback.onError(error);\n                    mCallback.onFinish();\n                }\n            });\n        }\n    }\n\n    @Override\n    public Response<T> requestSync(CacheEntity<T> cacheEntity) {\n        try {\n            prepareRawCall();\n        } catch (Throwable throwable) {\n            return Response.error(false, rawCall, null, throwable);\n        }\n        Response<T> response = requestNetworkSync();\n        if (!response.isSuccessful() && cacheEntity != null) {\n            response = Response.success(true, cacheEntity.getData(), rawCall, response.getRawResponse());\n        }\n        return response;\n    }\n\n    @Override\n    public void requestAsync(CacheEntity<T> cacheEntity, Callback<T> callback) {\n        mCallback = callback;\n        runOnUiThread(new Runnable() {\n            @Override\n            public void run() {\n                mCallback.onStart(request);\n\n                try {\n                    prepareRawCall();\n                } catch (Throwable throwable) {\n                    Response<T> error = Response.error(false, rawCall, null, throwable);\n                    mCallback.onError(error);\n                    return;\n                }\n                requestNetworkAsync();\n            }\n        });\n    }\n}\n"
  },
  {
    "path": "okgo/src/main/java/com/lzy/okgo/callback/AbsCallback.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.okgo.callback;\n\nimport com.lzy.okgo.model.Progress;\nimport com.lzy.okgo.model.Response;\nimport com.lzy.okgo.request.base.Request;\nimport com.lzy.okgo.utils.OkLogger;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版   本：1.0\n * 创建日期：2016/1/14\n * 描   述：抽象的回调接口\n * 修订历史：\n * ================================================\n */\npublic abstract class AbsCallback<T> implements Callback<T> {\n\n    @Override\n    public void onStart(Request<T, ? extends Request> request) {\n    }\n\n    @Override\n    public void onCacheSuccess(Response<T> response) {\n    }\n\n    @Override\n    public void onError(Response<T> response) {\n        OkLogger.printStackTrace(response.getException());\n    }\n\n    @Override\n    public void onFinish() {\n    }\n\n    @Override\n    public void uploadProgress(Progress progress) {\n    }\n\n    @Override\n    public void downloadProgress(Progress progress) {\n    }\n}\n"
  },
  {
    "path": "okgo/src/main/java/com/lzy/okgo/callback/BitmapCallback.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.okgo.callback;\n\nimport android.graphics.Bitmap;\nimport android.widget.ImageView;\n\nimport com.lzy.okgo.convert.BitmapConvert;\n\nimport okhttp3.Response;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：2016/1/12\n * 描    述：返回图片的Bitmap，这里没有进行图片的缩放，可能会发生 OOM\n * 修订历史：\n * ================================================\n */\npublic abstract class BitmapCallback extends AbsCallback<Bitmap> {\n\n    private BitmapConvert convert;\n\n    public BitmapCallback() {\n        convert = new BitmapConvert();\n    }\n\n    public BitmapCallback(int maxWidth, int maxHeight) {\n        convert = new BitmapConvert(maxWidth, maxHeight);\n    }\n\n    public BitmapCallback(int maxWidth, int maxHeight, Bitmap.Config decodeConfig, ImageView.ScaleType scaleType) {\n        convert = new BitmapConvert(maxWidth, maxHeight, decodeConfig, scaleType);\n    }\n\n    @Override\n    public Bitmap convertResponse(Response response) throws Throwable {\n        Bitmap bitmap = convert.convertResponse(response);\n        response.close();\n        return bitmap;\n    }\n}\n"
  },
  {
    "path": "okgo/src/main/java/com/lzy/okgo/callback/Callback.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.okgo.callback;\n\nimport com.lzy.okgo.cache.CacheMode;\nimport com.lzy.okgo.convert.Converter;\nimport com.lzy.okgo.model.Progress;\nimport com.lzy.okgo.model.Response;\nimport com.lzy.okgo.request.base.Request;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版   本：1.0\n * 创建日期：2016/1/14\n * 描   述：抽象的回调接口\n * 修订历史：\n * ================================================\n * <p>该类的回调具有如下顺序,虽然顺序写的很复杂,但是理解后,是很简单,并且合情合理的\n * <p>1.无缓存模式{@link CacheMode#NO_CACHE}<br>\n * ---网络请求成功 onStart -> convertResponse -> onSuccess -> onFinish<br>\n * ---网络请求失败 onStart -> onError -> onFinish<br>\n * <p>2.默认缓存模式,遵循304头{@link CacheMode#DEFAULT}<br>\n * ---网络请求成功,服务端返回非304 onStart -> convertResponse -> onSuccess -> onFinish<br>\n * ---网络请求成功服务端返回304 onStart -> onCacheSuccess -> onFinish<br>\n * ---网络请求失败 onStart -> onError -> onFinish<br>\n * <p>3.请求网络失败后读取缓存{@link CacheMode#REQUEST_FAILED_READ_CACHE}<br>\n * ---网络请求成功,不读取缓存 onStart -> convertResponse -> onSuccess -> onFinish<br>\n * ---网络请求失败,读取缓存成功 onStart -> onCacheSuccess -> onFinish<br>\n * ---网络请求失败,读取缓存失败 onStart -> onError -> onFinish<br>\n * <p>4.如果缓存不存在才请求网络，否则使用缓存{@link CacheMode#IF_NONE_CACHE_REQUEST}<br>\n * ---已经有缓存,不请求网络 onStart -> onCacheSuccess -> onFinish<br>\n * ---没有缓存请求网络成功 onStart -> convertResponse -> onSuccess -> onFinish<br>\n * ---没有缓存请求网络失败 onStart -> onError -> onFinish<br>\n * <p>5.先使用缓存，不管是否存在，仍然请求网络{@link CacheMode#FIRST_CACHE_THEN_REQUEST}<br>\n * ---无缓存时,网络请求成功 onStart -> convertResponse -> onSuccess -> onFinish<br>\n * ---无缓存时,网络请求失败 onStart -> onError -> onFinish<br>\n * ---有缓存时,网络请求成功 onStart -> onCacheSuccess -> convertResponse -> onSuccess -> onFinish<br>\n * ---有缓存时,网络请求失败 onStart -> onCacheSuccess -> onError -> onFinish<br>\n */\npublic interface Callback<T> extends Converter<T> {\n\n    /** 请求网络开始前，UI线程 */\n    void onStart(Request<T, ? extends Request> request);\n\n    /** 对返回数据进行操作的回调， UI线程 */\n    void onSuccess(Response<T> response);\n\n    /** 缓存成功的回调,UI线程 */\n    void onCacheSuccess(Response<T> response);\n\n    /** 请求失败，响应错误，数据解析错误等，都会回调该方法， UI线程 */\n    void onError(Response<T> response);\n\n    /** 请求网络结束后，UI线程 */\n    void onFinish();\n\n    /** 上传过程中的进度回调，get请求不回调，UI线程 */\n    void uploadProgress(Progress progress);\n\n    /** 下载过程中的进度回调，UI线程 */\n    void downloadProgress(Progress progress);\n}\n"
  },
  {
    "path": "okgo/src/main/java/com/lzy/okgo/callback/FileCallback.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.okgo.callback;\n\nimport com.lzy.okgo.convert.FileConvert;\n\nimport java.io.File;\n\nimport okhttp3.Response;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：2016/1/12\n * 描    述：文件的回调下载进度监听\n * 修订历史：\n * ================================================\n */\npublic abstract class FileCallback extends AbsCallback<File> {\n\n    private FileConvert convert;    //文件转换类\n\n    public FileCallback() {\n        this(null);\n    }\n\n    public FileCallback(String destFileName) {\n        this(null, destFileName);\n    }\n\n    public FileCallback(String destFileDir, String destFileName) {\n        convert = new FileConvert(destFileDir, destFileName);\n        convert.setCallback(this);\n    }\n\n    @Override\n    public File convertResponse(Response response) throws Throwable {\n        File file = convert.convertResponse(response);\n        response.close();\n        return file;\n    }\n}\n"
  },
  {
    "path": "okgo/src/main/java/com/lzy/okgo/callback/StringCallback.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.okgo.callback;\n\nimport com.lzy.okgo.convert.StringConvert;\n\nimport okhttp3.Response;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：2016/9/11\n * 描    述：返回字符串类型的数据\n * 修订历史：\n * ================================================\n */\npublic abstract class StringCallback extends AbsCallback<String> {\n\n    private StringConvert convert;\n\n    public StringCallback() {\n        convert = new StringConvert();\n    }\n\n    @Override\n    public String convertResponse(Response response) throws Throwable {\n        String s = convert.convertResponse(response);\n        response.close();\n        return s;\n    }\n}\n"
  },
  {
    "path": "okgo/src/main/java/com/lzy/okgo/convert/BitmapConvert.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.okgo.convert;\n\nimport android.graphics.Bitmap;\nimport android.graphics.BitmapFactory;\nimport android.widget.ImageView;\n\nimport okhttp3.Response;\nimport okhttp3.ResponseBody;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：16/9/11\n * 描    述：字符串的转换器\n * 修订历史：\n * ================================================\n */\npublic class BitmapConvert implements Converter<Bitmap> {\n\n    private int maxWidth;\n    private int maxHeight;\n    private Bitmap.Config decodeConfig;\n    private ImageView.ScaleType scaleType;\n\n    public BitmapConvert() {\n        this(1000, 1000, Bitmap.Config.ARGB_8888, ImageView.ScaleType.CENTER_INSIDE);\n    }\n\n    public BitmapConvert(int maxWidth, int maxHeight) {\n        this(maxWidth, maxHeight, Bitmap.Config.ARGB_8888, ImageView.ScaleType.CENTER_INSIDE);\n    }\n\n    public BitmapConvert(int maxWidth, int maxHeight, Bitmap.Config decodeConfig, ImageView.ScaleType scaleType) {\n        this.maxWidth = maxWidth;\n        this.maxHeight = maxHeight;\n        this.decodeConfig = decodeConfig;\n        this.scaleType = scaleType;\n    }\n\n    @Override\n    public Bitmap convertResponse(Response response) throws Throwable {\n        ResponseBody body = response.body();\n        if (body == null) return null;\n        return parse(body.bytes());\n    }\n\n    private Bitmap parse(byte[] byteArray) throws OutOfMemoryError {\n        BitmapFactory.Options decodeOptions = new BitmapFactory.Options();\n        Bitmap bitmap;\n        if (maxWidth == 0 && maxHeight == 0) {\n            decodeOptions.inPreferredConfig = decodeConfig;\n            bitmap = BitmapFactory.decodeByteArray(byteArray, 0, byteArray.length, decodeOptions);\n        } else {\n            decodeOptions.inJustDecodeBounds = true;\n            BitmapFactory.decodeByteArray(byteArray, 0, byteArray.length, decodeOptions);\n            int actualWidth = decodeOptions.outWidth;\n            int actualHeight = decodeOptions.outHeight;\n\n            int desiredWidth = getResizedDimension(maxWidth, maxHeight, actualWidth, actualHeight, scaleType);\n            int desiredHeight = getResizedDimension(maxHeight, maxWidth, actualHeight, actualWidth, scaleType);\n\n            decodeOptions.inJustDecodeBounds = false;\n            decodeOptions.inSampleSize = findBestSampleSize(actualWidth, actualHeight, desiredWidth, desiredHeight);\n            Bitmap tempBitmap = BitmapFactory.decodeByteArray(byteArray, 0, byteArray.length, decodeOptions);\n\n            if (tempBitmap != null && (tempBitmap.getWidth() > desiredWidth || tempBitmap.getHeight() > desiredHeight)) {\n                bitmap = Bitmap.createScaledBitmap(tempBitmap, desiredWidth, desiredHeight, true);\n                tempBitmap.recycle();\n            } else {\n                bitmap = tempBitmap;\n            }\n        }\n        return bitmap;\n    }\n\n    private static int getResizedDimension(int maxPrimary, int maxSecondary, int actualPrimary, int actualSecondary, ImageView.ScaleType scaleType) {\n\n        // If no dominant value at all, just return the actual.\n        if ((maxPrimary == 0) && (maxSecondary == 0)) {\n            return actualPrimary;\n        }\n\n        // If ScaleType.FIT_XY fill the whole rectangle, ignore ratio.\n        if (scaleType == ImageView.ScaleType.FIT_XY) {\n            if (maxPrimary == 0) {\n                return actualPrimary;\n            } else {\n                return maxPrimary;\n            }\n        }\n\n        // If primary is unspecified, scale primary to match secondary's scaling ratio.\n        if (maxPrimary == 0) {\n            double ratio = (double) maxSecondary / (double) actualSecondary;\n            return (int) (actualPrimary * ratio);\n        }\n\n        if (maxSecondary == 0) {\n            return maxPrimary;\n        }\n\n        double ratio = (double) actualSecondary / (double) actualPrimary;\n        int resized = maxPrimary;\n\n        // If ScaleType.CENTER_CROP fill the whole rectangle, preserve aspect ratio.\n        if (scaleType == ImageView.ScaleType.CENTER_CROP) {\n            if ((resized * ratio) < maxSecondary) {\n                resized = (int) (maxSecondary / ratio);\n            }\n            return resized;\n        }\n\n        if ((resized * ratio) > maxSecondary) {\n            resized = (int) (maxSecondary / ratio);\n        }\n        return resized;\n    }\n\n    private static int findBestSampleSize(int actualWidth, int actualHeight, int desiredWidth, int desiredHeight) {\n        double wr = (double) actualWidth / desiredWidth;\n        double hr = (double) actualHeight / desiredHeight;\n        double ratio = Math.min(wr, hr);\n        float n = 1.0f;\n        while ((n * 2) <= ratio) {\n            n *= 2;\n        }\n        return (int) n;\n    }\n}\n"
  },
  {
    "path": "okgo/src/main/java/com/lzy/okgo/convert/Converter.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.okgo.convert;\n\nimport okhttp3.Response;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：2016/9/11\n * 描    述：网络数据的转换接口\n * 修订历史：\n * ================================================\n */\npublic interface Converter<T> {\n\n    /**\n     * 拿到响应后，将数据转换成需要的格式，子线程中执行，可以是耗时操作\n     *\n     * @param response 需要转换的对象\n     * @return 转换后的结果\n     * @throws Exception 转换过程发生的异常\n     */\n    T convertResponse(Response response) throws Throwable;\n}\n"
  },
  {
    "path": "okgo/src/main/java/com/lzy/okgo/convert/FileConvert.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.okgo.convert;\n\nimport android.os.Environment;\nimport android.text.TextUtils;\n\nimport com.lzy.okgo.callback.Callback;\nimport com.lzy.okgo.model.Progress;\nimport com.lzy.okgo.utils.HttpUtils;\nimport com.lzy.okgo.utils.IOUtils;\n\nimport java.io.File;\nimport java.io.FileOutputStream;\nimport java.io.InputStream;\n\nimport okhttp3.Response;\nimport okhttp3.ResponseBody;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：16/9/11\n * 描    述：字符串的转换器\n * 修订历史：\n * ================================================\n */\npublic class FileConvert implements Converter<File> {\n\n    public static final String DM_TARGET_FOLDER = File.separator + \"download\" + File.separator; //下载目标文件夹\n\n    private String folder;                  //目标文件存储的文件夹路径\n    private String fileName;                //目标文件存储的文件名\n    private Callback<File> callback;        //下载回调\n\n    public FileConvert() {\n        this(null);\n    }\n\n    public FileConvert(String fileName) {\n        this(Environment.getExternalStorageDirectory() + DM_TARGET_FOLDER, fileName);\n    }\n\n    public FileConvert(String folder, String fileName) {\n        this.folder = folder;\n        this.fileName = fileName;\n    }\n\n    public void setCallback(Callback<File> callback) {\n        this.callback = callback;\n    }\n\n    @Override\n    public File convertResponse(Response response) throws Throwable {\n        String url = response.request().url().toString();\n        if (TextUtils.isEmpty(folder)) folder = Environment.getExternalStorageDirectory() + DM_TARGET_FOLDER;\n        if (TextUtils.isEmpty(fileName)) fileName = HttpUtils.getNetFileName(response, url);\n\n        File dir = new File(folder);\n        IOUtils.createFolder(dir);\n        File file = new File(dir, fileName);\n        IOUtils.delFileOrFolder(file);\n\n        InputStream bodyStream = null;\n        byte[] buffer = new byte[8192];\n        FileOutputStream fileOutputStream = null;\n        try {\n            ResponseBody body = response.body();\n            if (body == null) return null;\n\n            bodyStream = body.byteStream();\n            Progress progress = new Progress();\n            progress.totalSize = body.contentLength();\n            progress.fileName = fileName;\n            progress.filePath = file.getAbsolutePath();\n            progress.status = Progress.LOADING;\n            progress.url = url;\n            progress.tag = url;\n\n            int len;\n            fileOutputStream = new FileOutputStream(file);\n            while ((len = bodyStream.read(buffer)) != -1) {\n                fileOutputStream.write(buffer, 0, len);\n\n                if (callback == null) continue;\n                Progress.changeProgress(progress, len, new Progress.Action() {\n                    @Override\n                    public void call(Progress progress) {\n                        onProgress(progress);\n                    }\n                });\n            }\n            fileOutputStream.flush();\n            return file;\n        } finally {\n            IOUtils.closeQuietly(bodyStream);\n            IOUtils.closeQuietly(fileOutputStream);\n        }\n    }\n\n    private void onProgress(final Progress progress) {\n        HttpUtils.runOnUiThread(new Runnable() {\n            @Override\n            public void run() {\n                callback.downloadProgress(progress);   //进度回调的方法\n            }\n        });\n    }\n}\n"
  },
  {
    "path": "okgo/src/main/java/com/lzy/okgo/convert/StringConvert.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.okgo.convert;\n\nimport okhttp3.Response;\nimport okhttp3.ResponseBody;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：16/9/11\n * 描    述：字符串的转换器\n * 修订历史：\n * ================================================\n */\npublic class StringConvert implements Converter<String> {\n\n    @Override\n    public String convertResponse(Response response) throws Throwable {\n        ResponseBody body = response.body();\n        if (body == null) return null;\n        return body.string();\n    }\n}\n"
  },
  {
    "path": "okgo/src/main/java/com/lzy/okgo/cookie/CookieJarImpl.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.okgo.cookie;\n\nimport com.lzy.okgo.cookie.store.CookieStore;\n\nimport java.util.List;\n\nimport okhttp3.Cookie;\nimport okhttp3.CookieJar;\nimport okhttp3.HttpUrl;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：2016/1/12\n * 描    述：CookieJar的实现类，默认管理了用户自己维护的cookie\n * 修订历史：\n * ================================================\n */\npublic class CookieJarImpl implements CookieJar {\n\n    private CookieStore cookieStore;\n\n    public CookieJarImpl(CookieStore cookieStore) {\n        if (cookieStore == null) {\n            throw new IllegalArgumentException(\"cookieStore can not be null!\");\n        }\n        this.cookieStore = cookieStore;\n    }\n\n    @Override\n    public synchronized void saveFromResponse(HttpUrl url, List<Cookie> cookies) {\n        cookieStore.saveCookie(url, cookies);\n    }\n\n    @Override\n    public synchronized List<Cookie> loadForRequest(HttpUrl url) {\n        return cookieStore.loadCookie(url);\n    }\n\n    public CookieStore getCookieStore() {\n        return cookieStore;\n    }\n}\n"
  },
  {
    "path": "okgo/src/main/java/com/lzy/okgo/cookie/SerializableCookie.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.okgo.cookie;\n\nimport android.content.ContentValues;\nimport android.database.Cursor;\n\nimport com.lzy.okgo.utils.OkLogger;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\nimport java.io.ObjectInputStream;\nimport java.io.ObjectOutputStream;\nimport java.io.Serializable;\nimport java.util.Locale;\n\nimport okhttp3.Cookie;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：16/9/11\n * 描    述：\n * 修订历史：\n * ================================================\n */\npublic class SerializableCookie implements Serializable {\n    private static final long serialVersionUID = 6374381323722046732L;\n\n    public static final String HOST = \"host\";\n    public static final String NAME = \"name\";\n    public static final String DOMAIN = \"domain\";\n    public static final String COOKIE = \"cookie\";\n\n    public String host;\n    public String name;\n    public String domain;\n    private transient Cookie cookie;\n    private transient Cookie clientCookie;\n\n    public SerializableCookie(String host, Cookie cookie) {\n        this.cookie = cookie;\n        this.host = host;\n        this.name = cookie.name();\n        this.domain = cookie.domain();\n    }\n\n    public Cookie getCookie() {\n        Cookie bestCookie = cookie;\n        if (clientCookie != null) {\n            bestCookie = clientCookie;\n        }\n        return bestCookie;\n    }\n\n    private void writeObject(ObjectOutputStream out) throws IOException {\n        out.defaultWriteObject();\n        out.writeObject(cookie.name());\n        out.writeObject(cookie.value());\n        out.writeLong(cookie.expiresAt());\n        out.writeObject(cookie.domain());\n        out.writeObject(cookie.path());\n        out.writeBoolean(cookie.secure());\n        out.writeBoolean(cookie.httpOnly());\n        out.writeBoolean(cookie.hostOnly());\n        out.writeBoolean(cookie.persistent());\n    }\n\n    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {\n        in.defaultReadObject();\n        String name = (String) in.readObject();\n        String value = (String) in.readObject();\n        long expiresAt = in.readLong();\n        String domain = (String) in.readObject();\n        String path = (String) in.readObject();\n        boolean secure = in.readBoolean();\n        boolean httpOnly = in.readBoolean();\n        boolean hostOnly = in.readBoolean();\n        boolean persistent = in.readBoolean();\n        Cookie.Builder builder = new Cookie.Builder();\n        builder = builder.name(name);\n        builder = builder.value(value);\n        builder = builder.expiresAt(expiresAt);\n        builder = hostOnly ? builder.hostOnlyDomain(domain) : builder.domain(domain);\n        builder = builder.path(path);\n        builder = secure ? builder.secure() : builder;\n        builder = httpOnly ? builder.httpOnly() : builder;\n        clientCookie = builder.build();\n    }\n\n    public static SerializableCookie parseCursorToBean(Cursor cursor) {\n        String host = cursor.getString(cursor.getColumnIndex(HOST));\n        byte[] cookieBytes = cursor.getBlob(cursor.getColumnIndex(COOKIE));\n        Cookie cookie = bytesToCookie(cookieBytes);\n        return new SerializableCookie(host, cookie);\n    }\n\n    public static ContentValues getContentValues(SerializableCookie serializableCookie) {\n        ContentValues values = new ContentValues();\n        values.put(SerializableCookie.HOST, serializableCookie.host);\n        values.put(SerializableCookie.NAME, serializableCookie.name);\n        values.put(SerializableCookie.DOMAIN, serializableCookie.domain);\n        values.put(SerializableCookie.COOKIE, cookieToBytes(serializableCookie.host, serializableCookie.getCookie()));\n        return values;\n    }\n\n    /**\n     * cookies 序列化成 string\n     *\n     * @param cookie 要序列化\n     * @return 序列化之后的string\n     */\n    public static String encodeCookie(String host, Cookie cookie) {\n        if (cookie == null) return null;\n        byte[] cookieBytes = cookieToBytes(host, cookie);\n        return byteArrayToHexString(cookieBytes);\n    }\n\n    public static byte[] cookieToBytes(String host, Cookie cookie) {\n        SerializableCookie serializableCookie = new SerializableCookie(host, cookie);\n        ByteArrayOutputStream os = new ByteArrayOutputStream();\n        try {\n            ObjectOutputStream outputStream = new ObjectOutputStream(os);\n            outputStream.writeObject(serializableCookie);\n        } catch (IOException e) {\n            OkLogger.printStackTrace(e);\n            return null;\n        }\n        return os.toByteArray();\n    }\n\n    /**\n     * 将字符串反序列化成cookies\n     *\n     * @param cookieString cookies string\n     * @return cookie object\n     */\n    public static Cookie decodeCookie(String cookieString) {\n        byte[] bytes = hexStringToByteArray(cookieString);\n        return bytesToCookie(bytes);\n    }\n\n    public static Cookie bytesToCookie(byte[] bytes) {\n        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);\n        Cookie cookie = null;\n        try {\n            ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream);\n            cookie = ((SerializableCookie) objectInputStream.readObject()).getCookie();\n        } catch (Exception e) {\n            OkLogger.printStackTrace(e);\n        }\n        return cookie;\n    }\n\n    /**\n     * 二进制数组转十六进制字符串\n     *\n     * @param bytes byte array to be converted\n     * @return string containing hex values\n     */\n    private static String byteArrayToHexString(byte[] bytes) {\n        StringBuilder sb = new StringBuilder(bytes.length * 2);\n        for (byte element : bytes) {\n            int v = element & 0xff;\n            if (v < 16) {\n                sb.append('0');\n            }\n            sb.append(Integer.toHexString(v));\n        }\n        return sb.toString().toUpperCase(Locale.US);\n    }\n\n    /**\n     * 十六进制字符串转二进制数组\n     *\n     * @param hexString string of hex-encoded values\n     * @return decoded byte array\n     */\n    private static byte[] hexStringToByteArray(String hexString) {\n        int len = hexString.length();\n        byte[] data = new byte[len / 2];\n        for (int i = 0; i < len; i += 2) {\n            data[i / 2] = (byte) ((Character.digit(hexString.charAt(i), 16) << 4) + Character.digit(hexString.charAt(i + 1), 16));\n        }\n        return data;\n    }\n\n    /** host, name, domain 标识一个cookie是否唯一 */\n    @Override\n    public boolean equals(Object o) {\n        if (this == o) return true;\n        if (o == null || getClass() != o.getClass()) return false;\n\n        SerializableCookie that = (SerializableCookie) o;\n\n        if (host != null ? !host.equals(that.host) : that.host != null) return false;\n        if (name != null ? !name.equals(that.name) : that.name != null) return false;\n        return domain != null ? domain.equals(that.domain) : that.domain == null;\n    }\n\n    @Override\n    public int hashCode() {\n        int result = host != null ? host.hashCode() : 0;\n        result = 31 * result + (name != null ? name.hashCode() : 0);\n        result = 31 * result + (domain != null ? domain.hashCode() : 0);\n        return result;\n    }\n}\n"
  },
  {
    "path": "okgo/src/main/java/com/lzy/okgo/cookie/store/CookieStore.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.okgo.cookie.store;\n\nimport java.util.List;\n\nimport okhttp3.Cookie;\nimport okhttp3.HttpUrl;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：2016/1/14\n * 描    述：CookieStore 的公共接口\n * 修订历史：\n * ================================================\n */\npublic interface CookieStore {\n\n    /** 保存url对应所有cookie */\n    void saveCookie(HttpUrl url, List<Cookie> cookie);\n\n    /** 保存url对应所有cookie */\n    void saveCookie(HttpUrl url, Cookie cookie);\n\n    /** 加载url所有的cookie */\n    List<Cookie> loadCookie(HttpUrl url);\n\n    /** 获取当前所有保存的cookie */\n    List<Cookie> getAllCookie();\n\n    /** 获取当前url对应的所有的cookie */\n    List<Cookie> getCookie(HttpUrl url);\n\n    /** 根据url和cookie移除对应的cookie */\n    boolean removeCookie(HttpUrl url, Cookie cookie);\n\n    /** 根据url移除所有的cookie */\n    boolean removeCookie(HttpUrl url);\n\n    /** 移除所有的cookie */\n    boolean removeAllCookie();\n}\n"
  },
  {
    "path": "okgo/src/main/java/com/lzy/okgo/cookie/store/DBCookieStore.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.okgo.cookie.store;\n\nimport android.content.Context;\n\nimport com.lzy.okgo.cookie.SerializableCookie;\nimport com.lzy.okgo.db.CookieManager;\n\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.ConcurrentHashMap;\n\nimport okhttp3.Cookie;\nimport okhttp3.HttpUrl;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：2016/1/14\n * 描    述：使用数据库 持久化存储 cookie\n * 修订历史：\n * ================================================\n */\npublic class DBCookieStore implements CookieStore {\n\n    /**\n     * 数据结构如下\n     * Url.host -> cookie1.name@cookie1.domain,cookie2.name@cookie2.domain,cookie3.name@cookie3.domain\n     * cookie_cookie1.name@cookie1.domain -> cookie1\n     * cookie_cookie2.name@cookie2.domain -> cookie2\n     */\n    private final Map<String, ConcurrentHashMap<String, Cookie>> cookies;\n\n    public DBCookieStore(Context context) {\n        CookieManager.init(context);\n        cookies = new HashMap<>();\n        List<SerializableCookie> cookieList = CookieManager.getInstance().queryAll();\n        for (SerializableCookie serializableCookie : cookieList) {\n            if (!cookies.containsKey(serializableCookie.host)) {\n                cookies.put(serializableCookie.host, new ConcurrentHashMap<String, Cookie>());\n            }\n            Cookie cookie = serializableCookie.getCookie();\n            cookies.get(serializableCookie.host).put(getCookieToken(cookie), cookie);\n        }\n    }\n\n    private String getCookieToken(Cookie cookie) {\n        return cookie.name() + \"@\" + cookie.domain();\n    }\n\n    /** 当前cookie是否过期 */\n    private static boolean isCookieExpired(Cookie cookie) {\n        return cookie.expiresAt() < System.currentTimeMillis();\n    }\n\n    /** 将url的所有Cookie保存在本地 */\n    @Override\n    public synchronized void saveCookie(HttpUrl url, List<Cookie> urlCookies) {\n        for (Cookie cookie : urlCookies) {\n            saveCookie(url, cookie);\n        }\n    }\n\n    @Override\n    public synchronized void saveCookie(HttpUrl url, Cookie cookie) {\n        if (!cookies.containsKey(url.host())) {\n            cookies.put(url.host(), new ConcurrentHashMap<String, Cookie>());\n        }\n        //当前cookie是否过期\n        if (isCookieExpired(cookie)) {\n            removeCookie(url, cookie);\n        } else {\n            //内存缓存\n            cookies.get(url.host()).put(getCookieToken(cookie), cookie);\n            //数据库缓存\n            SerializableCookie serializableCookie = new SerializableCookie(url.host(), cookie);\n            CookieManager.getInstance().replace(serializableCookie);\n        }\n    }\n\n    /** 根据当前url获取所有需要的cookie,只返回没有过期的cookie */\n    @Override\n    public synchronized List<Cookie> loadCookie(HttpUrl url) {\n        List<Cookie> ret = new ArrayList<>();\n        if (!cookies.containsKey(url.host())) return ret;\n\n        List<SerializableCookie> query = CookieManager.getInstance().query(\"host=?\", new String[]{url.host()});\n        for (SerializableCookie serializableCookie : query) {\n            Cookie cookie = serializableCookie.getCookie();\n            if (isCookieExpired(cookie)) {\n                removeCookie(url, cookie);\n            } else {\n                ret.add(cookie);\n            }\n        }\n        return ret;\n    }\n\n    /** 根据url移除当前的cookie */\n    @Override\n    public synchronized boolean removeCookie(HttpUrl url, Cookie cookie) {\n        if (!cookies.containsKey(url.host())) return false;\n        String cookieToken = getCookieToken(cookie);\n        if (!cookies.get(url.host()).containsKey(cookieToken)) return false;\n\n        //内存移除\n        cookies.get(url.host()).remove(cookieToken);\n        //数据库移除\n        String whereClause = \"host=? and name=? and domain=?\";\n        String[] whereArgs = {url.host(), cookie.name(), cookie.domain()};\n        CookieManager.getInstance().delete(whereClause, whereArgs);\n        return true;\n    }\n\n    @Override\n    public synchronized boolean removeCookie(HttpUrl url) {\n        if (!cookies.containsKey(url.host())) return false;\n\n        //内存移除\n        cookies.remove(url.host());\n        //数据库移除\n        String whereClause = \"host=?\";\n        String[] whereArgs = {url.host()};\n        CookieManager.getInstance().delete(whereClause, whereArgs);\n        return true;\n    }\n\n    @Override\n    public synchronized boolean removeAllCookie() {\n        //内存移除\n        cookies.clear();\n        //数据库移除\n        CookieManager.getInstance().deleteAll();\n        return true;\n    }\n\n    /** 获取所有的cookie */\n    @Override\n    public synchronized List<Cookie> getAllCookie() {\n        List<Cookie> ret = new ArrayList<>();\n        for (String key : cookies.keySet()) {\n            ret.addAll(cookies.get(key).values());\n        }\n        return ret;\n    }\n\n    @Override\n    public synchronized List<Cookie> getCookie(HttpUrl url) {\n        List<Cookie> ret = new ArrayList<>();\n        Map<String, Cookie> mapCookie = cookies.get(url.host());\n        if (mapCookie != null) ret.addAll(mapCookie.values());\n        return ret;\n    }\n}\n"
  },
  {
    "path": "okgo/src/main/java/com/lzy/okgo/cookie/store/MemoryCookieStore.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.okgo.cookie.store;\n\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\n\nimport okhttp3.Cookie;\nimport okhttp3.HttpUrl;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：2016/1/14\n * 描    述：Cookie 的内存管理\n * 修订历史：\n * ================================================\n */\npublic class MemoryCookieStore implements CookieStore {\n\n    private final Map<String, List<Cookie>> memoryCookies = new HashMap<>();\n\n    @Override\n    public synchronized void saveCookie(HttpUrl url, List<Cookie> cookies) {\n        List<Cookie> oldCookies = memoryCookies.get(url.host());\n        List<Cookie> needRemove = new ArrayList<>();\n        for (Cookie newCookie : cookies) {\n            for (Cookie oldCookie : oldCookies) {\n                if (newCookie.name().equals(oldCookie.name())) {\n                    needRemove.add(oldCookie);\n                }\n            }\n        }\n        oldCookies.removeAll(needRemove);\n        oldCookies.addAll(cookies);\n    }\n\n    @Override\n    public synchronized void saveCookie(HttpUrl url, Cookie cookie) {\n        List<Cookie> cookies = memoryCookies.get(url.host());\n        List<Cookie> needRemove = new ArrayList<>();\n        for (Cookie item : cookies) {\n            if (cookie.name().equals(item.name())) {\n                needRemove.add(item);\n            }\n        }\n        cookies.removeAll(needRemove);\n        cookies.add(cookie);\n    }\n\n    @Override\n    public synchronized List<Cookie> loadCookie(HttpUrl url) {\n        List<Cookie> cookies = memoryCookies.get(url.host());\n        if (cookies == null) {\n            cookies = new ArrayList<>();\n            memoryCookies.put(url.host(), cookies);\n        }\n        return cookies;\n    }\n\n    @Override\n    public synchronized List<Cookie> getAllCookie() {\n        List<Cookie> cookies = new ArrayList<>();\n        Set<String> httpUrls = memoryCookies.keySet();\n        for (String url : httpUrls) {\n            cookies.addAll(memoryCookies.get(url));\n        }\n        return cookies;\n    }\n\n    @Override\n    public List<Cookie> getCookie(HttpUrl url) {\n        List<Cookie> cookies = new ArrayList<>();\n        List<Cookie> urlCookies = memoryCookies.get(url.host());\n        if (urlCookies != null) cookies.addAll(urlCookies);\n        return cookies;\n    }\n\n    @Override\n    public synchronized boolean removeCookie(HttpUrl url, Cookie cookie) {\n        List<Cookie> cookies = memoryCookies.get(url.host());\n        return (cookie != null) && cookies.remove(cookie);\n    }\n\n    @Override\n    public synchronized boolean removeCookie(HttpUrl url) {\n        return memoryCookies.remove(url.host()) != null;\n    }\n\n    @Override\n    public synchronized boolean removeAllCookie() {\n        memoryCookies.clear();\n        return true;\n    }\n}\n"
  },
  {
    "path": "okgo/src/main/java/com/lzy/okgo/cookie/store/SPCookieStore.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.okgo.cookie.store;\n\nimport android.content.Context;\nimport android.content.SharedPreferences;\nimport android.text.TextUtils;\n\nimport com.lzy.okgo.cookie.SerializableCookie;\n\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.concurrent.ConcurrentHashMap;\n\nimport okhttp3.Cookie;\nimport okhttp3.HttpUrl;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：2016/1/14\n * 描    述：使用 SharedPreferences 持久化存储 cookie\n * 修订历史：\n * ================================================\n */\npublic class SPCookieStore implements CookieStore {\n\n    private static final String COOKIE_PREFS = \"okgo_cookie\";           //cookie使用prefs保存\n    private static final String COOKIE_NAME_PREFIX = \"cookie_\";         //cookie持久化的统一前缀\n\n    /**\n     * 数据结构如下\n     * Url.host -> cookieToken1,cookieToken2,cookieToken3\n     * cookie_cookieToken1 -> cookie1\n     * cookie_cookieToken2 -> cookie2\n     * cookie_cookieToken3 -> cookie3\n     */\n    private final Map<String, ConcurrentHashMap<String, Cookie>> cookies;\n    private final SharedPreferences cookiePrefs;\n\n    public SPCookieStore(Context context) {\n        cookiePrefs = context.getSharedPreferences(COOKIE_PREFS, Context.MODE_PRIVATE);\n        cookies = new HashMap<>();\n\n        //将持久化的cookies缓存到内存中,数据结构为 Map<Url.host, Map<CookieToken, Cookie>>\n        Map<String, ?> prefsMap = cookiePrefs.getAll();\n        for (Map.Entry<String, ?> entry : prefsMap.entrySet()) {\n            if ((entry.getValue()) != null && !entry.getKey().startsWith(COOKIE_NAME_PREFIX)) {\n                //获取url对应的所有cookie的key,用\",\"分割\n                String[] cookieNames = TextUtils.split((String) entry.getValue(), \",\");\n                for (String name : cookieNames) {\n                    //根据对应cookie的Key,从xml中获取cookie的真实值\n                    String encodedCookie = cookiePrefs.getString(COOKIE_NAME_PREFIX + name, null);\n                    if (encodedCookie != null) {\n                        Cookie decodedCookie = SerializableCookie.decodeCookie(encodedCookie);\n                        if (decodedCookie != null) {\n                            if (!cookies.containsKey(entry.getKey())) {\n                                cookies.put(entry.getKey(), new ConcurrentHashMap<String, Cookie>());\n                            }\n                            cookies.get(entry.getKey()).put(name, decodedCookie);\n                        }\n                    }\n                }\n            }\n        }\n    }\n\n    private String getCookieToken(Cookie cookie) {\n        return cookie.name() + \"@\" + cookie.domain();\n    }\n\n    /** 当前cookie是否过期 */\n    private static boolean isCookieExpired(Cookie cookie) {\n        return cookie.expiresAt() < System.currentTimeMillis();\n    }\n\n    /** 将url的所有Cookie保存在本地 */\n    @Override\n    public synchronized void saveCookie(HttpUrl url, List<Cookie> urlCookies) {\n        for (Cookie cookie : urlCookies) {\n            saveCookie(url, cookie);\n        }\n    }\n\n    @Override\n    public synchronized void saveCookie(HttpUrl url, Cookie cookie) {\n        if (!cookies.containsKey(url.host())) {\n            cookies.put(url.host(), new ConcurrentHashMap<String, Cookie>());\n        }\n        //当前cookie是否过期\n        if (isCookieExpired(cookie)) {\n            removeCookie(url, cookie);\n        } else {\n            saveCookie(url, cookie, getCookieToken(cookie));\n        }\n    }\n\n    /** 保存cookie，并将cookies持久化到本地 */\n    private void saveCookie(HttpUrl url, Cookie cookie, String cookieToken) {\n        //内存缓存\n        cookies.get(url.host()).put(cookieToken, cookie);\n        //文件缓存\n        SharedPreferences.Editor prefsWriter = cookiePrefs.edit();\n        prefsWriter.putString(url.host(), TextUtils.join(\",\", cookies.get(url.host()).keySet()));\n        prefsWriter.putString(COOKIE_NAME_PREFIX + cookieToken, SerializableCookie.encodeCookie(url.host(), cookie));\n        prefsWriter.apply();\n    }\n\n    /** 根据当前url获取所有需要的cookie,只返回没有过期的cookie */\n    @Override\n    public synchronized List<Cookie> loadCookie(HttpUrl url) {\n        List<Cookie> ret = new ArrayList<>();\n        if (!cookies.containsKey(url.host())) return ret;\n\n        Collection<Cookie> urlCookies = cookies.get(url.host()).values();\n        for (Cookie cookie : urlCookies) {\n            if (isCookieExpired(cookie)) {\n                removeCookie(url, cookie);\n            } else {\n                ret.add(cookie);\n            }\n        }\n        return ret;\n    }\n\n    /** 根据url移除当前的cookie */\n    @Override\n    public synchronized boolean removeCookie(HttpUrl url, Cookie cookie) {\n        if (!cookies.containsKey(url.host())) return false;\n        String cookieToken = getCookieToken(cookie);\n        if (!cookies.get(url.host()).containsKey(cookieToken)) return false;\n\n        //内存移除\n        cookies.get(url.host()).remove(cookieToken);\n        //文件移除\n        SharedPreferences.Editor prefsWriter = cookiePrefs.edit();\n        if (cookiePrefs.contains(COOKIE_NAME_PREFIX + cookieToken)) {\n            prefsWriter.remove(COOKIE_NAME_PREFIX + cookieToken);\n        }\n        prefsWriter.putString(url.host(), TextUtils.join(\",\", cookies.get(url.host()).keySet()));\n        prefsWriter.apply();\n        return true;\n    }\n\n    @Override\n    public synchronized boolean removeCookie(HttpUrl url) {\n        if (!cookies.containsKey(url.host())) return false;\n\n        //内存移除\n        ConcurrentHashMap<String, Cookie> urlCookie = cookies.remove(url.host());\n        //文件移除\n        Set<String> cookieTokens = urlCookie.keySet();\n        SharedPreferences.Editor prefsWriter = cookiePrefs.edit();\n        for (String cookieToken : cookieTokens) {\n            if (cookiePrefs.contains(COOKIE_NAME_PREFIX + cookieToken)) {\n                prefsWriter.remove(COOKIE_NAME_PREFIX + cookieToken);\n            }\n        }\n        prefsWriter.remove(url.host());\n        prefsWriter.apply();\n\n        return true;\n    }\n\n    @Override\n    public synchronized boolean removeAllCookie() {\n        //内存移除\n        cookies.clear();\n        //文件移除\n        SharedPreferences.Editor prefsWriter = cookiePrefs.edit();\n        prefsWriter.clear();\n        prefsWriter.apply();\n        return true;\n    }\n\n    /** 获取所有的cookie */\n    @Override\n    public synchronized List<Cookie> getAllCookie() {\n        List<Cookie> ret = new ArrayList<>();\n        for (String key : cookies.keySet()) {\n            ret.addAll(cookies.get(key).values());\n        }\n        return ret;\n    }\n\n    @Override\n    public synchronized List<Cookie> getCookie(HttpUrl url) {\n        List<Cookie> ret = new ArrayList<>();\n        Map<String, Cookie> mapCookie = cookies.get(url.host());\n        if (mapCookie != null) ret.addAll(mapCookie.values());\n        return ret;\n    }\n}\n"
  },
  {
    "path": "okgo/src/main/java/com/lzy/okgo/db/BaseDao.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.okgo.db;\n\nimport android.content.ContentValues;\nimport android.database.Cursor;\nimport android.database.sqlite.SQLiteDatabase;\nimport android.database.sqlite.SQLiteOpenHelper;\nimport android.util.Pair;\n\nimport com.lzy.okgo.utils.OkLogger;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.concurrent.locks.Lock;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：16/9/11\n * 描    述：\n * 修订历史：\n * ================================================\n */\npublic abstract class BaseDao<T> {\n\n    protected static String TAG;\n    protected Lock lock;\n    protected SQLiteOpenHelper helper;\n    protected SQLiteDatabase database;\n\n    public BaseDao(SQLiteOpenHelper helper) {\n        TAG = getClass().getSimpleName();\n        lock = DBHelper.lock;\n        this.helper = helper;\n        this.database = openWriter();\n    }\n\n    public SQLiteDatabase openReader() {\n        return helper.getReadableDatabase();\n    }\n\n    public SQLiteDatabase openWriter() {\n        return helper.getWritableDatabase();\n    }\n\n    protected final void closeDatabase(SQLiteDatabase database, Cursor cursor) {\n        if (cursor != null && !cursor.isClosed()) cursor.close();\n        if (database != null && database.isOpen()) database.close();\n    }\n\n    /** 插入一条记录 */\n    public boolean insert(T t) {\n        if (t == null) return false;\n        long start = System.currentTimeMillis();\n        lock.lock();\n        try {\n            database.beginTransaction();\n            database.insert(getTableName(), null, getContentValues(t));\n            database.setTransactionSuccessful();\n            return true;\n        } catch (Exception e) {\n            OkLogger.printStackTrace(e);\n        } finally {\n            database.endTransaction();\n            lock.unlock();\n            OkLogger.v(TAG, System.currentTimeMillis() - start + \" insertT\");\n        }\n        return false;\n    }\n\n    /** 插入一条记录 */\n    public long insert(SQLiteDatabase database, T t) {\n        return database.insert(getTableName(), null, getContentValues(t));\n    }\n\n    /** 插入多条记录 */\n    public boolean insert(List<T> ts) {\n        if (ts == null) return false;\n        long start = System.currentTimeMillis();\n        lock.lock();\n        try {\n            database.beginTransaction();\n            for (T t : ts) {\n                database.insert(getTableName(), null, getContentValues(t));\n            }\n            database.setTransactionSuccessful();\n            return true;\n        } catch (Exception e) {\n            OkLogger.printStackTrace(e);\n        } finally {\n            database.endTransaction();\n            lock.unlock();\n            OkLogger.v(TAG, System.currentTimeMillis() - start + \" insertList\");\n        }\n        return false;\n    }\n\n    public boolean insert(SQLiteDatabase database, List<T> ts) {\n        try {\n            for (T t : ts) {\n                database.insert(getTableName(), null, getContentValues(t));\n            }\n            return true;\n        } catch (Exception e) {\n            OkLogger.printStackTrace(e);\n            return false;\n        }\n    }\n\n    /** 删除所有数据 */\n    public boolean deleteAll() {\n        return delete(null, null);\n    }\n\n    /** 删除所有数据 */\n    public long deleteAll(SQLiteDatabase database) {\n        return delete(database, null, null);\n    }\n\n    /** 根据条件删除数据库中的数据 */\n    public boolean delete(String whereClause, String[] whereArgs) {\n        long start = System.currentTimeMillis();\n        lock.lock();\n        try {\n            database.beginTransaction();\n            database.delete(getTableName(), whereClause, whereArgs);\n            database.setTransactionSuccessful();\n            return true;\n        } catch (Exception e) {\n            OkLogger.printStackTrace(e);\n        } finally {\n            database.endTransaction();\n            lock.unlock();\n            OkLogger.v(TAG, System.currentTimeMillis() - start + \" delete\");\n        }\n        return false;\n    }\n\n    /** 根据条件删除数据库中的数据 */\n    public long delete(SQLiteDatabase database, String whereClause, String[] whereArgs) {\n        return database.delete(getTableName(), whereClause, whereArgs);\n    }\n\n    public boolean deleteList(List<Pair<String, String[]>> where) {\n        long start = System.currentTimeMillis();\n        lock.lock();\n        try {\n            database.beginTransaction();\n            for (Pair<String, String[]> pair : where) {\n                database.delete(getTableName(), pair.first, pair.second);\n            }\n            database.setTransactionSuccessful();\n            return true;\n        } catch (Exception e) {\n            OkLogger.printStackTrace(e);\n        } finally {\n            database.endTransaction();\n            lock.unlock();\n            OkLogger.v(TAG, System.currentTimeMillis() - start + \" deleteList\");\n        }\n        return false;\n    }\n\n    /**\n     * replace 语句有如下行为特点\n     * 1. replace语句会删除原有的一条记录， 并且插入一条新的记录来替换原记录。\n     * 2. 一般用replace语句替换一条记录的所有列， 如果在replace语句中没有指定某列， 在replace之后这列的值被置空 。\n     * 3. replace语句根据主键的值确定被替换的是哪一条记录\n     * 4. 如果执行replace语句时， 不存在要替换的记录， 那么就会插入一条新的记录。\n     * 5. replace语句不能根据where子句来定位要被替换的记录\n     * 6. 如果新插入的或替换的记录中， 有字段和表中的其他记录冲突， 那么会删除那条其他记录。\n     */\n    public boolean replace(T t) {\n        if (t == null) return false;\n        long start = System.currentTimeMillis();\n        lock.lock();\n        try {\n            database.beginTransaction();\n            database.replace(getTableName(), null, getContentValues(t));\n            database.setTransactionSuccessful();\n            return true;\n        } catch (Exception e) {\n            OkLogger.printStackTrace(e);\n        } finally {\n            database.endTransaction();\n            lock.unlock();\n            OkLogger.v(TAG, System.currentTimeMillis() - start + \" replaceT\");\n        }\n        return false;\n    }\n\n    public long replace(SQLiteDatabase database, T t) {\n        return database.replace(getTableName(), null, getContentValues(t));\n    }\n\n    public boolean replace(ContentValues contentValues) {\n        long start = System.currentTimeMillis();\n        lock.lock();\n        try {\n            database.beginTransaction();\n            database.replace(getTableName(), null, contentValues);\n            database.setTransactionSuccessful();\n            return true;\n        } catch (Exception e) {\n            OkLogger.printStackTrace(e);\n        } finally {\n            database.endTransaction();\n            lock.unlock();\n            OkLogger.v(TAG, System.currentTimeMillis() - start + \" replaceContentValues\");\n        }\n        return false;\n    }\n\n    public long replace(SQLiteDatabase database, ContentValues contentValues) {\n        return database.replace(getTableName(), null, contentValues);\n    }\n\n    public boolean replace(List<T> ts) {\n        if (ts == null) return false;\n        long start = System.currentTimeMillis();\n        lock.lock();\n        try {\n            database.beginTransaction();\n            for (T t : ts) {\n                database.replace(getTableName(), null, getContentValues(t));\n            }\n            database.setTransactionSuccessful();\n            return true;\n        } catch (Exception e) {\n            OkLogger.printStackTrace(e);\n        } finally {\n            database.endTransaction();\n            lock.unlock();\n            OkLogger.v(TAG, System.currentTimeMillis() - start + \" replaceList\");\n        }\n        return false;\n    }\n\n    public boolean replace(SQLiteDatabase database, List<T> ts) {\n        try {\n            for (T t : ts) {\n                database.replace(getTableName(), null, getContentValues(t));\n            }\n            return true;\n        } catch (Exception e) {\n            OkLogger.printStackTrace(e);\n            return false;\n        }\n    }\n\n    /** 更新一条记录 */\n    public boolean update(T t, String whereClause, String[] whereArgs) {\n        if (t == null) return false;\n        long start = System.currentTimeMillis();\n        lock.lock();\n        try {\n            database.beginTransaction();\n            database.update(getTableName(), getContentValues(t), whereClause, whereArgs);\n            database.setTransactionSuccessful();\n            return true;\n        } catch (Exception e) {\n            OkLogger.printStackTrace(e);\n        } finally {\n            database.endTransaction();\n            lock.unlock();\n            OkLogger.v(TAG, System.currentTimeMillis() - start + \" updateT\");\n        }\n        return false;\n    }\n\n    /** 更新一条记录 */\n    public long update(SQLiteDatabase database, T t, String whereClause, String[] whereArgs) {\n        return database.update(getTableName(), getContentValues(t), whereClause, whereArgs);\n    }\n\n    /** 更新一条记录 */\n    public boolean update(ContentValues contentValues, String whereClause, String[] whereArgs) {\n        long start = System.currentTimeMillis();\n        lock.lock();\n        try {\n            database.beginTransaction();\n            database.update(getTableName(), contentValues, whereClause, whereArgs);\n            database.setTransactionSuccessful();\n            return true;\n        } catch (Exception e) {\n            OkLogger.printStackTrace(e);\n        } finally {\n            database.endTransaction();\n            lock.unlock();\n            OkLogger.v(TAG, System.currentTimeMillis() - start + \" updateContentValues\");\n        }\n        return false;\n    }\n\n    /** 更新一条记录 */\n    public long update(SQLiteDatabase database, ContentValues contentValues, String whereClause, String[] whereArgs) {\n        return database.update(getTableName(), contentValues, whereClause, whereArgs);\n    }\n\n    /** 查询并返回所有对象的集合 */\n    public List<T> queryAll(SQLiteDatabase database) {\n        return query(database, null, null);\n    }\n\n    /** 按条件查询对象并返回集合 */\n    public List<T> query(SQLiteDatabase database, String selection, String[] selectionArgs) {\n        return query(database, null, selection, selectionArgs, null, null, null, null);\n    }\n\n    /** 查询满足条件的一个结果 */\n    public T queryOne(SQLiteDatabase database, String selection, String[] selectionArgs) {\n        List<T> query = query(database, null, selection, selectionArgs, null, null, null, \"1\");\n        if (query.size() > 0) return query.get(0);\n        return null;\n    }\n\n    /** 按条件查询对象并返回集合 */\n    public List<T> query(SQLiteDatabase database, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy, String limit) {\n        List<T> list = new ArrayList<>();\n        Cursor cursor = null;\n        try {\n            cursor = database.query(getTableName(), columns, selection, selectionArgs, groupBy, having, orderBy, limit);\n            while (!cursor.isClosed() && cursor.moveToNext()) {\n                list.add(parseCursorToBean(cursor));\n            }\n        } catch (Exception e) {\n            OkLogger.printStackTrace(e);\n        } finally {\n            closeDatabase(null, cursor);\n        }\n        return list;\n    }\n\n    /** 查询并返回所有对象的集合 */\n    public List<T> queryAll() {\n        return query(null, null);\n    }\n\n    /** 按条件查询对象并返回集合 */\n    public List<T> query(String selection, String[] selectionArgs) {\n        return query(null, selection, selectionArgs, null, null, null, null);\n    }\n\n    /** 查询满足条件的一个结果 */\n    public T queryOne(String selection, String[] selectionArgs) {\n        long start = System.currentTimeMillis();\n        List<T> query = query(null, selection, selectionArgs, null, null, null, \"1\");\n        OkLogger.v(TAG, System.currentTimeMillis() - start + \" queryOne\");\n        return query.size() > 0 ? query.get(0) : null;\n    }\n\n    /** 按条件查询对象并返回集合 */\n    public List<T> query(String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy, String limit) {\n        long start = System.currentTimeMillis();\n        lock.lock();\n        List<T> list = new ArrayList<>();\n        Cursor cursor = null;\n        try {\n            database.beginTransaction();\n            cursor = database.query(getTableName(), columns, selection, selectionArgs, groupBy, having, orderBy, limit);\n            while (!cursor.isClosed() && cursor.moveToNext()) {\n                list.add(parseCursorToBean(cursor));\n            }\n            database.setTransactionSuccessful();\n        } catch (Exception e) {\n            OkLogger.printStackTrace(e);\n        } finally {\n            closeDatabase(null, cursor);\n            database.endTransaction();\n            lock.unlock();\n            OkLogger.v(TAG, System.currentTimeMillis() - start + \" query\");\n        }\n        return list;\n    }\n\n    public interface Action {\n        void call(SQLiteDatabase database);\n    }\n\n    /** 用于给外界提供事物开启的模板 */\n    public void startTransaction(Action action) {\n        lock.lock();\n        try {\n            database.beginTransaction();\n            action.call(database);\n            database.setTransactionSuccessful();\n        } catch (Exception e) {\n            OkLogger.printStackTrace(e);\n        } finally {\n            database.endTransaction();\n            lock.unlock();\n        }\n    }\n\n    /** 获取对应的表名 */\n    public abstract String getTableName();\n\n    public abstract void unInit();\n\n    /** 将Cursor解析成对应的JavaBean */\n    public abstract T parseCursorToBean(Cursor cursor);\n\n    /** 需要替换的列 */\n    public abstract ContentValues getContentValues(T t);\n}\n"
  },
  {
    "path": "okgo/src/main/java/com/lzy/okgo/db/CacheManager.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.okgo.db;\n\nimport android.content.ContentValues;\nimport android.database.Cursor;\n\nimport com.lzy.okgo.cache.CacheEntity;\n\nimport java.util.List;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：16/9/11\n * 描    述：\n * 修订历史：\n * ================================================\n */\npublic class CacheManager extends BaseDao<CacheEntity<?>> {\n\n    public static CacheManager getInstance() {\n        return CacheManagerHolder.instance;\n    }\n\n    private static class CacheManagerHolder {\n        private static final CacheManager instance = new CacheManager();\n    }\n\n    private CacheManager() {\n        super(new DBHelper());\n    }\n\n    @Override\n    public CacheEntity<?> parseCursorToBean(Cursor cursor) {\n        return CacheEntity.parseCursorToBean(cursor);\n    }\n\n    @Override\n    public ContentValues getContentValues(CacheEntity<?> cacheEntity) {\n        return CacheEntity.getContentValues(cacheEntity);\n    }\n\n    @Override\n    public String getTableName() {\n        return DBHelper.TABLE_CACHE;\n    }\n\n    @Override\n    public void unInit() {\n    }\n\n    /** 根据key获取缓存 */\n    public CacheEntity<?> get(String key) {\n        if (key == null) return null;\n        List<CacheEntity<?>> cacheEntities = query(CacheEntity.KEY + \"=?\", new String[]{key});\n        return cacheEntities.size() > 0 ? cacheEntities.get(0) : null;\n    }\n\n    /** 移除一个缓存 */\n    public boolean remove(String key) {\n        if (key == null) return false;\n        return delete(CacheEntity.KEY + \"=?\", new String[]{key});\n    }\n\n    /** 返回带泛型的对象,注意必须确保泛型和对象对应才不会发生类型转换异常 */\n    @SuppressWarnings(\"unchecked\")\n    public <T> CacheEntity<T> get(String key, Class<T> clazz) {\n        return (CacheEntity<T>) get(key);\n    }\n\n    /** 获取所有缓存 */\n    public List<CacheEntity<?>> getAll() {\n        return queryAll();\n    }\n\n    /**\n     * 更新缓存，没有就创建，有就替换\n     *\n     * @param key    缓存的key\n     * @param entity 需要替换的的缓存\n     * @return 被替换的缓存\n     */\n    public <T> CacheEntity<T> replace(String key, CacheEntity<T> entity) {\n        entity.setKey(key);\n        replace(entity);\n        return entity;\n    }\n\n    /** 清空缓存 */\n    public boolean clear() {\n        return deleteAll();\n    }\n}\n"
  },
  {
    "path": "okgo/src/main/java/com/lzy/okgo/db/ColumnEntity.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.okgo.db;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：16/8/9\n * 描    述：表字段的属性\n * 修订历史：\n * ================================================\n */\npublic class ColumnEntity {\n\n    public String columnName;               //列的名字\n    public String columnType;               //列的类型\n    public String[] compositePrimaryKey;    //复合主键\n    public boolean isPrimary;               //是否是主键\n    public boolean isNotNull;               //是否不能为空\n    public boolean isAutoincrement;         //AUTOINCREMENT 是否自增\n\n    /**\n     * @param compositePrimaryKey 复合主键\n     */\n    public ColumnEntity(String... compositePrimaryKey) {\n        this.compositePrimaryKey = compositePrimaryKey;\n    }\n\n    /**\n     * @param columnName 列名\n     * @param columnType 列的数据类型\n     */\n    public ColumnEntity(String columnName, String columnType) {\n        this(columnName, columnType, false, false, false);\n    }\n\n    /**\n     * @param columnName 列名\n     * @param columnType 列的数据类型\n     * @param isPrimary  是否为主键\n     * @param isNotNull  是否不能为空\n     */\n    public ColumnEntity(String columnName, String columnType, boolean isPrimary, boolean isNotNull) {\n        this(columnName, columnType, isPrimary, isNotNull, false);\n    }\n\n    /**\n     * @param columnName      列名\n     * @param columnType      列的数据类型\n     * @param isPrimary       是否为主键\n     * @param isNotNull       是否不能为空\n     * @param isAutoincrement 是否自增\n     */\n    public ColumnEntity(String columnName, String columnType, boolean isPrimary, boolean isNotNull, boolean isAutoincrement) {\n        this.columnName = columnName;\n        this.columnType = columnType;\n        this.isPrimary = isPrimary;\n        this.isNotNull = isNotNull;\n        this.isAutoincrement = isAutoincrement;\n    }\n}\n"
  },
  {
    "path": "okgo/src/main/java/com/lzy/okgo/db/CookieManager.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.okgo.db;\n\nimport android.content.ContentValues;\nimport android.content.Context;\nimport android.database.Cursor;\n\nimport com.lzy.okgo.cookie.SerializableCookie;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：16/9/11\n * 描    述：\n * 修订历史：\n * ================================================\n */\npublic class CookieManager extends BaseDao<SerializableCookie> {\n\n    private static Context context;\n    private volatile static CookieManager instance;\n\n    public static CookieManager getInstance() {\n        if (instance == null) {\n            synchronized (CookieManager.class) {\n                if (instance == null) {\n                    instance = new CookieManager();\n                }\n            }\n        }\n        return instance;\n    }\n\n    private CookieManager() {\n        super(new DBHelper(context));\n    }\n\n    public static void init(Context ctx) {\n        context = ctx;\n    }\n\n    @Override\n    public SerializableCookie parseCursorToBean(Cursor cursor) {\n        return SerializableCookie.parseCursorToBean(cursor);\n    }\n\n    @Override\n    public ContentValues getContentValues(SerializableCookie serializableCookie) {\n        return SerializableCookie.getContentValues(serializableCookie);\n    }\n\n    @Override\n    public String getTableName() {\n        return DBHelper.TABLE_COOKIE;\n    }\n\n    @Override\n    public void unInit() {\n    }\n}\n"
  },
  {
    "path": "okgo/src/main/java/com/lzy/okgo/db/DBHelper.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.okgo.db;\n\nimport android.content.Context;\nimport android.database.sqlite.SQLiteDatabase;\nimport android.database.sqlite.SQLiteOpenHelper;\n\nimport com.lzy.okgo.OkGo;\nimport com.lzy.okgo.cache.CacheEntity;\nimport com.lzy.okgo.cookie.SerializableCookie;\nimport com.lzy.okgo.model.Progress;\n\nimport java.util.concurrent.locks.Lock;\nimport java.util.concurrent.locks.ReentrantLock;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：16/9/11\n * 描    述：\n * 修订历史：\n * ================================================\n */\nclass DBHelper extends SQLiteOpenHelper {\n\n    private static final String DB_CACHE_NAME = \"okgo.db\";\n    private static final int DB_CACHE_VERSION = 1;\n    static final String TABLE_CACHE = \"cache\";\n    static final String TABLE_COOKIE = \"cookie\";\n    static final String TABLE_DOWNLOAD = \"download\";\n    static final String TABLE_UPLOAD = \"upload\";\n\n    static final Lock lock = new ReentrantLock();\n\n    private TableEntity cacheTableEntity = new TableEntity(TABLE_CACHE);\n    private TableEntity cookieTableEntity = new TableEntity(TABLE_COOKIE);\n    private TableEntity downloadTableEntity = new TableEntity(TABLE_DOWNLOAD);\n    private TableEntity uploadTableEntity = new TableEntity(TABLE_UPLOAD);\n\n    DBHelper() {\n        this(OkGo.getInstance().getContext());\n    }\n\n    DBHelper(Context context) {\n        super(context, DB_CACHE_NAME, null, DB_CACHE_VERSION);\n\n        cacheTableEntity.addColumn(new ColumnEntity(CacheEntity.KEY, \"VARCHAR\", true, true))//\n                .addColumn(new ColumnEntity(CacheEntity.LOCAL_EXPIRE, \"INTEGER\"))//\n                .addColumn(new ColumnEntity(CacheEntity.HEAD, \"BLOB\"))//\n                .addColumn(new ColumnEntity(CacheEntity.DATA, \"BLOB\"));\n\n        cookieTableEntity.addColumn(new ColumnEntity(SerializableCookie.HOST, \"VARCHAR\"))//\n                .addColumn(new ColumnEntity(SerializableCookie.NAME, \"VARCHAR\"))//\n                .addColumn(new ColumnEntity(SerializableCookie.DOMAIN, \"VARCHAR\"))//\n                .addColumn(new ColumnEntity(SerializableCookie.COOKIE, \"BLOB\"))//\n                .addColumn(new ColumnEntity(SerializableCookie.HOST, SerializableCookie.NAME, SerializableCookie.DOMAIN));\n\n        downloadTableEntity.addColumn(new ColumnEntity(Progress.TAG, \"VARCHAR\", true, true))//\n                .addColumn(new ColumnEntity(Progress.URL, \"VARCHAR\"))//\n                .addColumn(new ColumnEntity(Progress.FOLDER, \"VARCHAR\"))//\n                .addColumn(new ColumnEntity(Progress.FILE_PATH, \"VARCHAR\"))//\n                .addColumn(new ColumnEntity(Progress.FILE_NAME, \"VARCHAR\"))//\n                .addColumn(new ColumnEntity(Progress.FRACTION, \"VARCHAR\"))//\n                .addColumn(new ColumnEntity(Progress.TOTAL_SIZE, \"INTEGER\"))//\n                .addColumn(new ColumnEntity(Progress.CURRENT_SIZE, \"INTEGER\"))//\n                .addColumn(new ColumnEntity(Progress.STATUS, \"INTEGER\"))//\n                .addColumn(new ColumnEntity(Progress.PRIORITY, \"INTEGER\"))//\n                .addColumn(new ColumnEntity(Progress.DATE, \"INTEGER\"))//\n                .addColumn(new ColumnEntity(Progress.REQUEST, \"BLOB\"))//\n                .addColumn(new ColumnEntity(Progress.EXTRA1, \"BLOB\"))//\n                .addColumn(new ColumnEntity(Progress.EXTRA2, \"BLOB\"))//\n                .addColumn(new ColumnEntity(Progress.EXTRA3, \"BLOB\"));\n\n        uploadTableEntity.addColumn(new ColumnEntity(Progress.TAG, \"VARCHAR\", true, true))//\n                .addColumn(new ColumnEntity(Progress.URL, \"VARCHAR\"))//\n                .addColumn(new ColumnEntity(Progress.FOLDER, \"VARCHAR\"))//\n                .addColumn(new ColumnEntity(Progress.FILE_PATH, \"VARCHAR\"))//\n                .addColumn(new ColumnEntity(Progress.FILE_NAME, \"VARCHAR\"))//\n                .addColumn(new ColumnEntity(Progress.FRACTION, \"VARCHAR\"))//\n                .addColumn(new ColumnEntity(Progress.TOTAL_SIZE, \"INTEGER\"))//\n                .addColumn(new ColumnEntity(Progress.CURRENT_SIZE, \"INTEGER\"))//\n                .addColumn(new ColumnEntity(Progress.STATUS, \"INTEGER\"))//\n                .addColumn(new ColumnEntity(Progress.PRIORITY, \"INTEGER\"))//\n                .addColumn(new ColumnEntity(Progress.DATE, \"INTEGER\"))//\n                .addColumn(new ColumnEntity(Progress.REQUEST, \"BLOB\"))//\n                .addColumn(new ColumnEntity(Progress.EXTRA1, \"BLOB\"))//\n                .addColumn(new ColumnEntity(Progress.EXTRA2, \"BLOB\"))//\n                .addColumn(new ColumnEntity(Progress.EXTRA3, \"BLOB\"));\n    }\n\n    @Override\n    public void onCreate(SQLiteDatabase db) {\n        db.execSQL(cacheTableEntity.buildTableString());\n        db.execSQL(cookieTableEntity.buildTableString());\n        db.execSQL(downloadTableEntity.buildTableString());\n        db.execSQL(uploadTableEntity.buildTableString());\n    }\n\n    @Override\n    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {\n        if (DBUtils.isNeedUpgradeTable(db, cacheTableEntity)) db.execSQL(\"DROP TABLE IF EXISTS \" + TABLE_CACHE);\n        if (DBUtils.isNeedUpgradeTable(db, cookieTableEntity)) db.execSQL(\"DROP TABLE IF EXISTS \" + TABLE_COOKIE);\n        if (DBUtils.isNeedUpgradeTable(db, downloadTableEntity)) db.execSQL(\"DROP TABLE IF EXISTS \" + TABLE_DOWNLOAD);\n        if (DBUtils.isNeedUpgradeTable(db, uploadTableEntity)) db.execSQL(\"DROP TABLE IF EXISTS \" + TABLE_UPLOAD);\n        onCreate(db);\n    }\n\n    @Override\n    public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) {\n        onUpgrade(db, oldVersion, newVersion);\n    }\n}\n"
  },
  {
    "path": "okgo/src/main/java/com/lzy/okgo/db/DBUtils.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.okgo.db;\n\nimport android.database.Cursor;\nimport android.database.sqlite.SQLiteDatabase;\n\nimport com.lzy.okgo.utils.OkLogger;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：2017/5/11\n * 描    述：\n * 修订历史：\n * ================================================\n */\npublic class DBUtils {\n\n    /** 是否需要升级表 */\n    public static boolean isNeedUpgradeTable(SQLiteDatabase db, TableEntity table) {\n        if (!isTableExists(db, table.tableName)) return true;\n\n        Cursor cursor = db.rawQuery(\"select * from \" + table.tableName, null);\n        if (cursor == null) return false;\n        try {\n            int columnCount = table.getColumnCount();\n            if (columnCount == cursor.getColumnCount()) {\n                for (int i = 0; i < columnCount; i++) {\n                    if (table.getColumnIndex(cursor.getColumnName(i)) == -1) {\n                        return true;\n                    }\n                }\n            } else {\n                return true;\n            }\n            return false;\n        } finally {\n            cursor.close();\n        }\n    }\n\n    /**\n     * SQLite数据库中一个特殊的名叫 SQLITE_MASTER 上执行一个SELECT查询以获得所有表的索引。每一个 SQLite 数据库都有一个叫 SQLITE_MASTER 的表， 它定义数据库的模式。\n     * SQLITE_MASTER 表看起来如下：\n     * CREATE TABLE sqlite_master (\n     * type TEXT,\n     * name TEXT,\n     * tbl_name TEXT,\n     * rootpage INTEGER,\n     * sql TEXT\n     * );\n     * 对于表来说，type 字段永远是 ‘table’，name 字段永远是表的名字。\n     */\n    public static boolean isTableExists(SQLiteDatabase db, String tableName) {\n        if (tableName == null || db == null || !db.isOpen()) return false;\n\n        Cursor cursor = null;\n        int count = 0;\n        try {\n            cursor = db.rawQuery(\"SELECT COUNT(*) FROM sqlite_master WHERE type = ? AND name = ?\", new String[]{\"table\", tableName});\n            if (!cursor.moveToFirst()) {\n                return false;\n            }\n            count = cursor.getInt(0);\n        } catch (Exception e) {\n            OkLogger.printStackTrace(e);\n        } finally {\n            if (cursor != null) cursor.close();\n        }\n        return count > 0;\n    }\n\n    public static boolean isFieldExists(SQLiteDatabase db, String tableName, String fieldName) {\n        if (tableName == null || db == null || fieldName == null || !db.isOpen()) return false;\n\n        Cursor cursor = null;\n        try {\n            cursor = db.rawQuery(\"SELECT * FROM \" + tableName + \" LIMIT 0\", null);\n            return cursor != null && cursor.getColumnIndex(fieldName) != -1;\n        } catch (Exception e) {\n            OkLogger.printStackTrace(e);\n            return false;\n        } finally {\n            if (cursor != null) {\n                cursor.close();\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "okgo/src/main/java/com/lzy/okgo/db/DownloadManager.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.okgo.db;\n\nimport android.content.ContentValues;\nimport android.database.Cursor;\n\nimport com.lzy.okgo.model.Progress;\n\nimport java.util.List;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：16/8/8\n * 描    述：\n * 修订历史：\n * ================================================\n */\npublic class DownloadManager extends BaseDao<Progress> {\n\n    private DownloadManager() {\n        super(new DBHelper());\n    }\n\n    public static DownloadManager getInstance() {\n        return DownloadManagerHolder.instance;\n    }\n\n    private static class DownloadManagerHolder {\n        private static final DownloadManager instance = new DownloadManager();\n    }\n\n    @Override\n    public Progress parseCursorToBean(Cursor cursor) {\n        return Progress.parseCursorToBean(cursor);\n    }\n\n    @Override\n    public ContentValues getContentValues(Progress progress) {\n        return Progress.buildContentValues(progress);\n    }\n\n    @Override\n    public String getTableName() {\n        return DBHelper.TABLE_DOWNLOAD;\n    }\n\n    @Override\n    public void unInit() {\n    }\n\n    /** 获取下载任务 */\n    public Progress get(String tag) {\n        return queryOne(Progress.TAG + \"=?\", new String[]{tag});\n    }\n\n    /** 移除下载任务 */\n    public void delete(String taskKey) {\n        delete(Progress.TAG + \"=?\", new String[]{taskKey});\n    }\n\n    /** 更新下载任务 */\n    public boolean update(Progress progress) {\n        return update(progress, Progress.TAG + \"=?\", new String[]{progress.tag});\n    }\n\n    /** 更新下载任务 */\n    public boolean update(ContentValues contentValues, String tag) {\n        return update(contentValues, Progress.TAG + \"=?\", new String[]{tag});\n    }\n\n    /** 获取所有下载信息 */\n    public List<Progress> getAll() {\n        return query(null, null, null, null, null, Progress.DATE + \" ASC\", null);\n    }\n\n    /** 获取所有下载信息 */\n    public List<Progress> getFinished() {\n        return query(null, \"status=?\", new String[]{Progress.FINISH + \"\"}, null, null, Progress.DATE + \" ASC\", null);\n    }\n\n    /** 获取所有下载信息 */\n    public List<Progress> getDownloading() {\n        return query(null, \"status not in(?)\", new String[]{Progress.FINISH + \"\"}, null, null, Progress.DATE + \" ASC\", null);\n    }\n\n    /** 清空下载任务 */\n    public boolean clear() {\n        return deleteAll();\n    }\n}\n"
  },
  {
    "path": "okgo/src/main/java/com/lzy/okgo/db/TableEntity.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.okgo.db;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：16/8/9\n * 描    述：表的属性\n * 修订历史：\n * ================================================\n */\npublic class TableEntity {\n\n    public String tableName;           //表名\n    private List<ColumnEntity> list;    //所有的表字段\n\n    public TableEntity(String tableName) {\n        this.tableName = tableName;\n        list = new ArrayList<>();\n    }\n\n    public TableEntity addColumn(ColumnEntity columnEntity) {\n        list.add(columnEntity);\n        return this;\n    }\n\n    /** 建表语句 */\n    public String buildTableString() {\n        StringBuilder sb = new StringBuilder(\"CREATE TABLE IF NOT EXISTS \");\n        sb.append(tableName).append('(');\n        for (ColumnEntity entity : list) {\n            if (entity.compositePrimaryKey != null) {\n                sb.append(\"PRIMARY KEY (\");\n                for (String primaryKey : entity.compositePrimaryKey) {\n                    sb.append(primaryKey).append(\",\");\n                }\n                sb.deleteCharAt(sb.length() - 1);\n                sb.append(\")\");\n            } else {\n                sb.append(entity.columnName).append(\" \").append(entity.columnType);\n                if (entity.isNotNull) {\n                    sb.append(\" NOT NULL\");\n                }\n                if (entity.isPrimary) {\n                    sb.append(\" PRIMARY KEY\");\n                }\n                if (entity.isAutoincrement) {\n                    sb.append(\" AUTOINCREMENT\");\n                }\n                sb.append(\",\");\n            }\n        }\n        if (sb.toString().endsWith(\",\")) {\n            sb.deleteCharAt(sb.length() - 1);\n        }\n        sb.append(')');\n        return sb.toString();\n    }\n\n    /**\n     * 获取数据库表中列的名字\n     *\n     * @param columnIndex 列在表中的序号\n     * @return 返回列的名字\n     */\n    public String getColumnName(int columnIndex) {\n        return list.get(columnIndex).columnName;\n    }\n\n    /** 获取数据库表中列的个数 */\n    public int getColumnCount() {\n        return list.size();\n    }\n\n    public int getColumnIndex(String columnName) {\n        int columnCount = getColumnCount();\n        for (int i = 0; i < columnCount; i++) {\n            if (list.get(i).columnName.equals(columnName)) return i;\n        }\n        return -1;\n    }\n}\n"
  },
  {
    "path": "okgo/src/main/java/com/lzy/okgo/db/UploadManager.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.okgo.db;\n\nimport android.content.ContentValues;\nimport android.database.Cursor;\n\nimport com.lzy.okgo.model.Progress;\n\nimport java.util.List;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：16/8/8\n * 描    述：\n * 修订历史：\n * ================================================\n */\npublic class UploadManager extends BaseDao<Progress> {\n\n    private UploadManager() {\n        super(new DBHelper());\n    }\n\n    public static UploadManager getInstance() {\n        return UploadManagerHolder.instance;\n    }\n\n    private static class UploadManagerHolder {\n        private static final UploadManager instance = new UploadManager();\n    }\n\n    @Override\n    public Progress parseCursorToBean(Cursor cursor) {\n        return Progress.parseCursorToBean(cursor);\n    }\n\n    @Override\n    public ContentValues getContentValues(Progress progress) {\n        return Progress.buildContentValues(progress);\n    }\n\n    @Override\n    public String getTableName() {\n        return DBHelper.TABLE_UPLOAD;\n    }\n\n    @Override\n    public void unInit() {\n    }\n\n    /** 获取上传任务 */\n    public Progress get(String tag) {\n        return queryOne(Progress.TAG + \"=?\", new String[]{tag});\n    }\n\n    /** 移除上传任务 */\n    public void delete(String taskKey) {\n        delete(Progress.TAG + \"=?\", new String[]{taskKey});\n    }\n\n    /** 更新上传任务 */\n    public boolean update(Progress progress) {\n        return update(progress, Progress.TAG + \"=?\", new String[]{progress.tag});\n    }\n\n    /** 更新上传任务 */\n    public boolean update(ContentValues contentValues, String tag) {\n        return update(contentValues, Progress.TAG + \"=?\", new String[]{tag});\n    }\n\n    /** 获取所有上传信息 */\n    public List<Progress> getAll() {\n        return query(null, null, null, null, null, Progress.DATE + \" ASC\", null);\n    }\n\n    /** 获取所有上传信息 */\n    public List<Progress> getFinished() {\n        return query(null, \"status=?\", new String[]{Progress.FINISH + \"\"}, null, null, Progress.DATE + \" ASC\", null);\n    }\n\n    /** 获取所有上传信息 */\n    public List<Progress> getUploading() {\n        return query(null, \"status not in(?)\", new String[]{Progress.FINISH + \"\"}, null, null, Progress.DATE + \" ASC\", null);\n    }\n\n    /** 清空上传任务 */\n    public boolean clear() {\n        return deleteAll();\n    }\n}\n"
  },
  {
    "path": "okgo/src/main/java/com/lzy/okgo/exception/CacheException.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.okgo.exception;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：16/8/28\n * 描    述：\n * 修订历史：\n * ================================================\n */\npublic class CacheException extends Exception {\n    private static final long serialVersionUID = 845628123701073013L;\n\n    public static CacheException NON_OR_EXPIRE(String cacheKey) {\n        return new CacheException(\"cacheKey = \" + cacheKey + \" ,can't find cache by cacheKey, or cache has expired!\");\n    }\n\n    public static CacheException NON_AND_304(String cacheKey) {\n        return new CacheException(\"the http response code is 304, but the cache with cacheKey = \" + cacheKey + \" is null or expired!\");\n    }\n\n    public CacheException(String detailMessage) {\n        super(detailMessage);\n    }\n}\n"
  },
  {
    "path": "okgo/src/main/java/com/lzy/okgo/exception/HttpException.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.okgo.exception;\n\nimport com.lzy.okgo.model.Response;\nimport com.lzy.okgo.utils.HttpUtils;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：16/8/28\n * 描    述：\n * 修订历史：\n * ================================================\n */\npublic class HttpException extends RuntimeException {\n    private static final long serialVersionUID = 8773734741709178425L;\n\n    private int code;                               //HTTP status code\n    private String message;                         //HTTP status message\n    private transient Response<?> response;         //The full HTTP response. This may be null if the exception was serialized\n\n    public HttpException(String message) {\n        super(message);\n    }\n\n    public HttpException(Response<?> response) {\n        super(getMessage(response));\n        this.code = response.code();\n        this.message = response.message();\n        this.response = response;\n    }\n\n    private static String getMessage(Response<?> response) {\n        HttpUtils.checkNotNull(response, \"response == null\");\n        return \"HTTP \" + response.code() + \" \" + response.message();\n    }\n\n    public int code() {\n        return code;\n    }\n\n    public String message() {\n        return message;\n    }\n\n    public Response<?> response() {\n        return response;\n    }\n\n    public static HttpException NET_ERROR() {\n        return new HttpException(\"network error! http response code is 404 or 5xx!\");\n    }\n\n    public static HttpException COMMON(String message) {\n        return new HttpException(message);\n    }\n}\n"
  },
  {
    "path": "okgo/src/main/java/com/lzy/okgo/exception/OkGoException.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.okgo.exception;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：16/8/28\n * 描    述：\n * 修订历史：\n * ================================================\n */\npublic class OkGoException extends Exception {\n    private static final long serialVersionUID = -8641198158155821498L;\n\n    public OkGoException(String detailMessage) {\n        super(detailMessage);\n    }\n\n    public static OkGoException UNKNOWN() {\n        return new OkGoException(\"unknown exception!\");\n    }\n\n    public static OkGoException BREAKPOINT_NOT_EXIST() {\n        return new OkGoException(\"breakpoint file does not exist!\");\n    }\n\n    public static OkGoException BREAKPOINT_EXPIRED() {\n        return new OkGoException(\"breakpoint file has expired!\");\n    }\n}\n"
  },
  {
    "path": "okgo/src/main/java/com/lzy/okgo/exception/StorageException.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.okgo.exception;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：16/9/11\n * 描    述：\n * 修订历史：\n * ================================================\n */\npublic class StorageException extends Exception {\n\n    private static final long serialVersionUID = 178946465L;\n\n    public StorageException() {\n    }\n\n    public StorageException(String detailMessage) {\n        super(detailMessage);\n    }\n\n    public StorageException(String detailMessage, Throwable throwable) {\n        super(detailMessage, throwable);\n    }\n\n    public StorageException(Throwable throwable) {\n        super(throwable);\n    }\n\n    public static StorageException NOT_AVAILABLE() {\n        return new StorageException(\"SDCard isn't available, please check SD card and permission: WRITE_EXTERNAL_STORAGE, and you must pay attention to Android6.0 RunTime Permissions!\");\n    }\n}\n"
  },
  {
    "path": "okgo/src/main/java/com/lzy/okgo/https/HttpsUtils.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.okgo.https;\n\nimport com.lzy.okgo.utils.OkLogger;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.security.KeyManagementException;\nimport java.security.KeyStore;\nimport java.security.NoSuchAlgorithmException;\nimport java.security.cert.Certificate;\nimport java.security.cert.CertificateException;\nimport java.security.cert.CertificateFactory;\nimport java.security.cert.X509Certificate;\n\nimport javax.net.ssl.HostnameVerifier;\nimport javax.net.ssl.KeyManager;\nimport javax.net.ssl.KeyManagerFactory;\nimport javax.net.ssl.SSLContext;\nimport javax.net.ssl.SSLSession;\nimport javax.net.ssl.SSLSocketFactory;\nimport javax.net.ssl.TrustManager;\nimport javax.net.ssl.TrustManagerFactory;\nimport javax.net.ssl.X509TrustManager;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：16/9/11\n * 描    述：Https相关的工具类\n * 修订历史：\n * ================================================\n */\npublic class HttpsUtils {\n\n    public static class SSLParams {\n        public SSLSocketFactory sSLSocketFactory;\n        public X509TrustManager trustManager;\n    }\n\n    public static SSLParams getSslSocketFactory() {\n        return getSslSocketFactoryBase(null, null, null);\n    }\n\n    /**\n     * https单向认证\n     * 可以额外配置信任服务端的证书策略，否则默认是按CA证书去验证的，若不是CA可信任的证书，则无法通过验证\n     */\n    public static SSLParams getSslSocketFactory(X509TrustManager trustManager) {\n        return getSslSocketFactoryBase(trustManager, null, null);\n    }\n\n    /**\n     * https单向认证\n     * 用含有服务端公钥的证书校验服务端证书\n     */\n    public static SSLParams getSslSocketFactory(InputStream... certificates) {\n        return getSslSocketFactoryBase(null, null, null, certificates);\n    }\n\n    /**\n     * https双向认证\n     * bksFile 和 password -> 客户端使用bks证书校验服务端证书\n     * certificates -> 用含有服务端公钥的证书校验服务端证书\n     */\n    public static SSLParams getSslSocketFactory(InputStream bksFile, String password, InputStream... certificates) {\n        return getSslSocketFactoryBase(null, bksFile, password, certificates);\n    }\n\n    /**\n     * https双向认证\n     * bksFile 和 password -> 客户端使用bks证书校验服务端证书\n     * X509TrustManager -> 如果需要自己校验，那么可以自己实现相关校验，如果不需要自己校验，那么传null即可\n     */\n    public static SSLParams getSslSocketFactory(InputStream bksFile, String password, X509TrustManager trustManager) {\n        return getSslSocketFactoryBase(trustManager, bksFile, password);\n    }\n\n    private static SSLParams getSslSocketFactoryBase(X509TrustManager trustManager, InputStream bksFile, String password, InputStream... certificates) {\n        SSLParams sslParams = new SSLParams();\n        try {\n            KeyManager[] keyManagers = prepareKeyManager(bksFile, password);\n            TrustManager[] trustManagers = prepareTrustManager(certificates);\n            X509TrustManager manager;\n            if (trustManager != null) {\n                //优先使用用户自定义的TrustManager\n                manager = trustManager;\n            } else if (trustManagers != null) {\n                //然后使用默认的TrustManager\n                manager = chooseTrustManager(trustManagers);\n            } else {\n                //否则使用不安全的TrustManager\n                manager = UnSafeTrustManager;\n            }\n            // 创建TLS类型的SSLContext对象， that uses our TrustManager\n            SSLContext sslContext = SSLContext.getInstance(\"TLS\");\n            // 用上面得到的trustManagers初始化SSLContext，这样sslContext就会信任keyStore中的证书\n            // 第一个参数是授权的密钥管理器，用来授权验证，比如授权自签名的证书验证。第二个是被授权的证书管理器，用来验证服务器端的证书\n            sslContext.init(keyManagers, new TrustManager[]{manager}, null);\n            // 通过sslContext获取SSLSocketFactory对象\n            sslParams.sSLSocketFactory = sslContext.getSocketFactory();\n            sslParams.trustManager = manager;\n            return sslParams;\n        } catch (NoSuchAlgorithmException e) {\n            throw new AssertionError(e);\n        } catch (KeyManagementException e) {\n            throw new AssertionError(e);\n        }\n    }\n\n    private static KeyManager[] prepareKeyManager(InputStream bksFile, String password) {\n        try {\n            if (bksFile == null || password == null) return null;\n            KeyStore clientKeyStore = KeyStore.getInstance(\"BKS\");\n            clientKeyStore.load(bksFile, password.toCharArray());\n            KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());\n            kmf.init(clientKeyStore, password.toCharArray());\n            return kmf.getKeyManagers();\n        } catch (Exception e) {\n            OkLogger.printStackTrace(e);\n        }\n        return null;\n    }\n\n    private static TrustManager[] prepareTrustManager(InputStream... certificates) {\n        if (certificates == null || certificates.length <= 0) return null;\n        try {\n            CertificateFactory certificateFactory = CertificateFactory.getInstance(\"X.509\");\n            // 创建一个默认类型的KeyStore，存储我们信任的证书\n            KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());\n            keyStore.load(null);\n            int index = 0;\n            for (InputStream certStream : certificates) {\n                String certificateAlias = Integer.toString(index++);\n                // 证书工厂根据证书文件的流生成证书 cert\n                Certificate cert = certificateFactory.generateCertificate(certStream);\n                // 将 cert 作为可信证书放入到keyStore中\n                keyStore.setCertificateEntry(certificateAlias, cert);\n                try {\n                    if (certStream != null) certStream.close();\n                } catch (IOException e) {\n                    OkLogger.printStackTrace(e);\n                }\n            }\n            //我们创建一个默认类型的TrustManagerFactory\n            TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());\n            //用我们之前的keyStore实例初始化TrustManagerFactory，这样tmf就会信任keyStore中的证书\n            tmf.init(keyStore);\n            //通过tmf获取TrustManager数组，TrustManager也会信任keyStore中的证书\n            return tmf.getTrustManagers();\n        } catch (Exception e) {\n            OkLogger.printStackTrace(e);\n        }\n        return null;\n    }\n\n    private static X509TrustManager chooseTrustManager(TrustManager[] trustManagers) {\n        for (TrustManager trustManager : trustManagers) {\n            if (trustManager instanceof X509TrustManager) {\n                return (X509TrustManager) trustManager;\n            }\n        }\n        return null;\n    }\n\n    /**\n     * 为了解决客户端不信任服务器数字证书的问题，网络上大部分的解决方案都是让客户端不对证书做任何检查，\n     * 这是一种有很大安全漏洞的办法\n     */\n    public static X509TrustManager UnSafeTrustManager = new X509TrustManager() {\n        @Override\n        public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {\n        }\n\n        @Override\n        public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {\n        }\n\n        @Override\n        public X509Certificate[] getAcceptedIssuers() {\n            return new java.security.cert.X509Certificate[]{};\n        }\n    };\n\n    /**\n     * 此类是用于主机名验证的基接口。 在握手期间，如果 URL 的主机名和服务器的标识主机名不匹配，\n     * 则验证机制可以回调此接口的实现程序来确定是否应该允许此连接。策略可以是基于证书的或依赖于其他验证方案。\n     * 当验证 URL 主机名使用的默认规则失败时使用这些回调。如果主机名是可接受的，则返回 true\n     */\n    public static HostnameVerifier UnSafeHostnameVerifier = new HostnameVerifier() {\n        @Override\n        public boolean verify(String hostname, SSLSession session) {\n            return true;\n        }\n    };\n}\n"
  },
  {
    "path": "okgo/src/main/java/com/lzy/okgo/interceptor/HttpLoggingInterceptor.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.okgo.interceptor;\n\nimport com.lzy.okgo.utils.IOUtils;\nimport com.lzy.okgo.utils.OkLogger;\n\nimport java.io.IOException;\nimport java.nio.charset.Charset;\nimport java.util.concurrent.TimeUnit;\nimport java.util.logging.Logger;\n\nimport okhttp3.Connection;\nimport okhttp3.Headers;\nimport okhttp3.Interceptor;\nimport okhttp3.MediaType;\nimport okhttp3.Protocol;\nimport okhttp3.Request;\nimport okhttp3.RequestBody;\nimport okhttp3.Response;\nimport okhttp3.ResponseBody;\nimport okhttp3.internal.http.HttpHeaders;\nimport okio.Buffer;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：2016/1/12\n * 描    述：OkHttp拦截器，主要用于打印日志\n * 修订历史：\n * ================================================\n */\npublic class HttpLoggingInterceptor implements Interceptor {\n\n    private static final Charset UTF8 = Charset.forName(\"UTF-8\");\n\n    private volatile Level printLevel = Level.NONE;\n    private java.util.logging.Level colorLevel;\n    private Logger logger;\n\n    public enum Level {\n        NONE,       //不打印log\n        BASIC,      //只打印 请求首行 和 响应首行\n        HEADERS,    //打印请求和响应的所有 Header\n        BODY        //所有数据全部打印\n    }\n\n    public HttpLoggingInterceptor(String tag) {\n        logger = Logger.getLogger(tag);\n    }\n\n    public void setPrintLevel(Level level) {\n        if (level == null) throw new NullPointerException(\"level == null. Use Level.NONE instead.\");\n        printLevel = level;\n    }\n\n    public void setColorLevel(java.util.logging.Level level) {\n        colorLevel = level;\n    }\n\n    private void log(String message) {\n        logger.log(colorLevel, message);\n    }\n\n    @Override\n    public Response intercept(Chain chain) throws IOException {\n        Request request = chain.request();\n        if (printLevel == Level.NONE) {\n            return chain.proceed(request);\n        }\n\n        //请求日志拦截\n        logForRequest(request, chain.connection());\n\n        //执行请求，计算请求时间\n        long startNs = System.nanoTime();\n        Response response;\n        try {\n            response = chain.proceed(request);\n        } catch (Exception e) {\n            log(\"<-- HTTP FAILED: \" + e);\n            throw e;\n        }\n        long tookMs = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startNs);\n\n        //响应日志拦截\n        return logForResponse(response, tookMs);\n    }\n\n    private void logForRequest(Request request, Connection connection) throws IOException {\n        boolean logBody = (printLevel == Level.BODY);\n        boolean logHeaders = (printLevel == Level.BODY || printLevel == Level.HEADERS);\n        RequestBody requestBody = request.body();\n        boolean hasRequestBody = requestBody != null;\n        Protocol protocol = connection != null ? connection.protocol() : Protocol.HTTP_1_1;\n\n        try {\n            String requestStartMessage = \"--> \" + request.method() + ' ' + request.url() + ' ' + protocol;\n            log(requestStartMessage);\n\n            if (logHeaders) {\n                if (hasRequestBody) {\n                    // Request body headers are only present when installed as a network interceptor. Force\n                    // them to be included (when available) so there values are known.\n                    if (requestBody.contentType() != null) {\n                        log(\"\\tContent-Type: \" + requestBody.contentType());\n                    }\n                    if (requestBody.contentLength() != -1) {\n                        log(\"\\tContent-Length: \" + requestBody.contentLength());\n                    }\n                }\n                Headers headers = request.headers();\n                for (int i = 0, count = headers.size(); i < count; i++) {\n                    String name = headers.name(i);\n                    // Skip headers from the request body as they are explicitly logged above.\n                    if (!\"Content-Type\".equalsIgnoreCase(name) && !\"Content-Length\".equalsIgnoreCase(name)) {\n                        log(\"\\t\" + name + \": \" + headers.value(i));\n                    }\n                }\n\n                log(\" \");\n                if (logBody && hasRequestBody) {\n                    if (isPlaintext(requestBody.contentType())) {\n                        bodyToString(request);\n                    } else {\n                        log(\"\\tbody: maybe [binary body], omitted!\");\n                    }\n                }\n            }\n        } catch (Exception e) {\n            OkLogger.printStackTrace(e);\n        } finally {\n            log(\"--> END \" + request.method());\n        }\n    }\n\n    private Response logForResponse(Response response, long tookMs) {\n        Response.Builder builder = response.newBuilder();\n        Response clone = builder.build();\n        ResponseBody responseBody = clone.body();\n        boolean logBody = (printLevel == Level.BODY);\n        boolean logHeaders = (printLevel == Level.BODY || printLevel == Level.HEADERS);\n\n        try {\n            log(\"<-- \" + clone.code() + ' ' + clone.message() + ' ' + clone.request().url() + \" (\" + tookMs + \"ms）\");\n            if (logHeaders) {\n                Headers headers = clone.headers();\n                for (int i = 0, count = headers.size(); i < count; i++) {\n                    log(\"\\t\" + headers.name(i) + \": \" + headers.value(i));\n                }\n                log(\" \");\n                if (logBody && HttpHeaders.hasBody(clone)) {\n                    if (responseBody == null) return response;\n\n                    if (isPlaintext(responseBody.contentType())) {\n                        byte[] bytes = IOUtils.toByteArray(responseBody.byteStream());\n                        MediaType contentType = responseBody.contentType();\n                        String body = new String(bytes, getCharset(contentType));\n                        log(\"\\tbody:\" + body);\n                        responseBody = ResponseBody.create(responseBody.contentType(), bytes);\n                        return response.newBuilder().body(responseBody).build();\n                    } else {\n                        log(\"\\tbody: maybe [binary body], omitted!\");\n                    }\n                }\n            }\n        } catch (Exception e) {\n            OkLogger.printStackTrace(e);\n        } finally {\n            log(\"<-- END HTTP\");\n        }\n        return response;\n    }\n\n    private static Charset getCharset(MediaType contentType) {\n        Charset charset = contentType != null ? contentType.charset(UTF8) : UTF8;\n        if (charset == null) charset = UTF8;\n        return charset;\n    }\n\n    /**\n     * Returns true if the body in question probably contains human readable text. Uses a small sample\n     * of code points to detect unicode control characters commonly used in binary file signatures.\n     */\n    private static boolean isPlaintext(MediaType mediaType) {\n        if (mediaType == null) return false;\n        if (mediaType.type() != null && mediaType.type().equals(\"text\")) {\n            return true;\n        }\n        String subtype = mediaType.subtype();\n        if (subtype != null) {\n            subtype = subtype.toLowerCase();\n            if (subtype.contains(\"x-www-form-urlencoded\") || subtype.contains(\"json\") || subtype.contains(\"xml\") || subtype.contains(\"html\")) //\n                return true;\n        }\n        return false;\n    }\n\n    private void bodyToString(Request request) {\n        try {\n            Request copy = request.newBuilder().build();\n            RequestBody body = copy.body();\n            if (body == null) return;\n            Buffer buffer = new Buffer();\n            body.writeTo(buffer);\n            Charset charset = getCharset(body.contentType());\n            log(\"\\tbody:\" + buffer.readString(charset));\n        } catch (Exception e) {\n            OkLogger.printStackTrace(e);\n        }\n    }\n}\n"
  },
  {
    "path": "okgo/src/main/java/com/lzy/okgo/model/HttpHeaders.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.okgo.model;\n\nimport android.os.Build;\nimport android.text.TextUtils;\n\nimport com.lzy.okgo.OkGo;\nimport com.lzy.okgo.utils.OkLogger;\n\nimport org.json.JSONException;\nimport org.json.JSONObject;\n\nimport java.io.Serializable;\nimport java.lang.reflect.Field;\nimport java.text.ParseException;\nimport java.text.SimpleDateFormat;\nimport java.util.Date;\nimport java.util.LinkedHashMap;\nimport java.util.Locale;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.TimeZone;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：2015/10/10\n * 描    述：请求头的包装类\n * 修订历史：\n * ================================================\n */\npublic class HttpHeaders implements Serializable {\n    private static final long serialVersionUID = 8458647755751403873L;\n\n    public static final String FORMAT_HTTP_DATA = \"EEE, dd MMM y HH:mm:ss 'GMT'\";\n    public static final TimeZone GMT_TIME_ZONE = TimeZone.getTimeZone(\"GMT\");\n\n    public static final String HEAD_KEY_RESPONSE_CODE = \"ResponseCode\";\n    public static final String HEAD_KEY_RESPONSE_MESSAGE = \"ResponseMessage\";\n    public static final String HEAD_KEY_ACCEPT = \"Accept\";\n    public static final String HEAD_KEY_ACCEPT_ENCODING = \"Accept-Encoding\";\n    public static final String HEAD_VALUE_ACCEPT_ENCODING = \"gzip, deflate\";\n    public static final String HEAD_KEY_ACCEPT_LANGUAGE = \"Accept-Language\";\n    public static final String HEAD_KEY_CONTENT_TYPE = \"Content-Type\";\n    public static final String HEAD_KEY_CONTENT_LENGTH = \"Content-Length\";\n    public static final String HEAD_KEY_CONTENT_ENCODING = \"Content-Encoding\";\n    public static final String HEAD_KEY_CONTENT_DISPOSITION = \"Content-Disposition\";\n    public static final String HEAD_KEY_CONTENT_RANGE = \"Content-Range\";\n    public static final String HEAD_KEY_RANGE = \"Range\";\n    public static final String HEAD_KEY_CACHE_CONTROL = \"Cache-Control\";\n    public static final String HEAD_KEY_CONNECTION = \"Connection\";\n    public static final String HEAD_VALUE_CONNECTION_KEEP_ALIVE = \"keep-alive\";\n    public static final String HEAD_VALUE_CONNECTION_CLOSE = \"close\";\n    public static final String HEAD_KEY_DATE = \"Date\";\n    public static final String HEAD_KEY_EXPIRES = \"Expires\";\n    public static final String HEAD_KEY_E_TAG = \"ETag\";\n    public static final String HEAD_KEY_PRAGMA = \"Pragma\";\n    public static final String HEAD_KEY_IF_MODIFIED_SINCE = \"If-Modified-Since\";\n    public static final String HEAD_KEY_IF_NONE_MATCH = \"If-None-Match\";\n    public static final String HEAD_KEY_LAST_MODIFIED = \"Last-Modified\";\n    public static final String HEAD_KEY_LOCATION = \"Location\";\n    public static final String HEAD_KEY_USER_AGENT = \"User-Agent\";\n    public static final String HEAD_KEY_COOKIE = \"Cookie\";\n    public static final String HEAD_KEY_COOKIE2 = \"Cookie2\";\n    public static final String HEAD_KEY_SET_COOKIE = \"Set-Cookie\";\n    public static final String HEAD_KEY_SET_COOKIE2 = \"Set-Cookie2\";\n\n    public LinkedHashMap<String, String> headersMap;\n    private static String acceptLanguage;\n    private static String userAgent;\n\n    private void init() {\n        headersMap = new LinkedHashMap<>();\n    }\n\n    public HttpHeaders() {\n        init();\n    }\n\n    public HttpHeaders(String key, String value) {\n        init();\n        put(key, value);\n    }\n\n    public void put(String key, String value) {\n        if (key != null && value != null) {\n            headersMap.put(key, value);\n        }\n    }\n\n    public void put(HttpHeaders headers) {\n        if (headers != null) {\n            if (headers.headersMap != null && !headers.headersMap.isEmpty()) headersMap.putAll(headers.headersMap);\n        }\n    }\n\n    public String get(String key) {\n        return headersMap.get(key);\n    }\n\n    public String remove(String key) {\n        return headersMap.remove(key);\n    }\n\n    public void clear() {\n        headersMap.clear();\n    }\n\n    public Set<String> getNames() {\n        return headersMap.keySet();\n    }\n\n    public final String toJSONString() {\n        JSONObject jsonObject = new JSONObject();\n        try {\n            for (Map.Entry<String, String> entry : headersMap.entrySet()) {\n                jsonObject.put(entry.getKey(), entry.getValue());\n            }\n        } catch (JSONException e) {\n            OkLogger.printStackTrace(e);\n        }\n        return jsonObject.toString();\n    }\n\n    public static long getDate(String gmtTime) {\n        try {\n            return parseGMTToMillis(gmtTime);\n        } catch (ParseException e) {\n            return 0;\n        }\n    }\n\n    public static String getDate(long milliseconds) {\n        return formatMillisToGMT(milliseconds);\n    }\n\n    public static long getExpiration(String expiresTime) {\n        try {\n            return parseGMTToMillis(expiresTime);\n        } catch (ParseException e) {\n            return -1;\n        }\n    }\n\n    public static long getLastModified(String lastModified) {\n        try {\n            return parseGMTToMillis(lastModified);\n        } catch (ParseException e) {\n            return 0;\n        }\n    }\n\n    public static String getCacheControl(String cacheControl, String pragma) {\n        // first http1.1, second http1.0\n        if (cacheControl != null) return cacheControl;\n        else if (pragma != null) return pragma;\n        else return null;\n    }\n\n    public static void setAcceptLanguage(String language) {\n        acceptLanguage = language;\n    }\n\n    /**\n     * Accept-Language: zh-CN,zh;q=0.8\n     */\n    public static String getAcceptLanguage() {\n        if (TextUtils.isEmpty(acceptLanguage)) {\n            Locale locale = Locale.getDefault();\n            String language = locale.getLanguage();\n            String country = locale.getCountry();\n            StringBuilder acceptLanguageBuilder = new StringBuilder(language);\n            if (!TextUtils.isEmpty(country)) acceptLanguageBuilder.append('-').append(country).append(',').append(language).append(\";q=0.8\");\n            acceptLanguage = acceptLanguageBuilder.toString();\n            return acceptLanguage;\n        }\n        return acceptLanguage;\n    }\n\n    public static void setUserAgent(String agent) {\n        userAgent = agent;\n    }\n\n    /**\n     * User-Agent: Mozilla/5.0 (Linux; U; Android 5.0.2; zh-cn; Redmi Note 3 Build/LRX22G) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Mobile Safari/537.36\n     */\n    public static String getUserAgent() {\n        if (TextUtils.isEmpty(userAgent)) {\n            String webUserAgent = null;\n            try {\n                Class<?> sysResCls = Class.forName(\"com.android.internal.R$string\");\n                Field webUserAgentField = sysResCls.getDeclaredField(\"web_user_agent\");\n                Integer resId = (Integer) webUserAgentField.get(null);\n                webUserAgent = OkGo.getInstance().getContext().getString(resId);\n            } catch (Exception e) {\n                // We have nothing to do\n            }\n            if (TextUtils.isEmpty(webUserAgent)) {\n                webUserAgent = \"okhttp-okgo/jeasonlzy\";\n            }\n\n            Locale locale = Locale.getDefault();\n            StringBuffer buffer = new StringBuffer();\n            // Add version\n            final String version = Build.VERSION.RELEASE;\n            if (version.length() > 0) {\n                buffer.append(version);\n            } else {\n                // default to \"1.0\"\n                buffer.append(\"1.0\");\n            }\n            buffer.append(\"; \");\n            final String language = locale.getLanguage();\n            if (language != null) {\n                buffer.append(language.toLowerCase(locale));\n                final String country = locale.getCountry();\n                if (!TextUtils.isEmpty(country)) {\n                    buffer.append(\"-\");\n                    buffer.append(country.toLowerCase(locale));\n                }\n            } else {\n                // default to \"en\"\n                buffer.append(\"en\");\n            }\n            // add the model for the release build\n            if (\"REL\".equals(Build.VERSION.CODENAME)) {\n                final String model = Build.MODEL;\n                if (model.length() > 0) {\n                    buffer.append(\"; \");\n                    buffer.append(model);\n                }\n            }\n            final String id = Build.ID;\n            if (id.length() > 0) {\n                buffer.append(\" Build/\");\n                buffer.append(id);\n            }\n            userAgent = String.format(webUserAgent, buffer, \"Mobile \");\n            return userAgent;\n        }\n        return userAgent;\n    }\n\n    public static long parseGMTToMillis(String gmtTime) throws ParseException {\n        if (TextUtils.isEmpty(gmtTime)) return 0;\n        SimpleDateFormat formatter = new SimpleDateFormat(FORMAT_HTTP_DATA, Locale.US);\n        formatter.setTimeZone(GMT_TIME_ZONE);\n        Date date = formatter.parse(gmtTime);\n        return date.getTime();\n    }\n\n    public static String formatMillisToGMT(long milliseconds) {\n        Date date = new Date(milliseconds);\n        SimpleDateFormat simpleDateFormat = new SimpleDateFormat(FORMAT_HTTP_DATA, Locale.US);\n        simpleDateFormat.setTimeZone(GMT_TIME_ZONE);\n        return simpleDateFormat.format(date);\n    }\n\n    @Override\n    public String toString() {\n        return \"HttpHeaders{\" + \"headersMap=\" + headersMap + '}';\n    }\n}\n"
  },
  {
    "path": "okgo/src/main/java/com/lzy/okgo/model/HttpMethod.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.okgo.model;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：2017/5/24\n * 描    述：\n * 修订历史：\n * ================================================\n */\npublic enum HttpMethod {\n    GET(\"GET\"),\n\n    POST(\"POST\"),\n\n    PUT(\"PUT\"),\n\n    DELETE(\"DELETE\"),\n\n    HEAD(\"HEAD\"),\n\n    PATCH(\"PATCH\"),\n\n    OPTIONS(\"OPTIONS\"),\n\n    TRACE(\"TRACE\");\n\n    private final String value;\n\n    HttpMethod(String value) {\n        this.value = value;\n    }\n\n    @Override\n    public String toString() {\n        return this.value;\n    }\n\n    public boolean hasBody() {\n        switch (this) {\n            case POST:\n            case PUT:\n            case PATCH:\n            case DELETE:\n            case OPTIONS:\n                return true;\n            default:\n                return false;\n        }\n    }\n}\n"
  },
  {
    "path": "okgo/src/main/java/com/lzy/okgo/model/HttpParams.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.okgo.model;\n\nimport com.lzy.okgo.utils.HttpUtils;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.ObjectInputStream;\nimport java.io.ObjectOutputStream;\nimport java.io.Serializable;\nimport java.util.ArrayList;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.ConcurrentHashMap;\n\nimport okhttp3.MediaType;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：2015/10/9\n * 描    述：请求参数的包装类，支持一个key对应多个值\n * 修订历史：\n * ================================================\n */\npublic class HttpParams implements Serializable {\n    private static final long serialVersionUID = 7369819159227055048L;\n\n    public static final MediaType MEDIA_TYPE_PLAIN = MediaType.parse(\"text/plain;charset=utf-8\");\n    public static final MediaType MEDIA_TYPE_JSON = MediaType.parse(\"application/json;charset=utf-8\");\n    public static final MediaType MEDIA_TYPE_STREAM = MediaType.parse(\"application/octet-stream\");\n\n    public static final boolean IS_REPLACE = true;\n\n    /** 普通的键值对参数 */\n    public LinkedHashMap<String, List<String>> urlParamsMap;\n\n    /** 文件的键值对参数 */\n    public LinkedHashMap<String, List<FileWrapper>> fileParamsMap;\n\n    public HttpParams() {\n        init();\n    }\n\n    public HttpParams(String key, String value) {\n        init();\n        put(key, value, IS_REPLACE);\n    }\n\n    public HttpParams(String key, File file) {\n        init();\n        put(key, file);\n    }\n\n    private void init() {\n        urlParamsMap = new LinkedHashMap<>();\n        fileParamsMap = new LinkedHashMap<>();\n    }\n\n    public void put(HttpParams params) {\n        if (params != null) {\n            if (params.urlParamsMap != null && !params.urlParamsMap.isEmpty()) urlParamsMap.putAll(params.urlParamsMap);\n            if (params.fileParamsMap != null && !params.fileParamsMap.isEmpty()) fileParamsMap.putAll(params.fileParamsMap);\n        }\n    }\n\n    public void put(Map<String, String> params, boolean... isReplace) {\n        if (params == null || params.isEmpty()) return;\n        for (Map.Entry<String, String> entry : params.entrySet()) {\n            put(entry.getKey(), entry.getValue(), isReplace);\n        }\n    }\n\n    public void put(String key, String value, boolean... isReplace) {\n        if (isReplace != null && isReplace.length > 0) {\n            put(key, value, isReplace[0]);\n        } else {\n            put(key, value, IS_REPLACE);\n        }\n    }\n\n    public void put(String key, int value, boolean... isReplace) {\n        if (isReplace != null && isReplace.length > 0) {\n            put(key, String.valueOf(value), isReplace[0]);\n        } else {\n            put(key, String.valueOf(value), IS_REPLACE);\n        }\n    }\n\n    public void put(String key, long value, boolean... isReplace) {\n        if (isReplace != null && isReplace.length > 0) {\n            put(key, String.valueOf(value), isReplace[0]);\n        } else {\n            put(key, String.valueOf(value), IS_REPLACE);\n        }\n    }\n\n    public void put(String key, float value, boolean... isReplace) {\n        if (isReplace != null && isReplace.length > 0) {\n            put(key, String.valueOf(value), isReplace[0]);\n        } else {\n            put(key, String.valueOf(value), IS_REPLACE);\n        }\n    }\n\n    public void put(String key, double value, boolean... isReplace) {\n        if (isReplace != null && isReplace.length > 0) {\n            put(key, String.valueOf(value), isReplace[0]);\n        } else {\n            put(key, String.valueOf(value), IS_REPLACE);\n        }\n    }\n\n    public void put(String key, char value, boolean... isReplace) {\n        if (isReplace != null && isReplace.length > 0) {\n            put(key, String.valueOf(value), isReplace[0]);\n        } else {\n            put(key, String.valueOf(value), IS_REPLACE);\n        }\n    }\n\n    public void put(String key, boolean value, boolean... isReplace) {\n        if (isReplace != null && isReplace.length > 0) {\n            put(key, String.valueOf(value), isReplace[0]);\n        } else {\n            put(key, String.valueOf(value), IS_REPLACE);\n        }\n    }\n\n    private void put(String key, String value, boolean isReplace) {\n        if (key != null && value != null) {\n            List<String> urlValues = urlParamsMap.get(key);\n            if (urlValues == null) {\n                urlValues = new ArrayList<>();\n                urlParamsMap.put(key, urlValues);\n            }\n            if (isReplace) urlValues.clear();\n            urlValues.add(value);\n        }\n    }\n\n    public void putUrlParams(String key, List<String> values) {\n        if (key != null && values != null && !values.isEmpty()) {\n            for (String value : values) {\n                put(key, value, false);\n            }\n        }\n    }\n\n    public void put(String key, File file) {\n        put(key, file, file.getName());\n    }\n\n    public void put(String key, File file, String fileName) {\n        put(key, file, fileName, HttpUtils.guessMimeType(fileName));\n    }\n\n    public void put(String key, FileWrapper fileWrapper) {\n        if (key != null && fileWrapper != null) {\n            put(key, fileWrapper.file, fileWrapper.fileName, fileWrapper.contentType);\n        }\n    }\n\n    public void put(String key, File file, String fileName, MediaType contentType) {\n        if (key != null) {\n            List<FileWrapper> fileWrappers = fileParamsMap.get(key);\n            if (fileWrappers == null) {\n                fileWrappers = new ArrayList<>();\n                fileParamsMap.put(key, fileWrappers);\n            }\n            fileWrappers.add(new FileWrapper(file, fileName, contentType));\n        }\n    }\n\n    public void putFileParams(String key, List<File> files) {\n        if (key != null && files != null && !files.isEmpty()) {\n            for (File file : files) {\n                put(key, file);\n            }\n        }\n    }\n\n    public void putFileWrapperParams(String key, List<FileWrapper> fileWrappers) {\n        if (key != null && fileWrappers != null && !fileWrappers.isEmpty()) {\n            for (FileWrapper fileWrapper : fileWrappers) {\n                put(key, fileWrapper);\n            }\n        }\n    }\n\n    public void removeUrl(String key) {\n        urlParamsMap.remove(key);\n    }\n\n    public void removeFile(String key) {\n        fileParamsMap.remove(key);\n    }\n\n    public void remove(String key) {\n        removeUrl(key);\n        removeFile(key);\n    }\n\n    public void clear() {\n        urlParamsMap.clear();\n        fileParamsMap.clear();\n    }\n\n    /** 文件类型的包装类 */\n    public static class FileWrapper implements Serializable {\n        private static final long serialVersionUID = -2356139899636767776L;\n\n        public File file;\n        public String fileName;\n        public transient MediaType contentType;\n        public long fileSize;\n\n        public FileWrapper(File file, String fileName, MediaType contentType) {\n            this.file = file;\n            this.fileName = fileName;\n            this.contentType = contentType;\n            this.fileSize = file.length();\n        }\n\n        private void writeObject(ObjectOutputStream out) throws IOException {\n            out.defaultWriteObject();\n            out.writeObject(contentType.toString());\n        }\n\n        private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {\n            in.defaultReadObject();\n            contentType = MediaType.parse((String) in.readObject());\n        }\n\n        @Override\n        public String toString() {\n            return \"FileWrapper{\" + //\n                   \"file=\" + file + //\n                   \", fileName=\" + fileName + //\n                   \", contentType=\" + contentType + //\n                   \", fileSize=\" + fileSize +//\n                   \"}\";\n        }\n    }\n\n    @Override\n    public String toString() {\n        StringBuilder result = new StringBuilder();\n        for (ConcurrentHashMap.Entry<String, List<String>> entry : urlParamsMap.entrySet()) {\n            if (result.length() > 0) result.append(\"&\");\n            result.append(entry.getKey()).append(\"=\").append(entry.getValue());\n        }\n        for (ConcurrentHashMap.Entry<String, List<FileWrapper>> entry : fileParamsMap.entrySet()) {\n            if (result.length() > 0) result.append(\"&\");\n            result.append(entry.getKey()).append(\"=\").append(entry.getValue());\n        }\n        return result.toString();\n    }\n}\n"
  },
  {
    "path": "okgo/src/main/java/com/lzy/okgo/model/Priority.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.okgo.model;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：2016/1/19\n * 描    述：优先级的枚举类\n * 修订历史：\n * ================================================\n */\npublic interface Priority {\n    int UI_TOP = Integer.MAX_VALUE;\n    int UI_NORMAL = 1000;\n    int UI_LOW = 100;\n    int DEFAULT = 0;\n    int BG_TOP = -100;\n    int BG_NORMAL = -1000;\n    int BG_LOW = Integer.MIN_VALUE;\n}\n"
  },
  {
    "path": "okgo/src/main/java/com/lzy/okgo/model/Progress.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.okgo.model;\n\nimport android.content.ContentValues;\nimport android.database.Cursor;\nimport android.os.SystemClock;\n\nimport com.lzy.okgo.OkGo;\nimport com.lzy.okgo.request.base.Request;\nimport com.lzy.okgo.utils.IOUtils;\n\nimport java.io.Serializable;\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：2017/6/1\n * 描    述：\n * 修订历史：\n * ================================================\n */\npublic class Progress implements Serializable {\n    private static final long serialVersionUID = 6353658567594109891L;\n\n    public static final int NONE = 0;         //无状态\n    public static final int WAITING = 1;      //等待\n    public static final int LOADING = 2;      //下载中\n    public static final int PAUSE = 3;        //暂停\n    public static final int ERROR = 4;        //错误\n    public static final int FINISH = 5;       //完成\n\n    public static final String TAG = \"tag\";\n    public static final String URL = \"url\";\n    public static final String FOLDER = \"folder\";\n    public static final String FILE_PATH = \"filePath\";\n    public static final String FILE_NAME = \"fileName\";\n    public static final String FRACTION = \"fraction\";\n    public static final String TOTAL_SIZE = \"totalSize\";\n    public static final String CURRENT_SIZE = \"currentSize\";\n    public static final String STATUS = \"status\";\n    public static final String PRIORITY = \"priority\";\n    public static final String DATE = \"date\";\n    public static final String REQUEST = \"request\";\n    public static final String EXTRA1 = \"extra1\";\n    public static final String EXTRA2 = \"extra2\";\n    public static final String EXTRA3 = \"extra3\";\n\n    public String tag;                              //下载的标识键\n    public String url;                              //网址\n    public String folder;                           //保存文件夹\n    public String filePath;                         //保存文件地址\n    public String fileName;                         //保存的文件名\n    public float fraction;                          //下载的进度，0-1\n    public long totalSize;                          //总字节长度, byte\n    public long currentSize;                        //本次下载的大小, byte\n    public transient long speed;                    //网速，byte/s\n    public int status;                              //当前状态\n    public int priority;                            //任务优先级\n    public long date;                               //创建时间\n    public Request<?, ? extends Request> request;   //网络请求\n    public Serializable extra1;                     //额外的数据\n    public Serializable extra2;                     //额外的数据\n    public Serializable extra3;                     //额外的数据\n    public Throwable exception;                     //当前进度出现的异常\n\n    private transient long tempSize;                //每一小段时间间隔的网络流量\n    private transient long lastRefreshTime;         //最后一次刷新的时间\n    private transient List<Long> speedBuffer;       //网速做平滑的缓存，避免抖动过快\n\n    public Progress() {\n        lastRefreshTime = SystemClock.elapsedRealtime();\n        totalSize = -1;\n        priority = Priority.DEFAULT;\n        date = System.currentTimeMillis();\n        speedBuffer = new ArrayList<>();\n    }\n\n    public static Progress changeProgress(Progress progress, long writeSize, Action action) {\n        return changeProgress(progress, writeSize, progress.totalSize, action);\n    }\n\n    public static Progress changeProgress(final Progress progress, long writeSize, long totalSize, final Action action) {\n        progress.totalSize = totalSize;\n        progress.currentSize += writeSize;\n        progress.tempSize += writeSize;\n\n        long currentTime = SystemClock.elapsedRealtime();\n        boolean isNotify = (currentTime - progress.lastRefreshTime) >= OkGo.REFRESH_TIME;\n        if (isNotify || progress.currentSize == totalSize) {\n            long diffTime = currentTime - progress.lastRefreshTime;\n            if (diffTime == 0) diffTime = 1;\n            progress.fraction = progress.currentSize * 1.0f / totalSize;\n            progress.speed = progress.bufferSpeed(progress.tempSize * 1000 / diffTime);\n            progress.lastRefreshTime = currentTime;\n            progress.tempSize = 0;\n            if (action != null) {\n                action.call(progress);\n            }\n        }\n        return progress;\n    }\n\n    /** 平滑网速，避免抖动过大 */\n    private long bufferSpeed(long speed) {\n        speedBuffer.add(speed);\n        if (speedBuffer.size() > 10) {\n            speedBuffer.remove(0);\n        }\n        long sum = 0;\n        for (float speedTemp : speedBuffer) {\n            sum += speedTemp;\n        }\n        return sum / speedBuffer.size();\n    }\n\n    /** 转换进度信息 */\n    public void from(Progress progress) {\n        totalSize = progress.totalSize;\n        currentSize = progress.currentSize;\n        fraction = progress.fraction;\n        speed = progress.speed;\n        lastRefreshTime = progress.lastRefreshTime;\n        tempSize = progress.tempSize;\n    }\n\n    public interface Action {\n        void call(Progress progress);\n    }\n\n    public static ContentValues buildContentValues(Progress progress) {\n        ContentValues values = new ContentValues();\n        values.put(TAG, progress.tag);\n        values.put(URL, progress.url);\n        values.put(FOLDER, progress.folder);\n        values.put(FILE_PATH, progress.filePath);\n        values.put(FILE_NAME, progress.fileName);\n        values.put(FRACTION, progress.fraction);\n        values.put(TOTAL_SIZE, progress.totalSize);\n        values.put(CURRENT_SIZE, progress.currentSize);\n        values.put(STATUS, progress.status);\n        values.put(PRIORITY, progress.priority);\n        values.put(DATE, progress.date);\n        values.put(REQUEST, IOUtils.toByteArray(progress.request));\n        values.put(EXTRA1, IOUtils.toByteArray(progress.extra1));\n        values.put(EXTRA2, IOUtils.toByteArray(progress.extra2));\n        values.put(EXTRA3, IOUtils.toByteArray(progress.extra3));\n        return values;\n    }\n\n    public static ContentValues buildUpdateContentValues(Progress progress) {\n        ContentValues values = new ContentValues();\n        values.put(FRACTION, progress.fraction);\n        values.put(TOTAL_SIZE, progress.totalSize);\n        values.put(CURRENT_SIZE, progress.currentSize);\n        values.put(STATUS, progress.status);\n        values.put(PRIORITY, progress.priority);\n        values.put(DATE, progress.date);\n        return values;\n    }\n\n    public static Progress parseCursorToBean(Cursor cursor) {\n        Progress progress = new Progress();\n        progress.tag = cursor.getString(cursor.getColumnIndex(Progress.TAG));\n        progress.url = cursor.getString(cursor.getColumnIndex(Progress.URL));\n        progress.folder = cursor.getString(cursor.getColumnIndex(Progress.FOLDER));\n        progress.filePath = cursor.getString(cursor.getColumnIndex(Progress.FILE_PATH));\n        progress.fileName = cursor.getString(cursor.getColumnIndex(Progress.FILE_NAME));\n        progress.fraction = cursor.getFloat(cursor.getColumnIndex(Progress.FRACTION));\n        progress.totalSize = cursor.getLong(cursor.getColumnIndex(Progress.TOTAL_SIZE));\n        progress.currentSize = cursor.getLong(cursor.getColumnIndex(Progress.CURRENT_SIZE));\n        progress.status = cursor.getInt(cursor.getColumnIndex(Progress.STATUS));\n        progress.priority = cursor.getInt(cursor.getColumnIndex(Progress.PRIORITY));\n        progress.date = cursor.getLong(cursor.getColumnIndex(Progress.DATE));\n        progress.request = (Request<?, ? extends Request>) IOUtils.toObject(cursor.getBlob(cursor.getColumnIndex(Progress.REQUEST)));\n        progress.extra1 = (Serializable) IOUtils.toObject(cursor.getBlob(cursor.getColumnIndex(Progress.EXTRA1)));\n        progress.extra2 = (Serializable) IOUtils.toObject(cursor.getBlob(cursor.getColumnIndex(Progress.EXTRA2)));\n        progress.extra3 = (Serializable) IOUtils.toObject(cursor.getBlob(cursor.getColumnIndex(Progress.EXTRA3)));\n        return progress;\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        if (this == o) return true;\n        if (o == null || getClass() != o.getClass()) return false;\n\n        Progress progress = (Progress) o;\n        return tag != null ? tag.equals(progress.tag) : progress.tag == null;\n\n    }\n\n    @Override\n    public int hashCode() {\n        return tag != null ? tag.hashCode() : 0;\n    }\n\n    @Override\n    public String toString() {\n        return \"Progress{\" +//\n               \"fraction=\" + fraction +//\n               \", totalSize=\" + totalSize +//\n               \", currentSize=\" + currentSize +//\n               \", speed=\" + speed +//\n               \", status=\" + status +//\n               \", priority=\" + priority +//\n               \", folder=\" + folder +//\n               \", filePath=\" + filePath +//\n               \", fileName=\" + fileName +//\n               \", tag=\" + tag +//\n               \", url=\" + url +//\n               '}';\n    }\n}\n"
  },
  {
    "path": "okgo/src/main/java/com/lzy/okgo/model/Response.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.okgo.model;\n\nimport okhttp3.Call;\nimport okhttp3.Headers;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：2016/9/11\n * 描    述：响应体的包装类\n * 修订历史：\n * ================================================\n */\npublic final class Response<T> {\n\n    private T body;\n    private Throwable throwable;\n    private boolean isFromCache;\n    private okhttp3.Call rawCall;\n    private okhttp3.Response rawResponse;\n\n    public static <T> Response<T> success(boolean isFromCache, T body, Call rawCall, okhttp3.Response rawResponse) {\n        Response<T> response = new Response<>();\n        response.setFromCache(isFromCache);\n        response.setBody(body);\n        response.setRawCall(rawCall);\n        response.setRawResponse(rawResponse);\n        return response;\n    }\n\n    public static <T> Response<T> error(boolean isFromCache, Call rawCall, okhttp3.Response rawResponse, Throwable throwable) {\n        Response<T> response = new Response<>();\n        response.setFromCache(isFromCache);\n        response.setRawCall(rawCall);\n        response.setRawResponse(rawResponse);\n        response.setException(throwable);\n        return response;\n    }\n\n    public Response() {\n    }\n\n    public int code() {\n        if (rawResponse == null) return -1;\n        return rawResponse.code();\n    }\n\n    public String message() {\n        if (rawResponse == null) return null;\n        return rawResponse.message();\n    }\n\n    public Headers headers() {\n        if (rawResponse == null) return null;\n        return rawResponse.headers();\n    }\n\n    public boolean isSuccessful() {\n        return throwable == null;\n    }\n\n    public void setBody(T body) {\n        this.body = body;\n    }\n\n    public T body() {\n        return body;\n    }\n\n    public Throwable getException() {\n        return throwable;\n    }\n\n    public void setException(Throwable exception) {\n        this.throwable = exception;\n    }\n\n    public Call getRawCall() {\n        return rawCall;\n    }\n\n    public void setRawCall(Call rawCall) {\n        this.rawCall = rawCall;\n    }\n\n    public okhttp3.Response getRawResponse() {\n        return rawResponse;\n    }\n\n    public void setRawResponse(okhttp3.Response rawResponse) {\n        this.rawResponse = rawResponse;\n    }\n\n    public boolean isFromCache() {\n        return isFromCache;\n    }\n\n    public void setFromCache(boolean fromCache) {\n        isFromCache = fromCache;\n    }\n}\n"
  },
  {
    "path": "okgo/src/main/java/com/lzy/okgo/model/Result.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.okgo.model;\n\nimport java.io.IOException;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：16/9/11\n * 描    述：\n * 修订历史：\n * ================================================\n */\npublic final class Result<T> {\n    @SuppressWarnings(\"ConstantConditions\") // Guarding public API nullability.\n    public static <T> Result<T> error(Throwable error) {\n        if (error == null) throw new NullPointerException(\"error == null\");\n        return new Result<>(null, error);\n    }\n\n    @SuppressWarnings(\"ConstantConditions\") // Guarding public API nullability.\n    public static <T> Result<T> response(Response<T> response) {\n        if (response == null) throw new NullPointerException(\"response == null\");\n        return new Result<>(response, null);\n    }\n\n    private final Response<T> response;\n    private final Throwable error;\n\n    private Result(Response<T> response, Throwable error) {\n        this.response = response;\n        this.error = error;\n    }\n\n    /**\n     * The response received from executing an HTTP request. Only present when {@link #isError()} is\n     * false, null otherwise.\n     */\n\n    public Response<T> response() {\n        return response;\n    }\n\n    /**\n     * The error experienced while attempting to execute an HTTP request. Only present when {@link\n     * #isError()} is true, null otherwise.\n     * If the error is an {@link IOException} then there was a problem with the transport to the\n     * remote server. Any other exception type indicates an unexpected failure and should be\n     * considered fatal (configuration error, programming error, etc.).\n     */\n\n    public Throwable error() {\n        return error;\n    }\n\n    /** {@code true} if the request resulted in an error. See {@link #error()} for the cause. */\n    public boolean isError() {\n        return error != null;\n    }\n\n    @Override\n    public String toString() {\n        if (error != null) {\n            return \"Result{isError=true, error=\\\"\" + error + \"\\\"}\";\n        }\n        return \"Result{isError=false, response=\" + response + '}';\n    }\n}\n"
  },
  {
    "path": "okgo/src/main/java/com/lzy/okgo/request/DeleteRequest.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.okgo.request;\n\nimport com.lzy.okgo.model.HttpMethod;\nimport com.lzy.okgo.request.base.BodyRequest;\n\nimport okhttp3.Request;\nimport okhttp3.RequestBody;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：2016/1/16\n * 描    述：\n * 修订历史：\n * ================================================\n */\npublic class DeleteRequest<T> extends BodyRequest<T, DeleteRequest<T>> {\n\n    public DeleteRequest(String url) {\n        super(url);\n    }\n\n    @Override\n    public HttpMethod getMethod() {\n        return HttpMethod.DELETE;\n    }\n\n    @Override\n    public Request generateRequest(RequestBody requestBody) {\n        Request.Builder requestBuilder = generateRequestBuilder(requestBody);\n        return requestBuilder.delete(requestBody).url(url).tag(tag).build();\n    }\n}\n"
  },
  {
    "path": "okgo/src/main/java/com/lzy/okgo/request/GetRequest.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.okgo.request;\n\nimport com.lzy.okgo.model.HttpMethod;\nimport com.lzy.okgo.request.base.NoBodyRequest;\n\nimport okhttp3.Request;\nimport okhttp3.RequestBody;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：2016/1/12\n * 描    述：Get请求的实现类，注意需要传入本类的泛型\n * 修订历史：\n * ================================================\n */\npublic class GetRequest<T> extends NoBodyRequest<T, GetRequest<T>> {\n\n    public GetRequest(String url) {\n        super(url);\n    }\n\n    @Override\n    public HttpMethod getMethod() {\n        return HttpMethod.GET;\n    }\n\n    @Override\n    public okhttp3.Request generateRequest(RequestBody requestBody) {\n        Request.Builder requestBuilder = generateRequestBuilder(requestBody);\n        return requestBuilder.get().url(url).tag(tag).build();\n    }\n}\n"
  },
  {
    "path": "okgo/src/main/java/com/lzy/okgo/request/HeadRequest.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.okgo.request;\n\nimport com.lzy.okgo.model.HttpMethod;\nimport com.lzy.okgo.request.base.NoBodyRequest;\n\nimport okhttp3.Request;\nimport okhttp3.RequestBody;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：2016/1/16\n * 描    述：\n * 修订历史：\n * ================================================\n */\npublic class HeadRequest<T> extends NoBodyRequest<T, HeadRequest<T>> {\n\n    public HeadRequest(String url) {\n        super(url);\n    }\n\n    @Override\n    public HttpMethod getMethod() {\n        return HttpMethod.HEAD;\n    }\n\n    @Override\n    public okhttp3.Request generateRequest(RequestBody requestBody) {\n        Request.Builder requestBuilder = generateRequestBuilder(requestBody);\n        return requestBuilder.head().url(url).tag(tag).build();\n    }\n}\n"
  },
  {
    "path": "okgo/src/main/java/com/lzy/okgo/request/OptionsRequest.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.okgo.request;\n\nimport com.lzy.okgo.model.HttpMethod;\nimport com.lzy.okgo.request.base.BodyRequest;\n\nimport okhttp3.Request;\nimport okhttp3.RequestBody;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：2016/1/16\n * 描    述：Options请求\n * 修订历史：\n * ================================================\n */\npublic class OptionsRequest<T> extends BodyRequest<T, OptionsRequest<T>> {\n\n    public OptionsRequest(String url) {\n        super(url);\n    }\n\n    @Override\n    public HttpMethod getMethod() {\n        return HttpMethod.OPTIONS;\n    }\n\n    @Override\n    public Request generateRequest(RequestBody requestBody) {\n        Request.Builder requestBuilder = generateRequestBuilder(requestBody);\n        return requestBuilder.method(\"OPTIONS\", requestBody).url(url).tag(tag).build();\n    }\n}\n"
  },
  {
    "path": "okgo/src/main/java/com/lzy/okgo/request/PatchRequest.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.okgo.request;\n\nimport com.lzy.okgo.model.HttpMethod;\nimport com.lzy.okgo.request.base.BodyRequest;\n\nimport okhttp3.Request;\nimport okhttp3.RequestBody;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：2016/1/16\n * 描    述：\n * 修订历史：\n * ================================================\n */\npublic class PatchRequest<T> extends BodyRequest<T, PatchRequest<T>> {\n\n    public PatchRequest(String url) {\n        super(url);\n    }\n\n    @Override\n    public HttpMethod getMethod() {\n        return HttpMethod.PATCH;\n    }\n\n    @Override\n    public Request generateRequest(RequestBody requestBody) {\n        Request.Builder requestBuilder = generateRequestBuilder(requestBody);\n        return requestBuilder.patch(requestBody).url(url).tag(tag).build();\n    }\n}\n"
  },
  {
    "path": "okgo/src/main/java/com/lzy/okgo/request/PostRequest.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.okgo.request;\n\nimport com.lzy.okgo.model.HttpMethod;\nimport com.lzy.okgo.request.base.BodyRequest;\n\nimport okhttp3.Request;\nimport okhttp3.RequestBody;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：2016/1/12\n * 描    述：Post请求的实现类，注意需要传入本类的泛型\n * 修订历史：\n * ================================================\n */\npublic class PostRequest<T> extends BodyRequest<T, PostRequest<T>> {\n\n    public PostRequest(String url) {\n        super(url);\n    }\n\n    @Override\n    public HttpMethod getMethod() {\n        return HttpMethod.POST;\n    }\n\n    @Override\n    public Request generateRequest(RequestBody requestBody) {\n        Request.Builder requestBuilder = generateRequestBuilder(requestBody);\n        return requestBuilder.post(requestBody).url(url).tag(tag).build();\n    }\n}\n"
  },
  {
    "path": "okgo/src/main/java/com/lzy/okgo/request/PutRequest.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.okgo.request;\n\nimport com.lzy.okgo.model.HttpMethod;\nimport com.lzy.okgo.request.base.BodyRequest;\n\nimport okhttp3.Request;\nimport okhttp3.RequestBody;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：2016/1/16\n * 描    述：\n * 修订历史：\n * ================================================\n */\npublic class PutRequest<T> extends BodyRequest<T, PutRequest<T>> {\n\n    public PutRequest(String url) {\n        super(url);\n    }\n\n    @Override\n    public HttpMethod getMethod() {\n        return HttpMethod.PUT;\n    }\n\n    @Override\n    public Request generateRequest(RequestBody requestBody) {\n        Request.Builder requestBuilder = generateRequestBuilder(requestBody);\n        return requestBuilder.put(requestBody).url(url).tag(tag).build();\n    }\n}\n"
  },
  {
    "path": "okgo/src/main/java/com/lzy/okgo/request/TraceRequest.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.okgo.request;\n\nimport com.lzy.okgo.model.HttpMethod;\nimport com.lzy.okgo.request.base.NoBodyRequest;\n\nimport okhttp3.Request;\nimport okhttp3.RequestBody;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：2016/1/12\n * 描    述：Trace请求的实现类，注意需要传入本类的泛型\n * 修订历史：\n * ================================================\n */\npublic class TraceRequest<T> extends NoBodyRequest<T, TraceRequest<T>> {\n\n    public TraceRequest(String url) {\n        super(url);\n    }\n\n    @Override\n    public HttpMethod getMethod() {\n        return HttpMethod.TRACE;\n    }\n\n    @Override\n    public okhttp3.Request generateRequest(RequestBody requestBody) {\n        Request.Builder requestBuilder = generateRequestBuilder(requestBody);\n        return requestBuilder.method(\"TRACE\", requestBody).url(url).tag(tag).build();\n    }\n}\n"
  },
  {
    "path": "okgo/src/main/java/com/lzy/okgo/request/base/BodyRequest.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.okgo.request.base;\n\nimport android.text.TextUtils;\n\nimport com.lzy.okgo.model.HttpHeaders;\nimport com.lzy.okgo.model.HttpParams;\nimport com.lzy.okgo.utils.HttpUtils;\nimport com.lzy.okgo.utils.OkLogger;\n\nimport org.json.JSONArray;\nimport org.json.JSONObject;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.ObjectInputStream;\nimport java.io.ObjectOutputStream;\nimport java.util.List;\n\nimport okhttp3.MediaType;\nimport okhttp3.RequestBody;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：16/8/9\n * 描    述：\n * 修订历史：\n * ================================================\n */\npublic abstract class BodyRequest<T, R extends BodyRequest> extends Request<T, R> implements HasBody<R> {\n    private static final long serialVersionUID = -6459175248476927501L;\n\n    protected transient MediaType mediaType;        //上传的MIME类型\n    protected String content;                       //上传的文本内容\n    protected byte[] bs;                            //上传的字节数据\n    protected transient File file;                  //单纯的上传一个文件\n\n    protected boolean isMultipart = false;  //是否强制使用 multipart/form-data 表单上传\n    protected boolean isSpliceUrl = false;  //是否拼接url参数\n    protected RequestBody requestBody;\n\n    public BodyRequest(String url) {\n        super(url);\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    @Override\n    public R isMultipart(boolean isMultipart) {\n        this.isMultipart = isMultipart;\n        return (R) this;\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    @Override\n    public R isSpliceUrl(boolean isSpliceUrl) {\n        this.isSpliceUrl = isSpliceUrl;\n        return (R) this;\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    @Override\n    public R params(String key, File file) {\n        params.put(key, file);\n        return (R) this;\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    @Override\n    public R addFileParams(String key, List<File> files) {\n        params.putFileParams(key, files);\n        return (R) this;\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    @Override\n    public R addFileWrapperParams(String key, List<HttpParams.FileWrapper> fileWrappers) {\n        params.putFileWrapperParams(key, fileWrappers);\n        return (R) this;\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    @Override\n    public R params(String key, File file, String fileName) {\n        params.put(key, file, fileName);\n        return (R) this;\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    @Override\n    public R params(String key, File file, String fileName, MediaType contentType) {\n        params.put(key, file, fileName, contentType);\n        return (R) this;\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    @Override\n    public R upRequestBody(RequestBody requestBody) {\n        this.requestBody = requestBody;\n        return (R) this;\n    }\n\n    /** 注意使用该方法上传字符串会清空实体中其他所有的参数，头信息不清除 */\n    @SuppressWarnings(\"unchecked\")\n    @Override\n    public R upString(String string) {\n        this.content = string;\n        this.mediaType = HttpParams.MEDIA_TYPE_PLAIN;\n        return (R) this;\n    }\n\n    /**\n     * 注意使用该方法上传字符串会清空实体中其他所有的参数，头信息不清除\n     * 该方法用于定制请求content-type\n     */\n    @SuppressWarnings(\"unchecked\")\n    @Override\n    public R upString(String string, MediaType mediaType) {\n        this.content = string;\n        this.mediaType = mediaType;\n        return (R) this;\n    }\n\n    /** 注意使用该方法上传字符串会清空实体中其他所有的参数，头信息不清除 */\n    @SuppressWarnings(\"unchecked\")\n    @Override\n    public R upJson(String json) {\n        this.content = json;\n        this.mediaType = HttpParams.MEDIA_TYPE_JSON;\n        return (R) this;\n    }\n\n    /** 注意使用该方法上传字符串会清空实体中其他所有的参数，头信息不清除 */\n    @SuppressWarnings(\"unchecked\")\n    @Override\n    public R upJson(JSONObject jsonObject) {\n        this.content = jsonObject.toString();\n        this.mediaType = HttpParams.MEDIA_TYPE_JSON;\n        return (R) this;\n    }\n\n    /** 注意使用该方法上传字符串会清空实体中其他所有的参数，头信息不清除 */\n    @SuppressWarnings(\"unchecked\")\n    @Override\n    public R upJson(JSONArray jsonArray) {\n        this.content = jsonArray.toString();\n        this.mediaType = HttpParams.MEDIA_TYPE_JSON;\n        return (R) this;\n    }\n\n    /** 注意使用该方法上传字符串会清空实体中其他所有的参数，头信息不清除 */\n    @SuppressWarnings(\"unchecked\")\n    @Override\n    public R upBytes(byte[] bs) {\n        this.bs = bs;\n        this.mediaType = HttpParams.MEDIA_TYPE_STREAM;\n        return (R) this;\n    }\n\n    /** 注意使用该方法上传字符串会清空实体中其他所有的参数，头信息不清除 */\n    @SuppressWarnings(\"unchecked\")\n    @Override\n    public R upBytes(byte[] bs, MediaType mediaType) {\n        this.bs = bs;\n        this.mediaType = mediaType;\n        return (R) this;\n    }\n\n    /** 注意使用该方法上传字符串会清空实体中其他所有的参数，头信息不清除 */\n    @SuppressWarnings(\"unchecked\")\n    @Override\n    public R upFile(File file) {\n        this.file = file;\n        this.mediaType = HttpUtils.guessMimeType(file.getName());\n        return (R) this;\n    }\n\n    /** 注意使用该方法上传字符串会清空实体中其他所有的参数，头信息不清除 */\n    @SuppressWarnings(\"unchecked\")\n    @Override\n    public R upFile(File file, MediaType mediaType) {\n        this.file = file;\n        this.mediaType = mediaType;\n        return (R) this;\n    }\n\n    @Override\n    public RequestBody generateRequestBody() {\n        if (isSpliceUrl) url = HttpUtils.createUrlFromParams(baseUrl, params.urlParamsMap);\n\n        if (requestBody != null) return requestBody;                                                //自定义的请求体\n        if (content != null && mediaType != null) return RequestBody.create(mediaType, content);    //上传字符串数据\n        if (bs != null && mediaType != null) return RequestBody.create(mediaType, bs);              //上传字节数组\n        if (file != null && mediaType != null) return RequestBody.create(mediaType, file);          //上传一个文件\n        return HttpUtils.generateMultipartRequestBody(params, isMultipart);\n    }\n\n    protected okhttp3.Request.Builder generateRequestBuilder(RequestBody requestBody) {\n        try {\n            headers(HttpHeaders.HEAD_KEY_CONTENT_LENGTH, String.valueOf(requestBody.contentLength()));\n        } catch (IOException e) {\n            OkLogger.printStackTrace(e);\n        }\n        okhttp3.Request.Builder requestBuilder = new okhttp3.Request.Builder();\n        return HttpUtils.appendHeaders(requestBuilder, headers);\n    }\n\n    private void writeObject(ObjectOutputStream out) throws IOException {\n        out.defaultWriteObject();\n        out.writeObject(mediaType == null ? \"\" : mediaType.toString());\n    }\n\n    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {\n        in.defaultReadObject();\n        String mediaTypeString = (String) in.readObject();\n        if (!TextUtils.isEmpty(mediaTypeString)) {\n            mediaType = MediaType.parse(mediaTypeString);\n        }\n    }\n}\n"
  },
  {
    "path": "okgo/src/main/java/com/lzy/okgo/request/base/HasBody.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.okgo.request.base;\n\nimport com.lzy.okgo.model.HttpParams;\n\nimport org.json.JSONArray;\nimport org.json.JSONObject;\n\nimport java.io.File;\nimport java.util.List;\n\nimport okhttp3.MediaType;\nimport okhttp3.RequestBody;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：16/8/9\n * 描    述：表示当前请求是否具有请求体\n * 修订历史：\n * ================================================\n */\npublic interface HasBody<R> {\n\n    R isMultipart(boolean isMultipart);\n\n    R isSpliceUrl(boolean isSpliceUrl);\n\n    R upRequestBody(RequestBody requestBody);\n\n    R params(String key, File file);\n\n    R addFileParams(String key, List<File> files);\n\n    R addFileWrapperParams(String key, List<HttpParams.FileWrapper> fileWrappers);\n\n    R params(String key, File file, String fileName);\n\n    R params(String key, File file, String fileName, MediaType contentType);\n\n    R upString(String string);\n\n    R upString(String string, MediaType mediaType);\n\n    R upJson(String json);\n\n    R upJson(JSONObject jsonObject);\n\n    R upJson(JSONArray jsonArray);\n\n    R upBytes(byte[] bs);\n\n    R upBytes(byte[] bs, MediaType mediaType);\n\n    R upFile(File file);\n\n    R upFile(File file, MediaType mediaType);\n}\n"
  },
  {
    "path": "okgo/src/main/java/com/lzy/okgo/request/base/NoBodyRequest.java",
    "content": "package com.lzy.okgo.request.base;\n\nimport com.lzy.okgo.utils.HttpUtils;\n\nimport okhttp3.RequestBody;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：2017/6/21\n * 描    述：\n * 修订历史：\n * ================================================\n */\npublic abstract class NoBodyRequest<T, R extends NoBodyRequest> extends Request<T, R> {\n    private static final long serialVersionUID = 1200621102761691196L;\n\n    public NoBodyRequest(String url) {\n        super(url);\n    }\n\n    @Override\n    public RequestBody generateRequestBody() {\n        return null;\n    }\n\n    protected okhttp3.Request.Builder generateRequestBuilder(RequestBody requestBody) {\n        url = HttpUtils.createUrlFromParams(baseUrl, params.urlParamsMap);\n        okhttp3.Request.Builder requestBuilder = new okhttp3.Request.Builder();\n        return HttpUtils.appendHeaders(requestBuilder, headers);\n    }\n}\n"
  },
  {
    "path": "okgo/src/main/java/com/lzy/okgo/request/base/ProgressRequestBody.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.okgo.request.base;\n\nimport com.lzy.okgo.callback.Callback;\nimport com.lzy.okgo.model.Progress;\nimport com.lzy.okgo.utils.HttpUtils;\nimport com.lzy.okgo.utils.OkLogger;\n\nimport java.io.IOException;\n\nimport okhttp3.MediaType;\nimport okhttp3.RequestBody;\nimport okio.Buffer;\nimport okio.BufferedSink;\nimport okio.ForwardingSink;\nimport okio.Okio;\nimport okio.Sink;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：16/9/11\n * 描    述：包装的请求体，处理进度，可以处理任何的 RequestBody，\n * 修订历史：\n * ================================================\n */\npublic class ProgressRequestBody<T> extends RequestBody {\n\n    private RequestBody requestBody;         //实际的待包装请求体\n    private Callback<T> callback;\n    private UploadInterceptor interceptor;\n\n    ProgressRequestBody(RequestBody requestBody, Callback<T> callback) {\n        this.requestBody = requestBody;\n        this.callback = callback;\n    }\n\n    /** 重写调用实际的响应体的contentType */\n    @Override\n    public MediaType contentType() {\n        return requestBody.contentType();\n    }\n\n    /** 重写调用实际的响应体的contentLength */\n    @Override\n    public long contentLength() {\n        try {\n            return requestBody.contentLength();\n        } catch (IOException e) {\n            OkLogger.printStackTrace(e);\n            return -1;\n        }\n    }\n\n    /** 重写进行写入 */\n    @Override\n    public void writeTo(BufferedSink sink) throws IOException {\n        CountingSink countingSink = new CountingSink(sink);\n        BufferedSink bufferedSink = Okio.buffer(countingSink);\n        requestBody.writeTo(bufferedSink);\n        bufferedSink.flush();\n    }\n\n    /** 包装 */\n    private final class CountingSink extends ForwardingSink {\n\n        private Progress progress;\n\n        CountingSink(Sink delegate) {\n            super(delegate);\n            progress = new Progress();\n            progress.totalSize = contentLength();\n        }\n\n        @Override\n        public void write(Buffer source, long byteCount) throws IOException {\n            super.write(source, byteCount);\n\n            Progress.changeProgress(progress, byteCount, new Progress.Action() {\n                @Override\n                public void call(Progress progress) {\n                    if (interceptor != null) {\n                        interceptor.uploadProgress(progress);\n                    } else {\n                        onProgress(progress);\n                    }\n                }\n            });\n        }\n    }\n\n    private void onProgress(final Progress progress) {\n        HttpUtils.runOnUiThread(new Runnable() {\n            @Override\n            public void run() {\n                if (callback != null) {\n                    callback.uploadProgress(progress);\n                }\n            }\n        });\n    }\n\n    public void setInterceptor(UploadInterceptor interceptor) {\n        this.interceptor = interceptor;\n    }\n\n    public interface UploadInterceptor {\n        void uploadProgress(Progress progress);\n    }\n}\n"
  },
  {
    "path": "okgo/src/main/java/com/lzy/okgo/request/base/Request.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.okgo.request.base;\n\nimport android.text.TextUtils;\n\nimport com.lzy.okgo.OkGo;\nimport com.lzy.okgo.adapter.AdapterParam;\nimport com.lzy.okgo.adapter.CacheCall;\nimport com.lzy.okgo.adapter.Call;\nimport com.lzy.okgo.adapter.CallAdapter;\nimport com.lzy.okgo.cache.CacheEntity;\nimport com.lzy.okgo.cache.CacheMode;\nimport com.lzy.okgo.cache.policy.CachePolicy;\nimport com.lzy.okgo.callback.Callback;\nimport com.lzy.okgo.convert.Converter;\nimport com.lzy.okgo.model.HttpHeaders;\nimport com.lzy.okgo.model.HttpMethod;\nimport com.lzy.okgo.model.HttpParams;\nimport com.lzy.okgo.utils.HttpUtils;\n\nimport java.io.IOException;\nimport java.io.Serializable;\nimport java.util.List;\nimport java.util.Map;\n\nimport okhttp3.OkHttpClient;\nimport okhttp3.RequestBody;\nimport okhttp3.Response;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：2016/1/12\n * 描    述：所有请求的基类，其中泛型 R 主要用于属性设置方法后，返回对应的子类型，以便于实现链式调用\n * 修订历史：\n * ================================================\n */\npublic abstract class Request<T, R extends Request> implements Serializable {\n    private static final long serialVersionUID = -7174118653689916252L;\n\n    protected String url;\n    protected String baseUrl;\n    protected transient OkHttpClient client;\n    protected transient Object tag;\n    protected int retryCount;\n    protected CacheMode cacheMode;\n    protected String cacheKey;\n    protected long cacheTime;                           //默认缓存的超时时间\n    protected HttpParams params = new HttpParams();     //添加的param\n    protected HttpHeaders headers = new HttpHeaders();  //添加的header\n\n    protected transient okhttp3.Request mRequest;\n    protected transient Call<T> call;\n    protected transient Callback<T> callback;\n    protected transient Converter<T> converter;\n    protected transient CachePolicy<T> cachePolicy;\n    protected transient ProgressRequestBody.UploadInterceptor uploadInterceptor;\n\n    public Request(String url) {\n        this.url = url;\n        baseUrl = url;\n        OkGo go = OkGo.getInstance();\n        //默认添加 Accept-Language\n        String acceptLanguage = HttpHeaders.getAcceptLanguage();\n        if (!TextUtils.isEmpty(acceptLanguage)) headers(HttpHeaders.HEAD_KEY_ACCEPT_LANGUAGE, acceptLanguage);\n        //默认添加 User-Agent\n        String userAgent = HttpHeaders.getUserAgent();\n        if (!TextUtils.isEmpty(userAgent)) headers(HttpHeaders.HEAD_KEY_USER_AGENT, userAgent);\n        //添加公共请求参数\n        if (go.getCommonParams() != null) params(go.getCommonParams());\n        if (go.getCommonHeaders() != null) headers(go.getCommonHeaders());\n        //添加缓存模式\n        retryCount = go.getRetryCount();\n        cacheMode = go.getCacheMode();\n        cacheTime = go.getCacheTime();\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    public R tag(Object tag) {\n        this.tag = tag;\n        return (R) this;\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    public R retryCount(int retryCount) {\n        if (retryCount < 0) throw new IllegalArgumentException(\"retryCount must > 0\");\n        this.retryCount = retryCount;\n        return (R) this;\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    public R client(OkHttpClient client) {\n        HttpUtils.checkNotNull(client, \"OkHttpClient == null\");\n\n        this.client = client;\n        return (R) this;\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    public R call(Call<T> call) {\n        HttpUtils.checkNotNull(call, \"call == null\");\n\n        this.call = call;\n        return (R) this;\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    public R converter(Converter<T> converter) {\n        HttpUtils.checkNotNull(converter, \"converter == null\");\n\n        this.converter = converter;\n        return (R) this;\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    public R cacheMode(CacheMode cacheMode) {\n        this.cacheMode = cacheMode;\n        return (R) this;\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    public R cachePolicy(CachePolicy<T> cachePolicy) {\n        HttpUtils.checkNotNull(cachePolicy, \"cachePolicy == null\");\n\n        this.cachePolicy = cachePolicy;\n        return (R) this;\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    public R cacheKey(String cacheKey) {\n        HttpUtils.checkNotNull(cacheKey, \"cacheKey == null\");\n\n        this.cacheKey = cacheKey;\n        return (R) this;\n    }\n\n    /** 传入 -1 表示永久有效,默认值即为 -1 */\n    @SuppressWarnings(\"unchecked\")\n    public R cacheTime(long cacheTime) {\n        if (cacheTime <= -1) cacheTime = CacheEntity.CACHE_NEVER_EXPIRE;\n        this.cacheTime = cacheTime;\n        return (R) this;\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    public R headers(HttpHeaders headers) {\n        this.headers.put(headers);\n        return (R) this;\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    public R headers(String key, String value) {\n        headers.put(key, value);\n        return (R) this;\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    public R removeHeader(String key) {\n        headers.remove(key);\n        return (R) this;\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    public R removeAllHeaders() {\n        headers.clear();\n        return (R) this;\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    public R params(HttpParams params) {\n        this.params.put(params);\n        return (R) this;\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    public R params(Map<String, String> params, boolean... isReplace) {\n        this.params.put(params, isReplace);\n        return (R) this;\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    public R params(String key, String value, boolean... isReplace) {\n        params.put(key, value, isReplace);\n        return (R) this;\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    public R params(String key, int value, boolean... isReplace) {\n        params.put(key, value, isReplace);\n        return (R) this;\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    public R params(String key, float value, boolean... isReplace) {\n        params.put(key, value, isReplace);\n        return (R) this;\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    public R params(String key, double value, boolean... isReplace) {\n        params.put(key, value, isReplace);\n        return (R) this;\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    public R params(String key, long value, boolean... isReplace) {\n        params.put(key, value, isReplace);\n        return (R) this;\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    public R params(String key, char value, boolean... isReplace) {\n        params.put(key, value, isReplace);\n        return (R) this;\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    public R params(String key, boolean value, boolean... isReplace) {\n        params.put(key, value, isReplace);\n        return (R) this;\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    public R addUrlParams(String key, List<String> values) {\n        params.putUrlParams(key, values);\n        return (R) this;\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    public R removeParam(String key) {\n        params.remove(key);\n        return (R) this;\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    public R removeAllParams() {\n        params.clear();\n        return (R) this;\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    public R uploadInterceptor(ProgressRequestBody.UploadInterceptor uploadInterceptor) {\n        this.uploadInterceptor = uploadInterceptor;\n        return (R) this;\n    }\n\n    /** 默认返回第一个参数 */\n    public String getUrlParam(String key) {\n        List<String> values = params.urlParamsMap.get(key);\n        if (values != null && values.size() > 0) return values.get(0);\n        return null;\n    }\n\n    /** 默认返回第一个参数 */\n    public HttpParams.FileWrapper getFileParam(String key) {\n        List<HttpParams.FileWrapper> values = params.fileParamsMap.get(key);\n        if (values != null && values.size() > 0) return values.get(0);\n        return null;\n    }\n\n    public HttpParams getParams() {\n        return params;\n    }\n\n    public HttpHeaders getHeaders() {\n        return headers;\n    }\n\n    public String getUrl() {\n        return url;\n    }\n\n    public String getBaseUrl() {\n        return baseUrl;\n    }\n\n    public Object getTag() {\n        return tag;\n    }\n\n    public CacheMode getCacheMode() {\n        return cacheMode;\n    }\n\n    public CachePolicy<T> getCachePolicy() {\n        return cachePolicy;\n    }\n\n    public String getCacheKey() {\n        return cacheKey;\n    }\n\n    public long getCacheTime() {\n        return cacheTime;\n    }\n\n    public int getRetryCount() {\n        return retryCount;\n    }\n\n    public okhttp3.Request getRequest() {\n        return mRequest;\n    }\n\n    public void setCallback(Callback<T> callback) {\n        this.callback = callback;\n    }\n\n    public Converter<T> getConverter() {\n        // converter 优先级高于 callback\n        if (converter == null) converter = callback;\n        HttpUtils.checkNotNull(converter, \"converter == null, do you forget to call Request#converter(Converter<T>) ?\");\n        return converter;\n    }\n\n    public abstract HttpMethod getMethod();\n\n    /** 根据不同的请求方式和参数，生成不同的RequestBody */\n    protected abstract RequestBody generateRequestBody();\n\n    /** 根据不同的请求方式，将RequestBody转换成Request对象 */\n    public abstract okhttp3.Request generateRequest(RequestBody requestBody);\n\n    /** 获取okhttp的同步call对象 */\n    public okhttp3.Call getRawCall() {\n        //构建请求体，返回call对象\n        RequestBody requestBody = generateRequestBody();\n        if (requestBody != null) {\n            ProgressRequestBody<T> progressRequestBody = new ProgressRequestBody<>(requestBody, callback);\n            progressRequestBody.setInterceptor(uploadInterceptor);\n            mRequest = generateRequest(progressRequestBody);\n        } else {\n            mRequest = generateRequest(null);\n        }\n        if (client == null) client = OkGo.getInstance().getOkHttpClient();\n        return client.newCall(mRequest);\n    }\n\n    /** Rx支持，获取同步call对象 */\n    public Call<T> adapt() {\n        if (call == null) {\n            return new CacheCall<>(this);\n        } else {\n            return call;\n        }\n    }\n\n    /** Rx支持,获取同步call对象 */\n    public <E> E adapt(CallAdapter<T, E> adapter) {\n        Call<T> innerCall = call;\n        if (innerCall == null) {\n            innerCall = new CacheCall<>(this);\n        }\n        return adapter.adapt(innerCall, null);\n    }\n\n    /** Rx支持,获取同步call对象 */\n    public <E> E adapt(AdapterParam param, CallAdapter<T, E> adapter) {\n        Call<T> innerCall = call;\n        if (innerCall == null) {\n            innerCall = new CacheCall<>(this);\n        }\n        return adapter.adapt(innerCall, param);\n    }\n\n    /** 普通调用，阻塞方法，同步请求执行 */\n    public Response execute() throws IOException {\n        return getRawCall().execute();\n    }\n\n    /** 非阻塞方法，异步请求，但是回调在子线程中执行 */\n    public void execute(Callback<T> callback) {\n        HttpUtils.checkNotNull(callback, \"callback == null\");\n\n        this.callback = callback;\n        Call<T> call = adapt();\n        call.execute(callback);\n    }\n}\n"
  },
  {
    "path": "okgo/src/main/java/com/lzy/okgo/utils/HeaderParser.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.okgo.utils;\n\nimport android.text.TextUtils;\n\nimport com.lzy.okgo.cache.CacheEntity;\nimport com.lzy.okgo.cache.CacheMode;\nimport com.lzy.okgo.model.HttpHeaders;\nimport com.lzy.okgo.request.base.Request;\n\nimport java.util.Locale;\nimport java.util.StringTokenizer;\n\nimport okhttp3.Headers;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）\n * 版    本：1.0\n * 创建日期：2016/4/8\n * 描    述：我的Github地址  https://github.com/jeasonlzy\n * 修订历史：\n * ================================================\n */\npublic class HeaderParser {\n    /**\n     * 根据请求结果生成对应的缓存实体类，以下为缓存相关的响应头\n     * Cache-Control: public                             响应被缓存，并且在多用户间共享\n     * Cache-Control: private                            响应只能作为私有缓存，不能在用户之间共享\n     * Cache-Control: no-cache                           提醒浏览器要从服务器提取文档进行验证\n     * Cache-Control: no-store                           绝对禁止缓存（用于机密，敏感文件）\n     * Cache-Control: max-age=60                         60秒之后缓存过期（相对时间）,优先级比Expires高\n     * Date: Mon, 19 Nov 2012 08:39:00 GMT               当前response发送的时间\n     * Expires: Mon, 19 Nov 2012 08:40:01 GMT            缓存过期的时间（绝对时间）\n     * Last-Modified: Mon, 19 Nov 2012 08:38:01 GMT      服务器端文件的最后修改时间\n     * ETag: \"20b1add7ec1cd1:0\"                          服务器端文件的ETag值\n     * 如果同时存在cache-control和Expires，浏览器总是优先使用cache-control\n     *\n     * @param responseHeaders 返回数据中的响应头\n     * @param data            解析出来的数据\n     * @param cacheMode       缓存的模式\n     * @param cacheKey        缓存的key\n     * @return 缓存的实体类\n     */\n    public static <T> CacheEntity<T> createCacheEntity(Headers responseHeaders, T data, CacheMode cacheMode, String cacheKey) {\n\n        long localExpire = 0;   // 缓存相对于本地的到期时间\n\n        if (cacheMode == CacheMode.DEFAULT) {\n            long date = HttpHeaders.getDate(responseHeaders.get(HttpHeaders.HEAD_KEY_DATE));\n            long expires = HttpHeaders.getExpiration(responseHeaders.get(HttpHeaders.HEAD_KEY_EXPIRES));\n            String cacheControl = HttpHeaders.getCacheControl(responseHeaders.get(HttpHeaders.HEAD_KEY_CACHE_CONTROL), responseHeaders.get(HttpHeaders.HEAD_KEY_PRAGMA));\n\n            //没有缓存头控制，不需要缓存\n            if (TextUtils.isEmpty(cacheControl) && expires <= 0) return null;\n\n            long maxAge = 0;\n            if (!TextUtils.isEmpty(cacheControl)) {\n                StringTokenizer tokens = new StringTokenizer(cacheControl, \",\");\n                while (tokens.hasMoreTokens()) {\n                    String token = tokens.nextToken().trim().toLowerCase(Locale.getDefault());\n                    if (token.equals(\"no-cache\") || token.equals(\"no-store\")) {\n                        //服务器指定不缓存\n                        return null;\n                    } else if (token.startsWith(\"max-age=\")) {\n                        try {\n                            //获取最大缓存时间\n                            maxAge = Long.parseLong(token.substring(8));\n                            //服务器缓存设置立马过期，不缓存\n                            if (maxAge <= 0) return null;\n                        } catch (Exception e) {\n                            OkLogger.printStackTrace(e);\n                        }\n                    }\n                }\n            }\n\n            //获取基准缓存时间，优先使用response中的date头，如果没有就使用本地时间\n            long now = System.currentTimeMillis();\n            if (date > 0) now = date;\n\n            if (maxAge > 0) {\n                // Http1.1 优先验证 Cache-Control 头\n                localExpire = now + maxAge * 1000;\n            } else if (expires >= 0) {\n                // Http1.0 验证 Expires 头\n                localExpire = expires;\n            }\n        } else {\n            localExpire = System.currentTimeMillis();\n        }\n\n        //将response中所有的头存入 HttpHeaders，原因是写入数据库的对象需要实现序列化，而ok默认的Header没有序列化\n        HttpHeaders headers = new HttpHeaders();\n        for (String headerName : responseHeaders.names()) {\n            headers.put(headerName, responseHeaders.get(headerName));\n        }\n\n        //构建缓存实体对象\n        CacheEntity<T> cacheEntity = new CacheEntity<>();\n        cacheEntity.setKey(cacheKey);\n        cacheEntity.setData(data);\n        cacheEntity.setLocalExpire(localExpire);\n        cacheEntity.setResponseHeaders(headers);\n        return cacheEntity;\n    }\n\n    /**\n     * 对每个请求添加默认的请求头，如果有缓存，并返回缓存实体对象\n     * Cache-Control: max-age=0                            以秒为单位\n     * If-Modified-Since: Mon, 19 Nov 2012 08:38:01 GMT    缓存文件的最后修改时间。\n     * If-None-Match: \"0693f67a67cc1:0\"                    缓存文件的ETag值\n     * Cache-Control: no-cache                             不使用缓存\n     * Pragma: no-cache                                    不使用缓存\n     * Accept-Language: zh-CN,zh;q=0.8                     支持的语言\n     * User-Agent:                                         用户代理，它的信息包括硬件平台、系统软件、应用软件和用户个人偏好\n     * Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.101 Safari/537.36\n     *\n     * @param request     请求类\n     * @param cacheEntity 缓存实体类\n     * @param cacheMode   缓存模式\n     */\n    public static <T> void addCacheHeaders(Request request, CacheEntity<T> cacheEntity, CacheMode cacheMode) {\n        //1. 按照标准的 http 协议，添加304相关请求头\n        if (cacheEntity != null && cacheMode == CacheMode.DEFAULT) {\n            HttpHeaders responseHeaders = cacheEntity.getResponseHeaders();\n            if (responseHeaders != null) {\n                String eTag = responseHeaders.get(HttpHeaders.HEAD_KEY_E_TAG);\n                if (eTag != null) request.headers(HttpHeaders.HEAD_KEY_IF_NONE_MATCH, eTag);\n                long lastModified = HttpHeaders.getLastModified(responseHeaders.get(HttpHeaders.HEAD_KEY_LAST_MODIFIED));\n                if (lastModified > 0) request.headers(HttpHeaders.HEAD_KEY_IF_MODIFIED_SINCE, HttpHeaders.formatMillisToGMT(lastModified));\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "okgo/src/main/java/com/lzy/okgo/utils/HttpUtils.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.okgo.utils;\n\nimport android.text.TextUtils;\n\nimport com.lzy.okgo.OkGo;\nimport com.lzy.okgo.model.HttpHeaders;\nimport com.lzy.okgo.model.HttpParams;\n\nimport java.io.File;\nimport java.io.UnsupportedEncodingException;\nimport java.net.FileNameMap;\nimport java.net.URLConnection;\nimport java.net.URLDecoder;\nimport java.net.URLEncoder;\nimport java.util.List;\nimport java.util.Map;\n\nimport okhttp3.FormBody;\nimport okhttp3.Headers;\nimport okhttp3.MediaType;\nimport okhttp3.MultipartBody;\nimport okhttp3.Request;\nimport okhttp3.RequestBody;\nimport okhttp3.Response;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：16/8/9\n * 描    述：\n * 修订历史：\n * ================================================\n */\npublic class HttpUtils {\n    /** 将传递进来的参数拼接成 url */\n    public static String createUrlFromParams(String url, Map<String, List<String>> params) {\n        try {\n            StringBuilder sb = new StringBuilder();\n            sb.append(url);\n            if (url.indexOf('&') > 0 || url.indexOf('?') > 0) sb.append(\"&\");\n            else sb.append(\"?\");\n            for (Map.Entry<String, List<String>> urlParams : params.entrySet()) {\n                List<String> urlValues = urlParams.getValue();\n                for (String value : urlValues) {\n                    //对参数进行 utf-8 编码,防止头信息传中文\n                    String urlValue = URLEncoder.encode(value, \"UTF-8\");\n                    sb.append(urlParams.getKey()).append(\"=\").append(urlValue).append(\"&\");\n                }\n            }\n            sb.deleteCharAt(sb.length() - 1);\n            return sb.toString();\n        } catch (UnsupportedEncodingException e) {\n            OkLogger.printStackTrace(e);\n        }\n        return url;\n    }\n\n    /** 通用的拼接请求头 */\n    public static Request.Builder appendHeaders(Request.Builder builder, HttpHeaders headers) {\n        if (headers.headersMap.isEmpty()) return builder;\n        Headers.Builder headerBuilder = new Headers.Builder();\n        try {\n            for (Map.Entry<String, String> entry : headers.headersMap.entrySet()) {\n                //对头信息进行 utf-8 编码,防止头信息传中文,这里暂时不编码,可能出现未知问题,如有需要自行编码\n//                String headerValue = URLEncoder.encode(entry.getValue(), \"UTF-8\");\n                headerBuilder.add(entry.getKey(), entry.getValue());\n            }\n        } catch (Exception e) {\n            OkLogger.printStackTrace(e);\n        }\n        builder.headers(headerBuilder.build());\n        return builder;\n    }\n\n    /** 生成类似表单的请求体 */\n    public static RequestBody generateMultipartRequestBody(HttpParams params, boolean isMultipart) {\n        if (params.fileParamsMap.isEmpty() && !isMultipart) {\n            //表单提交，没有文件\n            FormBody.Builder bodyBuilder = new FormBody.Builder();\n            for (String key : params.urlParamsMap.keySet()) {\n                List<String> urlValues = params.urlParamsMap.get(key);\n                for (String value : urlValues) {\n                    bodyBuilder.addEncoded(key, value);\n                }\n            }\n            return bodyBuilder.build();\n        } else {\n            //表单提交，有文件\n            MultipartBody.Builder multipartBodybuilder = new MultipartBody.Builder().setType(MultipartBody.FORM);\n            //拼接键值对\n            if (!params.urlParamsMap.isEmpty()) {\n                for (Map.Entry<String, List<String>> entry : params.urlParamsMap.entrySet()) {\n                    List<String> urlValues = entry.getValue();\n                    for (String value : urlValues) {\n                        multipartBodybuilder.addFormDataPart(entry.getKey(), value);\n                    }\n                }\n            }\n            //拼接文件\n            for (Map.Entry<String, List<HttpParams.FileWrapper>> entry : params.fileParamsMap.entrySet()) {\n                List<HttpParams.FileWrapper> fileValues = entry.getValue();\n                for (HttpParams.FileWrapper fileWrapper : fileValues) {\n                    RequestBody fileBody = RequestBody.create(fileWrapper.contentType, fileWrapper.file);\n                    multipartBodybuilder.addFormDataPart(entry.getKey(), fileWrapper.fileName, fileBody);\n                }\n            }\n            return multipartBodybuilder.build();\n        }\n    }\n\n    /** 根据响应头或者url获取文件名 */\n    public static String getNetFileName(Response response, String url) {\n        String fileName = getHeaderFileName(response);\n        if (TextUtils.isEmpty(fileName)) fileName = getUrlFileName(url);\n        if (TextUtils.isEmpty(fileName)) fileName = \"unknownfile_\" + System.currentTimeMillis();\n        try {\n            fileName = URLDecoder.decode(fileName, \"UTF-8\");\n        } catch (UnsupportedEncodingException e) {\n            OkLogger.printStackTrace(e);\n        }\n        return fileName;\n    }\n\n    /**\n     * 解析文件头\n     * Content-Disposition:attachment;filename=FileName.txt\n     * Content-Disposition: attachment; filename*=\"UTF-8''%E6%9B%BF%E6%8D%A2%E5%AE%9E%E9%AA%8C%E6%8A%A5%E5%91%8A.pdf\"\n     */\n    private static String getHeaderFileName(Response response) {\n        String dispositionHeader = response.header(HttpHeaders.HEAD_KEY_CONTENT_DISPOSITION);\n        if (dispositionHeader != null) {\n            //文件名可能包含双引号，需要去除\n            dispositionHeader = dispositionHeader.replaceAll(\"\\\"\", \"\");\n            String split = \"filename=\";\n            int indexOf = dispositionHeader.indexOf(split);\n            if (indexOf != -1) {\n                return dispositionHeader.substring(indexOf + split.length(), dispositionHeader.length());\n            }\n            split = \"filename*=\";\n            indexOf = dispositionHeader.indexOf(split);\n            if (indexOf != -1) {\n                String fileName = dispositionHeader.substring(indexOf + split.length(), dispositionHeader.length());\n                String encode = \"UTF-8''\";\n                if (fileName.startsWith(encode)) {\n                    fileName = fileName.substring(encode.length(), fileName.length());\n                }\n                return fileName;\n            }\n        }\n        return null;\n    }\n\n    /**\n     * 通过 ‘？’ 和 ‘/’ 判断文件名\n     * http://mavin-manzhan.oss-cn-hangzhou.aliyuncs.com/1486631099150286149.jpg?x-oss-process=image/watermark,image_d2F0ZXJtYXJrXzIwMF81MC5wbmc\n     */\n    private static String getUrlFileName(String url) {\n        String filename = null;\n        String[] strings = url.split(\"/\");\n        for (String string : strings) {\n            if (string.contains(\"?\")) {\n                int endIndex = string.indexOf(\"?\");\n                if (endIndex != -1) {\n                    filename = string.substring(0, endIndex);\n                    return filename;\n                }\n            }\n        }\n        if (strings.length > 0) {\n            filename = strings[strings.length - 1];\n        }\n        return filename;\n    }\n\n    /** 根据路径删除文件 */\n    public static boolean deleteFile(String path) {\n        if (TextUtils.isEmpty(path)) return true;\n        File file = new File(path);\n        if (!file.exists()) return true;\n        if (file.isFile()) {\n            boolean delete = file.delete();\n            OkLogger.e(\"deleteFile:\" + delete + \" path:\" + path);\n            return delete;\n        }\n        return false;\n    }\n\n    /** 根据文件名获取MIME类型 */\n    public static MediaType guessMimeType(String fileName) {\n        FileNameMap fileNameMap = URLConnection.getFileNameMap();\n        fileName = fileName.replace(\"#\", \"\");   //解决文件名中含有#号异常的问题\n        String contentType = fileNameMap.getContentTypeFor(fileName);\n        if (contentType == null) {\n            return HttpParams.MEDIA_TYPE_STREAM;\n        }\n        return MediaType.parse(contentType);\n    }\n\n    public static <T> T checkNotNull(T object, String message) {\n        if (object == null) {\n            throw new NullPointerException(message);\n        }\n        return object;\n    }\n\n    public static void runOnUiThread(Runnable runnable) {\n        OkGo.getInstance().getDelivery().post(runnable);\n    }\n}\n"
  },
  {
    "path": "okgo/src/main/java/com/lzy/okgo/utils/IOUtils.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.okgo.utils;\n\nimport android.os.Build;\nimport android.os.StatFs;\nimport android.text.TextUtils;\n\nimport java.io.BufferedInputStream;\nimport java.io.BufferedOutputStream;\nimport java.io.BufferedReader;\nimport java.io.BufferedWriter;\nimport java.io.ByteArrayInputStream;\nimport java.io.ByteArrayOutputStream;\nimport java.io.CharArrayWriter;\nimport java.io.Closeable;\nimport java.io.File;\nimport java.io.Flushable;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.InputStreamReader;\nimport java.io.ObjectInputStream;\nimport java.io.ObjectOutputStream;\nimport java.io.OutputStream;\nimport java.io.OutputStreamWriter;\nimport java.io.Reader;\nimport java.io.UnsupportedEncodingException;\nimport java.io.Writer;\nimport java.lang.reflect.Method;\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：16/9/11\n * 描    述：\n * 修订历史：\n * ================================================\n */\npublic class IOUtils {\n\n    public static void closeQuietly(Closeable closeable) {\n        if (closeable == null) return;\n        try {\n            closeable.close();\n        } catch (Exception e) {\n            OkLogger.printStackTrace(e);\n        }\n    }\n\n    public static void flushQuietly(Flushable flushable) {\n        if (flushable == null) return;\n        try {\n            flushable.flush();\n        } catch (Exception e) {\n            OkLogger.printStackTrace(e);\n        }\n    }\n\n    public static InputStream toInputStream(CharSequence input) {\n        return new ByteArrayInputStream(input.toString().getBytes());\n    }\n\n    public static InputStream toInputStream(CharSequence input, String encoding) throws UnsupportedEncodingException {\n        byte[] bytes = input.toString().getBytes(encoding);\n        return new ByteArrayInputStream(bytes);\n    }\n\n    public static BufferedInputStream toBufferedInputStream(InputStream inputStream) {\n        return inputStream instanceof BufferedInputStream ? (BufferedInputStream) inputStream : new BufferedInputStream(inputStream);\n    }\n\n    public static BufferedOutputStream toBufferedOutputStream(OutputStream outputStream) {\n        return outputStream instanceof BufferedOutputStream ? (BufferedOutputStream) outputStream : new BufferedOutputStream(outputStream);\n    }\n\n    public static BufferedReader toBufferedReader(Reader reader) {\n        return reader instanceof BufferedReader ? (BufferedReader) reader : new BufferedReader(reader);\n    }\n\n    public static BufferedWriter toBufferedWriter(Writer writer) {\n        return writer instanceof BufferedWriter ? (BufferedWriter) writer : new BufferedWriter(writer);\n    }\n\n    public static String toString(InputStream input) throws IOException {\n        return new String(toByteArray(input));\n    }\n\n    public static String toString(InputStream input, String encoding) throws IOException {\n        return new String(toByteArray(input), encoding);\n    }\n\n    public static String toString(Reader input) throws IOException {\n        return new String(toByteArray(input));\n    }\n\n    public static String toString(Reader input, String encoding) throws IOException {\n        return new String(toByteArray(input), encoding);\n    }\n\n    public static String toString(byte[] byteArray) {\n        return new String(byteArray);\n    }\n\n    public static String toString(byte[] byteArray, String encoding) {\n        try {\n            return new String(byteArray, encoding);\n        } catch (UnsupportedEncodingException e) {\n            return new String(byteArray);\n        }\n    }\n\n    public static byte[] toByteArray(Object input) {\n        ByteArrayOutputStream baos = null;\n        ObjectOutputStream oos = null;\n        try {\n            baos = new ByteArrayOutputStream();\n            oos = new ObjectOutputStream(baos);\n            oos.writeObject(input);\n            oos.flush();\n            return baos.toByteArray();\n        } catch (IOException e) {\n            OkLogger.printStackTrace(e);\n        } finally {\n            IOUtils.closeQuietly(oos);\n            IOUtils.closeQuietly(baos);\n        }\n        return null;\n    }\n\n    public static Object toObject(byte[] input) {\n        if (input == null) return null;\n        ByteArrayInputStream bais = null;\n        ObjectInputStream ois = null;\n        try {\n            bais = new ByteArrayInputStream(input);\n            ois = new ObjectInputStream(bais);\n            return ois.readObject();\n        } catch (Exception e) {\n            OkLogger.printStackTrace(e);\n        } finally {\n            IOUtils.closeQuietly(ois);\n            IOUtils.closeQuietly(bais);\n        }\n        return null;\n    }\n\n    public static byte[] toByteArray(CharSequence input) {\n        if (input == null) return new byte[0];\n        return input.toString().getBytes();\n    }\n\n    public static byte[] toByteArray(CharSequence input, String encoding) throws UnsupportedEncodingException {\n        if (input == null) return new byte[0];\n        else return input.toString().getBytes(encoding);\n    }\n\n    public static byte[] toByteArray(InputStream input) throws IOException {\n        ByteArrayOutputStream output = new ByteArrayOutputStream();\n        write(input, output);\n        output.close();\n        return output.toByteArray();\n    }\n\n    public static byte[] toByteArray(Reader input) throws IOException {\n        ByteArrayOutputStream output = new ByteArrayOutputStream();\n        write(input, output);\n        output.close();\n        return output.toByteArray();\n    }\n\n    public static byte[] toByteArray(Reader input, String encoding) throws IOException {\n        ByteArrayOutputStream output = new ByteArrayOutputStream();\n        write(input, output, encoding);\n        output.close();\n        return output.toByteArray();\n    }\n\n    public static char[] toCharArray(CharSequence input) throws IOException {\n        CharArrayWriter output = new CharArrayWriter();\n        write(input, output);\n        return output.toCharArray();\n    }\n\n    public static char[] toCharArray(InputStream input) throws IOException {\n        CharArrayWriter output = new CharArrayWriter();\n        write(input, output);\n        return output.toCharArray();\n    }\n\n    public static char[] toCharArray(InputStream input, String encoding) throws IOException {\n        CharArrayWriter output = new CharArrayWriter();\n        write(input, output, encoding);\n        return output.toCharArray();\n    }\n\n    public static char[] toCharArray(Reader input) throws IOException {\n        CharArrayWriter output = new CharArrayWriter();\n        write(input, output);\n        return output.toCharArray();\n    }\n\n    public static List<String> readLines(InputStream input, String encoding) throws IOException {\n        Reader reader = new InputStreamReader(input, encoding);\n        return readLines(reader);\n    }\n\n    public static List<String> readLines(InputStream input) throws IOException {\n        Reader reader = new InputStreamReader(input);\n        return readLines(reader);\n    }\n\n    public static List<String> readLines(Reader input) throws IOException {\n        BufferedReader reader = toBufferedReader(input);\n        List<String> list = new ArrayList<String>();\n        String line = reader.readLine();\n        while (line != null) {\n            list.add(line);\n            line = reader.readLine();\n        }\n        return list;\n    }\n\n    public static void write(byte[] data, OutputStream output) throws IOException {\n        if (data != null) output.write(data);\n    }\n\n    public static void write(byte[] data, Writer output) throws IOException {\n        if (data != null) output.write(new String(data));\n    }\n\n    public static void write(byte[] data, Writer output, String encoding) throws IOException {\n        if (data != null) output.write(new String(data, encoding));\n    }\n\n    public static void write(char[] data, Writer output) throws IOException {\n        if (data != null) output.write(data);\n    }\n\n    public static void write(char[] data, OutputStream output) throws IOException {\n        if (data != null) output.write(new String(data).getBytes());\n    }\n\n    public static void write(char[] data, OutputStream output, String encoding) throws IOException {\n        if (data != null) output.write(new String(data).getBytes(encoding));\n    }\n\n    public static void write(CharSequence data, Writer output) throws IOException {\n        if (data != null) output.write(data.toString());\n    }\n\n    public static void write(CharSequence data, OutputStream output) throws IOException {\n        if (data != null) output.write(data.toString().getBytes());\n    }\n\n    public static void write(CharSequence data, OutputStream output, String encoding) throws IOException {\n        if (data != null) output.write(data.toString().getBytes(encoding));\n    }\n\n    public static void write(InputStream inputStream, OutputStream outputStream) throws IOException {\n        int len;\n        byte[] buffer = new byte[4096];\n        while ((len = inputStream.read(buffer)) != -1) outputStream.write(buffer, 0, len);\n    }\n\n    public static void write(Reader input, OutputStream output) throws IOException {\n        Writer out = new OutputStreamWriter(output);\n        write(input, out);\n        out.flush();\n    }\n\n    public static void write(InputStream input, Writer output) throws IOException {\n        Reader in = new InputStreamReader(input);\n        write(in, output);\n    }\n\n    public static void write(Reader input, OutputStream output, String encoding) throws IOException {\n        Writer out = new OutputStreamWriter(output, encoding);\n        write(input, out);\n        out.flush();\n    }\n\n    public static void write(InputStream input, OutputStream output, String encoding) throws IOException {\n        Reader in = new InputStreamReader(input, encoding);\n        write(in, output);\n    }\n\n    public static void write(InputStream input, Writer output, String encoding) throws IOException {\n        Reader in = new InputStreamReader(input, encoding);\n        write(in, output);\n    }\n\n    public static void write(Reader input, Writer output) throws IOException {\n        int len;\n        char[] buffer = new char[4096];\n        while (-1 != (len = input.read(buffer))) output.write(buffer, 0, len);\n    }\n\n    public static boolean contentEquals(InputStream input1, InputStream input2) throws IOException {\n        input1 = toBufferedInputStream(input1);\n        input2 = toBufferedInputStream(input2);\n\n        int ch = input1.read();\n        while (-1 != ch) {\n            int ch2 = input2.read();\n            if (ch != ch2) {\n                return false;\n            }\n            ch = input1.read();\n        }\n\n        int ch2 = input2.read();\n        return ch2 == -1;\n    }\n\n    public static boolean contentEquals(Reader input1, Reader input2) throws IOException {\n        input1 = toBufferedReader(input1);\n        input2 = toBufferedReader(input2);\n\n        int ch = input1.read();\n        while (-1 != ch) {\n            int ch2 = input2.read();\n            if (ch != ch2) {\n                return false;\n            }\n            ch = input1.read();\n        }\n\n        int ch2 = input2.read();\n        return ch2 == -1;\n    }\n\n    public static boolean contentEqualsIgnoreEOL(Reader input1, Reader input2) throws IOException {\n        BufferedReader br1 = toBufferedReader(input1);\n        BufferedReader br2 = toBufferedReader(input2);\n\n        String line1 = br1.readLine();\n        String line2 = br2.readLine();\n        while ((line1 != null) && (line2 != null) && (line1.equals(line2))) {\n            line1 = br1.readLine();\n            line2 = br2.readLine();\n        }\n        return line1 != null && (line2 == null || line1.equals(line2));\n    }\n\n    /**\n     * Access to a directory available size.\n     *\n     * @param path path.\n     * @return space size.\n     */\n    public static long getDirSize(String path) {\n        StatFs stat;\n        try {\n            stat = new StatFs(path);\n        } catch (Exception e) {\n            OkLogger.printStackTrace(e);\n            return 0;\n        }\n        if (Build.VERSION.SDK_INT >= 18) return getStatFsSize(stat, \"getBlockSizeLong\", \"getAvailableBlocksLong\");\n        else return getStatFsSize(stat, \"getBlockSize\", \"getAvailableBlocks\");\n    }\n\n    private static long getStatFsSize(StatFs statFs, String blockSizeMethod, String availableBlocksMethod) {\n        try {\n            Method getBlockSizeMethod = statFs.getClass().getMethod(blockSizeMethod);\n            getBlockSizeMethod.setAccessible(true);\n\n            Method getAvailableBlocksMethod = statFs.getClass().getMethod(availableBlocksMethod);\n            getAvailableBlocksMethod.setAccessible(true);\n\n            long blockSize = (Long) getBlockSizeMethod.invoke(statFs);\n            long availableBlocks = (Long) getAvailableBlocksMethod.invoke(statFs);\n            return blockSize * availableBlocks;\n        } catch (Throwable e) {\n            OkLogger.printStackTrace(e);\n        }\n        return 0;\n    }\n\n    /**\n     * If the folder can be written.\n     *\n     * @param path path.\n     * @return True: success, or false: failure.\n     */\n    public static boolean canWrite(String path) {\n        return new File(path).canWrite();\n    }\n\n    /**\n     * If the folder can be read.\n     *\n     * @param path path.\n     * @return True: success, or false: failure.\n     */\n    public static boolean canRead(String path) {\n        return new File(path).canRead();\n    }\n\n    /**\n     * Create a folder, If the folder exists is not created.\n     *\n     * @param folderPath folder path.\n     * @return True: success, or false: failure.\n     */\n    public static boolean createFolder(String folderPath) {\n        if (!TextUtils.isEmpty(folderPath)) {\n            File folder = new File(folderPath);\n            return createFolder(folder);\n        }\n        return false;\n    }\n\n    /**\n     * Create a folder, If the folder exists is not created.\n     *\n     * @param targetFolder folder path.\n     * @return True: success, or false: failure.\n     */\n    public static boolean createFolder(File targetFolder) {\n        if (targetFolder.exists()) {\n            if (targetFolder.isDirectory()) return true;\n            //noinspection ResultOfMethodCallIgnored\n            targetFolder.delete();\n        }\n        return targetFolder.mkdirs();\n    }\n\n    /**\n     * Create a folder, If the folder exists is not created.\n     *\n     * @param folderPath folder path.\n     * @return True: success, or false: failure.\n     */\n    public static boolean createNewFolder(String folderPath) {\n        return delFileOrFolder(folderPath) && createFolder(folderPath);\n    }\n\n    /**\n     * Create a folder, If the folder exists is not created.\n     *\n     * @param targetFolder folder path.\n     * @return True: success, or false: failure.\n     */\n    public static boolean createNewFolder(File targetFolder) {\n        return delFileOrFolder(targetFolder) && createFolder(targetFolder);\n    }\n\n    /**\n     * Create a file, If the file exists is not created.\n     *\n     * @param filePath file path.\n     * @return True: success, or false: failure.\n     */\n    public static boolean createFile(String filePath) {\n        if (!TextUtils.isEmpty(filePath)) {\n            File file = new File(filePath);\n            return createFile(file);\n        }\n        return false;\n    }\n\n    /**\n     * Create a file, If the file exists is not created.\n     *\n     * @param targetFile file.\n     * @return True: success, or false: failure.\n     */\n    public static boolean createFile(File targetFile) {\n        if (targetFile.exists()) {\n            if (targetFile.isFile()) return true;\n            delFileOrFolder(targetFile);\n        }\n        try {\n            return targetFile.createNewFile();\n        } catch (IOException e) {\n            return false;\n        }\n    }\n\n    /**\n     * Create a new file, if the file exists, delete and create again.\n     *\n     * @param filePath file path.\n     * @return True: success, or false: failure.\n     */\n    public static boolean createNewFile(String filePath) {\n        if (!TextUtils.isEmpty(filePath)) {\n            File file = new File(filePath);\n            return createNewFile(file);\n        }\n        return false;\n    }\n\n    /**\n     * Create a new file, if the file exists, delete and create again.\n     *\n     * @param targetFile file.\n     * @return True: success, or false: failure.\n     */\n    public static boolean createNewFile(File targetFile) {\n        if (targetFile.exists()) delFileOrFolder(targetFile);\n        try {\n            return targetFile.createNewFile();\n        } catch (IOException e) {\n            return false;\n        }\n    }\n\n    /**\n     * Delete file or folder.\n     *\n     * @param path path.\n     * @return is succeed.\n     * @see #delFileOrFolder(File)\n     */\n    public static boolean delFileOrFolder(String path) {\n        if (TextUtils.isEmpty(path)) return false;\n        return delFileOrFolder(new File(path));\n    }\n\n    /**\n     * Delete file or folder.\n     *\n     * @param file file.\n     * @return is succeed.\n     * @see #delFileOrFolder(String)\n     */\n    @SuppressWarnings(\"ResultOfMethodCallIgnored\")\n    public static boolean delFileOrFolder(File file) {\n        if (file == null || !file.exists()) {\n            // do nothing\n        } else if (file.isFile()) {\n            file.delete();\n        } else if (file.isDirectory()) {\n            File[] files = file.listFiles();\n            if (files != null) {\n                for (File sonFile : files) {\n                    delFileOrFolder(sonFile);\n                }\n            }\n            file.delete();\n        }\n        return true;\n    }\n}\n"
  },
  {
    "path": "okgo/src/main/java/com/lzy/okgo/utils/OkLogger.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.okgo.utils;\n\nimport android.util.Log;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：2015/10/12\n * 描    述：日志的工具类\n * 修订历史：\n * ================================================\n */\npublic class OkLogger {\n    private static boolean isLogEnable = true;\n\n    private static String tag = \"OkGo\";\n\n    public static void debug(boolean isEnable) {\n        debug(tag, isEnable);\n    }\n\n    public static void debug(String logTag, boolean isEnable) {\n        tag = logTag;\n        isLogEnable = isEnable;\n    }\n\n    public static void v(String msg) {\n        v(tag, msg);\n    }\n\n    public static void v(String tag, String msg) {\n        if (isLogEnable) Log.v(tag, msg);\n    }\n\n    public static void d(String msg) {\n        d(tag, msg);\n    }\n\n    public static void d(String tag, String msg) {\n        if (isLogEnable) Log.d(tag, msg);\n    }\n\n    public static void i(String msg) {\n        i(tag, msg);\n    }\n\n    public static void i(String tag, String msg) {\n        if (isLogEnable) Log.i(tag, msg);\n    }\n\n    public static void w(String msg) {\n        w(tag, msg);\n    }\n\n    public static void w(String tag, String msg) {\n        if (isLogEnable) Log.w(tag, msg);\n    }\n\n    public static void e(String msg) {\n        e(tag, msg);\n    }\n\n    public static void e(String tag, String msg) {\n        if (isLogEnable) Log.e(tag, msg);\n    }\n\n    public static void printStackTrace(Throwable t) {\n        if (isLogEnable && t != null) t.printStackTrace();\n    }\n}\n"
  },
  {
    "path": "okrx/.gitignore",
    "content": "/build\n"
  },
  {
    "path": "okrx/bintray.gradle",
    "content": "apply plugin: 'com.github.dcendents.android-maven'\napply plugin: 'com.jfrog.bintray'\n\nversion = rootProject.ext.versionName_okrx      // 数据仓库依赖第三部分\n\ndef siteUrl = 'https://github.com/jeasonlzy/OkGo'\ndef gitUrl = 'https://github.com/jeasonlzy/OkGo.git'\ngroup = \"com.lzy.net\"       // 数据仓库依赖第一部分\n\ninstall {\n    repositories.mavenInstaller {\n        pom {\n            project {\n                packaging 'aar'\n                name 'OkRx For Android'     // 项目描述\n                url siteUrl\n                licenses {\n                    license {\n                        name 'The Apache Software License, Version 2.0'\n                        url 'http://www.apache.org/licenses/LICENSE-2.0.txt'\n                    }\n                }\n                developers {\n                    developer {\n                        id 'jeasonlzy'                // 开发者信息\n                        name 'LiaoZiYao'              // 开发者信息\n                        email 'liaojeason@126.com'    // 开发者信息\n                    }\n                }\n                scm {\n                    connection gitUrl\n                    developerConnection gitUrl\n                    url siteUrl\n                }\n            }\n        }\n    }\n}\n\ntask sourcesJar(type: Jar) {\n    from android.sourceSets.main.java.srcDirs\n    classifier = 'sources'\n}\n\ntask javadoc(type: Javadoc) {\n    source = android.sourceSets.main.java.srcDirs\n    classpath += project.files(android.getBootClasspath().join(File.pathSeparator))\n}\n\ntask javadocJar(type: Jar, dependsOn: javadoc) {\n    classifier = 'javadoc'\n    from javadoc.destinationDir\n}\n\njavadoc {\n    options {\n        encoding \"UTF-8\"\n        charSet 'UTF-8'\n        author true\n        version true\n        links \"http://docs.oracle.com/javase/7/docs/api\"\n        title 'OkRx For Android'   // 文档标题\n    }\n}\n\nartifacts {\n//    archives javadocJar\n    archives sourcesJar\n}\n\n// 生成jar包\ntask releaseJar(type: Copy) {\n    from( 'build/intermediates/bundles/default')\n    into( '../jar')\n    include('classes.jar')\n    rename('classes.jar', 'okrx-' + version + '.jar')\n}\n\nProperties properties = new Properties()\nproperties.load(project.rootProject.file('local.properties').newDataInputStream())\nbintray {\n    user = properties.getProperty(\"bintray.user\")\n    key = properties.getProperty(\"bintray.apikey\")\n    configurations = ['archives']\n    pkg {\n        repo = \"maven\"\n        name = \"okrx\"             // 数据仓库依赖第二部分\n        websiteUrl = siteUrl\n        vcsUrl = gitUrl\n        licenses = [\"Apache-2.0\"]\n        publish = true\n    }\n}\n"
  },
  {
    "path": "okrx/build.gradle",
    "content": "apply plugin: 'com.android.library'\n\nandroid {\n    compileSdkVersion rootProject.ext.compileSdkVersion\n    buildToolsVersion rootProject.ext.buildToolsVersion\n\n    defaultConfig {\n        minSdkVersion rootProject.ext.libMinSdkVersion\n        targetSdkVersion rootProject.ext.targetSdkVersion\n        versionCode rootProject.ext.versionCode\n        versionName rootProject.ext.versionName_okrx\n    }\n}\n\ndependencies {\n    compile fileTree(include: ['*.jar'], dir: 'libs')\n    compile 'io.reactivex:rxjava:1.3.0'\n//    compile \"com.lzy.net:okgo:$versionName_okgo\"\n    compile project(':okgo')\n}\n\n//apply from: 'bintray.gradle'"
  },
  {
    "path": "okrx/proguard-rules.pro",
    "content": "# Add project specific ProGuard rules here.\n# By default, the flags in this file are appended to flags specified\n# in /Users/jeasonlzy/Android/sdk/tools/proguard/proguard-android.txt\n# You can edit the include path and order by changing the proguardFiles\n# directive in build.gradle.\n#\n# For more details, see\n#   http://developer.android.com/guide/developing/tools/proguard.html\n\n# Add any project specific keep options here:\n\n# If your project uses WebView with JS, uncomment the following\n# and specify the fully qualified class name to the JavaScript interface\n# class:\n#-keepclassmembers class fqcn.of.javascript.interface.for.webview {\n#   public *;\n#}\n"
  },
  {
    "path": "okrx/src/main/AndroidManifest.xml",
    "content": "<!--\n    Copyright 2016 jeasonlzy(廖子尧)\n    \n    Licensed under the Apache License, Version 2.0 (the \"License\");\n    you may not use this file except in compliance with the License.\n    You may obtain a copy of the License at\n    \n       http://www.apache.org/licenses/LICENSE-2.0\n       \n    Unless required by applicable law or agreed to in writing, software\n    distributed under the License is distributed on an \"AS IS\" BASIS,\n    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n    See the License for the specific language governing permissions and\n    limitations under the License.\n-->\n<manifest package=\"com.lzy.okrx\">\n\n</manifest>\n"
  },
  {
    "path": "okrx/src/main/java/com/lzy/okrx/adapter/AnalysisParams.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.okrx.adapter;\n\nimport com.lzy.okgo.adapter.AdapterParam;\nimport com.lzy.okgo.adapter.Call;\nimport com.lzy.okgo.model.Response;\nimport com.lzy.okrx.subscribe.CallEnqueueOnSubscribe;\nimport com.lzy.okrx.subscribe.CallExecuteOnSubscribe;\n\nimport rx.Observable;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：2017/5/27\n * 描    述：\n * 修订历史：\n * ================================================\n */\nclass AnalysisParams {\n\n    static <T> Observable.OnSubscribe<Response<T>> analysis(Call<T> call, AdapterParam param) {\n        Observable.OnSubscribe<Response<T>> onSubscribe;\n        if (param == null) param = new AdapterParam();\n        if (param.isAsync) {\n            onSubscribe = new CallEnqueueOnSubscribe<>(call);\n        } else {\n            onSubscribe = new CallExecuteOnSubscribe<>(call);\n        }\n        return onSubscribe;\n    }\n}\n"
  },
  {
    "path": "okrx/src/main/java/com/lzy/okrx/adapter/CompletableResponse.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.okrx.adapter;\n\nimport com.lzy.okgo.adapter.AdapterParam;\nimport com.lzy.okgo.adapter.Call;\nimport com.lzy.okgo.adapter.CallAdapter;\n\nimport rx.Completable;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：2017/5/26\n * 描    述：\n * 修订历史：\n * ================================================\n */\npublic class CompletableResponse<T> implements CallAdapter<T, Completable> {\n    @Override\n    public Completable adapt(Call<T> call, AdapterParam param) {\n        ObservableResponse<T> body = new ObservableResponse<>();\n        return body.adapt(call, param).toCompletable();\n    }\n}\n"
  },
  {
    "path": "okrx/src/main/java/com/lzy/okrx/adapter/ObservableBody.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.okrx.adapter;\n\nimport com.lzy.okgo.adapter.AdapterParam;\nimport com.lzy.okgo.adapter.Call;\nimport com.lzy.okgo.adapter.CallAdapter;\nimport com.lzy.okgo.model.Response;\nimport com.lzy.okrx.subscribe.BodyOnSubscribe;\n\nimport rx.Observable;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：2017/5/26\n * 描    述：\n * 修订历史：\n * ================================================\n */\npublic class ObservableBody<T> implements CallAdapter<T, Observable<T>> {\n    @Override\n    public Observable<T> adapt(Call<T> call, AdapterParam param) {\n        Observable.OnSubscribe<Response<T>> subscribe = AnalysisParams.analysis(call, param);\n        BodyOnSubscribe<T> bodySubscribe = new BodyOnSubscribe<>(subscribe);\n        return Observable.create(bodySubscribe);\n    }\n}\n"
  },
  {
    "path": "okrx/src/main/java/com/lzy/okrx/adapter/ObservableResponse.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.okrx.adapter;\n\nimport com.lzy.okgo.adapter.AdapterParam;\nimport com.lzy.okgo.adapter.Call;\nimport com.lzy.okgo.adapter.CallAdapter;\nimport com.lzy.okgo.model.Response;\n\nimport rx.Observable;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：2017/5/26\n * 描    述：\n * 修订历史：\n * ================================================\n */\npublic class ObservableResponse<T> implements CallAdapter<T, Observable<Response<T>>> {\n    @Override\n    public Observable<Response<T>> adapt(Call<T> call, AdapterParam param) {\n        Observable.OnSubscribe<Response<T>> subscribe = AnalysisParams.analysis(call, param);\n        return Observable.create(subscribe);\n    }\n}\n"
  },
  {
    "path": "okrx/src/main/java/com/lzy/okrx/adapter/ObservableResult.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.okrx.adapter;\n\nimport com.lzy.okgo.adapter.AdapterParam;\nimport com.lzy.okgo.adapter.Call;\nimport com.lzy.okgo.adapter.CallAdapter;\nimport com.lzy.okgo.model.Response;\nimport com.lzy.okgo.model.Result;\nimport com.lzy.okrx.subscribe.ResultOnSubscribe;\n\nimport rx.Observable;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：2017/5/26\n * 描    述：\n * 修订历史：\n * ================================================\n */\npublic class ObservableResult<T> implements CallAdapter<T, Observable<Result<T>>> {\n    @Override\n    public Observable<Result<T>> adapt(Call<T> call, AdapterParam param) {\n        Observable.OnSubscribe<Response<T>> subscribe = AnalysisParams.analysis(call, param);\n        ResultOnSubscribe<T> resultSubscribe = new ResultOnSubscribe<>(subscribe);\n        return Observable.create(resultSubscribe);\n    }\n}\n"
  },
  {
    "path": "okrx/src/main/java/com/lzy/okrx/adapter/SingleBody.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.okrx.adapter;\n\nimport com.lzy.okgo.adapter.AdapterParam;\nimport com.lzy.okgo.adapter.Call;\nimport com.lzy.okgo.adapter.CallAdapter;\n\nimport rx.Single;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：2017/5/26\n * 描    述：\n * 修订历史：\n * ================================================\n */\npublic class SingleBody<T> implements CallAdapter<T, Single<T>> {\n    @Override\n    public Single<T> adapt(Call<T> call, AdapterParam param) {\n        ObservableBody<T> body = new ObservableBody<>();\n        return body.adapt(call, param).toSingle();\n    }\n}\n"
  },
  {
    "path": "okrx/src/main/java/com/lzy/okrx/adapter/SingleResponse.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.okrx.adapter;\n\nimport com.lzy.okgo.adapter.AdapterParam;\nimport com.lzy.okgo.adapter.Call;\nimport com.lzy.okgo.adapter.CallAdapter;\nimport com.lzy.okgo.model.Response;\n\nimport rx.Single;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：2017/5/26\n * 描    述：\n * 修订历史：\n * ================================================\n */\npublic class SingleResponse<T> implements CallAdapter<T, Single<Response<T>>> {\n    @Override\n    public Single<Response<T>> adapt(Call<T> call, AdapterParam param) {\n        ObservableResponse<T> body = new ObservableResponse<>();\n        return body.adapt(call, param).toSingle();\n    }\n}\n"
  },
  {
    "path": "okrx/src/main/java/com/lzy/okrx/adapter/SingleResult.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.okrx.adapter;\n\nimport com.lzy.okgo.adapter.AdapterParam;\nimport com.lzy.okgo.adapter.Call;\nimport com.lzy.okgo.adapter.CallAdapter;\nimport com.lzy.okgo.model.Result;\n\nimport rx.Single;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：2017/5/26\n * 描    述：\n * 修订历史：\n * ================================================\n */\npublic class SingleResult<T> implements CallAdapter<T, Single<Result<T>>> {\n    @Override\n    public Single<Result<T>> adapt(Call<T> call, AdapterParam param) {\n        ObservableResult<T> body = new ObservableResult<>();\n        return body.adapt(call, param).toSingle();\n    }\n}\n"
  },
  {
    "path": "okrx/src/main/java/com/lzy/okrx/subscribe/BodyOnSubscribe.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.okrx.subscribe;\n\nimport com.lzy.okgo.exception.HttpException;\nimport com.lzy.okgo.model.Response;\n\nimport rx.Observable.OnSubscribe;\nimport rx.Subscriber;\nimport rx.exceptions.CompositeException;\nimport rx.exceptions.Exceptions;\nimport rx.exceptions.OnCompletedFailedException;\nimport rx.exceptions.OnErrorFailedException;\nimport rx.exceptions.OnErrorNotImplementedException;\nimport rx.plugins.RxJavaHooks;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：16/9/11\n * 描    述：\n * 修订历史：\n * ================================================\n */\npublic final class BodyOnSubscribe<T> implements OnSubscribe<T> {\n    private final OnSubscribe<Response<T>> upstream;\n\n    public BodyOnSubscribe(OnSubscribe<Response<T>> upstream) {\n        this.upstream = upstream;\n    }\n\n    @Override\n    public void call(Subscriber<? super T> subscriber) {\n        upstream.call(new BodySubscriber<>(subscriber));\n    }\n\n    private static class BodySubscriber<R> extends Subscriber<Response<R>> {\n\n        private final Subscriber<? super R> subscriber;\n        private boolean subscriberTerminated;\n\n        BodySubscriber(Subscriber<? super R> subscriber) {\n            super(subscriber);\n            this.subscriber = subscriber;\n        }\n\n        @Override\n        public void onNext(Response<R> response) {\n            if (response.isSuccessful()) {\n                subscriber.onNext(response.body());\n            } else {\n                subscriberTerminated = true;\n                Throwable t = new HttpException(response);\n                try {\n                    subscriber.onError(t);\n                } catch (OnCompletedFailedException | OnErrorFailedException | OnErrorNotImplementedException e) {\n                    RxJavaHooks.getOnError().call(e);\n                } catch (Throwable inner) {\n                    Exceptions.throwIfFatal(inner);\n                    RxJavaHooks.getOnError().call(new CompositeException(t, inner));\n                }\n            }\n        }\n\n        @Override\n        public void onError(Throwable throwable) {\n            if (!subscriberTerminated) {\n                subscriber.onError(throwable);\n            } else {\n                Throwable broken = new AssertionError(\"This should never happen! Report as a bug with the full stacktrace.\");\n                //noinspection UnnecessaryInitCause Two-arg AssertionError constructor is 1.7+ only.\n                broken.initCause(throwable);\n                RxJavaHooks.getOnError().call(broken);\n            }\n        }\n\n        @Override\n        public void onCompleted() {\n            if (!subscriberTerminated) {\n                subscriber.onCompleted();\n            } else {\n                Throwable broken = new AssertionError(\"This should never happen! Report as a bug with the full stacktrace.\");\n                RxJavaHooks.getOnError().call(broken);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "okrx/src/main/java/com/lzy/okrx/subscribe/CallArbiter.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.okrx.subscribe;\n\nimport com.lzy.okgo.adapter.Call;\nimport com.lzy.okgo.model.Response;\n\nimport java.util.Iterator;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.concurrent.atomic.AtomicInteger;\n\nimport rx.Producer;\nimport rx.Subscriber;\nimport rx.Subscription;\nimport rx.exceptions.CompositeException;\nimport rx.exceptions.Exceptions;\nimport rx.exceptions.OnCompletedFailedException;\nimport rx.exceptions.OnErrorFailedException;\nimport rx.exceptions.OnErrorNotImplementedException;\nimport rx.plugins.RxJavaHooks;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：16/9/11\n * 描    述：\n * 修订历史：\n * ================================================\n */\nfinal class CallArbiter<T> extends AtomicInteger implements Subscription, Producer {\n    private static final long serialVersionUID = 613435323949233509L;\n\n    private static final int STATE_WAITING = 0;\n    private static final int STATE_REQUESTED = 1;\n    private static final int STATE_HAS_RESPONSE = 2;\n    private static final int STATE_TERMINATED = 3;\n\n    private final Call<T> call;\n    private final Subscriber<? super Response<T>> subscriber;\n\n    private volatile LinkedList<Response<T>> responseList;\n\n    CallArbiter(Call<T> call, Subscriber<? super Response<T>> subscriber) {\n        super(STATE_WAITING);\n        responseList = new LinkedList<>();\n\n        this.call = call;\n        this.subscriber = subscriber;\n    }\n\n    @Override\n    public void unsubscribe() {\n        call.cancel();\n    }\n\n    @Override\n    public boolean isUnsubscribed() {\n        return call.isCanceled();\n    }\n\n    @Override\n    public void request(long amount) {\n        if (amount == 0) {\n            return;\n        }\n        while (true) {\n            int state = get();\n            switch (state) {\n                case STATE_WAITING:\n                    if (compareAndSet(STATE_WAITING, STATE_REQUESTED)) {\n                        return;\n                    }\n                    break; // State transition failed. Try again.\n\n                case STATE_HAS_RESPONSE:\n                    if (STATE_HAS_RESPONSE == get()) {\n                        emitResponse(responseList);\n                        return;\n                    }\n                    break; // State transition failed. Try again.\n\n                case STATE_REQUESTED:\n                case STATE_TERMINATED:\n                    return; // Nothing to do.\n\n                default:\n                    throw new IllegalStateException(\"Unknown state: \" + state);\n            }\n        }\n    }\n\n    void emitNext(Response<T> response) {\n        while (true) {\n            int state = get();\n            switch (state) {\n                case STATE_WAITING:\n                    synchronized (this) {\n                        responseList.add(response);\n                    }\n                    if (compareAndSet(STATE_WAITING, STATE_HAS_RESPONSE)) {\n                        return;\n                    }\n                    break; // State transition failed. Try again.\n\n                case STATE_REQUESTED:\n                    synchronized (this) {\n                        responseList.add(response);\n                    }\n                    if (STATE_REQUESTED == get()) {\n                        emitResponse(responseList);\n                        return;\n                    }\n                    break; // State transition failed. Try again.\n\n                case STATE_HAS_RESPONSE:\n                case STATE_TERMINATED:\n                    throw new AssertionError();\n\n                default:\n                    throw new IllegalStateException(\"Unknown state: \" + state);\n            }\n        }\n    }\n\n    private void emitResponse(List<Response<T>> responseList) {\n        try {\n            synchronized (this) {\n                Iterator<Response<T>> iterator = responseList.iterator();\n                while (iterator.hasNext()) {\n                    Response<T> next = iterator.next();\n                    iterator.remove();\n                    if (!isUnsubscribed()) {\n                        subscriber.onNext(next);\n                    } else {\n                        return;\n                    }\n                }\n            }\n        } catch (OnCompletedFailedException | OnErrorFailedException | OnErrorNotImplementedException e) {\n            RxJavaHooks.getOnError().call(e);\n        } catch (Throwable t) {\n            Exceptions.throwIfFatal(t);\n            try {\n                subscriber.onError(t);\n            } catch (OnCompletedFailedException | OnErrorFailedException | OnErrorNotImplementedException e) {\n                RxJavaHooks.getOnError().call(e);\n            } catch (Throwable inner) {\n                Exceptions.throwIfFatal(inner);\n                RxJavaHooks.getOnError().call(new CompositeException(t, inner));\n            }\n        }\n    }\n\n    void emitComplete() {\n        set(STATE_TERMINATED);\n        try {\n            if (!isUnsubscribed()) {\n                subscriber.onCompleted();\n            }\n        } catch (OnCompletedFailedException | OnErrorFailedException | OnErrorNotImplementedException e) {\n            RxJavaHooks.getOnError().call(e);\n        } catch (Throwable t) {\n            Exceptions.throwIfFatal(t);\n            RxJavaHooks.getOnError().call(t);\n        }\n    }\n\n    void emitError(Throwable t) {\n        set(STATE_TERMINATED);\n        if (!isUnsubscribed()) {\n            try {\n                subscriber.onError(t);\n            } catch (OnCompletedFailedException | OnErrorFailedException | OnErrorNotImplementedException e) {\n                RxJavaHooks.getOnError().call(e);\n            } catch (Throwable inner) {\n                Exceptions.throwIfFatal(inner);\n                RxJavaHooks.getOnError().call(new CompositeException(t, inner));\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "okrx/src/main/java/com/lzy/okrx/subscribe/CallEnqueueOnSubscribe.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.okrx.subscribe;\n\nimport com.lzy.okgo.adapter.Call;\nimport com.lzy.okgo.callback.Callback;\nimport com.lzy.okgo.model.Progress;\nimport com.lzy.okgo.model.Response;\nimport com.lzy.okgo.request.base.Request;\n\nimport rx.Observable.OnSubscribe;\nimport rx.Subscriber;\nimport rx.exceptions.Exceptions;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：16/9/11\n * 描    述：\n * 修订历史：\n * ================================================\n */\npublic final class CallEnqueueOnSubscribe<T> implements OnSubscribe<Response<T>> {\n    private final Call<T> originalCall;\n\n    public CallEnqueueOnSubscribe(Call<T> originalCall) {\n        this.originalCall = originalCall;\n    }\n\n    @Override\n    public void call(final Subscriber<? super Response<T>> subscriber) {\n        // Since Call is a one-shot type, clone it for each new subscriber.\n        Call<T> call = originalCall.clone();\n        final CallArbiter<T> arbiter = new CallArbiter<>(call, subscriber);\n        subscriber.add(arbiter);\n        subscriber.setProducer(arbiter);\n\n        call.execute(new Callback<T>() {\n            @Override\n            public T convertResponse(okhttp3.Response response) throws Throwable {\n                // okrx 使用converter转换，不需要这个解析方法\n                return null;\n            }\n\n            @Override\n            public void onStart(Request<T, ? extends Request> request) {\n            }\n\n            @Override\n            public void onSuccess(Response<T> response) {\n                arbiter.emitNext(response);\n            }\n\n            @Override\n            public void onCacheSuccess(Response<T> response) {\n                arbiter.emitNext(response);\n            }\n\n            @Override\n            public void onError(Response<T> response) {\n                Throwable throwable = response.getException();\n                Exceptions.throwIfFatal(throwable);\n                arbiter.emitError(throwable);\n            }\n\n            @Override\n            public void onFinish() {\n                arbiter.emitComplete();\n            }\n\n            @Override\n            public void uploadProgress(Progress progress) {\n            }\n\n            @Override\n            public void downloadProgress(Progress progress) {\n            }\n        });\n    }\n}\n"
  },
  {
    "path": "okrx/src/main/java/com/lzy/okrx/subscribe/CallExecuteOnSubscribe.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.okrx.subscribe;\n\nimport com.lzy.okgo.adapter.Call;\nimport com.lzy.okgo.model.Response;\n\nimport rx.Observable.OnSubscribe;\nimport rx.Subscriber;\nimport rx.exceptions.Exceptions;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：16/9/11\n * 描    述：\n * 修订历史：\n * ================================================\n */\npublic final class CallExecuteOnSubscribe<T> implements OnSubscribe<Response<T>> {\n    private final Call<T> originalCall;\n\n    public CallExecuteOnSubscribe(Call<T> originalCall) {\n        this.originalCall = originalCall;\n    }\n\n    @Override\n    public void call(Subscriber<? super Response<T>> subscriber) {\n        // Since Call is a one-shot type, clone it for each new subscriber.\n        Call<T> call = originalCall.clone();\n        CallArbiter<T> arbiter = new CallArbiter<>(call, subscriber);\n        subscriber.add(arbiter);\n        subscriber.setProducer(arbiter);\n\n        Response<T> response;\n        try {\n            response = call.execute();\n        } catch (Throwable t) {\n            Exceptions.throwIfFatal(t);\n            arbiter.emitError(t);\n            return;\n        }\n        arbiter.emitNext(response);\n        arbiter.emitComplete();\n    }\n}\n"
  },
  {
    "path": "okrx/src/main/java/com/lzy/okrx/subscribe/ResultOnSubscribe.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.okrx.subscribe;\n\nimport com.lzy.okgo.model.Response;\nimport com.lzy.okgo.model.Result;\n\nimport rx.Observable.OnSubscribe;\nimport rx.Subscriber;\nimport rx.exceptions.CompositeException;\nimport rx.exceptions.Exceptions;\nimport rx.exceptions.OnCompletedFailedException;\nimport rx.exceptions.OnErrorFailedException;\nimport rx.exceptions.OnErrorNotImplementedException;\nimport rx.plugins.RxJavaHooks;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：16/9/11\n * 描    述：\n * 修订历史：\n * ================================================\n */\npublic final class ResultOnSubscribe<T> implements OnSubscribe<Result<T>> {\n    private final OnSubscribe<Response<T>> upstream;\n\n    public ResultOnSubscribe(OnSubscribe<Response<T>> upstream) {\n        this.upstream = upstream;\n    }\n\n    @Override\n    public void call(Subscriber<? super Result<T>> subscriber) {\n        upstream.call(new ResultSubscriber<T>(subscriber));\n    }\n\n    private static class ResultSubscriber<R> extends Subscriber<Response<R>> {\n\n        private final Subscriber<? super Result<R>> subscriber;\n\n        ResultSubscriber(Subscriber<? super Result<R>> subscriber) {\n            super(subscriber);\n            this.subscriber = subscriber;\n        }\n\n        @Override\n        public void onNext(Response<R> response) {\n            subscriber.onNext(Result.response(response));\n        }\n\n        @Override\n        public void onError(Throwable throwable) {\n            try {\n                subscriber.onNext(Result.<R>error(throwable));\n            } catch (Throwable t) {\n                try {\n                    subscriber.onError(t);\n                } catch (OnCompletedFailedException | OnErrorFailedException | OnErrorNotImplementedException e) {\n                    RxJavaHooks.getOnError().call(e);\n                } catch (Throwable inner) {\n                    Exceptions.throwIfFatal(inner);\n                    RxJavaHooks.getOnError().call(new CompositeException(t, inner));\n                }\n                return;\n            }\n            subscriber.onCompleted();\n        }\n\n        @Override\n        public void onCompleted() {\n            subscriber.onCompleted();\n        }\n    }\n}\n"
  },
  {
    "path": "okrx2/.gitignore",
    "content": "/build\n"
  },
  {
    "path": "okrx2/bintray.gradle",
    "content": "apply plugin: 'com.github.dcendents.android-maven'\napply plugin: 'com.jfrog.bintray'\n\nversion = rootProject.ext.versionName_okrx2      // 数据仓库依赖第三部分\n\ndef siteUrl = 'https://github.com/jeasonlzy/OkGo'\ndef gitUrl = 'https://github.com/jeasonlzy/OkGo.git'\ngroup = \"com.lzy.net\"       // 数据仓库依赖第一部分\n\ninstall {\n    repositories.mavenInstaller {\n        pom {\n            project {\n                packaging 'aar'\n                name 'okserver For Android'     // 项目描述\n                url siteUrl\n                licenses {\n                    license {\n                        name 'The Apache Software License, Version 2.0'\n                        url 'http://www.apache.org/licenses/LICENSE-2.0.txt'\n                    }\n                }\n                developers {\n                    developer {\n                        id 'jeasonlzy'                // 开发者信息\n                        name 'LiaoZiYao'              // 开发者信息\n                        email 'liaojeason@126.com'    // 开发者信息\n                    }\n                }\n                scm {\n                    connection gitUrl\n                    developerConnection gitUrl\n                    url siteUrl\n                }\n            }\n        }\n    }\n}\n\ntask sourcesJar(type: Jar) {\n    from android.sourceSets.main.java.srcDirs\n    classifier = 'sources'\n}\n\ntask javadoc(type: Javadoc) {\n    source = android.sourceSets.main.java.srcDirs\n    classpath += project.files(android.getBootClasspath().join(File.pathSeparator))\n}\n\ntask javadocJar(type: Jar, dependsOn: javadoc) {\n    classifier = 'javadoc'\n    from javadoc.destinationDir\n}\n\njavadoc {\n    options {\n        encoding \"UTF-8\"\n        charSet 'UTF-8'\n        author true\n        version true\n        links \"http://docs.oracle.com/javase/7/docs/api\"\n        title 'okrx2 For Android'   // 文档标题\n    }\n}\n\nartifacts {\n//    archives javadocJar\n    archives sourcesJar\n}\n\n// 生成jar包\ntask releaseJar(type: Copy) {\n    from( 'build/intermediates/bundles/default')\n    into( '../jar')\n    include('classes.jar')\n    rename('classes.jar', 'okrx2-' + version + '.jar')\n}\n\nProperties properties = new Properties()\nproperties.load(project.rootProject.file('local.properties').newDataInputStream())\nbintray {\n    user = properties.getProperty(\"bintray.user\")\n    key = properties.getProperty(\"bintray.apikey\")\n    configurations = ['archives']\n    pkg {\n        repo = \"maven\"\n        name = \"okrx2\"             // 数据仓库依赖第二部分\n        websiteUrl = siteUrl\n        vcsUrl = gitUrl\n        licenses = [\"Apache-2.0\"]\n        publish = true\n    }\n}\n"
  },
  {
    "path": "okrx2/build.gradle",
    "content": "apply plugin: 'com.android.library'\n\nandroid {\n    compileSdkVersion rootProject.ext.compileSdkVersion\n    buildToolsVersion rootProject.ext.buildToolsVersion\n\n    defaultConfig {\n        minSdkVersion rootProject.ext.libMinSdkVersion\n        targetSdkVersion rootProject.ext.targetSdkVersion\n        versionCode rootProject.ext.versionCode\n        versionName rootProject.ext.versionName_okrx2\n    }\n}\n\ndependencies {\n    compile fileTree(include: ['*.jar'], dir: 'libs')\n    compile 'io.reactivex.rxjava2:rxjava:2.1.1'\n//    compile \"com.lzy.net:okgo:$versionName_okgo\"\n    compile project(':okgo')\n}\n\n//apply from: 'bintray.gradle'\n"
  },
  {
    "path": "okrx2/proguard-rules.pro",
    "content": "# Add project specific ProGuard rules here.\n# By default, the flags in this file are appended to flags specified\n# in /Users/jeasonlzy/Android/sdk/tools/proguard/proguard-android.txt\n# You can edit the include path and order by changing the proguardFiles\n# directive in build.gradle.\n#\n# For more details, see\n#   http://developer.android.com/guide/developing/tools/proguard.html\n\n# Add any project specific keep options here:\n\n# If your project uses WebView with JS, uncomment the following\n# and specify the fully qualified class name to the JavaScript interface\n# class:\n#-keepclassmembers class fqcn.of.javascript.interface.for.webview {\n#   public *;\n#}\n\n# Uncomment this to preserve the line number information for\n# debugging stack traces.\n#-keepattributes SourceFile,LineNumberTable\n\n# If you keep the line number information, uncomment this to\n# hide the original source file name.\n#-renamesourcefileattribute SourceFile\n"
  },
  {
    "path": "okrx2/src/main/AndroidManifest.xml",
    "content": "<!--\n    Copyright 2016 jeasonlzy(廖子尧)\n    \n    Licensed under the Apache License, Version 2.0 (the \"License\");\n    you may not use this file except in compliance with the License.\n    You may obtain a copy of the License at\n    \n       http://www.apache.org/licenses/LICENSE-2.0\n       \n    Unless required by applicable law or agreed to in writing, software\n    distributed under the License is distributed on an \"AS IS\" BASIS,\n    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n    See the License for the specific language governing permissions and\n    limitations under the License.\n-->\n<manifest package=\"com.lzy.okrx2\">\n\n</manifest>\n"
  },
  {
    "path": "okrx2/src/main/java/com/lzy/okrx2/adapter/AnalysisParams.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.okrx2.adapter;\n\nimport com.lzy.okgo.adapter.AdapterParam;\nimport com.lzy.okgo.adapter.Call;\nimport com.lzy.okgo.model.Response;\nimport com.lzy.okrx2.observable.CallEnqueueObservable;\nimport com.lzy.okrx2.observable.CallExecuteObservable;\n\nimport io.reactivex.Observable;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：2017/5/27\n * 描    述：\n * 修订历史：\n * ================================================\n */\nclass AnalysisParams {\n\n    static <T> Observable<Response<T>> analysis(Call<T> call, AdapterParam param) {\n        Observable<Response<T>> observable;\n        if (param == null) param = new AdapterParam();\n        if (param.isAsync) {\n            observable = new CallEnqueueObservable<>(call);\n        } else {\n            observable = new CallExecuteObservable<>(call);\n        }\n        return observable;\n    }\n}\n"
  },
  {
    "path": "okrx2/src/main/java/com/lzy/okrx2/adapter/CompletableResponse.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.okrx2.adapter;\n\nimport com.lzy.okgo.adapter.AdapterParam;\nimport com.lzy.okgo.adapter.Call;\nimport com.lzy.okgo.adapter.CallAdapter;\n\nimport io.reactivex.Completable;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：2017/5/27\n * 描    述：\n * 修订历史：\n * ================================================\n */\npublic class CompletableResponse<T> implements CallAdapter<T, Completable> {\n    @Override\n    public Completable adapt(Call<T> call, AdapterParam param) {\n        ObservableResponse<T> observable = new ObservableResponse<>();\n        return observable.adapt(call, param).ignoreElements();\n    }\n}\n"
  },
  {
    "path": "okrx2/src/main/java/com/lzy/okrx2/adapter/FlowableBody.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.okrx2.adapter;\n\nimport com.lzy.okgo.adapter.AdapterParam;\nimport com.lzy.okgo.adapter.Call;\nimport com.lzy.okgo.adapter.CallAdapter;\n\nimport io.reactivex.BackpressureStrategy;\nimport io.reactivex.Flowable;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：2017/5/27\n * 描    述：\n * 修订历史：\n * ================================================\n */\npublic class FlowableBody<T> implements CallAdapter<T, Flowable<T>> {\n    @Override\n    public Flowable<T> adapt(Call<T> call, AdapterParam param) {\n        ObservableBody<T> observable = new ObservableBody<>();\n        return observable.adapt(call, param).toFlowable(BackpressureStrategy.LATEST);\n    }\n}\n"
  },
  {
    "path": "okrx2/src/main/java/com/lzy/okrx2/adapter/FlowableResponse.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.okrx2.adapter;\n\nimport com.lzy.okgo.adapter.AdapterParam;\nimport com.lzy.okgo.adapter.Call;\nimport com.lzy.okgo.adapter.CallAdapter;\nimport com.lzy.okgo.model.Response;\n\nimport io.reactivex.BackpressureStrategy;\nimport io.reactivex.Flowable;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：2017/5/27\n * 描    述：\n * 修订历史：\n * ================================================\n */\npublic class FlowableResponse<T> implements CallAdapter<T, Flowable<Response<T>>> {\n    @Override\n    public Flowable<Response<T>> adapt(Call<T> call, AdapterParam param) {\n        ObservableResponse<T> observable = new ObservableResponse<>();\n        return observable.adapt(call, param).toFlowable(BackpressureStrategy.LATEST);\n    }\n}\n"
  },
  {
    "path": "okrx2/src/main/java/com/lzy/okrx2/adapter/FlowableResult.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.okrx2.adapter;\n\nimport com.lzy.okgo.adapter.AdapterParam;\nimport com.lzy.okgo.adapter.Call;\nimport com.lzy.okgo.adapter.CallAdapter;\nimport com.lzy.okgo.model.Result;\n\nimport io.reactivex.BackpressureStrategy;\nimport io.reactivex.Flowable;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：2017/5/27\n * 描    述：\n * 修订历史：\n * ================================================\n */\npublic class FlowableResult<T> implements CallAdapter<T, Flowable<Result<T>>> {\n    @Override\n    public Flowable<Result<T>> adapt(Call<T> call, AdapterParam param) {\n        ObservableResult<T> observable = new ObservableResult<>();\n        return observable.adapt(call, param).toFlowable(BackpressureStrategy.LATEST);\n    }\n}\n"
  },
  {
    "path": "okrx2/src/main/java/com/lzy/okrx2/adapter/MaybeBody.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.okrx2.adapter;\n\nimport com.lzy.okgo.adapter.AdapterParam;\nimport com.lzy.okgo.adapter.Call;\nimport com.lzy.okgo.adapter.CallAdapter;\n\nimport io.reactivex.Maybe;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：2017/5/27\n * 描    述：\n * 修订历史：\n * ================================================\n */\npublic class MaybeBody<T> implements CallAdapter<T, Maybe<T>> {\n    @Override\n    public Maybe<T> adapt(Call<T> call, AdapterParam param) {\n        ObservableBody<T> observable = new ObservableBody<>();\n        return observable.adapt(call, param).singleElement();\n    }\n}\n"
  },
  {
    "path": "okrx2/src/main/java/com/lzy/okrx2/adapter/MaybeResponse.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.okrx2.adapter;\n\nimport com.lzy.okgo.adapter.AdapterParam;\nimport com.lzy.okgo.adapter.Call;\nimport com.lzy.okgo.adapter.CallAdapter;\nimport com.lzy.okgo.model.Response;\n\nimport io.reactivex.Maybe;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：2017/5/27\n * 描    述：\n * 修订历史：\n * ================================================\n */\npublic class MaybeResponse<T> implements CallAdapter<T, Maybe<Response<T>>> {\n    @Override\n    public Maybe<Response<T>> adapt(Call<T> call, AdapterParam param) {\n        ObservableResponse<T> observable = new ObservableResponse<>();\n        return observable.adapt(call, param).singleElement();\n    }\n}\n"
  },
  {
    "path": "okrx2/src/main/java/com/lzy/okrx2/adapter/MaybeResult.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.okrx2.adapter;\n\nimport com.lzy.okgo.adapter.AdapterParam;\nimport com.lzy.okgo.adapter.Call;\nimport com.lzy.okgo.adapter.CallAdapter;\nimport com.lzy.okgo.model.Result;\n\nimport io.reactivex.Maybe;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：2017/5/27\n * 描    述：\n * 修订历史：\n * ================================================\n */\npublic class MaybeResult<T> implements CallAdapter<T, Maybe<Result<T>>> {\n    @Override\n    public Maybe<Result<T>> adapt(Call<T> call, AdapterParam param) {\n        ObservableResult<T> observable = new ObservableResult<>();\n        return observable.adapt(call, param).singleElement();\n    }\n}\n"
  },
  {
    "path": "okrx2/src/main/java/com/lzy/okrx2/adapter/ObservableBody.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.okrx2.adapter;\n\nimport com.lzy.okgo.adapter.AdapterParam;\nimport com.lzy.okgo.adapter.Call;\nimport com.lzy.okgo.adapter.CallAdapter;\nimport com.lzy.okgo.model.Response;\nimport com.lzy.okrx2.observable.BodyObservable;\n\nimport io.reactivex.Observable;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：2017/5/27\n * 描    述：\n * 修订历史：\n * ================================================\n */\npublic class ObservableBody<T> implements CallAdapter<T, Observable<T>> {\n    @Override\n    public Observable<T> adapt(Call<T> call, AdapterParam param) {\n        Observable<Response<T>> observable = AnalysisParams.analysis(call, param);\n        return new BodyObservable<>(observable);\n    }\n}\n"
  },
  {
    "path": "okrx2/src/main/java/com/lzy/okrx2/adapter/ObservableResponse.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.okrx2.adapter;\n\nimport com.lzy.okgo.adapter.AdapterParam;\nimport com.lzy.okgo.adapter.Call;\nimport com.lzy.okgo.adapter.CallAdapter;\nimport com.lzy.okgo.model.Response;\n\nimport io.reactivex.Observable;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：2017/5/27\n * 描    述：\n * 修订历史：\n * ================================================\n */\npublic class ObservableResponse<T> implements CallAdapter<T, Observable<Response<T>>> {\n    @Override\n    public Observable<Response<T>> adapt(Call<T> call, AdapterParam param) {\n        return AnalysisParams.analysis(call, param);\n    }\n}\n"
  },
  {
    "path": "okrx2/src/main/java/com/lzy/okrx2/adapter/ObservableResult.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.okrx2.adapter;\n\nimport com.lzy.okgo.adapter.AdapterParam;\nimport com.lzy.okgo.adapter.Call;\nimport com.lzy.okgo.adapter.CallAdapter;\nimport com.lzy.okgo.model.Response;\nimport com.lzy.okgo.model.Result;\nimport com.lzy.okrx2.observable.ResultObservable;\n\nimport io.reactivex.Observable;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：2017/5/27\n * 描    述：\n * 修订历史：\n * ================================================\n */\npublic class ObservableResult<T> implements CallAdapter<T, Observable<Result<T>>> {\n    @Override\n    public Observable<Result<T>> adapt(Call<T> call, AdapterParam param) {\n        Observable<Response<T>> observable = AnalysisParams.analysis(call, param);\n        return new ResultObservable<>(observable);\n    }\n}\n"
  },
  {
    "path": "okrx2/src/main/java/com/lzy/okrx2/adapter/SingleBody.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.okrx2.adapter;\n\nimport com.lzy.okgo.adapter.AdapterParam;\nimport com.lzy.okgo.adapter.Call;\nimport com.lzy.okgo.adapter.CallAdapter;\n\nimport io.reactivex.Single;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：2017/5/27\n * 描    述：\n * 修订历史：\n * ================================================\n */\npublic class SingleBody<T> implements CallAdapter<T, Single<T>> {\n    @Override\n    public Single<T> adapt(Call<T> call, AdapterParam param) {\n        ObservableBody<T> observable = new ObservableBody<>();\n        return observable.adapt(call, param).singleOrError();\n    }\n}\n"
  },
  {
    "path": "okrx2/src/main/java/com/lzy/okrx2/adapter/SingleResponse.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.okrx2.adapter;\n\nimport com.lzy.okgo.adapter.AdapterParam;\nimport com.lzy.okgo.adapter.Call;\nimport com.lzy.okgo.adapter.CallAdapter;\nimport com.lzy.okgo.model.Response;\n\nimport io.reactivex.Single;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：2017/5/27\n * 描    述：\n * 修订历史：\n * ================================================\n */\npublic class SingleResponse<T> implements CallAdapter<T, Single<Response<T>>> {\n    @Override\n    public Single<Response<T>> adapt(Call<T> call, AdapterParam param) {\n        ObservableResponse<T> observable = new ObservableResponse<>();\n        return observable.adapt(call, param).singleOrError();\n    }\n}\n"
  },
  {
    "path": "okrx2/src/main/java/com/lzy/okrx2/adapter/SingleResult.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.okrx2.adapter;\n\nimport com.lzy.okgo.adapter.AdapterParam;\nimport com.lzy.okgo.adapter.Call;\nimport com.lzy.okgo.adapter.CallAdapter;\nimport com.lzy.okgo.model.Result;\n\nimport io.reactivex.Single;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：2017/5/27\n * 描    述：\n * 修订历史：\n * ================================================\n */\npublic class SingleResult<T> implements CallAdapter<T, Single<Result<T>>> {\n    @Override\n    public Single<Result<T>> adapt(Call<T> call, AdapterParam param) {\n        ObservableResult<T> observable = new ObservableResult<>();\n        return observable.adapt(call, param).singleOrError();\n    }\n}\n"
  },
  {
    "path": "okrx2/src/main/java/com/lzy/okrx2/observable/BodyObservable.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.okrx2.observable;\n\nimport com.lzy.okgo.exception.HttpException;\nimport com.lzy.okgo.model.Response;\n\nimport io.reactivex.Observable;\nimport io.reactivex.Observer;\nimport io.reactivex.disposables.Disposable;\nimport io.reactivex.exceptions.CompositeException;\nimport io.reactivex.exceptions.Exceptions;\nimport io.reactivex.plugins.RxJavaPlugins;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：16/9/11\n * 描    述：\n * 修订历史：\n * ================================================\n */\npublic final class BodyObservable<T> extends Observable<T> {\n    private final Observable<Response<T>> upstream;\n\n    public BodyObservable(Observable<Response<T>> upstream) {\n        this.upstream = upstream;\n    }\n\n    @Override\n    protected void subscribeActual(Observer<? super T> observer) {\n        upstream.subscribe(new BodyObserver<T>(observer));\n    }\n\n    private static class BodyObserver<R> implements Observer<Response<R>> {\n        private final Observer<? super R> observer;\n        private boolean terminated;\n\n        BodyObserver(Observer<? super R> observer) {\n            this.observer = observer;\n        }\n\n        @Override\n        public void onSubscribe(Disposable disposable) {\n            observer.onSubscribe(disposable);\n        }\n\n        @Override\n        public void onNext(Response<R> response) {\n            if (response.isSuccessful()) {\n                observer.onNext(response.body());\n            } else {\n                terminated = true;\n                Throwable t = new HttpException(response);\n                try {\n                    observer.onError(t);\n                } catch (Throwable inner) {\n                    Exceptions.throwIfFatal(inner);\n                    RxJavaPlugins.onError(new CompositeException(t, inner));\n                }\n            }\n        }\n\n        @Override\n        public void onComplete() {\n            if (!terminated) {\n                observer.onComplete();\n            } else {\n                // This should never happen! onNext handles and forwards errors automatically.\n                Throwable broken = new AssertionError(\"This should never happen! Report as a bug with the full stacktrace.\");\n                RxJavaPlugins.onError(broken);\n            }\n        }\n\n        @Override\n        public void onError(Throwable throwable) {\n            if (!terminated) {\n                observer.onError(throwable);\n            } else {\n                // This should never happen! onNext handles and forwards errors automatically.\n                Throwable broken = new AssertionError(\"This should never happen! Report as a bug with the full stacktrace.\");\n                //noinspection UnnecessaryInitCause Two-arg AssertionError constructor is 1.7+ only.\n                broken.initCause(throwable);\n                RxJavaPlugins.onError(broken);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "okrx2/src/main/java/com/lzy/okrx2/observable/CallEnqueueObservable.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.okrx2.observable;\n\nimport com.lzy.okgo.adapter.Call;\nimport com.lzy.okgo.callback.Callback;\nimport com.lzy.okgo.model.Progress;\nimport com.lzy.okgo.model.Response;\nimport com.lzy.okgo.request.base.Request;\n\nimport io.reactivex.Observable;\nimport io.reactivex.Observer;\nimport io.reactivex.disposables.Disposable;\nimport io.reactivex.exceptions.CompositeException;\nimport io.reactivex.exceptions.Exceptions;\nimport io.reactivex.plugins.RxJavaPlugins;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：16/9/11\n * 描    述：\n * 修订历史：\n * ================================================\n */\npublic class CallEnqueueObservable<T> extends Observable<Response<T>> {\n    private final Call<T> originalCall;\n\n    public CallEnqueueObservable(Call<T> originalCall) {\n        this.originalCall = originalCall;\n    }\n\n    @Override\n    protected void subscribeActual(Observer<? super Response<T>> observer) {\n        // Since Call is a one-shot type, clone it for each new observer.\n        Call<T> call = originalCall.clone();\n        CallCallback<T> callback = new CallCallback<>(call, observer);\n        observer.onSubscribe(callback);\n        call.execute(callback);\n    }\n\n    private static final class CallCallback<T> implements Disposable, Callback<T> {\n        private final Call<T> call;\n        private final Observer<? super Response<T>> observer;\n        boolean terminated = false;\n\n        CallCallback(Call<T> call, Observer<? super Response<T>> observer) {\n            this.call = call;\n            this.observer = observer;\n        }\n\n        @Override\n        public void dispose() {\n            call.cancel();\n        }\n\n        @Override\n        public boolean isDisposed() {\n            return call.isCanceled();\n        }\n\n        @Override\n        public T convertResponse(okhttp3.Response response) throws Throwable {\n            // okrx 使用converter转换，不需要这个解析方法\n            return null;\n        }\n\n        @Override\n        public void onStart(Request<T, ? extends Request> request) {\n        }\n\n        @Override\n        public void onSuccess(Response<T> response) {\n            if (call.isCanceled()) return;\n\n            try {\n                observer.onNext(response);\n            } catch (Exception e) {\n                if (terminated) {\n                    RxJavaPlugins.onError(e);\n                } else {\n                    onError(response);\n                }\n            }\n        }\n\n        @Override\n        public void onCacheSuccess(Response<T> response) {\n            onSuccess(response);\n        }\n\n        @Override\n        public void onError(Response<T> response) {\n            if (call.isCanceled()) return;\n\n            Throwable throwable = response.getException();\n            try {\n                terminated = true;\n                observer.onError(throwable);\n            } catch (Throwable inner) {\n                Exceptions.throwIfFatal(inner);\n                RxJavaPlugins.onError(new CompositeException(throwable, inner));\n            }\n        }\n\n        @Override\n        public void onFinish() {\n            if (call.isCanceled()) return;\n\n            try {\n                terminated = true;\n                observer.onComplete();\n            } catch (Throwable inner) {\n                Exceptions.throwIfFatal(inner);\n                RxJavaPlugins.onError(inner);\n            }\n\n        }\n\n        @Override\n        public void uploadProgress(Progress progress) {\n        }\n\n        @Override\n        public void downloadProgress(Progress progress) {\n        }\n    }\n}\n"
  },
  {
    "path": "okrx2/src/main/java/com/lzy/okrx2/observable/CallExecuteObservable.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.okrx2.observable;\n\nimport com.lzy.okgo.adapter.Call;\nimport com.lzy.okgo.model.Response;\n\nimport io.reactivex.Observable;\nimport io.reactivex.Observer;\nimport io.reactivex.disposables.Disposable;\nimport io.reactivex.exceptions.CompositeException;\nimport io.reactivex.exceptions.Exceptions;\nimport io.reactivex.plugins.RxJavaPlugins;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：16/9/11\n * 描    述：\n * 修订历史：\n * ================================================\n */\npublic class CallExecuteObservable<T> extends Observable<Response<T>> {\n    private final Call<T> originalCall;\n\n    public CallExecuteObservable(Call<T> originalCall) {\n        this.originalCall = originalCall;\n    }\n\n    @Override\n    protected void subscribeActual(Observer<? super Response<T>> observer) {\n        // Since Call is a one-shot type, clone it for each new observer.\n        Call<T> call = originalCall.clone();\n        observer.onSubscribe(new CallDisposable(call));\n\n        boolean terminated = false;\n        try {\n            Response<T> response = call.execute();\n            if (!call.isCanceled()) {\n                observer.onNext(response);\n            }\n            if (!call.isCanceled()) {\n                terminated = true;\n                observer.onComplete();\n            }\n        } catch (Throwable t) {\n            Exceptions.throwIfFatal(t);\n            if (terminated) {\n                RxJavaPlugins.onError(t);\n            } else if (!call.isCanceled()) {\n                try {\n                    observer.onError(t);\n                } catch (Throwable inner) {\n                    Exceptions.throwIfFatal(inner);\n                    RxJavaPlugins.onError(new CompositeException(t, inner));\n                }\n            }\n        }\n    }\n\n    private static final class CallDisposable implements Disposable {\n        private final Call<?> call;\n\n        CallDisposable(Call<?> call) {\n            this.call = call;\n        }\n\n        @Override\n        public void dispose() {\n            call.cancel();\n        }\n\n        @Override\n        public boolean isDisposed() {\n            return call.isCanceled();\n        }\n    }\n}\n"
  },
  {
    "path": "okrx2/src/main/java/com/lzy/okrx2/observable/ResultObservable.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.okrx2.observable;\n\nimport com.lzy.okgo.model.Response;\nimport com.lzy.okgo.model.Result;\n\nimport io.reactivex.Observable;\nimport io.reactivex.Observer;\nimport io.reactivex.disposables.Disposable;\nimport io.reactivex.exceptions.CompositeException;\nimport io.reactivex.exceptions.Exceptions;\nimport io.reactivex.plugins.RxJavaPlugins;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：16/9/11\n * 描    述：\n * 修订历史：\n * ================================================\n */\npublic class ResultObservable<T> extends Observable<Result<T>> {\n    private final Observable<Response<T>> upstream;\n\n    public ResultObservable(Observable<Response<T>> upstream) {\n        this.upstream = upstream;\n    }\n\n    @Override\n    protected void subscribeActual(Observer<? super Result<T>> observer) {\n        upstream.subscribe(new ResultObserver<T>(observer));\n    }\n\n    private static class ResultObserver<R> implements Observer<Response<R>> {\n        private final Observer<? super Result<R>> observer;\n\n        ResultObserver(Observer<? super Result<R>> observer) {\n            this.observer = observer;\n        }\n\n        @Override\n        public void onSubscribe(Disposable disposable) {\n            observer.onSubscribe(disposable);\n        }\n\n        @Override\n        public void onNext(Response<R> response) {\n            observer.onNext(Result.response(response));\n        }\n\n        @Override\n        public void onError(Throwable throwable) {\n            try {\n                observer.onNext(Result.<R>error(throwable));\n            } catch (Throwable t) {\n                try {\n                    observer.onError(t);\n                } catch (Throwable inner) {\n                    Exceptions.throwIfFatal(inner);\n                    RxJavaPlugins.onError(new CompositeException(t, inner));\n                }\n                return;\n            }\n            observer.onComplete();\n        }\n\n        @Override\n        public void onComplete() {\n            observer.onComplete();\n        }\n    }\n}\n"
  },
  {
    "path": "okserver/.gitignore",
    "content": "/build\n"
  },
  {
    "path": "okserver/bintray.gradle",
    "content": "apply plugin: 'com.github.dcendents.android-maven'\napply plugin: 'com.jfrog.bintray'\n\nversion = rootProject.ext.versionName_okserver      // 数据仓库依赖第三部分\n\ndef siteUrl = 'https://github.com/jeasonlzy/OkGo'\ndef gitUrl = 'https://github.com/jeasonlzy/OkGo.git'\ngroup = \"com.lzy.net\"       // 数据仓库依赖第一部分\n\ninstall {\n    repositories.mavenInstaller {\n        pom {\n            project {\n                packaging 'aar'\n                name 'okserver For Android'     // 项目描述\n                url siteUrl\n                licenses {\n                    license {\n                        name 'The Apache Software License, Version 2.0'\n                        url 'http://www.apache.org/licenses/LICENSE-2.0.txt'\n                    }\n                }\n                developers {\n                    developer {\n                        id 'jeasonlzy'                // 开发者信息\n                        name 'LiaoZiYao'              // 开发者信息\n                        email 'liaojeason@126.com'    // 开发者信息\n                    }\n                }\n                scm {\n                    connection gitUrl\n                    developerConnection gitUrl\n                    url siteUrl\n                }\n            }\n        }\n    }\n}\n\ntask sourcesJar(type: Jar) {\n    from android.sourceSets.main.java.srcDirs\n    classifier = 'sources'\n}\n\ntask javadoc(type: Javadoc) {\n    source = android.sourceSets.main.java.srcDirs\n    classpath += project.files(android.getBootClasspath().join(File.pathSeparator))\n}\n\ntask javadocJar(type: Jar, dependsOn: javadoc) {\n    classifier = 'javadoc'\n    from javadoc.destinationDir\n}\n\njavadoc {\n    options {\n        encoding \"UTF-8\"\n        charSet 'UTF-8'\n        author true\n        version true\n        links \"http://docs.oracle.com/javase/7/docs/api\"\n        title 'okserver For Android'   // 文档标题\n    }\n}\n\nartifacts {\n//    archives javadocJar\n    archives sourcesJar\n}\n\n// 生成jar包\ntask releaseJar(type: Copy) {\n    from( 'build/intermediates/bundles/default')\n    into( '../jar')\n    include('classes.jar')\n    rename('classes.jar', 'okserver-' + version + '.jar')\n}\n\nProperties properties = new Properties()\nproperties.load(project.rootProject.file('local.properties').newDataInputStream())\nbintray {\n    user = properties.getProperty(\"bintray.user\")\n    key = properties.getProperty(\"bintray.apikey\")\n    configurations = ['archives']\n    pkg {\n        repo = \"maven\"\n        name = \"okserver\"             // 数据仓库依赖第二部分\n        websiteUrl = siteUrl\n        vcsUrl = gitUrl\n        licenses = [\"Apache-2.0\"]\n        publish = true\n    }\n}\n"
  },
  {
    "path": "okserver/build.gradle",
    "content": "apply plugin: 'com.android.library'\n\nandroid {\n    compileSdkVersion rootProject.ext.compileSdkVersion\n    buildToolsVersion rootProject.ext.buildToolsVersion\n\n    defaultConfig {\n        minSdkVersion rootProject.ext.libMinSdkVersion\n        targetSdkVersion rootProject.ext.targetSdkVersion\n        versionCode rootProject.ext.versionCode\n        versionName rootProject.ext.versionName_okserver\n    }\n}\n\ndependencies {\n    compile fileTree(include: ['*.jar'], dir: 'libs')\n//    compile \"com.lzy.net:okgo:$versionName_okgo\"\n    compile project(':okgo')\n}\n\n//apply from: 'bintray.gradle'"
  },
  {
    "path": "okserver/proguard-rules.pro",
    "content": "# Add project specific ProGuard rules here.\n# By default, the flags in this file are appended to flags specified\n# in E:\\Android\\SDK/tools/proguard/proguard-android.txt\n# You can edit the include path and order by changing the proguardFiles\n# directive in build.gradle.\n#\n# For more details, see\n#   http://developer.android.com/guide/developing/tools/proguard.html\n\n# Add any project specific keep options here:\n\n# If your project uses WebView with JS, uncomment the following\n# and specify the fully qualified class name to the JavaScript interface\n# class:\n#-keepclassmembers class fqcn.of.javascript.interface.for.webview {\n#   public *;\n#}\n"
  },
  {
    "path": "okserver/src/main/AndroidManifest.xml",
    "content": "<!--\n    Copyright 2016 jeasonlzy(廖子尧)\n    \n    Licensed under the Apache License, Version 2.0 (the \"License\");\n    you may not use this file except in compliance with the License.\n    You may obtain a copy of the License at\n    \n       http://www.apache.org/licenses/LICENSE-2.0\n       \n    Unless required by applicable law or agreed to in writing, software\n    distributed under the License is distributed on an \"AS IS\" BASIS,\n    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n    See the License for the specific language governing permissions and\n    limitations under the License.\n-->\n<manifest package=\"com.lzy.okserver\">\n\n</manifest>\n"
  },
  {
    "path": "okserver/src/main/java/com/lzy/okserver/OkDownload.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.okserver;\n\nimport android.os.Environment;\n\nimport com.lzy.okgo.db.DownloadManager;\nimport com.lzy.okgo.model.Progress;\nimport com.lzy.okgo.request.base.Request;\nimport com.lzy.okgo.utils.IOUtils;\nimport com.lzy.okgo.utils.OkLogger;\nimport com.lzy.okserver.download.DownloadTask;\nimport com.lzy.okserver.download.DownloadThreadPool;\nimport com.lzy.okserver.task.XExecutor;\n\nimport java.io.File;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.ConcurrentHashMap;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：2016/1/19\n * 描    述：全局的下载管理类\n * 修订历史：\n * ================================================\n */\npublic class OkDownload {\n\n    private String folder;                                      //下载的默认文件夹\n    private DownloadThreadPool threadPool;                      //下载的线程池\n    private ConcurrentHashMap<String, DownloadTask> taskMap;    //所有任务\n\n    public static OkDownload getInstance() {\n        return OkDownloadHolder.instance;\n    }\n\n    private static class OkDownloadHolder {\n        private static final OkDownload instance = new OkDownload();\n    }\n\n    private OkDownload() {\n        folder = Environment.getExternalStorageDirectory() + File.separator + \"download\" + File.separator;\n        IOUtils.createFolder(folder);\n        threadPool = new DownloadThreadPool();\n        taskMap = new ConcurrentHashMap<>();\n\n        //校验数据的有效性，防止下载过程中退出，第二次进入的时候，由于状态没有更新导致的状态错误\n        List<Progress> taskList = DownloadManager.getInstance().getDownloading();\n        for (Progress info : taskList) {\n            if (info.status == Progress.WAITING || info.status == Progress.LOADING || info.status == Progress.PAUSE) {\n                info.status = Progress.NONE;\n            }\n        }\n        DownloadManager.getInstance().replace(taskList);\n    }\n\n    public static DownloadTask request(String tag, Request<File, ? extends Request> request) {\n        Map<String, DownloadTask> taskMap = OkDownload.getInstance().getTaskMap();\n        DownloadTask task = taskMap.get(tag);\n        if (task == null) {\n            task = new DownloadTask(tag, request);\n            taskMap.put(tag, task);\n        }\n        return task;\n    }\n\n    /** 从数据库中恢复任务 */\n    public static DownloadTask restore(Progress progress) {\n        Map<String, DownloadTask> taskMap = OkDownload.getInstance().getTaskMap();\n        DownloadTask task = taskMap.get(progress.tag);\n        if (task == null) {\n            task = new DownloadTask(progress);\n            taskMap.put(progress.tag, task);\n        }\n        return task;\n    }\n\n    /** 从数据库中恢复任务 */\n    public static List<DownloadTask> restore(List<Progress> progressList) {\n        Map<String, DownloadTask> taskMap = OkDownload.getInstance().getTaskMap();\n        List<DownloadTask> tasks = new ArrayList<>();\n        for (Progress progress : progressList) {\n            DownloadTask task = taskMap.get(progress.tag);\n            if (task == null) {\n                task = new DownloadTask(progress);\n                taskMap.put(progress.tag, task);\n            }\n            tasks.add(task);\n        }\n        return tasks;\n    }\n\n    /** 开始所有任务 */\n    public void startAll() {\n        for (Map.Entry<String, DownloadTask> entry : taskMap.entrySet()) {\n            DownloadTask task = entry.getValue();\n            if (task == null) {\n                OkLogger.w(\"can't find task with tag = \" + entry.getKey());\n                continue;\n            }\n            task.start();\n        }\n    }\n\n    /** 暂停全部任务 */\n    public void pauseAll() {\n        //先停止未开始的任务\n        for (Map.Entry<String, DownloadTask> entry : taskMap.entrySet()) {\n            DownloadTask task = entry.getValue();\n            if (task == null) {\n                OkLogger.w(\"can't find task with tag = \" + entry.getKey());\n                continue;\n            }\n            if (task.progress.status != Progress.LOADING) {\n                task.pause();\n            }\n        }\n        //再停止进行中的任务\n        for (Map.Entry<String, DownloadTask> entry : taskMap.entrySet()) {\n            DownloadTask task = entry.getValue();\n            if (task == null) {\n                OkLogger.w(\"can't find task with tag = \" + entry.getKey());\n                continue;\n            }\n            if (task.progress.status == Progress.LOADING) {\n                task.pause();\n            }\n        }\n    }\n\n    /** 删除所有任务 */\n    public void removeAll() {\n        removeAll(false);\n    }\n\n    /**\n     * 删除所有任务\n     *\n     * @param isDeleteFile 删除任务是否删除文件\n     */\n    public void removeAll(boolean isDeleteFile) {\n        Map<String, DownloadTask> map = new HashMap<>(taskMap);\n        //先删除未开始的任务\n        for (Map.Entry<String, DownloadTask> entry : map.entrySet()) {\n            DownloadTask task = entry.getValue();\n            if (task == null) {\n                OkLogger.w(\"can't find task with tag = \" + entry.getKey());\n                continue;\n            }\n            if (task.progress.status != Progress.LOADING) {\n                task.remove(isDeleteFile);\n            }\n        }\n        //再删除进行中的任务\n        for (Map.Entry<String, DownloadTask> entry : map.entrySet()) {\n            DownloadTask task = entry.getValue();\n            if (task == null) {\n                OkLogger.w(\"can't find task with tag = \" + entry.getKey());\n                continue;\n            }\n            if (task.progress.status == Progress.LOADING) {\n                task.remove(isDeleteFile);\n            }\n        }\n    }\n\n    /** 设置下载目录 */\n    public String getFolder() {\n        return folder;\n    }\n\n    public OkDownload setFolder(String folder) {\n        this.folder = folder;\n        return this;\n    }\n\n    public DownloadThreadPool getThreadPool() {\n        return threadPool;\n    }\n\n    public Map<String, DownloadTask> getTaskMap() {\n        return taskMap;\n    }\n\n    public DownloadTask getTask(String tag) {\n        return taskMap.get(tag);\n    }\n\n    public boolean hasTask(String tag) {\n        return taskMap.containsKey(tag);\n    }\n\n    public DownloadTask removeTask(String tag) {\n        return taskMap.remove(tag);\n    }\n\n    public void addOnAllTaskEndListener(XExecutor.OnAllTaskEndListener listener) {\n        threadPool.getExecutor().addOnAllTaskEndListener(listener);\n    }\n\n    public void removeOnAllTaskEndListener(XExecutor.OnAllTaskEndListener listener) {\n        threadPool.getExecutor().removeOnAllTaskEndListener(listener);\n    }\n}\n"
  },
  {
    "path": "okserver/src/main/java/com/lzy/okserver/OkUpload.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.okserver;\n\nimport com.lzy.okgo.db.UploadManager;\nimport com.lzy.okgo.model.Progress;\nimport com.lzy.okgo.request.base.Request;\nimport com.lzy.okgo.utils.OkLogger;\nimport com.lzy.okserver.task.XExecutor;\nimport com.lzy.okserver.upload.UploadTask;\nimport com.lzy.okserver.upload.UploadThreadPool;\n\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：2016/1/26\n * 描    述：全局的上传管理\n * 修订历史：\n * ================================================\n */\npublic class OkUpload {\n\n    private Map<String, UploadTask<?>> taskMap;         //所有任务\n    private UploadThreadPool threadPool;                //上传的线程池\n\n    public static OkUpload getInstance() {\n        return OkUploadHolder.instance;\n    }\n\n    private static class OkUploadHolder {\n        private static final OkUpload instance = new OkUpload();\n    }\n\n    private OkUpload() {\n        threadPool = new UploadThreadPool();\n        taskMap = new LinkedHashMap<>();\n\n        //校验数据的有效性，防止下载过程中退出，第二次进入的时候，由于状态没有更新导致的状态错误\n        List<Progress> taskList = UploadManager.getInstance().getUploading();\n        for (Progress info : taskList) {\n            if (info.status == Progress.WAITING || info.status == Progress.LOADING || info.status == Progress.PAUSE) {\n                info.status = Progress.NONE;\n            }\n        }\n        UploadManager.getInstance().replace(taskList);\n    }\n\n    public static <T> UploadTask<T> request(String tag, Request<T, ? extends Request> request) {\n        Map<String, UploadTask<?>> taskMap = OkUpload.getInstance().getTaskMap();\n        //noinspection unchecked\n        UploadTask<T> task = (UploadTask<T>) taskMap.get(tag);\n        if (task == null) {\n            task = new UploadTask<>(tag, request);\n            taskMap.put(tag, task);\n        }\n        return task;\n    }\n\n    /** 从数据库中恢复任务 */\n    public static <T> UploadTask<T> restore(Progress progress) {\n        Map<String, UploadTask<?>> taskMap = OkUpload.getInstance().getTaskMap();\n        //noinspection unchecked\n        UploadTask<T> task = (UploadTask<T>) taskMap.get(progress.tag);\n        if (task == null) {\n            task = new UploadTask<>(progress);\n            taskMap.put(progress.tag, task);\n        }\n        return task;\n    }\n\n    /** 从数据库中恢复任务 */\n    public static List<UploadTask<?>> restore(List<Progress> progressList) {\n        Map<String, UploadTask<?>> taskMap = OkUpload.getInstance().getTaskMap();\n        List<UploadTask<?>> tasks = new ArrayList<>();\n        for (Progress progress : progressList) {\n            UploadTask<?> task = taskMap.get(progress.tag);\n            if (task == null) {\n                task = new UploadTask<>(progress);\n                taskMap.put(progress.tag, task);\n            }\n            tasks.add(task);\n        }\n        return tasks;\n    }\n\n    /** 开始所有任务 */\n    public void startAll() {\n        for (Map.Entry<String, UploadTask<?>> entry : taskMap.entrySet()) {\n            UploadTask<?> task = entry.getValue();\n            if (task == null) {\n                OkLogger.w(\"can't find task with tag = \" + entry.getKey());\n                continue;\n            }\n            task.start();\n        }\n    }\n\n    /** 暂停全部任务 */\n    public void pauseAll() {\n        //先停止未开始的任务\n        for (Map.Entry<String, UploadTask<?>> entry : taskMap.entrySet()) {\n            UploadTask<?> task = entry.getValue();\n            if (task == null) {\n                OkLogger.w(\"can't find task with tag = \" + entry.getKey());\n                continue;\n            }\n            if (task.progress.status != Progress.LOADING) {\n                task.pause();\n            }\n        }\n        //再停止进行中的任务\n        for (Map.Entry<String, UploadTask<?>> entry : taskMap.entrySet()) {\n            UploadTask<?> task = entry.getValue();\n            if (task == null) {\n                OkLogger.w(\"can't find task with tag = \" + entry.getKey());\n                continue;\n            }\n            if (task.progress.status == Progress.LOADING) {\n                task.pause();\n            }\n        }\n    }\n\n    /** 删除所有任务 */\n    public void removeAll() {\n        Map<String, UploadTask<?>> map = new HashMap<>(taskMap);\n        //先删除未开始的任务\n        for (Map.Entry<String, UploadTask<?>> entry : map.entrySet()) {\n            UploadTask<?> task = entry.getValue();\n            if (task == null) {\n                OkLogger.w(\"can't find task with tag = \" + entry.getKey());\n                continue;\n            }\n            if (task.progress.status != Progress.LOADING) {\n                task.remove();\n            }\n        }\n        //再删除进行中的任务\n        for (Map.Entry<String, UploadTask<?>> entry : map.entrySet()) {\n            UploadTask<?> task = entry.getValue();\n            if (task == null) {\n                OkLogger.w(\"can't find task with tag = \" + entry.getKey());\n                continue;\n            }\n            if (task.progress.status == Progress.LOADING) {\n                task.remove();\n            }\n        }\n    }\n\n    public UploadThreadPool getThreadPool() {\n        return threadPool;\n    }\n\n    public Map<String, UploadTask<?>> getTaskMap() {\n        return taskMap;\n    }\n\n    public UploadTask<?> getTask(String tag) {\n        return taskMap.get(tag);\n    }\n\n    public boolean hasTask(String tag) {\n        return taskMap.containsKey(tag);\n    }\n\n    public UploadTask<?> removeTask(String tag) {\n        return taskMap.remove(tag);\n    }\n\n    public void addOnAllTaskEndListener(XExecutor.OnAllTaskEndListener listener) {\n        threadPool.getExecutor().addOnAllTaskEndListener(listener);\n    }\n\n    public void removeOnAllTaskEndListener(XExecutor.OnAllTaskEndListener listener) {\n        threadPool.getExecutor().removeOnAllTaskEndListener(listener);\n    }\n}\n"
  },
  {
    "path": "okserver/src/main/java/com/lzy/okserver/ProgressListener.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.okserver;\n\nimport com.lzy.okgo.model.Progress;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：2017/6/4\n * 描    述：\n * 修订历史：\n * ================================================\n */\npublic interface ProgressListener<T> {\n    /** 成功添加任务的回调 */\n    void onStart(Progress progress);\n\n    /** 下载进行时回调 */\n    void onProgress(Progress progress);\n\n    /** 下载出错时回调 */\n    void onError(Progress progress);\n\n    /** 下载完成时回调 */\n    void onFinish(T t, Progress progress);\n\n    /** 被移除时回调 */\n    void onRemove(Progress progress);\n}\n"
  },
  {
    "path": "okserver/src/main/java/com/lzy/okserver/download/DownloadListener.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.okserver.download;\n\nimport com.lzy.okserver.ProgressListener;\n\nimport java.io.File;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：2016/1/19\n * 描    述：全局的下载监听\n * 修订历史：\n * ================================================\n */\npublic abstract class DownloadListener implements ProgressListener<File> {\n\n    public final Object tag;\n\n    public DownloadListener(Object tag) {\n        this.tag = tag;\n    }\n}\n"
  },
  {
    "path": "okserver/src/main/java/com/lzy/okserver/download/DownloadTask.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.okserver.download;\n\nimport android.content.ContentValues;\nimport android.text.TextUtils;\n\nimport com.lzy.okgo.db.DownloadManager;\nimport com.lzy.okgo.exception.HttpException;\nimport com.lzy.okgo.exception.OkGoException;\nimport com.lzy.okgo.exception.StorageException;\nimport com.lzy.okgo.model.HttpHeaders;\nimport com.lzy.okgo.model.Progress;\nimport com.lzy.okgo.request.base.Request;\nimport com.lzy.okgo.utils.HttpUtils;\nimport com.lzy.okgo.utils.IOUtils;\nimport com.lzy.okgo.utils.OkLogger;\nimport com.lzy.okserver.OkDownload;\nimport com.lzy.okserver.task.PriorityRunnable;\n\nimport java.io.BufferedInputStream;\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.RandomAccessFile;\nimport java.io.Serializable;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.concurrent.ThreadPoolExecutor;\n\nimport okhttp3.Response;\nimport okhttp3.ResponseBody;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：2016/1/19\n * 描    述：文件的下载任务类\n * 修订历史：\n * ================================================\n */\npublic class DownloadTask implements Runnable {\n\n    private static final int BUFFER_SIZE = 1024 * 8;\n\n    public Progress progress;\n    public Map<Object, DownloadListener> listeners;\n    private ThreadPoolExecutor executor;\n    private PriorityRunnable priorityRunnable;\n\n    public DownloadTask(String tag, Request<File, ? extends Request> request) {\n        HttpUtils.checkNotNull(tag, \"tag == null\");\n        progress = new Progress();\n        progress.tag = tag;\n        progress.folder = OkDownload.getInstance().getFolder();\n        progress.url = request.getBaseUrl();\n        progress.status = Progress.NONE;\n        progress.totalSize = -1;\n        progress.request = request;\n\n        executor = OkDownload.getInstance().getThreadPool().getExecutor();\n        listeners = new HashMap<>();\n    }\n\n    public DownloadTask(Progress progress) {\n        HttpUtils.checkNotNull(progress, \"progress == null\");\n        this.progress = progress;\n        executor = OkDownload.getInstance().getThreadPool().getExecutor();\n        listeners = new HashMap<>();\n    }\n\n    public DownloadTask folder(String folder) {\n        if (folder != null && !TextUtils.isEmpty(folder.trim())) {\n            progress.folder = folder;\n        } else {\n            OkLogger.w(\"folder is null, ignored!\");\n        }\n        return this;\n    }\n\n    public DownloadTask fileName(String fileName) {\n        if (fileName != null && !TextUtils.isEmpty(fileName.trim())) {\n            progress.fileName = fileName;\n        } else {\n            OkLogger.w(\"fileName is null, ignored!\");\n        }\n        return this;\n    }\n\n    public DownloadTask priority(int priority) {\n        progress.priority = priority;\n        return this;\n    }\n\n    public DownloadTask extra1(Serializable extra1) {\n        progress.extra1 = extra1;\n        return this;\n    }\n\n    public DownloadTask extra2(Serializable extra2) {\n        progress.extra2 = extra2;\n        return this;\n    }\n\n    public DownloadTask extra3(Serializable extra3) {\n        progress.extra3 = extra3;\n        return this;\n    }\n\n    public DownloadTask save() {\n        if (!TextUtils.isEmpty(progress.folder) && !TextUtils.isEmpty(progress.fileName)) {\n            progress.filePath = new File(progress.folder, progress.fileName).getAbsolutePath();\n        }\n        DownloadManager.getInstance().replace(progress);\n        return this;\n    }\n\n    public DownloadTask register(DownloadListener listener) {\n        if (listener != null) {\n            listeners.put(listener.tag, listener);\n        }\n        return this;\n    }\n\n    public void unRegister(DownloadListener listener) {\n        HttpUtils.checkNotNull(listener, \"listener == null\");\n        listeners.remove(listener.tag);\n    }\n\n    public void unRegister(String tag) {\n        HttpUtils.checkNotNull(tag, \"tag == null\");\n        listeners.remove(tag);\n    }\n\n    public void start() {\n        if (OkDownload.getInstance().getTask(progress.tag) == null || DownloadManager.getInstance().get(progress.tag) == null) {\n            throw new IllegalStateException(\"you must call DownloadTask#save() before DownloadTask#start()！\");\n        }\n        if (progress.status == Progress.NONE || progress.status == Progress.PAUSE || progress.status == Progress.ERROR) {\n            postOnStart(progress);\n            postWaiting(progress);\n            priorityRunnable = new PriorityRunnable(progress.priority, this);\n            executor.execute(priorityRunnable);\n        } else if (progress.status == Progress.FINISH) {\n            if (progress.filePath == null) {\n                postOnError(progress, new StorageException(\"the file of the task with tag:\" + progress.tag + \" may be invalid or damaged, please call the method restart() to download again！\"));\n            } else {\n                File file = new File(progress.filePath);\n                if (file.exists() && file.length() == progress.totalSize) {\n                    postOnFinish(progress, new File(progress.filePath));\n                } else {\n                    postOnError(progress, new StorageException(\"the file \" + progress.filePath + \" may be invalid or damaged, please call the method restart() to download again！\"));\n                }\n            }\n        } else {\n            OkLogger.w(\"the task with tag \" + progress.tag + \" is already in the download queue, current task status is \" + progress.status);\n        }\n    }\n\n    public void restart() {\n        pause();\n        IOUtils.delFileOrFolder(progress.filePath);\n        progress.status = Progress.NONE;\n        progress.currentSize = 0;\n        progress.fraction = 0;\n        progress.speed = 0;\n        DownloadManager.getInstance().replace(progress);\n        start();\n    }\n\n    /** 暂停的方法 */\n    public void pause() {\n        executor.remove(priorityRunnable);\n        if (progress.status == Progress.WAITING) {\n            postPause(progress);\n        } else if (progress.status == Progress.LOADING) {\n            progress.speed = 0;\n            progress.status = Progress.PAUSE;\n        } else {\n            OkLogger.w(\"only the task with status WAITING(1) or LOADING(2) can pause, current status is \" + progress.status);\n        }\n    }\n\n    /** 删除一个任务,会删除下载文件 */\n    public void remove() {\n        remove(false);\n    }\n\n    /** 删除一个任务,会删除下载文件 */\n    public DownloadTask remove(boolean isDeleteFile) {\n        pause();\n        if (isDeleteFile) IOUtils.delFileOrFolder(progress.filePath);\n        DownloadManager.getInstance().delete(progress.tag);\n        DownloadTask task = OkDownload.getInstance().removeTask(progress.tag);\n        postOnRemove(progress);\n        return task;\n    }\n\n    @Override\n    public void run() {\n        //check breakpoint\n        long startPosition = progress.currentSize;\n        if (startPosition < 0) {\n            postOnError(progress, OkGoException.BREAKPOINT_EXPIRED());\n            return;\n        }\n        if (startPosition > 0) {\n            if (!TextUtils.isEmpty(progress.filePath)) {\n                File file = new File(progress.filePath);\n                if (!file.exists()) {\n                    postOnError(progress, OkGoException.BREAKPOINT_NOT_EXIST());\n                    return;\n                }\n            }\n        }\n\n        //request network from startPosition\n        Response response;\n        try {\n            Request<?, ? extends Request> request = progress.request;\n            request.headers(HttpHeaders.HEAD_KEY_RANGE, \"bytes=\" + startPosition + \"-\");\n            response = request.execute();\n        } catch (IOException e) {\n            postOnError(progress, e);\n            return;\n        }\n\n        //check network data\n        int code = response.code();\n        if (code == 404 || code >= 500) {\n            postOnError(progress, HttpException.NET_ERROR());\n            return;\n        }\n        ResponseBody body = response.body();\n        if (body == null) {\n            postOnError(progress, new HttpException(\"response body is null\"));\n            return;\n        }\n        if (progress.totalSize == -1) {\n            progress.totalSize = body.contentLength();\n        }\n\n        //create filename\n        String fileName = progress.fileName;\n        if (TextUtils.isEmpty(fileName)) {\n            fileName = HttpUtils.getNetFileName(response, progress.url);\n            progress.fileName = fileName;\n        }\n        if (!IOUtils.createFolder(progress.folder)) {\n            postOnError(progress, StorageException.NOT_AVAILABLE());\n            return;\n        }\n\n        //create and check file\n        File file;\n        if (TextUtils.isEmpty(progress.filePath)) {\n            file = new File(progress.folder, fileName);\n            progress.filePath = file.getAbsolutePath();\n        } else {\n            file = new File(progress.filePath);\n        }\n        if (startPosition > 0 && !file.exists()) {\n            postOnError(progress, OkGoException.BREAKPOINT_EXPIRED());\n            return;\n        }\n        if (startPosition > progress.totalSize) {\n            postOnError(progress, OkGoException.BREAKPOINT_EXPIRED());\n            return;\n        }\n        if (startPosition == 0 && file.exists()) {\n            IOUtils.delFileOrFolder(file);\n        }\n        if (startPosition == progress.totalSize && startPosition > 0) {\n            if (file.exists() && startPosition == file.length()) {\n                postOnFinish(progress, file);\n                return;\n            } else {\n                postOnError(progress, OkGoException.BREAKPOINT_EXPIRED());\n                return;\n            }\n        }\n\n        //start downloading\n        RandomAccessFile randomAccessFile;\n        try {\n            randomAccessFile = new RandomAccessFile(file, \"rw\");\n            randomAccessFile.seek(startPosition);\n            progress.currentSize = startPosition;\n        } catch (Exception e) {\n            postOnError(progress, e);\n            return;\n        }\n        try {\n            DownloadManager.getInstance().replace(progress);\n            download(body.byteStream(), randomAccessFile, progress);\n        } catch (IOException e) {\n            postOnError(progress, e);\n            return;\n        }\n\n        //check finish status\n        if (progress.status == Progress.PAUSE) {\n            postPause(progress);\n        } else if (progress.status == Progress.LOADING) {\n            if (file.length() == progress.totalSize) {\n                postOnFinish(progress, file);\n            } else {\n                postOnError(progress, OkGoException.BREAKPOINT_EXPIRED());\n            }\n        } else {\n            postOnError(progress, OkGoException.UNKNOWN());\n        }\n    }\n\n    /** 执行文件下载 */\n    private void download(InputStream input, RandomAccessFile out, Progress progress) throws IOException {\n        if (input == null || out == null) return;\n\n        progress.status = Progress.LOADING;\n        byte[] buffer = new byte[BUFFER_SIZE];\n        BufferedInputStream in = new BufferedInputStream(input, BUFFER_SIZE);\n        int len;\n        try {\n            while ((len = in.read(buffer, 0, BUFFER_SIZE)) != -1 && progress.status == Progress.LOADING) {\n                out.write(buffer, 0, len);\n\n                Progress.changeProgress(progress, len, progress.totalSize, new Progress.Action() {\n                    @Override\n                    public void call(Progress progress) {\n                        postLoading(progress);\n                    }\n                });\n            }\n        } finally {\n            IOUtils.closeQuietly(out);\n            IOUtils.closeQuietly(in);\n            IOUtils.closeQuietly(input);\n        }\n    }\n\n    private void postOnStart(final Progress progress) {\n        progress.speed = 0;\n        progress.status = Progress.NONE;\n        updateDatabase(progress);\n        HttpUtils.runOnUiThread(new Runnable() {\n            @Override\n            public void run() {\n                for (DownloadListener listener : listeners.values()) {\n                    listener.onStart(progress);\n                }\n            }\n        });\n    }\n\n    private void postWaiting(final Progress progress) {\n        progress.speed = 0;\n        progress.status = Progress.WAITING;\n        updateDatabase(progress);\n        HttpUtils.runOnUiThread(new Runnable() {\n            @Override\n            public void run() {\n                for (DownloadListener listener : listeners.values()) {\n                    listener.onProgress(progress);\n                }\n            }\n        });\n    }\n\n    private void postPause(final Progress progress) {\n        progress.speed = 0;\n        progress.status = Progress.PAUSE;\n        updateDatabase(progress);\n        HttpUtils.runOnUiThread(new Runnable() {\n            @Override\n            public void run() {\n                for (DownloadListener listener : listeners.values()) {\n                    listener.onProgress(progress);\n                }\n            }\n        });\n    }\n\n    private void postLoading(final Progress progress) {\n        updateDatabase(progress);\n        HttpUtils.runOnUiThread(new Runnable() {\n            @Override\n            public void run() {\n                for (DownloadListener listener : listeners.values()) {\n                    listener.onProgress(progress);\n                }\n            }\n        });\n    }\n\n    private void postOnError(final Progress progress, final Throwable throwable) {\n        progress.speed = 0;\n        progress.status = Progress.ERROR;\n        progress.exception = throwable;\n        updateDatabase(progress);\n        HttpUtils.runOnUiThread(new Runnable() {\n            @Override\n            public void run() {\n                for (DownloadListener listener : listeners.values()) {\n                    listener.onProgress(progress);\n                    listener.onError(progress);\n                }\n            }\n        });\n    }\n\n    private void postOnFinish(final Progress progress, final File file) {\n        progress.speed = 0;\n        progress.fraction = 1.0f;\n        progress.status = Progress.FINISH;\n        updateDatabase(progress);\n        HttpUtils.runOnUiThread(new Runnable() {\n            @Override\n            public void run() {\n                for (DownloadListener listener : listeners.values()) {\n                    listener.onProgress(progress);\n                    listener.onFinish(file, progress);\n                }\n            }\n        });\n    }\n\n    private void postOnRemove(final Progress progress) {\n        updateDatabase(progress);\n        HttpUtils.runOnUiThread(new Runnable() {\n            @Override\n            public void run() {\n                for (DownloadListener listener : listeners.values()) {\n                    listener.onRemove(progress);\n                }\n                listeners.clear();\n            }\n        });\n    }\n\n    private void updateDatabase(Progress progress) {\n        ContentValues contentValues = Progress.buildUpdateContentValues(progress);\n        DownloadManager.getInstance().update(contentValues, progress.tag);\n    }\n}\n"
  },
  {
    "path": "okserver/src/main/java/com/lzy/okserver/download/DownloadThreadPool.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.okserver.download;\n\nimport com.lzy.okserver.task.XExecutor;\nimport com.lzy.okserver.task.PriorityBlockingQueue;\n\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.ThreadPoolExecutor;\nimport java.util.concurrent.TimeUnit;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：2016/1/19\n * 描    述：下载管理的线程池\n * 修订历史：\n * ================================================\n */\npublic class DownloadThreadPool {\n    private static final int MAX_POOL_SIZE = 5;          //最大线程池的数量\n    private static final int KEEP_ALIVE_TIME = 1;        //存活的时间\n    private static final TimeUnit UNIT = TimeUnit.HOURS; //时间单位\n    private int corePoolSize = 3;                        //核心线程池的数量，同时能执行的线程数量，默认3个\n    private XExecutor executor;               //线程池执行器\n\n    public XExecutor getExecutor() {\n        if (executor == null) {\n            synchronized (DownloadThreadPool.class) {\n                if (executor == null) {\n                    executor = new XExecutor(corePoolSize, MAX_POOL_SIZE, KEEP_ALIVE_TIME, UNIT, //\n                                             new PriorityBlockingQueue<Runnable>(),   //无限容量的缓冲队列\n                                             Executors.defaultThreadFactory(),        //线程创建工厂\n                                             new ThreadPoolExecutor.AbortPolicy());   //继续超出上限的策略，阻止\n                }\n            }\n        }\n        return executor;\n    }\n\n    /** 必须在首次执行前设置，否者无效 ,范围1-5之间 */\n    public void setCorePoolSize(int corePoolSize) {\n        if (corePoolSize <= 0) corePoolSize = 1;\n        if (corePoolSize > MAX_POOL_SIZE) corePoolSize = MAX_POOL_SIZE;\n        this.corePoolSize = corePoolSize;\n    }\n\n    /** 执行任务 */\n    public void execute(Runnable runnable) {\n        if (runnable != null) {\n            getExecutor().execute(runnable);\n        }\n    }\n\n    /** 移除线程 */\n    public void remove(Runnable runnable) {\n        if (runnable != null) {\n            getExecutor().remove(runnable);\n        }\n    }\n}\n"
  },
  {
    "path": "okserver/src/main/java/com/lzy/okserver/task/PriorityBlockingQueue.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.okserver.task;\n\nimport com.lzy.okgo.model.Priority;\n\nimport java.util.AbstractQueue;\nimport java.util.Collection;\nimport java.util.Iterator;\nimport java.util.NoSuchElementException;\nimport java.util.concurrent.BlockingQueue;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.atomic.AtomicInteger;\nimport java.util.concurrent.locks.Condition;\nimport java.util.concurrent.locks.ReentrantLock;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：2016/1/19\n * 描    述：带有优先级的阻塞队列\n * 修订历史：\n * ================================================\n */\npublic class PriorityBlockingQueue<E> extends AbstractQueue<E> implements BlockingQueue<E>, java.io.Serializable {\n    private static final long serialVersionUID = -6903933977591709194L;\n\n    /**\n     * The capacity bound, or Integer.MAX_VALUE if none\n     */\n    private final int capacity;\n\n    /**\n     * Current number of elements\n     */\n    private final AtomicInteger count = new AtomicInteger();\n\n    /**\n     * Head of linked list.\n     * Invariant: head.item == null\n     */\n    transient Node<E> head;\n\n    /**\n     * Tail of linked list.\n     * Invariant: last.next == null\n     */\n    private transient Node<E> last;\n\n    /**\n     * Lock held by take, poll, etc\n     */\n    private final ReentrantLock takeLock = new ReentrantLock();\n\n    /**\n     * Wait queue for waiting takes\n     */\n    private final Condition notEmpty = takeLock.newCondition();\n\n    /**\n     * Lock held by put, offer, etc\n     */\n    private final ReentrantLock putLock = new ReentrantLock();\n\n    /**\n     * Wait queue for waiting puts\n     */\n    private final Condition notFull = putLock.newCondition();\n\n    /**\n     * Signals a waiting take. Called only from put/offer (which do not\n     * otherwise ordinarily lock takeLock.)\n     */\n    private void signalNotEmpty() {\n        final ReentrantLock takeLock = this.takeLock;\n        takeLock.lock();\n        try {\n            notEmpty.signal();\n        } finally {\n            takeLock.unlock();\n        }\n    }\n\n    /**\n     * Signals a waiting put. Called only from take/poll.\n     */\n    private void signalNotFull() {\n        final ReentrantLock putLock = this.putLock;\n        putLock.lock();\n        try {\n            notFull.signal();\n        } finally {\n            putLock.unlock();\n        }\n    }\n\n    private synchronized E opQueue(Node<E> node) {\n        if (node == null) {\n            return _dequeue();\n        } else {\n            _enqueue(node);\n            return null;\n        }\n    }\n\n    // only invoke in opQueue\n    private void _enqueue(Node<E> node) {\n        boolean added = false;\n\n        Node<E> curr = head;\n        Node<E> temp = null;\n\n        while (curr.next != null) {\n            temp = curr.next;\n            if (temp.getPriority() < node.getPriority()) {\n                curr.next = node;\n                node.next = temp;\n                added = true;\n                break;\n            }\n            curr = curr.next;\n        }\n\n        if (!added) {\n            last = last.next = node;\n        }\n    }\n\n    // only invoke in opQueue\n    private E _dequeue() {\n        // assert takeLock.isHeldByCurrentThread();\n        // assert head.item == null;\n        Node<E> h = head;\n        Node<E> first = h.next;\n        h.next = h; // help GC\n        head = first;\n        E x = first.getValue();\n        first.setValue(null);\n        return x;\n    }\n\n    /**\n     * Locks to prevent both puts and takes.\n     */\n    void fullyLock() {\n        putLock.lock();\n        takeLock.lock();\n    }\n\n    /**\n     * Unlocks to allow both puts and takes.\n     */\n    void fullyUnlock() {\n        takeLock.unlock();\n        putLock.unlock();\n    }\n\n    public PriorityBlockingQueue() {\n        this(Integer.MAX_VALUE);\n    }\n\n    public PriorityBlockingQueue(int capacity) {\n        if (capacity <= 0) throw new IllegalArgumentException();\n        this.capacity = capacity;\n        last = head = new Node<E>(null);\n    }\n\n    public PriorityBlockingQueue(Collection<? extends E> c) {\n        this(Integer.MAX_VALUE);\n        final ReentrantLock putLock = this.putLock;\n        putLock.lock(); // Never contended, but necessary for visibility\n        try {\n            int n = 0;\n            for (E e : c) {\n                if (e == null) throw new NullPointerException();\n                if (n == capacity) throw new IllegalStateException(\"Queue full\");\n                opQueue(new Node<E>(e));\n                ++n;\n            }\n            count.set(n);\n        } finally {\n            putLock.unlock();\n        }\n    }\n\n    public int size() {\n        return count.get();\n    }\n\n    public int remainingCapacity() {\n        return capacity - count.get();\n    }\n\n    public void put(E e) throws InterruptedException {\n        if (e == null) throw new NullPointerException();\n        // Note: convention in all put/take/etc is to preset local var\n        // holding count negative to indicate failure unless set.\n        int c = -1;\n        Node<E> node = new Node<E>(e);\n        final ReentrantLock putLock = this.putLock;\n        final AtomicInteger count = this.count;\n        putLock.lockInterruptibly();\n        try {\n            while (count.get() == capacity) {\n                notFull.await();\n            }\n            opQueue(node);\n            c = count.getAndIncrement();\n            if (c + 1 < capacity) notFull.signal();\n        } finally {\n            putLock.unlock();\n        }\n        if (c == 0) signalNotEmpty();\n    }\n\n    public boolean offer(E e, long timeout, TimeUnit unit) throws InterruptedException {\n\n        if (e == null) throw new NullPointerException();\n        long nanos = unit.toNanos(timeout);\n        int c = -1;\n        final ReentrantLock putLock = this.putLock;\n        final AtomicInteger count = this.count;\n        putLock.lockInterruptibly();\n        try {\n            while (count.get() == capacity) {\n                if (nanos <= 0) return false;\n                nanos = notFull.awaitNanos(nanos);\n            }\n            opQueue(new Node<E>(e));\n            c = count.getAndIncrement();\n            if (c + 1 < capacity) notFull.signal();\n        } finally {\n            putLock.unlock();\n        }\n        if (c == 0) signalNotEmpty();\n        return true;\n    }\n\n    public boolean offer(E e) {\n        if (e == null) throw new NullPointerException();\n        final AtomicInteger count = this.count;\n        if (count.get() == capacity) return false;\n        int c = -1;\n        Node<E> node = new Node<E>(e);\n        final ReentrantLock putLock = this.putLock;\n        putLock.lock();\n        try {\n            if (count.get() < capacity) {\n                opQueue(node);\n                c = count.getAndIncrement();\n                if (c + 1 < capacity) notFull.signal();\n            }\n        } finally {\n            putLock.unlock();\n        }\n        if (c == 0) signalNotEmpty();\n        return c >= 0;\n    }\n\n    public E take() throws InterruptedException {\n        E x;\n        int c = -1;\n        final AtomicInteger count = this.count;\n        final ReentrantLock takeLock = this.takeLock;\n        takeLock.lockInterruptibly();\n        try {\n            while (count.get() == 0) {\n                notEmpty.await();\n            }\n            x = opQueue(null);\n            c = count.getAndDecrement();\n            if (c > 1) notEmpty.signal();\n        } finally {\n            takeLock.unlock();\n        }\n        if (c == capacity) signalNotFull();\n        return x;\n    }\n\n    public E poll(long timeout, TimeUnit unit) throws InterruptedException {\n        E x = null;\n        int c = -1;\n        long nanos = unit.toNanos(timeout);\n        final AtomicInteger count = this.count;\n        final ReentrantLock takeLock = this.takeLock;\n        takeLock.lockInterruptibly();\n        try {\n            while (count.get() == 0) {\n                if (nanos <= 0) return null;\n                nanos = notEmpty.awaitNanos(nanos);\n            }\n            x = opQueue(null);\n            c = count.getAndDecrement();\n            if (c > 1) notEmpty.signal();\n        } finally {\n            takeLock.unlock();\n        }\n        if (c == capacity) signalNotFull();\n        return x;\n    }\n\n    public E poll() {\n        final AtomicInteger count = this.count;\n        if (count.get() == 0) return null;\n        E x = null;\n        int c = -1;\n        final ReentrantLock takeLock = this.takeLock;\n        takeLock.lock();\n        try {\n            if (count.get() > 0) {\n                x = opQueue(null);\n                c = count.getAndDecrement();\n                if (c > 1) notEmpty.signal();\n            }\n        } finally {\n            takeLock.unlock();\n        }\n        if (c == capacity) signalNotFull();\n        return x;\n    }\n\n    public E peek() {\n        if (count.get() == 0) return null;\n        final ReentrantLock takeLock = this.takeLock;\n        takeLock.lock();\n        try {\n            Node<E> first = head.next;\n            if (first == null) return null;\n            else return first.getValue();\n        } finally {\n            takeLock.unlock();\n        }\n    }\n\n    /**\n     * Unlinks interior Node p with predecessor trail.\n     */\n    void unlink(Node<E> p, Node<E> trail) {\n        // assert isFullyLocked();\n        // p.next is not changed, to allow iterators that are\n        // traversing p to maintain their weak-consistency guarantee.\n        p.setValue(null);\n        trail.next = p.next;\n        if (last == p) last = trail;\n        if (count.getAndDecrement() == capacity) notFull.signal();\n    }\n\n    public boolean remove(Object o) {\n        if (o == null) return false;\n        fullyLock();\n        try {\n            for (Node<E> trail = head, p = trail.next; p != null; trail = p, p = p.next) {\n                if (o.equals(p.getValue())) {\n                    unlink(p, trail);\n                    return true;\n                }\n            }\n            return false;\n        } finally {\n            fullyUnlock();\n        }\n    }\n\n    public boolean contains(Object o) {\n        if (o == null) return false;\n        fullyLock();\n        try {\n            for (Node<E> p = head.next; p != null; p = p.next)\n                if (o.equals(p.getValue())) return true;\n            return false;\n        } finally {\n            fullyUnlock();\n        }\n    }\n\n    public Object[] toArray() {\n        fullyLock();\n        try {\n            int size = count.get();\n            Object[] a = new Object[size];\n            int k = 0;\n            for (Node<E> p = head.next; p != null; p = p.next)\n                a[k++] = p.getValue();\n            return a;\n        } finally {\n            fullyUnlock();\n        }\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    public <T> T[] toArray(T[] a) {\n        fullyLock();\n        try {\n            int size = count.get();\n            if (a.length < size) a = (T[]) java.lang.reflect.Array.newInstance(a.getClass().getComponentType(), size);\n\n            int k = 0;\n            for (Node<T> p = (Node<T>) head.next; p != null; p = p.next)\n                a[k++] = (T) p.getValue();\n            if (a.length > k) a[k] = null;\n            return a;\n        } finally {\n            fullyUnlock();\n        }\n    }\n\n    public void clear() {\n        fullyLock();\n        try {\n            for (Node<E> p, h = head; (p = h.next) != null; h = p) {\n                h.next = h;\n                p.setValue(null);\n            }\n            head = last;\n            // assert head.item == null && head.next == null;\n            if (count.getAndSet(0) == capacity) notFull.signal();\n        } finally {\n            fullyUnlock();\n        }\n    }\n\n    public int drainTo(Collection<? super E> c) {\n        return drainTo(c, Integer.MAX_VALUE);\n    }\n\n    public int drainTo(Collection<? super E> c, int maxElements) {\n        if (c == null) throw new NullPointerException();\n        if (c == this) throw new IllegalArgumentException();\n        if (maxElements <= 0) return 0;\n        boolean signalNotFull = false;\n        final ReentrantLock takeLock = this.takeLock;\n        takeLock.lock();\n        try {\n            int n = Math.min(maxElements, count.get());\n            // count.query provides visibility to first n Nodes\n            Node<E> h = head;\n            int i = 0;\n            try {\n                while (i < n) {\n                    Node<E> p = h.next;\n                    c.add(p.getValue());\n                    p.setValue(null);\n                    h.next = h;\n                    h = p;\n                    ++i;\n                }\n                return n;\n            } finally {\n                // Restore invariants even if c.add() threw\n                if (i > 0) {\n                    // assert h.item == null;\n                    head = h;\n                    signalNotFull = (count.getAndAdd(-i) == capacity);\n                }\n            }\n        } finally {\n            takeLock.unlock();\n            if (signalNotFull) signalNotFull();\n        }\n    }\n\n    public Iterator<E> iterator() {\n        return new Itr();\n    }\n\n    private class Itr implements Iterator<E> {\n\n        private Node<E> current;\n        private Node<E> lastRet;\n        private E currentElement;\n\n        Itr() {\n            fullyLock();\n            try {\n                current = head.next;\n                if (current != null) currentElement = current.getValue();\n            } finally {\n                fullyUnlock();\n            }\n        }\n\n        public boolean hasNext() {\n            return current != null;\n        }\n\n        private Node<E> nextNode(Node<E> p) {\n            for (; ; ) {\n                Node<E> s = p.next;\n                if (s == p) return head.next;\n                if (s == null || s.getValue() != null) return s;\n                p = s;\n            }\n        }\n\n        public E next() {\n            fullyLock();\n            try {\n                if (current == null) throw new NoSuchElementException();\n                E x = currentElement;\n                lastRet = current;\n                current = nextNode(current);\n                currentElement = (current == null) ? null : current.getValue();\n                return x;\n            } finally {\n                fullyUnlock();\n            }\n        }\n\n        public void remove() {\n            if (lastRet == null) throw new IllegalStateException();\n            fullyLock();\n            try {\n                Node<E> node = lastRet;\n                lastRet = null;\n                for (Node<E> trail = head, p = trail.next; p != null; trail = p, p = p.next) {\n                    if (p == node) {\n                        unlink(p, trail);\n                        break;\n                    }\n                }\n            } finally {\n                fullyUnlock();\n            }\n        }\n    }\n\n    private void writeObject(java.io.ObjectOutputStream s) throws java.io.IOException {\n\n        fullyLock();\n        try {\n            // Write out any hidden stuff, plus capacity\n            s.defaultWriteObject();\n\n            // Write out all elements in the proper order.\n            for (Node<E> p = head.next; p != null; p = p.next)\n                s.writeObject(p.getValue());\n\n            // Use trailing null as sentinel\n            s.writeObject(null);\n        } finally {\n            fullyUnlock();\n        }\n    }\n\n    /**\n     * Reconstitutes this queue from a stream (that is, deserializes it).\n     */\n    private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException {\n        // Read in capacity, and any hidden stuff\n        s.defaultReadObject();\n\n        count.set(0);\n        last = head = new Node<E>(null);\n\n        // Read in all elements and place in queue\n        for (; ; ) {\n            @SuppressWarnings(\"unchecked\") E item = (E) s.readObject();\n            if (item == null) break;\n            add(item);\n        }\n    }\n\n    /**\n     * Linked list node class\n     */\n    class Node<T> {\n        private boolean valueAsT = false;\n        private PriorityObject<?> value;\n        Node<T> next;\n\n        Node(T value) {\n            setValue(value);\n        }\n\n        public int getPriority() {\n            return value.priority;\n        }\n\n        @SuppressWarnings(\"unchecked\")\n        public T getValue() {\n            if (value == null) {\n                return null;\n            } else if (valueAsT) {\n                return (T) value;\n            } else {\n                return (T) value.obj;\n            }\n        }\n\n        public void setValue(T value) {\n            if (value == null) {\n                this.value = null;\n            } else if (value instanceof PriorityObject) {\n                this.value = (PriorityObject<?>) value;\n                this.valueAsT = true;\n            } else {\n                this.value = new PriorityObject<T>(Priority.DEFAULT, value);\n            }\n        }\n    }\n\n}\n"
  },
  {
    "path": "okserver/src/main/java/com/lzy/okserver/task/PriorityObject.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.okserver.task;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：2016/1/19\n * 描    述：具有优先级对象的公共类\n * 修订历史：\n * ================================================\n */\npublic class PriorityObject<E> {\n\n    public final int priority;\n    public final E obj;\n\n    public PriorityObject(int priority, E obj) {\n        this.priority = priority;\n        this.obj = obj;\n    }\n}\n"
  },
  {
    "path": "okserver/src/main/java/com/lzy/okserver/task/PriorityRunnable.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.okserver.task;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：2016/1/19\n * 描    述：Runnable对象的优先级封装\n * 修订历史：\n * ================================================\n */\npublic class PriorityRunnable extends PriorityObject<Runnable> implements Runnable {\n\n    public PriorityRunnable(int priority, Runnable obj) {\n        super(priority, obj);\n    }\n\n    @Override\n    public void run() {\n        this.obj.run();\n    }\n}\n"
  },
  {
    "path": "okserver/src/main/java/com/lzy/okserver/task/XExecutor.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.okserver.task;\n\nimport android.os.Handler;\nimport android.os.Looper;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.concurrent.BlockingQueue;\nimport java.util.concurrent.RejectedExecutionHandler;\nimport java.util.concurrent.ThreadFactory;\nimport java.util.concurrent.ThreadPoolExecutor;\nimport java.util.concurrent.TimeUnit;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：2016/1/22\n * 描    述：用于监听任务结束的回调\n * 修订历史：\n * ================================================\n */\npublic class XExecutor extends ThreadPoolExecutor {\n\n    private Handler innerHandler = new Handler(Looper.getMainLooper());\n\n    public XExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, RejectedExecutionHandler handler) {\n        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, handler);\n    }\n\n    public XExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler) {\n        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, handler);\n    }\n\n    public XExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory) {\n        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory);\n    }\n\n    public XExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) {\n        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);\n    }\n\n    /** 任务结束后回调 */\n    @Override\n    protected void afterExecute(final Runnable r, Throwable t) {\n        super.afterExecute(r, t);\n        if (taskEndListenerList != null && taskEndListenerList.size() > 0) {\n            for (final OnTaskEndListener listener : taskEndListenerList) {\n                innerHandler.post(new Runnable() {\n                    @Override\n                    public void run() {\n                        listener.onTaskEnd(r);\n                    }\n                });\n            }\n        }\n        //当前正在运行的数量为1 表示当前正在停止的任务，同时队列中没有任务，表示所有任务下载完毕\n        if (getActiveCount() == 1 && getQueue().size() == 0) {\n            if (allTaskEndListenerList != null && allTaskEndListenerList.size() > 0) {\n                for (final OnAllTaskEndListener listener : allTaskEndListenerList) {\n                    innerHandler.post(new Runnable() {\n                        @Override\n                        public void run() {\n                            listener.onAllTaskEnd();\n                        }\n                    });\n                }\n            }\n        }\n    }\n\n    private List<OnTaskEndListener> taskEndListenerList;\n\n    public void addOnTaskEndListener(OnTaskEndListener taskEndListener) {\n        if (taskEndListenerList == null) taskEndListenerList = new ArrayList<>();\n        taskEndListenerList.add(taskEndListener);\n    }\n\n    public void removeOnTaskEndListener(OnTaskEndListener taskEndListener) {\n        taskEndListenerList.remove(taskEndListener);\n    }\n\n    public interface OnTaskEndListener {\n        void onTaskEnd(Runnable r);\n    }\n\n    private List<OnAllTaskEndListener> allTaskEndListenerList;\n\n    public void addOnAllTaskEndListener(OnAllTaskEndListener allTaskEndListener) {\n        if (allTaskEndListenerList == null) allTaskEndListenerList = new ArrayList<>();\n        allTaskEndListenerList.add(allTaskEndListener);\n    }\n\n    public void removeOnAllTaskEndListener(OnAllTaskEndListener allTaskEndListener) {\n        allTaskEndListenerList.remove(allTaskEndListener);\n    }\n\n    public interface OnAllTaskEndListener {\n        void onAllTaskEnd();\n    }\n}\n"
  },
  {
    "path": "okserver/src/main/java/com/lzy/okserver/upload/UploadListener.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.okserver.upload;\n\nimport com.lzy.okserver.ProgressListener;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：2016/1/19\n * 描    述：全局的上传监听\n * 修订历史：\n * ================================================\n */\npublic abstract class UploadListener<T> implements ProgressListener<T> {\n\n    public final Object tag;\n\n    public UploadListener(Object tag) {\n        this.tag = tag;\n    }\n}\n"
  },
  {
    "path": "okserver/src/main/java/com/lzy/okserver/upload/UploadTask.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.okserver.upload;\n\nimport android.content.ContentValues;\n\nimport com.lzy.okgo.db.UploadManager;\nimport com.lzy.okgo.model.Progress;\nimport com.lzy.okgo.model.Response;\nimport com.lzy.okgo.request.base.ProgressRequestBody;\nimport com.lzy.okgo.request.base.Request;\nimport com.lzy.okgo.utils.HttpUtils;\nimport com.lzy.okgo.utils.OkLogger;\nimport com.lzy.okserver.OkUpload;\nimport com.lzy.okserver.task.PriorityRunnable;\n\nimport java.io.Serializable;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.concurrent.ThreadPoolExecutor;\n\nimport okhttp3.Call;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：2016/1/26\n * 描    述：上传任务类\n * 修订历史：\n * ================================================\n */\npublic class UploadTask<T> implements Runnable {\n\n    public Progress progress;\n    public Map<Object, UploadListener<T>> listeners;\n    private ThreadPoolExecutor executor;\n    private PriorityRunnable priorityRunnable;\n\n    public UploadTask(String tag, Request<T, ? extends Request> request) {\n        HttpUtils.checkNotNull(tag, \"tag == null\");\n        progress = new Progress();\n        progress.tag = tag;\n        progress.url = request.getBaseUrl();\n        progress.status = Progress.NONE;\n        progress.totalSize = -1;\n        progress.request = request;\n\n        executor = OkUpload.getInstance().getThreadPool().getExecutor();\n        listeners = new HashMap<>();\n    }\n\n    public UploadTask(Progress progress) {\n        HttpUtils.checkNotNull(progress, \"progress == null\");\n        this.progress = progress;\n        executor = OkUpload.getInstance().getThreadPool().getExecutor();\n        listeners = new HashMap<>();\n    }\n\n    public UploadTask<T> priority(int priority) {\n        progress.priority = priority;\n        return this;\n    }\n\n    public UploadTask<T> extra1(Serializable extra1) {\n        progress.extra1 = extra1;\n        return this;\n    }\n\n    public UploadTask<T> extra2(Serializable extra2) {\n        progress.extra2 = extra2;\n        return this;\n    }\n\n    public UploadTask<T> extra3(Serializable extra3) {\n        progress.extra3 = extra3;\n        return this;\n    }\n\n    public UploadTask<T> save() {\n        UploadManager.getInstance().replace(progress);\n        return this;\n    }\n\n    public UploadTask<T> register(UploadListener<T> listener) {\n        if (listener != null) {\n            listeners.put(listener.tag, listener);\n        }\n        return this;\n    }\n\n    public void unRegister(UploadListener<T> listener) {\n        HttpUtils.checkNotNull(listener, \"listener == null\");\n        listeners.remove(listener.tag);\n    }\n\n    public void unRegister(String tag) {\n        HttpUtils.checkNotNull(tag, \"tag == null\");\n        listeners.remove(tag);\n    }\n\n    public UploadTask<T> start() {\n        if (OkUpload.getInstance().getTask(progress.tag) == null || UploadManager.getInstance().get(progress.tag) == null) {\n            throw new IllegalStateException(\"you must call UploadTask#save() before UploadTask#start()！\");\n        }\n        if (progress.status != Progress.WAITING && progress.status != Progress.LOADING) {\n            postOnStart(progress);\n            postWaiting(progress);\n            priorityRunnable = new PriorityRunnable(progress.priority, this);\n            executor.execute(priorityRunnable);\n        } else {\n            OkLogger.w(\"the task with tag \" + progress.tag + \" is already in the upload queue, current task status is \" + progress.status);\n        }\n        return this;\n    }\n\n    public void restart() {\n        pause();\n        progress.status = Progress.NONE;\n        progress.currentSize = 0;\n        progress.fraction = 0;\n        progress.speed = 0;\n        UploadManager.getInstance().replace(progress);\n        start();\n    }\n\n    /** 暂停的方法 */\n    public void pause() {\n        executor.remove(priorityRunnable);\n        if (progress.status == Progress.WAITING) {\n            postPause(progress);\n        } else if (progress.status == Progress.LOADING) {\n            progress.speed = 0;\n            progress.status = Progress.PAUSE;\n        } else {\n            OkLogger.w(\"only the task with status WAITING(1) or LOADING(2) can pause, current status is \" + progress.status);\n        }\n    }\n\n    /** 删除一个任务,会删除下载文件 */\n    public UploadTask<T> remove() {\n        pause();\n        UploadManager.getInstance().delete(progress.tag);\n        //noinspection unchecked\n        UploadTask<T> task = (UploadTask<T>) OkUpload.getInstance().removeTask(progress.tag);\n        postOnRemove(progress);\n        return task;\n    }\n\n    @Override\n    public void run() {\n        progress.status = Progress.LOADING;\n        postLoading(progress);\n        final Response<T> response;\n        try {\n            //noinspection unchecked\n            Request<T, ? extends Request> request = (Request<T, ? extends Request>) progress.request;\n            final Call rawCall = request.getRawCall();\n            request.uploadInterceptor(new ProgressRequestBody.UploadInterceptor() {\n                @Override\n                public void uploadProgress(Progress innerProgress) {\n                    if (rawCall.isCanceled()) return;\n                    if (progress.status != Progress.LOADING) {\n                        rawCall.cancel();\n                        return;\n                    }\n                    progress.from(innerProgress);\n                    postLoading(progress);\n                }\n            });\n            response = request.adapt().execute();\n        } catch (Exception e) {\n            postOnError(progress, e);\n            return;\n        }\n\n        if (response.isSuccessful()) {\n            postOnFinish(progress, response.body());\n        } else {\n            postOnError(progress, response.getException());\n        }\n    }\n\n    private void postOnStart(final Progress progress) {\n        progress.speed = 0;\n        progress.status = Progress.NONE;\n        updateDatabase(progress);\n        HttpUtils.runOnUiThread(new Runnable() {\n            @Override\n            public void run() {\n                for (UploadListener<T> listener : listeners.values()) {\n                    listener.onStart(progress);\n                }\n            }\n        });\n    }\n\n    private void postWaiting(final Progress progress) {\n        progress.speed = 0;\n        progress.status = Progress.WAITING;\n        updateDatabase(progress);\n        HttpUtils.runOnUiThread(new Runnable() {\n            @Override\n            public void run() {\n                for (UploadListener<T> listener : listeners.values()) {\n                    listener.onProgress(progress);\n                }\n            }\n        });\n    }\n\n    private void postPause(final Progress progress) {\n        progress.speed = 0;\n        progress.status = Progress.PAUSE;\n        updateDatabase(progress);\n        HttpUtils.runOnUiThread(new Runnable() {\n            @Override\n            public void run() {\n                for (UploadListener<T> listener : listeners.values()) {\n                    listener.onProgress(progress);\n                }\n            }\n        });\n    }\n\n    private void postLoading(final Progress progress) {\n        updateDatabase(progress);\n        HttpUtils.runOnUiThread(new Runnable() {\n            @Override\n            public void run() {\n                for (UploadListener<T> listener : listeners.values()) {\n                    listener.onProgress(progress);\n                }\n            }\n        });\n    }\n\n    private void postOnError(final Progress progress, final Throwable throwable) {\n        progress.speed = 0;\n        progress.status = Progress.ERROR;\n        progress.exception = throwable;\n        updateDatabase(progress);\n        HttpUtils.runOnUiThread(new Runnable() {\n            @Override\n            public void run() {\n                for (UploadListener<T> listener : listeners.values()) {\n                    listener.onProgress(progress);\n                    listener.onError(progress);\n                }\n            }\n        });\n    }\n\n    private void postOnFinish(final Progress progress, final T t) {\n        progress.speed = 0;\n        progress.fraction = 1.0f;\n        progress.status = Progress.FINISH;\n        updateDatabase(progress);\n        HttpUtils.runOnUiThread(new Runnable() {\n            @Override\n            public void run() {\n                for (UploadListener<T> listener : listeners.values()) {\n                    listener.onProgress(progress);\n                    listener.onFinish(t, progress);\n                }\n            }\n        });\n    }\n\n    private void postOnRemove(final Progress progress) {\n        updateDatabase(progress);\n        HttpUtils.runOnUiThread(new Runnable() {\n            @Override\n            public void run() {\n                for (UploadListener<T> listener : listeners.values()) {\n                    listener.onRemove(progress);\n                }\n                listeners.clear();\n            }\n        });\n    }\n\n    private void updateDatabase(Progress progress) {\n        ContentValues contentValues = Progress.buildUpdateContentValues(progress);\n        UploadManager.getInstance().update(contentValues, progress.tag);\n    }\n}\n"
  },
  {
    "path": "okserver/src/main/java/com/lzy/okserver/upload/UploadThreadPool.java",
    "content": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lzy.okserver.upload;\n\nimport com.lzy.okserver.task.XExecutor;\nimport com.lzy.okserver.task.PriorityBlockingQueue;\n\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.ThreadPoolExecutor;\nimport java.util.concurrent.TimeUnit;\n\n/**\n * ================================================\n * 作    者：jeasonlzy（廖子尧）Github地址：https://github.com/jeasonlzy\n * 版    本：1.0\n * 创建日期：2016/1/26\n * 描    述：上传管理的线程池\n * 修订历史：\n * ================================================\n */\npublic class UploadThreadPool {\n    private static final int MAX_IMUM_POOL_SIZE = 5;     //最大线程池的数量\n    private static final int KEEP_ALIVE_TIME = 1;        //存活的时间\n    private static final TimeUnit UNIT = TimeUnit.HOURS; //时间单位\n    private int corePoolSize = 1;                        //核心线程池的数量，同时能执行的线程数量，默认1个\n    private XExecutor executor;               //线程池执行器\n\n    public XExecutor getExecutor() {\n        if (executor == null) {\n            synchronized (UploadThreadPool.class) {\n                if (executor == null) {\n                    executor = new XExecutor(corePoolSize, MAX_IMUM_POOL_SIZE, KEEP_ALIVE_TIME, UNIT, //\n                                             new PriorityBlockingQueue<Runnable>(),   //无限容量的缓冲队列\n                                             Executors.defaultThreadFactory(),        //线程创建工厂\n                                             new ThreadPoolExecutor.AbortPolicy());   //继续超出上限的策略，阻止\n                }\n            }\n        }\n        return executor;\n    }\n\n    /** 必须在首次执行前设置，否者无效 ,范围1-5之间 */\n    public void setCorePoolSize(int corePoolSize) {\n        if (corePoolSize <= 0) corePoolSize = 1;\n        if (corePoolSize > MAX_IMUM_POOL_SIZE) corePoolSize = MAX_IMUM_POOL_SIZE;\n        this.corePoolSize = corePoolSize;\n    }\n\n    /** 执行任务 */\n    public void execute(Runnable runnable) {\n        if (runnable != null) {\n            getExecutor().execute(runnable);\n        }\n    }\n\n    /** 移除线程 */\n    public void remove(Runnable runnable) {\n        if (runnable != null) {\n            getExecutor().remove(runnable);\n        }\n    }\n}\n"
  },
  {
    "path": "settings.gradle",
    "content": "include ':demo', ':okgo', ':okserver', ':okrx', ':okrx2'\n"
  }
]