[
  {
    "path": ".gitignore",
    "content": "# built application files\n*.ap_\n\n# files for the dex VM\n*.dex\n*.iml\n\n# Java class files\n*.class\n\n# generated files\nbin/\ngen/\n*target/\n*build/\n.gradle/\n.idea/\ngen-external-apklibs/\n\n# Local configuration file (sdk path, etc)\nlocal.properties\n\n# Eclipse project files\n.classpath\n.project\n\n# Mac os\n.DS_Store\n"
  },
  {
    "path": ".travis.yml",
    "content": "language: android\n\nandroid:\n  components:\n    - build-tools-20.0.0\n    - android-16\n\njdk: oraclejdk7\n\nscript:\n    - ./gradlew check --refresh-dependencies\n"
  },
  {
    "path": "LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) <2015> <liaohuqiu.net>\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE."
  },
  {
    "path": "README-cn.md",
    "content": "###### 欢迎关注我\n\nGitHub: https://github.com/liaohuqiu\n\n微博: http://weibo.com/liaohuqiu\n\n知乎: http://www.zhihu.com/people/liao-hu-qiu\n\n---\n\n# Ultra Pull To Refresh\n\n这是现在已经停止维护的下拉刷新项目的替代方案。继承于ViewGroup可以包含任何View。功能比SwipeRefreshLayout强大。\n\n使用起来非常简单。良好的设计，如果你想定制自己的UI样式，非常简单，就像给ListView加一个Header View那么简单。\n\n支持 `API LEVEL >= 8`。\n\n[APK下载](https://raw.githubusercontent.com/liaohuqiu/android-Ultra-Pull-To-Refresh/master/ptr-demo.apk)\n\n#### 下拉刷新 + 加载更多？\n\n本类库是单纯的下拉刷新。如果你需要用到`加载更多`，看这个项目: https://github.com/liaohuqiu/android-cube-app\n\n#### 使用eclipse的同学请注意, Intellij IDEA / Android Studio 请忽略\n\n**demo可以直接在eclipse中运行, 编译demo项目的同学看这里:  http://www.liaohuqiu.net/cn/posts/compile-ultra-ptr-in-eclipse/**\n\n* 先上两张StoreHouse风格的截图! 感谢 [CBStoreHouseRefreshControl](https://github.com/coolbeet/CBStoreHouseRefreshControl).\n    <div class='row'>\n        <img src='http://srain-github.qiniudn.com/ultra-ptr/store-house-string-array.gif' width=\"300px\" style='border: #f1f1f1 solid 1px'/>\n        <img src='http://srain-github.qiniudn.com/ultra-ptr/store-house-string.gif' width=\"300px\" style='border: #f1f1f1 solid 1px'/>\n    </div>\n\n* 5.0 Material 风格 2014-12-09 新增。**阴影效果，gif图看起来有些失真，看demo吧！**\n    <div class='row'>\n        <img src='http://srain-github.qiniudn.com/ultra-ptr/material-style.gif' width=\"300px\"/>\n    </div>\n\n* **支持所有的View**: \n\n    ListView, GridView, ScrollView, FrameLayout, 甚至 TextView.\n    <div><img src='http://srain-github.qiniudn.com/ultra-ptr/contains-all-of-views.gif' width=\"300px\" style='border: #f1f1f1 solid 1px'/></div>\n\n* 支持各种下拉刷新交互.\n    * 下拉刷新(iOS风格)\n        <div><img src='http://srain-github.qiniudn.com/ultra-ptr/pull-to-refresh.gif' width=\"300px\" style='border: #f1f1f1 solid 1px'/></div>\n\n    * 释放刷新(经典风格)\n        <div><img src='http://srain-github.qiniudn.com/ultra-ptr/release-to-refresh.gif' width=\"300px\" style='border: #f1f1f1 solid 1px'/></div>\n\n    * 刷新时，头部保持(新浪微博)\n\n        <img src='http://srain-github.qiniudn.com/ultra-ptr/keep-header.gif' width=\"300px\"/>\n\n    * 刷新时，头部不保持(微信朋友圈)\n\n        <img src='http://srain-github.qiniudn.com/ultra-ptr/hide-header.gif' width=\"300px\" sytle='border: #f1f1f1 solid 1px'/>\n\n    * 自动刷新，进入界面时自动刷新\n\n        <img src='http://srain-github.qiniudn.com/ultra-ptr/auto-refresh.gif' width=\"300px\" sytle='border: #f1f1f1 solid 1px'/></div>\n\n# 使用方式\n\n#### 中央库依赖\n\n项目已经发布到了Maven中央库，包括`aar`和`apklib`两种格式。在Maven或者Gradle下可如下直接引入:\n\n最新版版本号: `1.0.11`, 发布到了: https://oss.sonatype.org/content/repositories/snapshots\n\n在gradle中:\n\n```\nmaven {\n    url 'https://oss.sonatype.org/content/repositories/snapshots'\n}\n```\n\n稳定版: `1.0.11`, https://oss.sonatype.org/content/repositories/releases, in gradle:\n\n```\nmavenCentral()\n```\n\n`pom.xml` 文件中\n\n最新版:\n\n```xml\n<dependency>\n    <groupId>in.srain.cube</groupId>\n    <artifactId>ultra-ptr</artifactId>\n    <type>aar</type>\n    <!-- or apklib format, if you want -->\n    <!-- <type>apklib</type> -->\n    <version>1.0.11</version>\n</dependency>\n\n稳定版\n\n```xml\n<dependency>\n    <groupId>in.srain.cube</groupId>\n    <artifactId>ultra-ptr</artifactId>\n    <type>aar</type>\n    <!-- or apklib format, if you want -->\n    <!-- <type>apklib</type> -->\n    <version>1.0.11</version>\n</dependency>\n```\n\ngradle / Android Studio, 最新版\n\n```\ncompile 'in.srain.cube:ultra-ptr:1.0.11'\n```\n\ngradle / Android Studio, 稳定版\n\n```\ncompile 'in.srain.cube:ultra-ptr:1.0.11'\n```\n\n#### 配置\n\n有6个参数可配置:\n\n* 阻尼系数\n\n    默认: `1.7f`，越大，感觉下拉时越吃力。\n\n* 触发刷新时移动的位置比例\n\n    默认，`1.2f`，移动达到头部高度1.2倍时可触发刷新操作。\n\n* 回弹延时\n\n    默认 `200ms`，回弹到刷新高度所用时间\n\n* 头部回弹时间\n\n    默认`1000ms`\n\n* 刷新是保持头部\n\n    默认值 `true`.\n\n* 下拉刷新 / 释放刷新\n\n    默认为释放刷新\n\n##### xml中配置示例\n\n```xml\n<in.srain.cube.views.ptr.PtrFrameLayout\n    android:id=\"@+id/store_house_ptr_frame\"\n    xmlns:cube_ptr=\"http://schemas.android.com/apk/res-auto\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n\n    cube_ptr:ptr_resistance=\"1.7\"\n    cube_ptr:ptr_ratio_of_header_height_to_refresh=\"1.2\"\n    cube_ptr:ptr_duration_to_close=\"300\"\n    cube_ptr:ptr_duration_to_close_header=\"2000\"\n    cube_ptr:ptr_keep_header_when_refresh=\"true\"\n    cube_ptr:ptr_pull_to_fresh=\"false\" >\n\n    <LinearLayout\n        android:id=\"@+id/store_house_ptr_image_content\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:background=\"@color/cube_mints_333333\"\n        android:clickable=\"true\"\n        android:padding=\"10dp\">\n\n        <in.srain.cube.image.CubeImageView\n            android:id=\"@+id/store_house_ptr_image\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\" />\n    </LinearLayout>\n\n</in.srain.cube.views.ptr.PtrFrameLayout>\n```\n\n### 也可以在java代码中配置\n\n```java\n// the following are default settings\nmPtrFrame.setResistance(1.7f);\nmPtrFrame.setRatioOfHeaderHeightToRefresh(1.2f);\nmPtrFrame.setDurationToClose(200);\nmPtrFrame.setDurationToCloseHeader(1000);\n// default is false\nmPtrFrame.setPullToRefresh(false);\n// default is true\nmPtrFrame.setKeepHeaderWhenRefresh(true);\n```\n\n### 其他配置\n\n*  刷新时，保持内容不动，仅头部下移, `setPinContent()`\n\n    `Material` 风格时，效果不错，其他风格的头部，效果不好。issue #29\n\n## StoreHouse 风格\n\n* 使用字符串, 支持A-Z, 0-7 以及 `-` `.`\n\n```java\n// header\nfinal StoreHouseHeader header = new StoreHouseHeader(getContext());\nheader.setPadding(0, LocalDisplay.dp2px(15), 0, 0);\n\n/**\n * using a string, support: A-Z 0-9 - .\n * you can add more letters by {@link in.srain.cube.views.ptr.header.StoreHousePath#addChar}\n */\nheader.initWithString('Alibaba');\n```\n\n* 使用资源文件中的路径信息\n\n```java\nheader.initWithStringArray(R.array.storehouse);\n```\n\n资源文件 `res/values/arrays.xml` 内容如下:\n\n```xml\n<resources>\n    <string-array name=\"storehouse\">\n        <item>0,35,12,42,</item>\n        <item>12,42,24,35,</item>\n        <item>24,35,12,28,</item>\n        <item>0,35,12,28,</item>\n        <item>0,21,12,28,</item>\n        <item>12,28,24,21,</item>\n        <item>24,35,24,21,</item>\n        <item>24,21,12,14,</item>\n        <item>0,21,12,14,</item>\n        <item>0,21,0,7,</item>\n        <item>12,14,0,7,</item>\n        <item>12,14,24,7,</item>\n        <item>24,7,12,0,</item>\n        <item>0,7,12,0,</item>\n    </string-array>\n</resources>\n```\n\n# 处理刷新\n\n通过`PtrHandler`，可以检查确定是否可以下来刷新以及在合适的时间刷新数据。\n\n检查是否可以下拉刷新在`PtrDefaultHandler.checkContentCanBePulledDown`中有默认简单的实现，你可以根据实际情况完成这个逻辑。\n\n```\npublic interface PtrHandler {\n\n    /**\n     * 检查是否可以执行下来刷新，比如列表为空或者列表第一项在最上面时。\n     * <p/>\n     * {@link in.srain.cube.views.ptr.PtrDefaultHandler#checkContentCanBePulledDown}\n     */\n    public boolean checkCanDoRefresh(final PtrFrameLayout frame, final View content, final View header);\n\n    /**\n     * 需要加载数据时触发\n     *\n     * @param frame\n     */\n    public void onRefreshBegin(final PtrFrameLayout frame);\n}\n```\n\n例子:\n\n```java\nptrFrame.setPtrHandler(new PtrHandler() {\n    @Override\n    public void onRefreshBegin(PtrFrameLayout frame) {\n        frame.postDelayed(new Runnable() {\n            @Override\n            public void run() {\n                ptrFrame.refreshComplete();\n            }\n        }, 1800);\n    }\n\n    @Override\n    public boolean checkCanDoRefresh(PtrFrameLayout frame, View content, View header) {\n        // 默认实现，根据实际情况做改动\n        return PtrDefaultHandler.checkContentCanBePulledDown(frame, content, header);\n    }\n});\n```\n\n# 常见问题\n\n*  ViewPager滑动冲突: `disableWhenHorizontalMove()`\n\n*  长按LongPressed, `setInterceptEventWhileWorking()`\n\n\n# 联系方式和问题建议\n\n* 微博: http://weibo.com/liaohuqiu\n* QQ 群: \n\n    1. cube系列开源项目使用交流，问题解答: 271918140 (cube-sdk)\n\n        加群前请先阅读群约定: https://github.com/liaohuqiu/qq-tribe-rule\n\n    2. 如果你会通过google解决问题，喜欢独立思考，喜欢和优秀却又温和的人成为朋友，欢迎加入我们在 Slack 上的群组: 我们在 Slack 上的群组: \n    \n        http://join-add1bit.liaohuqiu.net/?channel=git-android-ultra-ptr\n\n* srain@php.net\n* twitter: https://twitter.com/liaohuqiu\n* blog: http://www.liaohuqiu.net\n"
  },
  {
    "path": "README.md",
    "content": "###### Welcome to follow me on GitHub or Twitter\n\nGitHub: https://github.com/liaohuqiu\n\nTwitter: https://twitter.com/liaohuqiu\n\n---\n\n[![Build Status](https://travis-ci.org/liaohuqiu/android-Ultra-Pull-To-Refresh.svg?branch=master)](https://travis-ci.org/liaohuqiu/android-Ultra-Pull-To-Refresh)\n[![Android Arsenal](https://img.shields.io/badge/Android%20Arsenal-Ultra%20Pull%20To%20Refresh-brightgreen.svg?style=flat)](https://android-arsenal.com/details/1/1180)\n\n#### [中文版文档](https://github.com/liaohuqiu/android-Ultra-Pull-To-Refresh/blob/master/README-cn.md)\n\nWanna auto-load-more? This will be what you want: https://github.com/liaohuqiu/android-cube-app\n\n# Ultra Pull To Refresh\n\nIt's a replacement for the deprecated pull to refresh solution. It can contain any view you want.\n\nIt's easy to use and more powerful than SwipeRefreshLayout.\n\nIt's well designed, you can customize the UI effect you want as easy as adding a headview to ListView.\n\nSupport `API LEVEL >= 8`, all snapshots are taken from Genymotion, 2.3.7.\n\n[Download APK](https://raw.githubusercontent.com/liaohuqiu/android-Ultra-Pull-To-Refresh/master/ptr-demo.apk)\n\n* StoreHouse Style first! Thanks to [CBStoreHouseRefreshControl](https://github.com/coolbeet/CBStoreHouseRefreshControl).\n    <div class='row'>\n        <img src='http://srain-github.qiniudn.com/ultra-ptr/store-house-string-array.gif' width=\"300px\" style='border: #f1f1f1 solid 1px'/>\n        <img src='http://srain-github.qiniudn.com/ultra-ptr/store-house-string.gif' width=\"300px\" style='border: #f1f1f1 solid 1px'/>\n    </div>\n\n* Material Style, added @ 2014-12-09. **There is a beautiful shadow which looks terrible in gif snapshot. Please Check out the DEMO.**\n    <div class='row'>\n        <img src='http://srain-github.qiniudn.com/ultra-ptr/material-style.gif' width=\"300px\"/>\n    </div>\n\n* **Supports all of the views**: \n    ListView, GridView, ScrollView, FrameLayout, or Even a single TextView.\n    <div><img src='http://srain-github.qiniudn.com/ultra-ptr/contains-all-of-views.gif' width=\"300px\" style='border: #f1f1f1 solid 1px'/></div>\n\n* Supports all of the refresh types.\n    * pull to refresh\n        <div><img src='http://srain-github.qiniudn.com/ultra-ptr/pull-to-refresh.gif' width=\"300px\" style='border: #f1f1f1 solid 1px'/></div>\n    * release to refresh\n        <div><img src='http://srain-github.qiniudn.com/ultra-ptr/release-to-refresh.gif' width=\"300px\" style='border: #f1f1f1 solid 1px'/></div>\n\n    * keep header when refresh \n\n        <img src='http://srain-github.qiniudn.com/ultra-ptr/keep-header.gif' width=\"300px\"/>\n\n    * hide header when refresh\n\n        <img src='http://srain-github.qiniudn.com/ultra-ptr/hide-header.gif' width=\"300px\" sytle='border: #f1f1f1 solid 1px'/>\n\n    * auto refresh\n\n        <img src='http://srain-github.qiniudn.com/ultra-ptr/auto-refresh.gif' width=\"300px\" sytle='border: #f1f1f1 solid 1px'/></div>\n\n# Usage\n\n#### Maven Central\n\nThis project has been pushed to Maven Central, both in `aar` and `apklib`.\n\nThe latest version: `1.0.11`, has been published to: https://oss.sonatype.org/content/repositories/snapshots, in gradle:\n\n```\nmaven {\n    url 'https://oss.sonatype.org/content/repositories/snapshots'\n}\n```\n\nThe stable version: `1.0.11`, https://oss.sonatype.org/content/repositories/releases, in gradle:\n\n```\nmavenCentral()\n```\n\npom.xml, latest version:\n\n```xml\n<dependency>\n    <groupId>in.srain.cube</groupId>\n    <artifactId>ultra-ptr</artifactId>\n    <type>aar</type>\n    <!-- or apklib format, if you want -->\n    <!-- <type>apklib</type> -->\n    <version>1.0.11</version>\n</dependency>\n```\n\npom.xml, stable version:\n\n```xml\n<dependency>\n    <groupId>in.srain.cube</groupId>\n    <artifactId>ultra-ptr</artifactId>\n    <type>aar</type>\n    <!-- or apklib format, if you want -->\n    <!-- <type>apklib</type> -->\n    <version>1.0.11</version>\n</dependency>\n```\n\ngradle, latest version:\n\n```\ncompile 'in.srain.cube:ultra-ptr:1.0.11'\n```\n\ngradle, stable version:\n\n```\ncompile 'in.srain.cube:ultra-ptr:1.0.11'\n```\n\n#### Config\n\nThere are 6 properties:\n\n* Resistence\n\n    This is the resistence while you are moving the frame, default is: `1.7f`.\n\n* Ratio of the Height of the Header to Refresh\n\n    The ratio of the height of the header to trigger refresh, default is: `1.2f`.\n\n* Duration to Close\n\n    The duration for moving from the position you relase the view to the height of header, default is `200ms`.\n\n* Duration to Close Header\n\n    The default value is `1000ms`\n\n* Keep Header while Refreshing\n\n    The default value is `true`.\n\n* Pull to Refresh / Release to Refresh\n\n    The default value is Release to Refresh.\n\n##### Config in xml\n\n```xml\n<in.srain.cube.views.ptr.PtrFrameLayout\n    android:id=\"@+id/store_house_ptr_frame\"\n    xmlns:cube_ptr=\"http://schemas.android.com/apk/res-auto\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n\n    cube_ptr:ptr_resistance=\"1.7\"\n    cube_ptr:ptr_ratio_of_header_height_to_refresh=\"1.2\"\n    cube_ptr:ptr_duration_to_close=\"300\"\n    cube_ptr:ptr_duration_to_close_header=\"2000\"\n    cube_ptr:ptr_keep_header_when_refresh=\"true\"\n    cube_ptr:ptr_pull_to_fresh=\"false\" >\n\n    <LinearLayout\n        android:id=\"@+id/store_house_ptr_image_content\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:background=\"@color/cube_mints_333333\"\n        android:clickable=\"true\"\n        android:padding=\"10dp\">\n\n        <in.srain.cube.image.CubeImageView\n            android:id=\"@+id/store_house_ptr_image\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\" />\n    </LinearLayout>\n\n</in.srain.cube.views.ptr.PtrFrameLayout>\n```\n\n### Or config in java code\n\n```java\n// the following are default settings\nmPtrFrame.setResistance(1.7f);\nmPtrFrame.setRatioOfHeaderHeightToRefresh(1.2f);\nmPtrFrame.setDurationToClose(200);\nmPtrFrame.setDurationToCloseHeader(1000);\n// default is false\nmPtrFrame.setPullToRefresh(false);\n// default is true\nmPtrFrame.setKeepHeaderWhenRefresh(true);\n```\n\n### Other Config\n\n*  `setPinContent`. Pin the content, only the `HeaderView` will be moved. \n\n    This's the the performance of material style in support package v19.\n\n## StoreHouse Style\n\n* Config using string:\n\n```java\n// header\nfinal StoreHouseHeader header = new StoreHouseHeader(getContext());\nheader.setPadding(0, LocalDisplay.dp2px(15), 0, 0);\n\n/**\n * using a string, support: A-Z 0-9 - .\n * you can add more letters by {@link in.srain.cube.views.ptr.header.StoreHousePath#addChar}\n */\nheader.initWithString('Alibaba');\n```\n\n* Config using string array from xml:\n\n```java\nheader.initWithStringArray(R.array.storehouse);\n```\n\nAnd in `res/values/arrays.xml`:\n\n```xml\n<resources>\n    <string-array name=\"storehouse\">\n        <item>0,35,12,42,</item>\n        <item>12,42,24,35,</item>\n        <item>24,35,12,28,</item>\n        <item>0,35,12,28,</item>\n        <item>0,21,12,28,</item>\n        <item>12,28,24,21,</item>\n        <item>24,35,24,21,</item>\n        <item>24,21,12,14,</item>\n        <item>0,21,12,14,</item>\n        <item>0,21,0,7,</item>\n        <item>12,14,0,7,</item>\n        <item>12,14,24,7,</item>\n        <item>24,7,12,0,</item>\n        <item>0,7,12,0,</item>\n    </string-array>\n</resources>\n```\n\n# Process Refresh\n\nThere is a `PtrHandler`, by which you can refresh the data.\n\n```\npublic interface PtrHandler {\n\n    /**\n     * Check can do refresh or not. For example the content is empty or the first child is in view.\n     * <p/>\n     * {@link in.srain.cube.views.ptr.PtrDefaultHandler#checkContentCanBePulledDown}\n     */\n    public boolean checkCanDoRefresh(final PtrFrameLayout frame, final View content, final View header);\n\n    /**\n     * When refresh begin\n     *\n     * @param frame\n     */\n    public void onRefreshBegin(final PtrFrameLayout frame);\n}\n```\n\nAn example:\n\n```java\nptrFrame.setPtrHandler(new PtrHandler() {\n    @Override\n    public void onRefreshBegin(PtrFrameLayout frame) {\n        frame.postDelayed(new Runnable() {\n            @Override\n            public void run() {\n                ptrFrame.refreshComplete();\n            }\n        }, 1800);\n    }\n\n    @Override\n    public boolean checkCanDoRefresh(PtrFrameLayout frame, View content, View header) {\n        return PtrDefaultHandler.checkContentCanBePulledDown(frame, content, header);\n    }\n});\n```\n\n\n# Customize\n\nYou can add a `PtrUIHandler` to `PtrFrameLayout` to implement any UI effect you want.\n\n```java\npublic interface PtrUIHandler {\n\n    /**\n     * When the content view has reached top and refresh has been completed, view will be reset.\n     *\n     * @param frame\n     */\n    public void onUIReset(PtrFrameLayout frame);\n\n    /**\n     * prepare for loading\n     *\n     * @param frame\n     */\n    public void onUIRefreshPrepare(PtrFrameLayout frame);\n\n    /**\n     * perform refreshing UI\n     */\n    public void onUIRefreshBegin(PtrFrameLayout frame);\n\n    /**\n     * perform UI after refresh\n     */\n    public void onUIRefreshComplete(PtrFrameLayout frame);\n\n    public void onUIPositionChange(PtrFrameLayout frame, boolean isUnderTouch, byte status, int oldPosition, int currentPosition, float oldPercent, float currentPercent);\n}\n```\n\n# Q & A\n\n*  work with ViewPager: `disableWhenHorizontalMove()`\n\n*  work with LongPressed, `setInterceptEventWhileWorking()`\n\n# Contact & Help\n\nPlease fell free to contact me if there is any problem when using the library.\n\n* srain@php.net\n* twitter: https://twitter.com/liaohuqiu\n* weibo: http://weibo.com/liaohuqiu\n* blog: http://www.liaohuqiu.net\n\n    1. About how to use cube-sdk / Ultra Ptr: 271918140 (cube-sdk)\n\n        This the rule for our tribes, please read it before you request to join: https://github.com/liaohuqiu/qq-tribe-rule\n\n    2. For those who like thinking independently and are good at solving problem independently. Please join us, we are all here on Slack: \n    \n        http://join-add1bit.liaohuqiu.net/\n"
  },
  {
    "path": "build.gradle",
    "content": "buildscript {\n    repositories {\n        jcenter()\n    }\n    dependencies {\n        classpath 'com.android.tools.build:gradle:1.0.0'\n    }\n}\n\nallprojects {\n    repositories {\n        jcenter()\n        mavenCentral();\n        maven {\n            url 'https://oss.sonatype.org/content/repositories/releases'\n        }\n        maven {\n            url 'https://oss.sonatype.org/content/repositories/snapshots'\n        }\n    }\n}\n"
  },
  {
    "path": "buildSrc/src/main/groovy/copy-libs.gradle",
    "content": "buildscript {\n    repositories {\n        jcenter()\n    }\n    dependencies {\n        classpath 'com.android.tools.build:gradle:0.12.+'\n    }\n}\n\nEXCLUDE_JAR_LIST = ['cube-sdk', 'support-v4-r7-source', 'ultra-ptr', 'support-annotation']\n\nclass CopyLibsTask extends DefaultTask {\n\n    @TaskAction\n    def copyLibs() {\n\n        // copy jars\n        copy {\n            from configurations.compile\n            into \"libs\"\n\n            eachFile { file ->\n                println file.name\n                for (name in EXCLUDE_JAR_LIST) {\n                    if (file.name.contains(name)) {\n                        file.exclude()\n                        return\n                    }\n                }\n            }\n        }\n\n        // copy source\n        copy {\n\n            def sourceList = configurations.compile.incoming.dependencies.collect { dependency ->\n                dependency.artifact { artifact ->\n                    artifact.name = dependency.name\n                    artifact.type = 'source'\n                    artifact.extension = 'jar'\n                    artifact.classifier = 'sources'\n                }\n                dependency\n            }\n            from(configurations.detachedConfiguration(sourceList as Dependency[]).resolvedConfiguration.\n                    resolvedConfiguration.lenientConfiguration.getFiles(Specs.SATISFIES_ALL)) {\n            }\n\n            into(\"libs\")\n\n            eachFile { file ->\n                println file.name\n                for (name in EXCLUDE_JAR_LIST) {\n                    if (file.name.contains(name)) {\n                        file.exclude()\n                        return\n                    }\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "gradle/wrapper/gradle-wrapper.properties",
    "content": "#Thu Dec 18 15:33:58 CST 2014\r\ndistributionBase=GRADLE_USER_HOME\r\ndistributionPath=wrapper/dists\r\nzipStoreBase=GRADLE_USER_HOME\r\nzipStorePath=wrapper/dists\r\ndistributionUrl=https\\://services.gradle.org/distributions/gradle-2.2.1-all.zip\r\n"
  },
  {
    "path": "gradle.properties",
    "content": "ANDROID_BUILD_MIN_SDK_VERSION=8\nANDROID_BUILD_TARGET_SDK_VERSION=22\nANDROID_BUILD_SDK_VERSION=22\nANDROID_BUILD_TOOLS_VERSION=22.0.1\n"
  },
  {
    "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# For Cygwin, ensure paths are in UNIX format before anything is touched.\nif $cygwin ; then\n    [ -n \"$JAVA_HOME\" ] && JAVA_HOME=`cygpath --unix \"$JAVA_HOME\"`\nfi\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\\\"`/\" >&-\nAPP_HOME=\"`pwd -P`\"\ncd \"$SAVED\" >&-\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\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\r\n@rem ##########################################################################\r\n@rem\r\n@rem  Gradle startup script for Windows\r\n@rem\r\n@rem ##########################################################################\r\n\r\n@rem Set local scope for the variables with windows NT shell\r\nif \"%OS%\"==\"Windows_NT\" setlocal\r\n\r\n@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\r\nset DEFAULT_JVM_OPTS=\r\n\r\nset DIRNAME=%~dp0\r\nif \"%DIRNAME%\" == \"\" set DIRNAME=.\r\nset APP_BASE_NAME=%~n0\r\nset APP_HOME=%DIRNAME%\r\n\r\n@rem Find java.exe\r\nif defined JAVA_HOME goto findJavaFromJavaHome\r\n\r\nset JAVA_EXE=java.exe\r\n%JAVA_EXE% -version >NUL 2>&1\r\nif \"%ERRORLEVEL%\" == \"0\" goto init\r\n\r\necho.\r\necho ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\r\necho.\r\necho Please set the JAVA_HOME variable in your environment to match the\r\necho location of your Java installation.\r\n\r\ngoto fail\r\n\r\n:findJavaFromJavaHome\r\nset JAVA_HOME=%JAVA_HOME:\"=%\r\nset JAVA_EXE=%JAVA_HOME%/bin/java.exe\r\n\r\nif exist \"%JAVA_EXE%\" goto init\r\n\r\necho.\r\necho ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%\r\necho.\r\necho Please set the JAVA_HOME variable in your environment to match the\r\necho location of your Java installation.\r\n\r\ngoto fail\r\n\r\n:init\r\n@rem Get command-line arguments, handling Windowz variants\r\n\r\nif not \"%OS%\" == \"Windows_NT\" goto win9xME_args\r\nif \"%@eval[2+2]\" == \"4\" goto 4NT_args\r\n\r\n:win9xME_args\r\n@rem Slurp the command line arguments.\r\nset CMD_LINE_ARGS=\r\nset _SKIP=2\r\n\r\n:win9xME_args_slurp\r\nif \"x%~1\" == \"x\" goto execute\r\n\r\nset CMD_LINE_ARGS=%*\r\ngoto execute\r\n\r\n:4NT_args\r\n@rem Get arguments from the 4NT Shell from JP Software\r\nset CMD_LINE_ARGS=%$\r\n\r\n:execute\r\n@rem Setup the command line\r\n\r\nset CLASSPATH=%APP_HOME%\\gradle\\wrapper\\gradle-wrapper.jar\r\n\r\n@rem Execute Gradle\r\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%\r\n\r\n:end\r\n@rem End local scope for the variables with windows NT shell\r\nif \"%ERRORLEVEL%\"==\"0\" goto mainEnd\r\n\r\n:fail\r\nrem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of\r\nrem the _cmd.exe /c_ return code!\r\nif  not \"\" == \"%GRADLE_EXIT_CONSOLE%\" exit 1\r\nexit /b 1\r\n\r\n:mainEnd\r\nif \"%OS%\"==\"Windows_NT\" endlocal\r\n\r\n:omega\r\n"
  },
  {
    "path": "pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n    xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n\n    <parent>\n        <groupId>in.srain</groupId>\n        <artifactId>cube-parent-for-oss</artifactId>\n        <version>1.0.1</version>\n    </parent>\n\n    <groupId>in.srain</groupId>\n    <artifactId>cube-ptr-parent</artifactId>\n    <version>1.0.1</version>\n    <packaging>pom</packaging>\n\n    <name>Ultra Pull to Refersh Parent</name>\n    <modules>\n        <module>ptr-lib</module>\n        <module>ptr-demo</module>\n    </modules>\n\n</project>\n"
  },
  {
    "path": "proguard-project.txt",
    "content": "# To enable ProGuard in your project, edit project.properties\n# to define the proguard.config property as described in that file.\n#\n# Add project specific ProGuard rules here.\n# By default, the flags in this file are appended to flags specified\n# in ${sdk.dir}/tools/proguard/proguard-android.txt\n# You can edit the include path and order by changing the ProGuard\n# include property in project.properties.\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-keep class in.srain.*\n-dontwarn class in.srain.cube.image.ImageProvider\n-dontwarn class android.graphics.Bitmap\n-ignorewarnings class in.srain.cube.image.ImageProvider\n-ignorewarnings class android.graphics.Bitmap\n"
  },
  {
    "path": "project.properties",
    "content": "# This file is automatically generated by Android Tools.\n# Do not modify this file -- YOUR CHANGES WILL BE ERASED!\n#\n# This file must be checked in Version Control Systems.\n#\n# To customize properties used by the Ant build system edit\n# \"ant.properties\", and override values to adapt the script to your\n# project structure.\n#\n# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):\n#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt\n\nandroid.library=true\n# Project target.\ntarget=android-19\nandroid.library.reference.1=../../android-CLog\n"
  },
  {
    "path": "ptr-demo/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest\n    package=\"in.srain.cube.views.ptr.demo\"\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:versionCode=\"1\"\n    android:versionName=\"1.0\">\n\n    <uses-sdk\n        android:minSdkVersion=\"8\"\n        android:targetSdkVersion=\"16\" />\n\n    <uses-permission android:name=\"android.permission.INTERNET\" />\n    <uses-permission android:name=\"android.permission.GET_TASKS\" />\n    <uses-permission android:name=\"android.permission.WRITE_EXTERNAL_STORAGE\" />\n    <uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\" />\n\n    <application\n        android:name=\".app.PtrDemoApplication\"\n        android:allowBackup=\"true\"\n        android:icon=\"@drawable/ic_launcher\"\n        android:label=\"@string/app_name\"\n        android:theme=\"@style/CubeTheme.NoWindowAniAndNoTitle\">\n        <activity android:name=\".ui.activity.PtrDemoHomeActivity\">\n            <intent-filter>\n                <action android:name=\"android.intent.action.MAIN\" />\n                <category android:name=\"android.intent.category.LAUNCHER\" />\n            </intent-filter>\n        </activity>\n\n        <activity\n            android:name=\".ui.viewpager.ViewPagerActivity\"\n            android:windowSoftInputMode=\"stateAlwaysHidden|adjustResize\"></activity>\n\n    </application>\n\n</manifest>"
  },
  {
    "path": "ptr-demo/assets/request_init/demo/image-list.json",
    "content": "{\"data\":{\"time\":\"2014-08-27 02:13:01 UTC\",\"list\":[{\"pic\":\"http:\\/\\/img4.duitang.com\\/uploads\\/blog\\/201311\\/04\\/20131104193715_NCexN.thumb.jpeg\"},{\"pic\":\"http:\\/\\/img5.duitang.com\\/uploads\\/item\\/201408\\/09\\/20140809210610_iTSJx.thumb.jpeg\"},{\"pic\":\"http:\\/\\/cdn.duitang.com\\/uploads\\/blog\\/201401\\/07\\/20140107223310_LH3Uy.thumb.jpeg\"},{\"pic\":\"http:\\/\\/img5.duitang.com\\/uploads\\/item\\/201405\\/09\\/20140509222156_kVexJ.thumb.jpeg\"},{\"pic\":\"http:\\/\\/img5.duitang.com\\/uploads\\/item\\/201306\\/14\\/20130614185903_raNR3.thumb.jpeg\"},{\"pic\":\"http:\\/\\/img5.duitang.com\\/uploads\\/item\\/201112\\/11\\/20111211191621_HU4Bj.thumb.jpg\"},{\"pic\":\"http:\\/\\/cdn.duitang.com\\/uploads\\/item\\/201408\\/07\\/20140807224553_VXaUc.thumb.jpeg\"},{\"pic\":\"http:\\/\\/img5.duitang.com\\/uploads\\/blog\\/201407\\/29\\/20140729105929_GQLwC.thumb.jpeg\"},{\"pic\":\"http:\\/\\/img4.duitang.com\\/uploads\\/blog\\/201408\\/04\\/20140804160432_LnFeB.thumb.jpeg\"},{\"pic\":\"http:\\/\\/img5.duitang.com\\/uploads\\/blog\\/201408\\/04\\/20140804161101_JVJea.thumb.jpeg\"},{\"pic\":\"http:\\/\\/cdn.duitang.com\\/uploads\\/blog\\/201408\\/04\\/20140804093210_FxFNd.thumb.jpeg\"},{\"pic\":\"http:\\/\\/img5.duitang.com\\/uploads\\/blog\\/201408\\/04\\/20140804160314_hRKtv.thumb.jpeg\"},{\"pic\":\"http:\\/\\/cdn.duitang.com\\/uploads\\/item\\/201408\\/01\\/20140801080524_SnGfE.thumb.jpeg\"},{\"pic\":\"http:\\/\\/img5.duitang.com\\/uploads\\/item\\/201407\\/23\\/20140723140958_NSWfE.thumb.jpeg\"},{\"pic\":\"http:\\/\\/img4.duitang.com\\/uploads\\/blog\\/201407\\/22\\/20140722153305_WHejQ.thumb.jpeg\"},{\"pic\":\"http:\\/\\/img5.duitang.com\\/uploads\\/item\\/201407\\/21\\/20140721010148_ZBQwe.thumb.jpeg\"},{\"pic\":\"http:\\/\\/cdn.duitang.com\\/uploads\\/item\\/201407\\/23\\/20140723085122_cmteu.thumb.jpeg\"},{\"pic\":\"http:\\/\\/img5.duitang.com\\/uploads\\/item\\/201407\\/23\\/20140723130620_Z2yJB.thumb.jpeg\"},{\"pic\":\"http:\\/\\/cdn.duitang.com\\/uploads\\/blog\\/201407\\/20\\/20140720204738_NXxLE.thumb.jpeg\"},{\"pic\":\"http:\\/\\/cdn.duitang.com\\/uploads\\/item\\/201407\\/20\\/20140720134916_VGfyh.thumb.jpeg\"},{\"pic\":\"http:\\/\\/img5.duitang.com\\/uploads\\/blog\\/201407\\/17\\/20140717113117_mUssJ.thumb.jpeg\"},{\"pic\":\"http:\\/\\/img5.duitang.com\\/uploads\\/blog\\/201407\\/17\\/20140717121501_wfFEm.thumb.jpeg\"},{\"pic\":\"http:\\/\\/img5.duitang.com\\/uploads\\/blog\\/201407\\/17\\/20140717121431_w4AV8.thumb.jpeg\"},{\"pic\":\"http:\\/\\/img5.duitang.com\\/uploads\\/blog\\/201407\\/17\\/20140717121918_TtJjY.thumb.jpeg\"},{\"pic\":\"http:\\/\\/img5.duitang.com\\/uploads\\/item\\/201407\\/11\\/20140711234806_FNLBQ.thumb.jpeg\"},{\"pic\":\"http:\\/\\/img5.duitang.com\\/uploads\\/item\\/201407\\/18\\/20140718121437_UyiAS.thumb.jpeg\"},{\"pic\":\"http:\\/\\/img5.duitang.com\\/uploads\\/blog\\/201407\\/17\\/20140717114829_RiCXR.thumb.jpeg\"},{\"pic\":\"http:\\/\\/img4.duitang.com\\/uploads\\/blog\\/201407\\/17\\/20140717120301_wGFYL.thumb.jpeg\"},{\"pic\":\"http:\\/\\/img5.duitang.com\\/uploads\\/blog\\/201405\\/11\\/20140511121106_JXS4B.thumb.jpeg\"},{\"pic\":\"http:\\/\\/img5.duitang.com\\/uploads\\/blog\\/201405\\/10\\/20140510094144_kfLji.thumb.jpeg\"},{\"pic\":\"http:\\/\\/img5.duitang.com\\/uploads\\/blog\\/201405\\/09\\/20140509201906_kERjy.thumb.jpeg\"},{\"pic\":\"http:\\/\\/img5.duitang.com\\/uploads\\/blog\\/201405\\/08\\/20140508193226_UaSGB.thumb.jpeg\"},{\"pic\":\"http:\\/\\/img4.duitang.com\\/uploads\\/blog\\/201405\\/05\\/20140505201747_aPNtf.thumb.jpeg\"},{\"pic\":\"http:\\/\\/img5.duitang.com\\/uploads\\/blog\\/201405\\/06\\/20140506104824_jPWQj.thumb.jpeg\"},{\"pic\":\"http:\\/\\/img5.duitang.com\\/uploads\\/blog\\/201405\\/05\\/20140505201105_MkXdn.thumb.jpeg\"},{\"pic\":\"http:\\/\\/img5.duitang.com\\/uploads\\/blog\\/201405\\/03\\/20140503205822_GCzta.thumb.jpeg\"},{\"pic\":\"http:\\/\\/img5.duitang.com\\/uploads\\/blog\\/201405\\/03\\/20140503205535_cCHPB.thumb.jpeg\"},{\"pic\":\"http:\\/\\/img5.duitang.com\\/uploads\\/blog\\/201405\\/03\\/20140503204354_xxSQX.thumb.jpeg\"},{\"pic\":\"http:\\/\\/img4.duitang.com\\/uploads\\/blog\\/201404\\/06\\/20140406191307_GTxFd.thumb.jpeg\"},{\"pic\":\"http:\\/\\/img4.duitang.com\\/uploads\\/blog\\/201404\\/06\\/20140406191247_BG2cU.thumb.jpeg\"},{\"pic\":\"http:\\/\\/img4.duitang.com\\/uploads\\/blog\\/201404\\/06\\/20140406191114_MzYtw.thumb.jpeg\"},{\"pic\":\"http:\\/\\/img4.duitang.com\\/uploads\\/blog\\/201404\\/06\\/20140406191127_fazJA.thumb.jpeg\"},{\"pic\":\"http:\\/\\/img5.duitang.com\\/uploads\\/item\\/201407\\/10\\/20140710081204_vYnCi.thumb.jpeg\"},{\"pic\":\"http:\\/\\/img5.duitang.com\\/uploads\\/item\\/201407\\/15\\/20140715133758_M2Y3J.thumb.jpeg\"},{\"pic\":\"http:\\/\\/img4.duitang.com\\/uploads\\/item\\/201407\\/13\\/20140713190806_TGJHm.thumb.jpeg\"},{\"pic\":\"http:\\/\\/img4.duitang.com\\/uploads\\/blog\\/201407\\/05\\/20140705223413_5r3ze.thumb.jpeg\"},{\"pic\":\"http:\\/\\/img5.duitang.com\\/uploads\\/item\\/201407\\/13\\/20140713012526_tcy5u.thumb.jpeg\"},{\"pic\":\"http:\\/\\/img5.duitang.com\\/uploads\\/blog\\/201407\\/13\\/20140713121424_Gy43T.thumb.jpeg\"},{\"pic\":\"http:\\/\\/img4.duitang.com\\/uploads\\/item\\/201407\\/15\\/20140715033844_tcvrY.thumb.jpeg\"},{\"pic\":\"http:\\/\\/img5.duitang.com\\/uploads\\/item\\/201407\\/10\\/20140710181106_4HHay.thumb.jpeg\"},{\"pic\":\"http:\\/\\/img5.duitang.com\\/uploads\\/blog\\/201407\\/06\\/20140706122850_8PER3.thumb.jpeg\"},{\"pic\":\"http:\\/\\/img5.duitang.com\\/uploads\\/blog\\/201407\\/07\\/20140707192042_8xKXF.thumb.jpeg\"},{\"pic\":\"http:\\/\\/img5.duitang.com\\/uploads\\/item\\/201407\\/07\\/20140707063954_mVa3y.thumb.jpeg\"},{\"pic\":\"http:\\/\\/img5.duitang.com\\/uploads\\/item\\/201407\\/08\\/20140708093733_AFFhc.thumb.jpeg\"},{\"pic\":\"http:\\/\\/img5.duitang.com\\/uploads\\/blog\\/201407\\/07\\/20140707161220_unvzn.thumb.jpeg\"},{\"pic\":\"http:\\/\\/img4.duitang.com\\/uploads\\/blog\\/201407\\/07\\/20140707113856_hBf3R.thumb.jpeg\"},{\"pic\":\"http:\\/\\/img5.duitang.com\\/uploads\\/item\\/201308\\/26\\/20130826090203_NtuYA.thumb.jpeg\"},{\"pic\":\"http:\\/\\/img4.duitang.com\\/uploads\\/item\\/201407\\/07\\/20140707145925_dHeKV.thumb.jpeg\"},{\"pic\":\"http:\\/\\/img5.duitang.com\\/uploads\\/item\\/201406\\/25\\/20140625101534_xiZxN.thumb.jpeg\"},{\"pic\":\"http:\\/\\/img5.duitang.com\\/uploads\\/blog\\/201406\\/30\\/20140630150534_EWUVY.thumb.jpeg\"},{\"pic\":\"http:\\/\\/img5.duitang.com\\/uploads\\/item\\/201406\\/25\\/20140625121626_ZmT5n.thumb.jpeg\"},{\"pic\":\"http:\\/\\/img4.duitang.com\\/uploads\\/blog\\/201307\\/31\\/20130731231806_4yGxV.thumb.jpeg\"},{\"pic\":\"http:\\/\\/img5.duitang.com\\/uploads\\/item\\/201406\\/28\\/20140628122218_fLQyP.thumb.jpeg\"},{\"pic\":\"http:\\/\\/img5.duitang.com\\/uploads\\/blog\\/201406\\/26\\/20140626131831_MrdKP.thumb.jpeg\"},{\"pic\":\"http:\\/\\/img5.duitang.com\\/uploads\\/blog\\/201406\\/16\\/20140616165201_nuKWj.thumb.jpeg\"},{\"pic\":\"http:\\/\\/img5.duitang.com\\/uploads\\/item\\/201406\\/25\\/20140625140308_KP4rn.thumb.jpeg\"},{\"pic\":\"http:\\/\\/img5.duitang.com\\/uploads\\/item\\/201406\\/25\\/20140625121604_2auuA.thumb.jpeg\"},{\"pic\":\"http:\\/\\/img4.duitang.com\\/uploads\\/item\\/201406\\/25\\/20140625131625_LmmLZ.thumb.jpeg\"},{\"pic\":\"http:\\/\\/img5.duitang.com\\/uploads\\/item\\/201406\\/25\\/20140625132851_mPmKY.thumb.jpeg\"},{\"pic\":\"http:\\/\\/img5.duitang.com\\/uploads\\/item\\/201406\\/25\\/20140625133312_ZtmW4.thumb.jpeg\"},{\"pic\":\"http:\\/\\/img5.duitang.com\\/uploads\\/item\\/201406\\/25\\/20140625164858_AuafS.thumb.jpeg\"}]},\"server_time\":\"2014-08-27 02:13:01\"}"
  },
  {
    "path": "ptr-demo/build.gradle",
    "content": "apply plugin: 'com.android.application'\n\nandroid {\n    compileSdkVersion Integer.parseInt(project.ANDROID_BUILD_SDK_VERSION)\n    buildToolsVersion project.ANDROID_BUILD_TOOLS_VERSION\n\n    defaultConfig {\n        applicationId \"in.srain.cube.views.ptr.demo\"\n        minSdkVersion 8\n        targetSdkVersion Integer.parseInt(project.ANDROID_BUILD_TARGET_SDK_VERSION)\n    }\n\n    lintOptions {\n        abortOnError false\n    }\n\n    buildTypes {\n        release {\n            minifyEnabled true\n            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'\n        }\n    }\n\n    sourceSets {\n        main {\n            manifest.srcFile 'AndroidManifest.xml'\n            java.srcDirs = ['src']\n            resources.srcDirs = ['resources']\n            res.srcDirs = ['res']\n            assets.srcDirs = ['assets']\n            // aidl.srcDirs = ['src']\n            // renderscript.srcDirs = ['src']\n        }\n\n        androidTest.setRoot('tests')\n    }\n    dexOptions {\n        preDexLibraries = false\n    }\n}\n\n\ndef EXCLUDE_JAR_LIST = ['cube-sdk', 'support-v4-r7-source', 'ultra-ptr', 'support-annotation', 'ptr-lib']\n\ntask copyLibs << {\n\n    // copy jars\n    copy {\n        from configurations.compile\n        into \"libs\"\n\n        eachFile { file ->\n            println file.name\n            for (name in EXCLUDE_JAR_LIST) {\n                if (file.name.contains(name)) {\n                    file.exclude()\n                    return\n                }\n            }\n        }\n    }\n\n    // copy source\n    copy {\n\n        def sourceList = configurations.compile.incoming.dependencies.collect { dependency ->\n            dependency.artifact { artifact ->\n                artifact.name = dependency.name\n                artifact.type = 'source'\n                artifact.extension = 'jar'\n                artifact.classifier = 'sources'\n            }\n            dependency\n        }\n        from(configurations.detachedConfiguration(sourceList as Dependency[]).resolvedConfiguration.\n                resolvedConfiguration.lenientConfiguration.getFiles(Specs.SATISFIES_ALL)) {\n        }\n\n        into(\"libs\")\n\n        eachFile { file ->\n            println file.name\n            for (name in EXCLUDE_JAR_LIST) {\n                if (file.name.contains(name)) {\n                    file.exclude()\n                    return\n                }\n            }\n        }\n    }\n}\n\ndependencies {\n    compile(project(':ptr-lib')) {\n    }\n    compile 'in.srain.cube:clog:1.0.2'\n    compile 'in.srain.cube:cube-sdk:1.0.44.39-SNAPSHOT@aar'\n    compile 'com.google.android:support-v4:r7'\n}\n"
  },
  {
    "path": "ptr-demo/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n    xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n\n    <parent>\n        <groupId>in.srain</groupId>\n        <artifactId>cube-parent-for-oss</artifactId>\n        <version>1.0.1</version>\n    </parent>\n\n    <groupId>in.srain.cube</groupId>\n    <artifactId>ultra-ptr-demo</artifactId>\n    <packaging>apk</packaging>\n    <name>Ultra Pull to Refresh Demo</name>\n    <version>1.0.1</version>\n\n    <dependencies>\n        <dependency>\n            <groupId>com.google.android</groupId>\n            <artifactId>android</artifactId>\n            <version>4.1.1.4</version>\n            <scope>provided</scope>\n        </dependency>\n        <dependency>\n            <groupId>com.google.android</groupId>\n            <artifactId>support-v4</artifactId>\n            <version>r7</version>\n        </dependency>\n        <dependency>\n            <groupId>in.srain.cube</groupId>\n            <artifactId>ultra-ptr</artifactId>\n            <type>aar</type>\n            <version>1.0.11</version>\n        </dependency>\n        <dependency>\n            <groupId>in.srain.cube</groupId>\n            <artifactId>cube-sdk</artifactId>\n            <type>aar</type>\n            <version>1.0.44.39-SNAPSHOT</version>\n        </dependency>\n    </dependencies>\n\n    <properties>\n        <android_maven_plugin_version>3.8.2</android_maven_plugin_version>\n        <android_compile_api_level>16</android_compile_api_level>\n    </properties>\n\n    <build>\n        <finalName>${project.artifactId}</finalName>\n        <sourceDirectory>src/</sourceDirectory>\n        <plugins>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n                <configuration>\n                    <source>1.6</source>\n                    <target>1.6</target>\n                </configuration>\n            </plugin>\n            <!-- compile plugin -->\n            <plugin>\n                <groupId>com.jayway.maven.plugins.android.generation2</groupId>\n                <artifactId>android-maven-plugin</artifactId>\n                <extensions>true</extensions>\n                <version>${android_maven_plugin_version}</version>\n                <configuration>\n                    <sdk>\n                        <platform>${android_compile_api_level}</platform>\n                    </sdk>\n                    <sign>\n                        <debug>false</debug>\n                    </sign>\n                </configuration>\n            </plugin>\n        </plugins>\n    </build>\n</project>\n"
  },
  {
    "path": "ptr-demo/proguard-project.txt",
    "content": "# To enable ProGuard in your project, edit project.properties\n# to define the proguard.config property as described in that file.\n#\n# Add project specific ProGuard rules here.\n# By default, the flags in this file are appended to flags specified\n# in ${sdk.dir}/tools/proguard/proguard-android.txt\n# You can edit the include path and order by changing the ProGuard\n# include property in project.properties.\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": "ptr-demo/proguard-rules.pro",
    "content": "-keep class in.srain.*\n-dontwarn android.graphics.Bitmap\n"
  },
  {
    "path": "ptr-demo/project.properties",
    "content": "# This file is automatically generated by Android Tools.\n# Do not modify this file -- YOUR CHANGES WILL BE ERASED!\n#\n# This file must be checked in Version Control Systems.\n#\n# To customize properties used by the Ant build system edit\n# \"ant.properties\", and override values to adapt the script to your\n# project structure.\n#\n# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):\n#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt\n\n# Project target.\ntarget=android-19\n"
  },
  {
    "path": "ptr-demo/res/drawable/image_border.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <solid android:color=\"#ffffff\" />\n\n    <stroke\n        android:width=\"1px\"\n        android:color=\"#007edf\" />\n\n</shape>"
  },
  {
    "path": "ptr-demo/res/drawable/text_view_bg.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\r\n    <item android:drawable=\"@color/cube_holo_orange_light\" android:state_pressed=\"true\" />\r\n    <item android:drawable=\"@color/cube_holo_orange_dark\" />\r\n</selector>"
  },
  {
    "path": "ptr-demo/res/drawable/with_long_press_list_item_background.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item android:drawable=\"@color/cube_mints_f1f1f1\" android:state_selected=\"true\" />\n    <item android:drawable=\"@color/cube_mints_f1f1f1\" android:state_pressed=\"true\" />\n    <item android:drawable=\"@color/cube_mints_white\" android:state_selected=\"false\" />\n</selector>"
  },
  {
    "path": "ptr-demo/res/layout/activity_main.xml",
    "content": "<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    <FrameLayout\n        android:id=\"@+id/id_fragment\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\">\n\n    </FrameLayout>\n\n</LinearLayout>"
  },
  {
    "path": "ptr-demo/res/layout/activity_view_pager.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\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:background=\"@color/cube_mints_f1f1f1\"\n    android:orientation=\"vertical\">\n\n    <in.srain.cube.views.pager.TabPageIndicator\n        android:id=\"@+id/view_pager_tab_indicator\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"36dp\"\n        android:background=\"@color/cube_mints_white\"\n        android:fadingEdge=\"none\"\n        android:paddingLeft=\"15dp\"\n        android:paddingRight=\"15dp\" />\n\n    <in.srain.cube.views.ptr.PtrClassicFrameLayout\n        android:id=\"@+id/view_pager_ptr_frame\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:layout_weight=\"1\">\n\n        <android.support.v4.view.ViewPager\n            android:id=\"@+id/view_pager_view_pager\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\"\n            android:background=\"@color/cube_mints_white\" />\n\n    </in.srain.cube.views.ptr.PtrClassicFrameLayout>\n\n\n</LinearLayout>"
  },
  {
    "path": "ptr-demo/res/layout/fragment_classic_header_with_gridview.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\">\n\n    <in.srain.cube.views.ptr.PtrClassicFrameLayout\n        android:id=\"@+id/rotate_header_grid_view_frame\"\n        xmlns:cube_ptr=\"http://schemas.android.com/apk/res-auto\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:background=\"@color/cube_mints_f1f1f1\"\n        cube_ptr:ptr_duration_to_close=\"200\"\n        cube_ptr:ptr_duration_to_close_header=\"1000\"\n        cube_ptr:ptr_keep_header_when_refresh=\"true\"\n        cube_ptr:ptr_pull_to_fresh=\"false\"\n        cube_ptr:ptr_ratio_of_header_height_to_refresh=\"1.2\"\n        cube_ptr:ptr_resistance=\"1.7\">\n\n        <GridView\n            android:id=\"@+id/rotate_header_grid_view\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\"\n            android:background=\"@color/cube_mints_white\"\n            android:fadingEdge=\"none\"\n            android:focusable=\"false\"\n            android:horizontalSpacing=\"10dp\"\n            android:listSelector=\"@android:color/transparent\"\n            android:numColumns=\"2\"\n            android:paddingBottom=\"12dp\"\n            android:paddingLeft=\"12dp\"\n            android:paddingRight=\"12dp\"\n            android:scrollbars=\"none\"\n            android:stretchMode=\"columnWidth\" />\n\n    </in.srain.cube.views.ptr.PtrClassicFrameLayout>\n</RelativeLayout>"
  },
  {
    "path": "ptr-demo/res/layout/fragment_classic_header_with_list_view.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\">\n\n    <in.srain.cube.views.ptr.PtrClassicFrameLayout\n        android:id=\"@+id/rotate_header_list_view_frame\"\n        xmlns:cube_ptr=\"http://schemas.android.com/apk/res-auto\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:background=\"@color/cube_mints_f1f1f1\"\n        cube_ptr:ptr_duration_to_close=\"200\"\n        cube_ptr:ptr_duration_to_close_header=\"1000\"\n        cube_ptr:ptr_keep_header_when_refresh=\"true\"\n        cube_ptr:ptr_pull_to_fresh=\"false\"\n        cube_ptr:ptr_ratio_of_header_height_to_refresh=\"1.2\"\n        cube_ptr:ptr_resistance=\"1.7\">\n\n        <ListView\n            android:id=\"@+id/rotate_header_list_view\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\"\n            android:divider=\"@null\"\n            android:fadingEdge=\"none\"\n            android:listSelector=\"@android:color/transparent\"\n            android:paddingLeft=\"12dp\"\n            android:paddingRight=\"12dp\"\n            android:scrollbarStyle=\"outsideOverlay\"\n            android:choiceMode=\"singleChoice\" />\n\n    </in.srain.cube.views.ptr.PtrClassicFrameLayout>\n</RelativeLayout>"
  },
  {
    "path": "ptr-demo/res/layout/fragment_classic_header_with_list_view_and_empty_view.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:background=\"@color/cube_mints_white\">\n\n    <TextView\n        android:id=\"@+id/list_view_with_empty_view_fragment_empty_view\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_centerInParent=\"true\"\n        android:gravity=\"center\"\n        android:text=\"@string/ptr_demo_block_with_list_view_and_empty_view_tip\"\n        android:textColor=\"@color/cube_holo_blue_dark\"\n        android:textSize=\"20sp\" />\n\n    <in.srain.cube.views.ptr.PtrClassicFrameLayout\n        android:id=\"@+id/list_view_with_empty_view_fragment_ptr_frame\"\n        xmlns:cube_ptr=\"http://schemas.android.com/apk/res-auto\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:background=\"@color/cube_mints_f1f1f1\"\n        cube_ptr:ptr_duration_to_close=\"200\"\n        cube_ptr:ptr_duration_to_close_header=\"1000\"\n        cube_ptr:ptr_keep_header_when_refresh=\"true\"\n        cube_ptr:ptr_pull_to_fresh=\"false\"\n        cube_ptr:ptr_ratio_of_header_height_to_refresh=\"1.2\"\n        cube_ptr:ptr_resistance=\"1.7\">\n\n        <FrameLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\">\n\n            <ListView\n                android:id=\"@+id/list_view_with_empty_view_fragment_list_view\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"match_parent\"\n                android:choiceMode=\"singleChoice\"\n                android:divider=\"@null\"\n                android:fadingEdge=\"none\"\n                android:listSelector=\"@android:color/transparent\"\n                android:paddingLeft=\"12dp\"\n                android:paddingRight=\"12dp\"\n                android:scrollbarStyle=\"outsideOverlay\" />\n\n        </FrameLayout>\n\n    </in.srain.cube.views.ptr.PtrClassicFrameLayout>\n</RelativeLayout>"
  },
  {
    "path": "ptr-demo/res/layout/fragment_classic_header_with_scroll_view.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout 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    <in.srain.cube.views.ptr.PtrClassicFrameLayout\n        android:id=\"@+id/rotate_header_web_view_frame\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:background=\"@color/cube_mints_f1f1f1\"\n        app:ptr_duration_to_close=\"200\"\n        app:ptr_duration_to_close_header=\"1000\"\n        app:ptr_keep_header_when_refresh=\"true\"\n        app:ptr_pull_to_fresh=\"false\"\n        app:ptr_ratio_of_header_height_to_refresh=\"1.2\"\n        app:ptr_resistance=\"1.7\">\n\n        <ScrollView\n            android:id=\"@+id/rotate_header_scroll_view\"\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\n                <TextView\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"200dp\"\n                    android:layout_margin=\"@dimen/cube_mints_content_view_padding\"\n                    android:background=\"@drawable/text_view_bg\"\n                    android:clickable=\"true\"\n                    android:gravity=\"center\"\n                    android:text=\"text 1\"\n                    android:textColor=\"@color/cube_mints_white\"\n                    android:textSize=\"30sp\" />\n\n                <TextView\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"400dp\"\n                    android:layout_margin=\"@dimen/cube_mints_content_view_padding\"\n                    android:background=\"@drawable/text_view_bg\"\n                    android:clickable=\"true\"\n                    android:gravity=\"center\"\n                    android:text=\"text 2\"\n                    android:textColor=\"@color/cube_mints_white\"\n                    android:textSize=\"30sp\" />\n\n                <TextView\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"300dp\"\n                    android:layout_margin=\"@dimen/cube_mints_content_view_padding\"\n                    android:background=\"@drawable/text_view_bg\"\n                    android:clickable=\"true\"\n                    android:gravity=\"center\"\n                    android:text=\"text 3\"\n                    android:textColor=\"@color/cube_mints_white\"\n                    android:textSize=\"30sp\" />\n\n            </LinearLayout>\n        </ScrollView>\n\n    </in.srain.cube.views.ptr.PtrClassicFrameLayout>\n</RelativeLayout>"
  },
  {
    "path": "ptr-demo/res/layout/fragment_classic_header_with_textview.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:background=\"#f1f1f1\">\n\n    <in.srain.cube.views.ptr.PtrClassicFrameLayout\n        android:id=\"@+id/fragment_rotate_header_with_text_view_frame\"\n        xmlns:cube_ptr=\"http://schemas.android.com/apk/res-auto\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:background=\"#fff\"\n        cube_ptr:ptr_duration_to_close=\"200\"\n        cube_ptr:ptr_duration_to_close_header=\"1000\"\n        cube_ptr:ptr_keep_header_when_refresh=\"true\"\n        cube_ptr:ptr_pull_to_fresh=\"false\"\n        cube_ptr:ptr_ratio_of_header_height_to_refresh=\"1.2\"\n        cube_ptr:ptr_resistance=\"1.7\">\n\n        <TextView\n            android:id=\"@+id/fragment_rotate_header_with_text_view_content\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\"\n            android:layout_margin=\"@dimen/cube_mints_content_view_padding\"\n            android:clickable=\"true\"\n            android:background=\"@drawable/text_view_bg\"\n            android:gravity=\"center\"\n            android:text=\"I am a TextView\"\n            android:textColor=\"@color/cube_mints_white\"\n            android:textSize=\"30sp\" />\n\n    </in.srain.cube.views.ptr.PtrClassicFrameLayout>\n</RelativeLayout>"
  },
  {
    "path": "ptr-demo/res/layout/fragment_classic_header_with_viewgroup.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:background=\"@color/cube_mints_f1f1f1\">\n\n    <in.srain.cube.views.ptr.PtrClassicFrameLayout\n        android:id=\"@+id/fragment_rotate_header_with_view_group_frame\"\n        xmlns:cube_ptr=\"http://schemas.android.com/apk/res-auto\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        cube_ptr:ptr_duration_to_close=\"200\"\n        cube_ptr:ptr_duration_to_close_header=\"1000\"\n        cube_ptr:ptr_keep_header_when_refresh=\"true\"\n        cube_ptr:ptr_pull_to_fresh=\"false\"\n        cube_ptr:ptr_ratio_of_header_height_to_refresh=\"1.2\"\n        cube_ptr:ptr_resistance=\"1.7\">\n\n        <FrameLayout\n            android:id=\"@+id/fragment_rotate_header_with_view_group_content\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\"\n            android:background=\"@color/cube_mints_white\"\n            android:paddingLeft=\"@dimen/cube_mints_content_view_padding\"\n            android:paddingRight=\"@dimen/cube_mints_content_view_padding\"\n            android:paddingTop=\"100dp\">\n\n            <TextView\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:background=\"@color/cube_mints_4d90fe\"\n                android:gravity=\"center\"\n                android:padding=\"@dimen/cube_mints_content_view_padding\"\n                android:text=\"I am a TextView in FrameLayout\"\n                android:textColor=\"@color/cube_mints_white\"\n                android:textSize=\"30sp\" />\n\n        </FrameLayout>\n    </in.srain.cube.views.ptr.PtrClassicFrameLayout>\n</RelativeLayout>"
  },
  {
    "path": "ptr-demo/res/layout/fragment_classic_header_with_webview.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\">\n\n    <in.srain.cube.views.ptr.PtrClassicFrameLayout\n        android:id=\"@+id/rotate_header_web_view_frame\"\n        xmlns:cube_ptr=\"http://schemas.android.com/apk/res-auto\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:background=\"@color/cube_mints_f1f1f1\"\n        cube_ptr:ptr_duration_to_close=\"200\"\n        cube_ptr:ptr_duration_to_close_header=\"1000\"\n        cube_ptr:ptr_keep_header_when_refresh=\"true\"\n        cube_ptr:ptr_pull_to_fresh=\"false\"\n        cube_ptr:ptr_ratio_of_header_height_to_refresh=\"1.2\"\n        cube_ptr:ptr_resistance=\"1.7\">\n\n        <WebView\n            android:id=\"@+id/rotate_header_web_view\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\" />\n\n    </in.srain.cube.views.ptr.PtrClassicFrameLayout>\n</RelativeLayout>"
  },
  {
    "path": "ptr-demo/res/layout/fragment_materail_style.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:background=\"@color/cube_mints_f1f1f1\">\n\n    <in.srain.cube.views.ptr.PtrFrameLayout\n        android:id=\"@+id/material_style_ptr_frame\"\n        xmlns:cube_ptr=\"http://schemas.android.com/apk/res-auto\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        cube_ptr:ptr_duration_to_close=\"300\"\n        cube_ptr:ptr_duration_to_close_header=\"2000\"\n        cube_ptr:ptr_keep_header_when_refresh=\"true\"\n        cube_ptr:ptr_pull_to_fresh=\"false\"\n        cube_ptr:ptr_ratio_of_header_height_to_refresh=\"1.2\"\n        cube_ptr:ptr_resistance=\"1.7\">\n\n        <LinearLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\"\n            android:background=\"@color/cube_mints_white\"\n            android:clickable=\"true\"\n            android:padding=\"10dp\">\n\n            <in.srain.cube.image.CubeImageView\n                android:id=\"@+id/material_style_image_view\"\n                android:layout_width=\"match_parent\"\n                android:scaleType=\"fitCenter\"\n                android:layout_height=\"match_parent\" />\n        </LinearLayout>\n\n    </in.srain.cube.views.ptr.PtrFrameLayout>\n</RelativeLayout>"
  },
  {
    "path": "ptr-demo/res/layout/fragment_ptr_home.xml",
    "content": "<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    <in.srain.cube.views.ptr.PtrFrameLayout\n        android:id=\"@+id/fragment_ptr_home_ptr_frame\"\n        xmlns:cube_ptr=\"http://schemas.android.com/apk/res-auto\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        cube_ptr:ptr_duration_to_close=\"200\"\n        cube_ptr:ptr_duration_to_close_header=\"1000\"\n        cube_ptr:ptr_keep_header_when_refresh=\"true\"\n        cube_ptr:ptr_pull_to_fresh=\"false\"\n        cube_ptr:ptr_ratio_of_header_height_to_refresh=\"1.2\"\n        cube_ptr:ptr_resistance=\"1.7\">\n\n        <ScrollView\n            android:id=\"@+id/fragment_block_menu_scroll_view\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\"\n            android:background=\"@color/cube_mints_white\">\n\n            <in.srain.cube.views.block.BlockListView\n                android:id=\"@+id/fragment_block_menu_block_list\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:padding=\"@dimen/cube_mints_content_view_padding\" />\n        </ScrollView>\n\n    </in.srain.cube.views.ptr.PtrFrameLayout>\n</LinearLayout>"
  },
  {
    "path": "ptr-demo/res/layout/fragment_storehouse_header.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:background=\"#333333\">\n\n    <in.srain.cube.views.ptr.PtrFrameLayout\n        android:id=\"@+id/store_house_ptr_frame\"\n        xmlns:cube_ptr=\"http://schemas.android.com/apk/res-auto\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        cube_ptr:ptr_duration_to_close=\"300\"\n        cube_ptr:ptr_duration_to_close_header=\"2000\"\n        cube_ptr:ptr_keep_header_when_refresh=\"true\"\n        cube_ptr:ptr_pull_to_fresh=\"false\"\n        cube_ptr:ptr_ratio_of_header_height_to_refresh=\"1.2\"\n        cube_ptr:ptr_resistance=\"1.7\">\n\n        <LinearLayout\n            android:id=\"@+id/store_house_ptr_image_content\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\"\n            android:background=\"@color/cube_mints_333333\"\n            android:clickable=\"true\"\n            android:padding=\"10dp\">\n\n            <in.srain.cube.image.CubeImageView\n                android:id=\"@+id/store_house_ptr_image\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"match_parent\" />\n        </LinearLayout>\n\n    </in.srain.cube.views.ptr.PtrFrameLayout>\n</RelativeLayout>"
  },
  {
    "path": "ptr-demo/res/layout/fragment_view_pager.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:background=\"@color/cube_mints_white\">\n\n    <ListView\n        android:id=\"@+id/view_pager_list_view\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:divider=\"@null\"\n        android:fadingEdge=\"none\"\n        android:listSelector=\"@android:color/transparent\"\n        android:paddingLeft=\"12dp\"\n        android:paddingRight=\"12dp\"\n        android:scrollbarStyle=\"outsideOverlay\" />\n\n</RelativeLayout>"
  },
  {
    "path": "ptr-demo/res/layout/fragment_with_long_press.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\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:background=\"@color/cube_mints_f1f1f1\"\n    android:orientation=\"vertical\">\n\n    <in.srain.cube.views.ptr.PtrClassicFrameLayout\n        android:id=\"@+id/with_long_press_list_view_frame\"\n        xmlns:cube_ptr=\"http://schemas.android.com/apk/res-auto\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:layout_weight=\"1\"\n        cube_ptr:ptr_content=\"@+id/with_long_press_list_view\">\n\n        <ListView\n            android:id=\"@+id/with_long_press_list_view\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\"\n            android:background=\"@color/cube_mints_white\"\n            android:cacheColorHint=\"@android:color/transparent\"\n            android:divider=\"#dddddd\"\n            android:dividerHeight=\"1px\"\n            android:fadingEdge=\"none\"\n            android:focusable=\"false\"\n            android:listSelector=\"@android:color/transparent\"\n            android:scrollbars=\"none\" />\n\n    </in.srain.cube.views.ptr.PtrClassicFrameLayout>\n\n</LinearLayout>"
  },
  {
    "path": "ptr-demo/res/layout/list_view_item.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<FrameLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\">\n\n    <FrameLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginBottom=\"15dp\"\n        android:background=\"@drawable/image_border\">\n\n        <in.srain.cube.image.CubeImageView\n            android:id=\"@+id/list_view_item_image_view\"\n            android:layout_width=\"100dp\"\n            android:layout_height=\"100dp\"\n            android:layout_marginBottom=\"5dp\"\n            android:layout_marginLeft=\"5dp\"\n            android:layout_marginTop=\"5dp\"\n            android:scaleType=\"fitCenter\" />\n    </FrameLayout>\n\n</FrameLayout>"
  },
  {
    "path": "ptr-demo/res/layout/view_pager_fragment_list_view_header.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\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:paddingBottom=\"15dp\"\n    android:paddingTop=\"15dp\">\n\n    <TextView\n        android:id=\"@+id/view_pager_fragment_list_view_header_title\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"200dp\"\n        android:layout_weight=\"1\"\n        android:gravity=\"center\"\n        android:padding=\"5dp\"\n        android:textColor=\"#000\"\n        android:textSize=\"16sp\" />\n\n</LinearLayout>\n"
  },
  {
    "path": "ptr-demo/res/layout/view_pager_indicator_item.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout 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:layout_gravity=\"center_horizontal\"\n        android:orientation=\"vertical\">\n\n        <TextView\n            android:id=\"@+id/view_pager_indicator_name\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"0dp\"\n            android:layout_weight=\"1\"\n            android:gravity=\"center\"\n            android:paddingLeft=\"10dp\"\n            android:paddingRight=\"10dp\"\n            android:textColor=\"#000\"\n            android:textSize=\"16sp\" />\n\n        <TextView\n            android:id=\"@+id/view_pager_indicator_tab_current\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"2dp\"\n            android:background=\"@color/cube_mints_4d90fe\" />\n\n    </LinearLayout>\n</LinearLayout>\n"
  },
  {
    "path": "ptr-demo/res/layout/with_grid_view_item_image_list_grid.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\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    android:paddingTop=\"15dp\">\n\n    <LinearLayout\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:orientation=\"horizontal\"\n        android:padding=\"1dp\">\n\n        <in.srain.cube.image.CubeImageView\n            android:id=\"@+id/with_grid_view_item_image\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\"\n            android:scaleType=\"fitCenter\" />\n    </LinearLayout>\n\n</LinearLayout>"
  },
  {
    "path": "ptr-demo/res/layout/with_long_press_list_view_item.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<FrameLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\">\n\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:background=\"@drawable/with_long_press_list_item_background\"\n        android:orientation=\"horizontal\"\n        android:paddingBottom=\"15dp\"\n        android:paddingLeft=\"20dp\"\n        android:paddingTop=\"15dp\">\n\n        <in.srain.cube.image.CubeImageView\n            android:id=\"@+id/with_long_press_list_image\"\n            android:layout_width=\"100dp\"\n            android:layout_height=\"100dp\"\n            android:layout_marginBottom=\"5dp\"\n            android:layout_marginLeft=\"5dp\"\n            android:layout_marginTop=\"5dp\"\n            android:scaleType=\"centerCrop\" />\n    </LinearLayout>\n</FrameLayout>\n"
  },
  {
    "path": "ptr-demo/res/values/arrays.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n\n    <string-array name=\"akta\">\n        <item>22,0,0,30,</item>\n        <item>22,0,30,0,</item>\n        <item>30,0,52,30,</item>\n        <item>0,30,26,30,</item>\n        <item>60,0,60,15,</item>\n        <item>60,15,60,30,</item>\n        <item>60,15,85,15,</item>\n        <item>85,15,108,0,</item>\n        <item>85,15,108,30,</item>\n        <item>117,0,147,0,</item>\n        <item>147,0,177,0,</item>\n        <item>147,0,147,32,</item>\n        <item>198,0,176,30,</item>\n        <item>198,0,206,0,</item>\n        <item>206,0,228,30,</item>\n        <item>176,30,202,30,</item>\n    </string-array>\n\n    <string-array name=\"storehouse\">\n        <item>0,35,12,42,</item>\n        <item>12,42,24,35,</item>\n        <item>24,35,12,28,</item>\n        <item>0,35,12,28,</item>\n        <item>0,21,12,28,</item>\n        <item>12,28,24,21,</item>\n        <item>24,35,24,21,</item>\n        <item>24,21,12,14,</item>\n        <item>0,21,12,14,</item>\n        <item>0,21,0,7,</item>\n        <item>12,14,0,7,</item>\n        <item>12,14,24,7,</item>\n        <item>24,7,12,0,</item>\n        <item>0,7,12,0,</item>\n    </string-array>\n\n    <integer-array name=\"google_colors\">\n        <item>@color/red</item>\n        <item>@color/blue</item>\n        <item>@color/yellow</item>\n        <item>@color/green</item>\n    </integer-array>\n</resources>"
  },
  {
    "path": "ptr-demo/res/values/ptr_demo_colors.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <color name=\"red\">#FFC93437</color>\n    <color name=\"blue\">#FF375BF1</color>\n    <color name=\"yellow\">#FFF7D23E</color>\n    <color name=\"green\">#FF34A350</color>\n</resources>"
  },
  {
    "path": "ptr-demo/res/values/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n\n    <string name=\"app_name\">Ultra PTR</string>\n    <string name=\"ptr_demo_block_for_home\">Ultra Pull to Refresh</string>\n\n    <string name=\"ptr_demo_block_grid_view\">Contains A GridView</string>\n    <string name=\"ptr_demo_block_list_view\">Contains A ListView</string>\n    <string name=\"ptr_demo_block_web_view\">Contains A WebView</string>\n    <string name=\"ptr_demo_block_scroll_view\">Contains ScrollView</string>\n    <string name=\"ptr_demo_block_frame_layout\">Contains A FrameLayout</string>\n    <string name=\"ptr_demo_block_only_text_view\">Contains Even A TextView</string>\n    <string name=\"ptr_demo_block_with_list_view_and_empty_view\">EmptyView and ListView</string>\n    <string name=\"ptr_demo_block_with_list_view_and_empty_view_tip\">It\\' empty. \\n\\nClick to load data.</string>\n\n    <string name=\"ptr_demo_block_pull_to_refresh\">Pull to Refresh</string>\n    <string name=\"ptr_demo_block_release_to_refresh\">Release to Refresh</string>\n    <string name=\"ptr_demo_block_auto_fresh\">Auto Refresh</string>\n\n    <string name=\"ptr_demo_block_keep_header\">Keep Header while Refreshing</string>\n    <string name=\"ptr_demo_block_hide_header\">Hide Header while Refreshing</string>\n    <string name=\"ptr_demo_block_with_long_press\">Long Press</string>\n    <string name=\"ptr_demo_block_with_view_pager\">View Pager</string>\n    <string name=\"ptr_demo_block_storehouse_header_using_string_array\">StoreHouse Style \\nusing string array from xml</string>\n    <string name=\"ptr_demo_storehouse_header_using_string_array_in_title\">using xml:&#160;</string>\n    <string name=\"ptr_demo_block_storehouse_header_using_string\">StoreHouse Style \\n\\nusing string</string>\n    <string name=\"ptr_demo_storehouse_header_using_string_in_title\">using string:&#160;</string>\n    <string name=\"ptr_demo_storehouse_header_using_point_list\">Using Point List</string>\n    <string name=\"ptr_demo_material_style\">Material Style</string>\n    <string name=\"ptr_demo_rentals_style\">Rentals Style</string>\n    <string name=\"ptr_demo_placeholder\">To be continued</string>\n\n    <string name=\"ptr_demo_material_style_pin_content\">Material Style\\nPin Content\\n v4 style</string>\n    <string name=\"ptr_demo_enable_next_ptr_at_once\">Enable Next PTR at once</string>\n\n</resources>"
  },
  {
    "path": "ptr-demo/res/values-zh/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"app_name\">Ultra PTR</string>\n    <string name=\"ptr_demo_block_auto_fresh\">自动刷新</string>\n    <string name=\"ptr_demo_block_frame_layout\">包含FrameLayout</string>\n    <string name=\"ptr_demo_block_grid_view\">包含GridView</string>\n    <string name=\"ptr_demo_block_hide_header\">刷新时不显示头部</string>\n    <string name=\"ptr_demo_block_keep_header\">刷新时显示头部</string>\n    <string name=\"ptr_demo_block_only_text_view\">仅包含一个TextView</string>\n    <string name=\"ptr_demo_block_pull_to_refresh\">下拉刷新</string>\n    <string name=\"ptr_demo_block_release_to_refresh\">释放刷新</string>\n\n    <string name=\"ptr_demo_block_storehouse_header_using_string_array\">StoreHouse Style \\n使用xml中的字符串数组</string>\n    <string name=\"ptr_demo_storehouse_header_using_string_array_in_title\">使用xml: &#160;</string>\n    <string name=\"ptr_demo_block_storehouse_header_using_string\">StoreHouse Style \\n\\n使用字符串</string>\n    <string name=\"ptr_demo_storehouse_header_using_string_in_title\">使用字符串:&#160;</string>\n\n    <string name=\"ptr_demo_material_style_pin_content\">Material Style\\n内容不动，原生风格</string>\n    <string name=\"ptr_demo_enable_next_ptr_at_once\">立即下拉刷新，不等UIReset</string>\n</resources>\n"
  },
  {
    "path": "ptr-demo/src/in/srain/cube/views/ptr/demo/app/PtrDemoApplication.java",
    "content": "package in.srain.cube.views.ptr.demo.app;\n\nimport android.app.Application;\nimport in.srain.cube.Cube;\nimport in.srain.cube.image.ImageLoaderFactory;\nimport in.srain.cube.request.RequestCacheManager;\nimport in.srain.cube.util.CLog;\nimport in.srain.cube.util.CubeDebug;\nimport in.srain.cube.views.ptr.PtrFrameLayout;\nimport in.srain.cube.views.ptr.demo.image.DemoDuiTangImageReSizer;\nimport in.srain.cube.views.ptr.demo.image.PtrImageLoadHandler;\n\npublic class PtrDemoApplication extends Application {\n\n    public static PtrDemoApplication instance;\n\n    @Override\n    public void onCreate() {\n        super.onCreate();\n        instance = this;\n\n        String environment = \"\";\n\n        if (environment.equals(\"production\")) {\n            CLog.setLogLevel(CLog.LEVEL_ERROR);\n        } else if (environment.equals(\"beta\")) {\n            CLog.setLogLevel(CLog.LEVEL_WARNING);\n        } else {\n            // development\n            CLog.setLogLevel(CLog.LEVEL_VERBOSE);\n        }\n\n        CubeDebug.DEBUG_IMAGE = true;\n        PtrFrameLayout.DEBUG = true;\n        PtrFrameLayout.DEBUG = false;\n\n        ImageLoaderFactory.setDefaultImageReSizer(DemoDuiTangImageReSizer.getInstance());\n        ImageLoaderFactory.setDefaultImageLoadHandler(new PtrImageLoadHandler());\n        String dir = \"request-cache\";\n        // ImageLoaderFactory.init(this);\n        RequestCacheManager.init(this, dir, 1024 * 10, 1024 * 10);\n        Cube.onCreate(this);\n    }\n}"
  },
  {
    "path": "ptr-demo/src/in/srain/cube/views/ptr/demo/data/DemoRequestData.java",
    "content": "package in.srain.cube.views.ptr.demo.data;\n\nimport in.srain.cube.request.*;\n\npublic class DemoRequestData {\n\n    public static void getImageList(final RequestFinishHandler<JsonData> requestFinishHandler) {\n\n        CacheAbleRequestHandler requestHandler = new CacheAbleRequestJsonHandler() {\n            @Override\n            public void onCacheAbleRequestFinish(JsonData data, CacheAbleRequest.ResultType type, boolean outOfDate) {\n                requestFinishHandler.onRequestFinish(data);\n            }\n        };\n\n        CacheAbleRequest<JsonData> request = new CacheAbleRequest<JsonData>(requestHandler);\n        String url = \"http://cube-server.liaohuqiu.net/api_demo/image-list.php\";\n        request.setCacheTime(3600);\n        request.setTimeout(1000);\n        request.getRequestData().setRequestUrl(url);\n        request.setAssertInitDataPath(\"request_init/demo/image-list.json\");\n        request.setCacheKey(\"image-list-1\");\n        request.send();\n    }\n}\n"
  },
  {
    "path": "ptr-demo/src/in/srain/cube/views/ptr/demo/image/DemoDuiTangImageReSizer.java",
    "content": "package in.srain.cube.views.ptr.demo.image;\n\nimport in.srain.cube.image.ImageTask;\nimport in.srain.cube.image.impl.DefaultImageReSizer;\nimport in.srain.cube.util.CLog;\n\n/**\n * Created by srain on 8/19/14.\n */\npublic class DemoDuiTangImageReSizer extends DefaultImageReSizer {\n\n\n    private static DemoDuiTangImageReSizer sInstance;\n\n    public static DemoDuiTangImageReSizer getInstance() {\n        if (sInstance == null) {\n            sInstance = new DemoDuiTangImageReSizer();\n        }\n        return sInstance;\n    }\n\n    private static String TAG = \"thumb\";\n    private static String SP = \"_\";\n    private static String DOT = \".\";\n\n    private static final int[] CDN_FIX_WIDTH_SIZE = {110, 150, 170, 220, 240, 290, 450, 580, 620, 790};\n\n    @Override\n    public String getRemoteUrl(ImageTask imageTask) {\n        String url = imageTask.getOriginUrl();\n        int size = findBestCDNSize(CDN_FIX_WIDTH_SIZE, imageTask.getRequestSize().x, true);\n        url = url.replace(TAG, TAG + DOT + size + SP + size);\n        CLog.d(\"test\", \"getRemoteUrl: %s %s\", imageTask.getRequestSize(), url);\n        return url;\n    }\n\n    private static int binarySearch(int[] srcArray, int des, boolean higher) {\n        int low = 0;\n        int high = srcArray.length - 1;\n        while (low <= high) {\n            int middle = (low + high) / 2;\n            if (des == srcArray[middle]) {\n                return middle;\n            } else if (des < srcArray[middle]) {\n                high = middle - 1;\n            } else {\n                low = middle + 1;\n            }\n        }\n        if (high < 0)\n            return 0;\n        if (higher) {\n            if (des > srcArray[high] && high + 1 <= srcArray.length - 1) {\n                high = high + 1;\n            }\n        } else {\n            if (des < srcArray[high] && high - 1 >= 0)\n                high = high - 1;\n        }\n        return high;\n    }\n\n    private static int findBestCDNSize(int[] array, int size, boolean higher) {\n\n        if (size >= array[array.length - 1]) {\n            return array[array.length - 1];\n        }\n\n        int pos = binarySearch(array, size, higher);\n        return array[pos];\n    }\n}\n"
  },
  {
    "path": "ptr-demo/src/in/srain/cube/views/ptr/demo/image/Images.java",
    "content": "package in.srain.cube.views.ptr.demo.image;\n\nimport in.srain.cube.image.ImageReuseInfoManger;\n\npublic class Images {\n\n    private static final String[] sizeList = new String[]{\"small_180\", \"big_360\", \"big\"};\n    public static final ImageReuseInfoManger sImageReuseInfoManger = new ImageReuseInfoManger(sizeList);\n\n    public final static String[] imageUrls = new String[]{\n            \"http://img4.duitang.com/uploads/blog/201311/04/20131104193715_NCexN.thumb.jpeg\",\n            \"http://img5.duitang.com/uploads/item/201408/09/20140809210610_iTSJx.thumb.jpeg\",\n            \"http://cdn.duitang.com/uploads/blog/201401/07/20140107223310_LH3Uy.thumb.jpeg\",\n            \"http://img5.duitang.com/uploads/item/201405/09/20140509222156_kVexJ.thumb.jpeg\",\n            \"http://img5.duitang.com/uploads/item/201306/14/20130614185903_raNR3.thumb.jpeg\",\n            \"http://img5.duitang.com/uploads/item/201112/11/20111211191621_HU4Bj.thumb.jpg\",\n            \"http://cdn.duitang.com/uploads/item/201408/07/20140807224553_VXaUc.thumb.jpeg\",\n            \"http://img5.duitang.com/uploads/blog/201407/29/20140729105929_GQLwC.thumb.jpeg\",\n            \"http://img4.duitang.com/uploads/blog/201408/04/20140804160432_LnFeB.thumb.jpeg\",\n            \"http://img5.duitang.com/uploads/blog/201408/04/20140804161101_JVJea.thumb.jpeg\",\n            \"http://cdn.duitang.com/uploads/blog/201408/04/20140804093210_FxFNd.thumb.jpeg\",\n            \"http://img5.duitang.com/uploads/blog/201408/04/20140804160314_hRKtv.thumb.jpeg\",\n            \"http://cdn.duitang.com/uploads/item/201408/01/20140801080524_SnGfE.thumb.jpeg\",\n            \"http://img5.duitang.com/uploads/item/201407/23/20140723140958_NSWfE.thumb.jpeg\",\n            \"http://img4.duitang.com/uploads/blog/201407/22/20140722153305_WHejQ.thumb.jpeg\",\n            \"http://img5.duitang.com/uploads/item/201407/21/20140721010148_ZBQwe.thumb.jpeg\",\n            \"http://cdn.duitang.com/uploads/item/201407/23/20140723085122_cmteu.thumb.jpeg\",\n            \"http://img5.duitang.com/uploads/item/201407/23/20140723130620_Z2yJB.thumb.jpeg\",\n            \"http://cdn.duitang.com/uploads/blog/201407/20/20140720204738_NXxLE.thumb.jpeg\",\n            \"http://cdn.duitang.com/uploads/item/201407/20/20140720134916_VGfyh.thumb.jpeg\",\n            \"http://img5.duitang.com/uploads/blog/201407/17/20140717113117_mUssJ.thumb.jpeg\",\n            \"http://img5.duitang.com/uploads/blog/201407/17/20140717121501_wfFEm.thumb.jpeg\",\n            \"http://img5.duitang.com/uploads/blog/201407/17/20140717121431_w4AV8.thumb.jpeg\",\n            \"http://img5.duitang.com/uploads/blog/201407/17/20140717121918_TtJjY.thumb.jpeg\",\n            \"http://img5.duitang.com/uploads/item/201407/11/20140711234806_FNLBQ.thumb.jpeg\",\n            \"http://img5.duitang.com/uploads/item/201407/18/20140718121437_UyiAS.thumb.jpeg\",\n            \"http://img5.duitang.com/uploads/blog/201407/17/20140717114829_RiCXR.thumb.jpeg\",\n            \"http://img4.duitang.com/uploads/blog/201407/17/20140717120301_wGFYL.thumb.jpeg\",\n            \"http://img5.duitang.com/uploads/blog/201405/11/20140511121106_JXS4B.thumb.jpeg\",\n            \"http://img5.duitang.com/uploads/blog/201405/10/20140510094144_kfLji.thumb.jpeg\",\n            \"http://img5.duitang.com/uploads/blog/201405/09/20140509201906_kERjy.thumb.jpeg\",\n            \"http://img5.duitang.com/uploads/blog/201405/08/20140508193226_UaSGB.thumb.jpeg\",\n            \"http://img4.duitang.com/uploads/blog/201405/05/20140505201747_aPNtf.thumb.jpeg\",\n            \"http://img5.duitang.com/uploads/blog/201405/06/20140506104824_jPWQj.thumb.jpeg\",\n            \"http://img5.duitang.com/uploads/blog/201405/05/20140505201105_MkXdn.thumb.jpeg\",\n            \"http://img5.duitang.com/uploads/blog/201405/03/20140503205822_GCzta.thumb.jpeg\",\n            \"http://img5.duitang.com/uploads/blog/201405/03/20140503205535_cCHPB.thumb.jpeg\",\n            \"http://img5.duitang.com/uploads/blog/201405/03/20140503204354_xxSQX.thumb.jpeg\",\n            \"http://img4.duitang.com/uploads/blog/201404/06/20140406191307_GTxFd.thumb.jpeg\",\n            \"http://img4.duitang.com/uploads/blog/201404/06/20140406191247_BG2cU.thumb.jpeg\",\n            \"http://img4.duitang.com/uploads/blog/201404/06/20140406191114_MzYtw.thumb.jpeg\",\n            \"http://img4.duitang.com/uploads/blog/201404/06/20140406191127_fazJA.thumb.jpeg\",\n            \"http://img5.duitang.com/uploads/item/201407/10/20140710081204_vYnCi.thumb.jpeg\",\n            \"http://img5.duitang.com/uploads/item/201407/15/20140715133758_M2Y3J.thumb.jpeg\",\n            \"http://img4.duitang.com/uploads/item/201407/13/20140713190806_TGJHm.thumb.jpeg\",\n            \"http://img4.duitang.com/uploads/blog/201407/05/20140705223413_5r3ze.thumb.jpeg\",\n            \"http://img5.duitang.com/uploads/item/201407/13/20140713012526_tcy5u.thumb.jpeg\",\n            \"http://img5.duitang.com/uploads/blog/201407/13/20140713121424_Gy43T.thumb.jpeg\",\n            \"http://img4.duitang.com/uploads/item/201407/15/20140715033844_tcvrY.thumb.jpeg\",\n            \"http://img5.duitang.com/uploads/item/201407/10/20140710181106_4HHay.thumb.jpeg\",\n            \"http://img5.duitang.com/uploads/blog/201407/06/20140706122850_8PER3.thumb.jpeg\",\n            \"http://img5.duitang.com/uploads/blog/201407/07/20140707192042_8xKXF.thumb.jpeg\",\n            \"http://img5.duitang.com/uploads/item/201407/07/20140707063954_mVa3y.thumb.jpeg\",\n            \"http://img5.duitang.com/uploads/item/201407/08/20140708093733_AFFhc.thumb.jpeg\",\n            \"http://img5.duitang.com/uploads/blog/201407/07/20140707161220_unvzn.thumb.jpeg\",\n            \"http://img4.duitang.com/uploads/blog/201407/07/20140707113856_hBf3R.thumb.jpeg\",\n            \"http://img5.duitang.com/uploads/item/201308/26/20130826090203_NtuYA.thumb.jpeg\",\n            \"http://img4.duitang.com/uploads/item/201407/07/20140707145925_dHeKV.thumb.jpeg\",\n            \"http://img5.duitang.com/uploads/item/201406/25/20140625101534_xiZxN.thumb.jpeg\",\n            \"http://img5.duitang.com/uploads/blog/201406/30/20140630150534_EWUVY.thumb.jpeg\",\n            \"http://img5.duitang.com/uploads/item/201406/25/20140625121626_ZmT5n.thumb.jpeg\",\n            \"http://img4.duitang.com/uploads/blog/201307/31/20130731231806_4yGxV.thumb.jpeg\",\n            \"http://img5.duitang.com/uploads/item/201406/28/20140628122218_fLQyP.thumb.jpeg\",\n            \"http://img5.duitang.com/uploads/blog/201406/26/20140626131831_MrdKP.thumb.jpeg\",\n            \"http://img5.duitang.com/uploads/blog/201406/16/20140616165201_nuKWj.thumb.jpeg\",\n            \"http://img5.duitang.com/uploads/item/201406/25/20140625140308_KP4rn.thumb.jpeg\",\n            \"http://img5.duitang.com/uploads/item/201406/25/20140625121604_2auuA.thumb.jpeg\",\n            \"http://img4.duitang.com/uploads/item/201406/25/20140625131625_LmmLZ.thumb.jpeg\",\n            \"http://img5.duitang.com/uploads/item/201406/25/20140625132851_mPmKY.thumb.jpeg\",\n            \"http://img5.duitang.com/uploads/item/201406/25/20140625133312_ZtmW4.thumb.jpeg\",\n            \"http://img5.duitang.com/uploads/item/201406/25/20140625164858_AuafS.thumb.jpeg\",\n            \"http://img5.duitang.com/uploads/item/201406/24/20140624114145_e4iVw.thumb.jpeg\",\n            \"http://cdn.duitang.com/uploads/item/201406/25/20140625100427_Hkxj5.thumb.jpeg\",\n            \"http://cdn.duitang.com/uploads/blog/201406/25/20140625213455_VHHcL.thumb.jpeg\",\n            \"http://img5.duitang.com/uploads/item/201406/25/20140625132659_UuES4.thumb.jpeg\",\n            \"http://img5.duitang.com/uploads/item/201406/24/20140624020050_zCE4U.thumb.jpeg\",\n            \"http://img5.duitang.com/uploads/item/201406/18/20140618152533_dJjtW.thumb.jpeg\",\n            \"http://cdn.duitang.com/uploads/item/201406/20/20140620075216_twZE4.thumb.jpeg\",\n            \"http://img5.duitang.com/uploads/item/201406/22/20140622162247_Z4WK4.thumb.jpeg\",\n            \"http://cdn.duitang.com/uploads/item/201406/20/20140620075158_TnyKU.thumb.jpeg\",\n            \"http://img5.duitang.com/uploads/blog/201406/18/20140618235506_5QJwc.thumb.jpeg\",\n            \"http://img5.duitang.com/uploads/item/201406/18/20140618152515_AFcLy.thumb.jpeg\",\n            \"http://img5.duitang.com/uploads/item/201406/03/20140603001954_NjKfX.thumb.jpeg\",\n            \"http://cdn.duitang.com/uploads/item/201405/31/20140531232042_4FkHQ.thumb.jpeg\",\n            \"http://img4.duitang.com/uploads/blog/201406/13/20140613002234_LHXcT.thumb.jpeg\",\n            \"http://img4.duitang.com/uploads/item/201405/31/20140531231843_J5Euh.thumb.jpeg\",\n            \"http://img5.duitang.com/uploads/item/201406/11/20140611220941_xBeyi.thumb.jpeg\",\n            \"http://img5.duitang.com/uploads/item/201406/13/20140613114809_yuHRV.thumb.jpeg\",\n            \"http://cdn.duitang.com/uploads/item/201406/13/20140613120109_yL8hk.thumb.jpeg\",\n            \"http://img5.duitang.com/uploads/blog/201406/01/20140601185856_Q5jZr.thumb.jpeg\",\n            \"http://img5.duitang.com/uploads/item/201406/06/20140606004724_GxQHQ.thumb.jpeg\",\n            \"http://img4.duitang.com/uploads/item/201406/08/20140608003809_3JnEK.thumb.jpeg\",\n            \"http://img5.duitang.com/uploads/item/201406/10/20140610085447_zeXJU.thumb.jpeg\",\n            \"http://img4.duitang.com/uploads/blog/201406/08/20140608193617_HyFrY.thumb.jpeg\",\n            \"http://img4.duitang.com/uploads/item/201405/30/20140530190040_KQdsM.thumb.jpeg\",\n            \"http://cdn.duitang.com/uploads/item/201406/09/20140609101937_UBfJJ.thumb.jpeg\",\n            \"http://img5.duitang.com/uploads/blog/201406/10/20140610170410_cFhwW.thumb.jpeg\",\n            \"http://img5.duitang.com/uploads/item/201406/09/20140609225334_PdGwG.thumb.jpeg\",\n            \"http://img4.duitang.com/uploads/blog/201406/09/20140609184438_e33i2.thumb.jpeg\",\n            \"http://img5.duitang.com/uploads/blog/201405/29/20140529200010_AfL8f.thumb.jpeg\",\n            \"http://img4.duitang.com/uploads/blog/201406/08/20140608104649_KVtMx.thumb.png\",\n            \"http://img5.duitang.com/uploads/item/201406/01/20140601215152_wi4wf.thumb.jpeg\",\n            \"http://cdn.duitang.com/uploads/blog/201406/08/20140608194234_FEGkW.thumb.jpeg\",\n            \"http://img4.duitang.com/uploads/item/201405/31/20140531221002_Awtv8.thumb.jpeg\",\n            \"http://img5.duitang.com/uploads/item/201406/08/20140608091030_TJ3Cc.thumb.jpeg\",\n            \"http://cdn.duitang.com/uploads/item/201405/31/20140531221355_cSCTt.thumb.jpeg\",\n            \"http://cdn.duitang.com/uploads/item/201406/08/20140608005415_arBdK.thumb.jpeg\",\n            \"http://img5.duitang.com/uploads/item/201406/08/20140608000002_2MTjn.thumb.jpeg\",\n            \"http://img5.duitang.com/uploads/item/201406/03/20140603012613_z88sn.thumb.jpeg\",\n            \"http://cdn.duitang.com/uploads/item/201405/31/20140531221745_rnAzU.thumb.jpeg\",\n            \"http://img5.duitang.com/uploads/item/201405/31/20140531220735_XBxFP.thumb.jpeg\",\n            \"http://cdn.duitang.com/uploads/blog/201406/08/20140608194112_uEYf5.thumb.jpeg\",\n            \"http://img5.duitang.com/uploads/blog/201406/08/20140608225626_xc2QT.thumb.jpeg\",\n            \"http://img5.duitang.com/uploads/item/201406/07/20140607235759_sNS5Z.thumb.jpeg\",\n            \"http://img5.duitang.com/uploads/item/201405/31/20140531220635_Lrw3w.thumb.jpeg\",\n            \"http://cdn.duitang.com/uploads/item/201406/08/20140608004245_jmBmP.thumb.jpeg\",\n            \"http://img4.duitang.com/uploads/item/201406/08/20140608020213_SBfGH.thumb.jpeg\",\n            \"http://cdn.duitang.com/uploads/item/201406/08/20140608214105_kvVVY.thumb.jpeg\",\n            \"http://img5.duitang.com/uploads/item/201406/03/20140603001556_XsMEv.thumb.jpeg\",\n            \"http://cdn.duitang.com/uploads/item/201406/08/20140608024120_XjjGB.thumb.jpeg\",\n    };\n}\n\n"
  },
  {
    "path": "ptr-demo/src/in/srain/cube/views/ptr/demo/image/PtrImageLoadHandler.java",
    "content": "package in.srain.cube.views.ptr.demo.image;\r\n\r\nimport android.graphics.Color;\r\nimport android.graphics.drawable.BitmapDrawable;\r\nimport android.graphics.drawable.ColorDrawable;\r\nimport in.srain.cube.image.CubeImageView;\r\nimport in.srain.cube.image.ImageTask;\r\nimport in.srain.cube.image.iface.ImageLoadHandler;\r\n\r\npublic class PtrImageLoadHandler implements ImageLoadHandler {\r\n\r\n    @Override\r\n    public void onLoading(ImageTask imageTask, CubeImageView cubeImageView) {\r\n        if (cubeImageView != null) {\r\n            cubeImageView.setImageDrawable(new ColorDrawable(Color.GRAY));\r\n        }\r\n    }\r\n\r\n    @Override\r\n    public void onLoadFinish(ImageTask imageTask, CubeImageView cubeImageView, BitmapDrawable bitmapDrawable) {\r\n        if (bitmapDrawable != null && cubeImageView != null) {\r\n            cubeImageView.setImageDrawable(bitmapDrawable);\r\n        }\r\n    }\r\n\r\n    @Override\r\n    public void onLoadError(ImageTask imageTask, CubeImageView cubeImageView, int i) {\r\n        if (cubeImageView != null) {\r\n            cubeImageView.setImageDrawable(new ColorDrawable(Color.RED));\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "ptr-demo/src/in/srain/cube/views/ptr/demo/ui/EnableNextPTRAtOnce.java",
    "content": "package in.srain.cube.views.ptr.demo.ui;\n\nimport in.srain.cube.views.ptr.PtrClassicFrameLayout;\nimport in.srain.cube.views.ptr.demo.R;\nimport in.srain.cube.views.ptr.demo.ui.classic.WithTextViewInFrameLayoutFragment;\n\npublic class EnableNextPTRAtOnce extends WithTextViewInFrameLayoutFragment {\n\n    @Override\n    protected void setupViews(PtrClassicFrameLayout ptrFrame) {\n        setHeaderTitle(R.string.ptr_demo_enable_next_ptr_at_once);\n        ptrFrame.setEnabledNextPtrAtOnce(true);\n        ptrFrame.setPullToRefresh(false);\n    }\n}"
  },
  {
    "path": "ptr-demo/src/in/srain/cube/views/ptr/demo/ui/MaterialStyleFragment.java",
    "content": "package in.srain.cube.views.ptr.demo.ui;\n\nimport android.graphics.Color;\nimport android.graphics.drawable.BitmapDrawable;\nimport android.graphics.drawable.ColorDrawable;\nimport android.graphics.drawable.Drawable;\nimport android.graphics.drawable.TransitionDrawable;\nimport android.os.Bundle;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport in.srain.cube.image.CubeImageView;\nimport in.srain.cube.image.ImageLoader;\nimport in.srain.cube.image.ImageLoaderFactory;\nimport in.srain.cube.image.ImageTask;\nimport in.srain.cube.image.iface.ImageLoadHandler;\nimport in.srain.cube.mints.base.TitleBaseFragment;\nimport in.srain.cube.util.LocalDisplay;\nimport in.srain.cube.views.ptr.PtrFrameLayout;\nimport in.srain.cube.views.ptr.PtrHandler;\nimport in.srain.cube.views.ptr.demo.R;\nimport in.srain.cube.views.ptr.header.MaterialHeader;\n\npublic class MaterialStyleFragment extends TitleBaseFragment {\n\n    private String mUrl = \"http://img5.duitang.com/uploads/blog/201407/17/20140717113117_mUssJ.thumb.jpeg\";\n    private long mStartLoadingTime = -1;\n    private boolean mImageHasLoaded = false;\n    protected PtrFrameLayout mPtrFrameLayout;\n\n    @Override\n    public void onEnter(Object data) {\n        if (data != null && data instanceof String) {\n            mUrl = (String) data;\n        }\n    }\n\n    @Override\n    protected View createView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {\n\n        View view = inflater.inflate(R.layout.fragment_materail_style, null);\n        setHeaderTitle(R.string.ptr_demo_material_style);\n\n        final CubeImageView imageView = (CubeImageView) view.findViewById(R.id.material_style_image_view);\n        final ImageLoader imageLoader = ImageLoaderFactory.create(getContext());\n\n        mPtrFrameLayout = (PtrFrameLayout) view.findViewById(R.id.material_style_ptr_frame);\n\n        // header\n        final MaterialHeader header = new MaterialHeader(getContext());\n        int[] colors = getResources().getIntArray(R.array.google_colors);\n        header.setColorSchemeColors(colors);\n        header.setLayoutParams(new PtrFrameLayout.LayoutParams(-1, -2));\n        header.setPadding(0, LocalDisplay.dp2px(15), 0, LocalDisplay.dp2px(10));\n        header.setPtrFrameLayout(mPtrFrameLayout);\n\n        mPtrFrameLayout.setLoadingMinTime(1000);\n        mPtrFrameLayout.setDurationToCloseHeader(1500);\n        mPtrFrameLayout.setHeaderView(header);\n        mPtrFrameLayout.addPtrUIHandler(header);\n        mPtrFrameLayout.postDelayed(new Runnable() {\n            @Override\n            public void run() {\n                mPtrFrameLayout.autoRefresh(false);\n            }\n        }, 100);\n\n        mPtrFrameLayout.setPtrHandler(new PtrHandler() {\n            @Override\n            public boolean checkCanDoRefresh(PtrFrameLayout frame, View content, View header) {\n                return true;\n            }\n\n            @Override\n            public void onRefreshBegin(final PtrFrameLayout frame) {\n                if (mImageHasLoaded) {\n                    long delay = (long) (1000 + Math.random() * 2000);\n                    delay = Math.max(0, delay);\n                    delay = 0;\n                    frame.postDelayed(new Runnable() {\n                        @Override\n                        public void run() {\n                            frame.refreshComplete();\n                        }\n                    }, delay);\n                } else {\n                    mStartLoadingTime = System.currentTimeMillis();\n                    imageView.loadImage(imageLoader, mUrl);\n                }\n            }\n        });\n\n        ImageLoadHandler imageLoadHandler = new ImageLoadHandler() {\n            @Override\n            public void onLoading(ImageTask imageTask, CubeImageView cubeImageView) {\n            }\n\n            @Override\n            public void onLoadFinish(ImageTask imageTask, final CubeImageView cubeImageView, final BitmapDrawable bitmapDrawable) {\n                mImageHasLoaded = true;\n                long delay = Math.max(0, 1000 - (System.currentTimeMillis() - mStartLoadingTime));\n                delay = 0;\n                mPtrFrameLayout.postDelayed(new Runnable() {\n                    @Override\n                    public void run() {\n                        if (cubeImageView != null && bitmapDrawable != null) {\n                            TransitionDrawable w1 = new TransitionDrawable(new Drawable[]{new ColorDrawable(Color.WHITE), (Drawable) bitmapDrawable});\n                            imageView.setImageDrawable(w1);\n                            w1.startTransition(200);\n                        }\n                        mPtrFrameLayout.refreshComplete();\n                    }\n                }, delay);\n            }\n\n            @Override\n            public void onLoadError(ImageTask imageTask, CubeImageView cubeImageView, int i) {\n\n            }\n        };\n        imageLoader.setImageLoadHandler(imageLoadHandler);\n        return view;\n    }\n}\n"
  },
  {
    "path": "ptr-demo/src/in/srain/cube/views/ptr/demo/ui/MaterialStylePinContentFragment.java",
    "content": "package in.srain.cube.views.ptr.demo.ui;\n\nimport android.os.Bundle;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\n\npublic class MaterialStylePinContentFragment extends MaterialStyleFragment {\n\n    @Override\n    protected View createView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {\n        View view = super.createView(inflater, container, savedInstanceState);\n        // close at once\n        mPtrFrameLayout.setDurationToClose(100);\n        mPtrFrameLayout.setPinContent(true);\n        return view;\n    }\n}\n"
  },
  {
    "path": "ptr-demo/src/in/srain/cube/views/ptr/demo/ui/PtrDemoHomeFragment.java",
    "content": "package in.srain.cube.views.ptr.demo.ui;\n\nimport android.content.Intent;\nimport android.os.Bundle;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.View.OnClickListener;\nimport android.view.ViewGroup;\nimport in.srain.cube.mints.base.BlockMenuFragment;\nimport in.srain.cube.util.LocalDisplay;\nimport in.srain.cube.views.ptr.PtrDefaultHandler;\nimport in.srain.cube.views.ptr.PtrFrameLayout;\nimport in.srain.cube.views.ptr.PtrHandler;\nimport in.srain.cube.views.ptr.demo.R;\nimport in.srain.cube.views.ptr.demo.ui.classic.*;\nimport in.srain.cube.views.ptr.demo.ui.storehouse.StoreHouseUsingPointList;\nimport in.srain.cube.views.ptr.demo.ui.storehouse.StoreHouseUsingString;\nimport in.srain.cube.views.ptr.demo.ui.storehouse.StoreHouseUsingStringArray;\nimport in.srain.cube.views.ptr.demo.ui.viewpager.ViewPagerActivity;\nimport in.srain.cube.views.ptr.header.StoreHouseHeader;\n\nimport java.util.ArrayList;\n\npublic class PtrDemoHomeFragment extends BlockMenuFragment {\n\n    @Override\n    protected void addItemInfo(ArrayList<BlockMenuFragment.MenuItemInfo> itemInfos) {\n\n        // GridView\n        itemInfos.add(newItemInfo(R.string.ptr_demo_block_grid_view, R.color.cube_mints_4d90fe, new OnClickListener() {\n\n            @Override\n            public void onClick(View v) {\n                getContext().pushFragmentToBackStack(WithGridView.class, null);\n            }\n        }));\n        itemInfos.add(newItemInfo(R.string.ptr_demo_block_frame_layout, R.color.cube_mints_4d90fe, new OnClickListener() {\n\n            @Override\n            public void onClick(View v) {\n                getContext().pushFragmentToBackStack(WithTextViewInFrameLayoutFragment.class, null);\n            }\n        }));\n        itemInfos.add(newItemInfo(R.string.ptr_demo_block_only_text_view, R.color.cube_mints_4d90fe, new OnClickListener() {\n\n            @Override\n            public void onClick(View v) {\n                getContext().pushFragmentToBackStack(EvenOnlyATextView.class, null);\n            }\n        }));\n        itemInfos.add(newItemInfo(R.string.ptr_demo_block_list_view, R.color.cube_mints_4d90fe, new OnClickListener() {\n\n            @Override\n            public void onClick(View v) {\n                getContext().pushFragmentToBackStack(WithListView.class, null);\n            }\n        }));\n        itemInfos.add(newItemInfo(R.string.ptr_demo_block_web_view, R.color.cube_mints_4d90fe, new OnClickListener() {\n\n            @Override\n            public void onClick(View v) {\n                getContext().pushFragmentToBackStack(WithWebView.class, null);\n            }\n        }));\n\n        itemInfos.add(newItemInfo(R.string.ptr_demo_block_with_list_view_and_empty_view, R.color.cube_mints_4d90fe, new OnClickListener() {\n\n            @Override\n            public void onClick(View v) {\n                getContext().pushFragmentToBackStack(WithListViewAndEmptyView.class, null);\n            }\n        }));\n\n        itemInfos.add(newItemInfo(R.string.ptr_demo_block_scroll_view, R.color.cube_mints_4d90fe, new OnClickListener() {\n\n            @Override\n            public void onClick(View v) {\n                getContext().pushFragmentToBackStack(WithScrollView.class, null);\n            }\n        }));\n        itemInfos.add(null);\n        itemInfos.add(null);\n\n        itemInfos.add(newItemInfo(R.string.ptr_demo_block_keep_header, R.color.cube_mints_4d90fe, new OnClickListener() {\n\n            @Override\n            public void onClick(View v) {\n                getContext().pushFragmentToBackStack(KeepHeader.class, null);\n            }\n        }));\n        itemInfos.add(newItemInfo(R.string.ptr_demo_block_hide_header, R.color.cube_mints_4d90fe, new OnClickListener() {\n\n            @Override\n            public void onClick(View v) {\n                getContext().pushFragmentToBackStack(HideHeader.class, null);\n            }\n        }));\n\n        itemInfos.add(newItemInfo(R.string.ptr_demo_block_release_to_refresh, R.color.cube_mints_4d90fe, new OnClickListener() {\n\n            @Override\n            public void onClick(View v) {\n                getContext().pushFragmentToBackStack(ReleaseToRefresh.class, null);\n            }\n        }));\n\n        itemInfos.add(newItemInfo(R.string.ptr_demo_block_pull_to_refresh, R.color.cube_mints_4d90fe, new OnClickListener() {\n\n            @Override\n            public void onClick(View v) {\n                getContext().pushFragmentToBackStack(PullToRefresh.class, null);\n            }\n        }));\n        itemInfos.add(newItemInfo(R.string.ptr_demo_block_auto_fresh, R.color.cube_mints_4d90fe, new OnClickListener() {\n\n            @Override\n            public void onClick(View v) {\n                getContext().pushFragmentToBackStack(AutoRefresh.class, null);\n            }\n        }));\n        itemInfos.add(null);\n\n        itemInfos.add(newItemInfo(R.string.ptr_demo_block_storehouse_header_using_string_array, R.color.cube_mints_4d90fe, new OnClickListener() {\n\n            @Override\n            public void onClick(View v) {\n                getContext().pushFragmentToBackStack(StoreHouseUsingStringArray.class, null);\n            }\n        }));\n        itemInfos.add(newItemInfo(R.string.ptr_demo_block_storehouse_header_using_string, R.color.cube_mints_4d90fe, new OnClickListener() {\n\n            @Override\n            public void onClick(View v) {\n                getContext().pushFragmentToBackStack(StoreHouseUsingString.class, null);\n            }\n        }));\n        itemInfos.add(newItemInfo(R.string.ptr_demo_storehouse_header_using_point_list, R.color.cube_mints_4d90fe, new OnClickListener() {\n\n            @Override\n            public void onClick(View v) {\n                getContext().pushFragmentToBackStack(StoreHouseUsingPointList.class, null);\n            }\n        }));\n        itemInfos.add(newItemInfo(R.string.ptr_demo_material_style, R.color.cube_mints_4d90fe, new OnClickListener() {\n\n            @Override\n            public void onClick(View v) {\n                getContext().pushFragmentToBackStack(MaterialStyleFragment.class, null);\n            }\n        }));\n        itemInfos.add(newItemInfo(R.string.ptr_demo_material_style_pin_content, R.color.cube_mints_4d90fe, new OnClickListener() {\n\n            @Override\n            public void onClick(View v) {\n                getContext().pushFragmentToBackStack(MaterialStylePinContentFragment.class, null);\n            }\n        }));\n        itemInfos.add(newItemInfo(R.string.ptr_demo_block_with_long_press, R.color.cube_mints_4d90fe, new OnClickListener() {\n\n            @Override\n            public void onClick(View v) {\n                getContext().pushFragmentToBackStack(WithLongPressFragment.class, null);\n            }\n        }));\n        itemInfos.add(newItemInfo(R.string.ptr_demo_block_with_view_pager, R.color.cube_mints_4d90fe, new OnClickListener() {\n\n            @Override\n            public void onClick(View v) {\n                Intent intent = new Intent();\n                intent.setClass(getContext(), ViewPagerActivity.class);\n                startActivity(intent);\n            }\n        }));\n        itemInfos.add(newItemInfo(R.string.ptr_demo_rentals_style, R.color.cube_mints_4d90fe, new OnClickListener() {\n\n            @Override\n            public void onClick(View v) {\n                getContext().pushFragmentToBackStack(RentalsStyleFragment.class, null);\n            }\n        }));\n        itemInfos.add(newItemInfo(R.string.ptr_demo_enable_next_ptr_at_once, R.color.cube_mints_4d90fe, new OnClickListener() {\n\n            @Override\n            public void onClick(View v) {\n                getContext().pushFragmentToBackStack(EnableNextPTRAtOnce.class, null);\n            }\n        }));\n\n        itemInfos.add(newItemInfo(R.string.ptr_demo_placeholder, R.color.cube_mints_4d90fe, new OnClickListener() {\n\n            @Override\n            public void onClick(View v) {\n            }\n        }));\n        itemInfos.add(newItemInfo(R.string.ptr_demo_placeholder, R.color.cube_mints_4d90fe, new OnClickListener() {\n\n            @Override\n            public void onClick(View v) {\n            }\n        }));\n        itemInfos.add(newItemInfo(R.string.ptr_demo_placeholder, R.color.cube_mints_4d90fe, new OnClickListener() {\n\n            @Override\n            public void onClick(View v) {\n            }\n        }));\n    }\n\n    @Override\n    protected View createView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {\n        View view = super.createView(inflater, container, savedInstanceState);\n        view.setBackgroundColor(getResources().getColor(R.color.cube_mints_333333));\n\n        final PtrFrameLayout ptrFrameLayout = (PtrFrameLayout) view.findViewById(R.id.fragment_ptr_home_ptr_frame);\n        StoreHouseHeader header = new StoreHouseHeader(getContext());\n        header.setPadding(0, LocalDisplay.dp2px(20), 0, LocalDisplay.dp2px(20));\n        header.initWithString(\"Ultra PTR\");\n\n        ptrFrameLayout.setDurationToCloseHeader(1500);\n        ptrFrameLayout.setHeaderView(header);\n        ptrFrameLayout.addPtrUIHandler(header);\n        ptrFrameLayout.setPtrHandler(new PtrHandler() {\n            @Override\n            public boolean checkCanDoRefresh(PtrFrameLayout frame, View content, View header) {\n                return PtrDefaultHandler.checkContentCanBePulledDown(frame, content, header);\n            }\n\n            @Override\n            public void onRefreshBegin(PtrFrameLayout frame) {\n                ptrFrameLayout.postDelayed(new Runnable() {\n                    @Override\n                    public void run() {\n                        ptrFrameLayout.refreshComplete();\n                    }\n                }, 1500);\n            }\n        });\n        return view;\n    }\n\n    @Override\n    protected int getLayoutId() {\n        return R.layout.fragment_ptr_home;\n    }\n\n    @Override\n    protected void setupViews(View view) {\n        super.setupViews(view);\n        setHeaderTitle(R.string.ptr_demo_block_for_home);\n    }\n}\n"
  },
  {
    "path": "ptr-demo/src/in/srain/cube/views/ptr/demo/ui/RentalsStyleFragment.java",
    "content": "package in.srain.cube.views.ptr.demo.ui;\n\nimport android.graphics.Color;\nimport android.graphics.drawable.BitmapDrawable;\nimport android.graphics.drawable.ColorDrawable;\nimport android.graphics.drawable.Drawable;\nimport android.graphics.drawable.TransitionDrawable;\nimport android.os.Bundle;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport in.srain.cube.image.CubeImageView;\nimport in.srain.cube.image.ImageLoader;\nimport in.srain.cube.image.ImageLoaderFactory;\nimport in.srain.cube.image.ImageTask;\nimport in.srain.cube.image.iface.ImageLoadHandler;\nimport in.srain.cube.mints.base.TitleBaseFragment;\nimport in.srain.cube.util.LocalDisplay;\nimport in.srain.cube.views.ptr.PtrFrameLayout;\nimport in.srain.cube.views.ptr.PtrHandler;\nimport in.srain.cube.views.ptr.demo.R;\nimport in.srain.cube.views.ptr.demo.ui.header.RentalsSunHeaderView;\n\npublic class RentalsStyleFragment extends TitleBaseFragment {\n\n    private String mUrl = \"http://img4.duitang.com/uploads/blog/201407/07/20140707113856_hBf3R.thumb.jpeg\";\n    private long mStartLoadingTime = -1;\n    private boolean mImageHasLoaded = false;\n\n    @Override\n    public void onEnter(Object data) {\n        if (data != null && data instanceof String) {\n            mUrl = (String) data;\n        }\n    }\n\n    @Override\n    protected View createView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {\n\n        View view = inflater.inflate(R.layout.fragment_materail_style, null);\n        setHeaderTitle(R.string.ptr_demo_rentals_style);\n\n        final CubeImageView imageView = (CubeImageView) view.findViewById(R.id.material_style_image_view);\n        final ImageLoader imageLoader = ImageLoaderFactory.create(getContext());\n\n        final PtrFrameLayout frame = (PtrFrameLayout) view.findViewById(R.id.material_style_ptr_frame);\n\n        // header\n        final RentalsSunHeaderView header = new RentalsSunHeaderView(getContext());\n        header.setLayoutParams(new PtrFrameLayout.LayoutParams(-1, -2));\n        header.setPadding(0, LocalDisplay.dp2px(15), 0, LocalDisplay.dp2px(10));\n        header.setUp(frame);\n\n        frame.setLoadingMinTime(1000);\n        frame.setDurationToCloseHeader(1500);\n        frame.setHeaderView(header);\n        frame.addPtrUIHandler(header);\n        // frame.setPullToRefresh(true);\n        frame.postDelayed(new Runnable() {\n            @Override\n            public void run() {\n                frame.autoRefresh(true);\n            }\n        }, 100);\n\n        frame.setPtrHandler(new PtrHandler() {\n            @Override\n            public boolean checkCanDoRefresh(PtrFrameLayout frame, View content, View header) {\n                return true;\n            }\n\n            @Override\n            public void onRefreshBegin(final PtrFrameLayout frame) {\n                if (mImageHasLoaded) {\n                    long delay = 1500;\n                    frame.postDelayed(new Runnable() {\n                        @Override\n                        public void run() {\n                            frame.refreshComplete();\n                        }\n                    }, delay);\n                } else {\n                    mStartLoadingTime = System.currentTimeMillis();\n                    imageView.loadImage(imageLoader, mUrl);\n                }\n            }\n        });\n\n        ImageLoadHandler imageLoadHandler = new ImageLoadHandler() {\n            @Override\n            public void onLoading(ImageTask imageTask, CubeImageView cubeImageView) {\n            }\n\n            @Override\n            public void onLoadFinish(ImageTask imageTask, final CubeImageView cubeImageView, final BitmapDrawable bitmapDrawable) {\n                mImageHasLoaded = true;\n                long delay = 1500;\n                frame.postDelayed(new Runnable() {\n                    @Override\n                    public void run() {\n                        if (cubeImageView != null && bitmapDrawable != null) {\n                            TransitionDrawable w1 = new TransitionDrawable(new Drawable[]{new ColorDrawable(Color.WHITE), (Drawable) bitmapDrawable});\n                            imageView.setImageDrawable(w1);\n                            w1.startTransition(200);\n                        }\n                        frame.refreshComplete();\n                    }\n                }, delay);\n            }\n\n            @Override\n            public void onLoadError(ImageTask imageTask, CubeImageView cubeImageView, int i) {\n\n            }\n        };\n        imageLoader.setImageLoadHandler(imageLoadHandler);\n        return view;\n    }\n}\n"
  },
  {
    "path": "ptr-demo/src/in/srain/cube/views/ptr/demo/ui/Utils.java",
    "content": "package in.srain.cube.views.ptr.demo.ui;\n\nimport android.content.Context;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.widget.RelativeLayout;\nimport in.srain.cube.util.LocalDisplay;\nimport in.srain.cube.views.ptr.demo.R;\n\npublic class Utils {\n\n    public static View createSimpleLoadingTip(Context context) {\n        final View view = LayoutInflater.from(context).inflate(R.layout.cube_ptr_simple_loading, null);\n        RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(-2, -2);\n        lp.setMargins(0, 0, 0, LocalDisplay.dp2px(4));\n        lp.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);\n        lp.addRule(RelativeLayout.CENTER_VERTICAL);\n        view.setLayoutParams(lp);\n        view.setVisibility(View.INVISIBLE);\n        return view;\n    }\n}\n"
  },
  {
    "path": "ptr-demo/src/in/srain/cube/views/ptr/demo/ui/WithLongPressFragment.java",
    "content": "package in.srain.cube.views.ptr.demo.ui;\n\nimport android.os.Bundle;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.AdapterView;\nimport android.widget.ListView;\nimport android.widget.Toast;\nimport in.srain.cube.image.CubeImageView;\nimport in.srain.cube.image.ImageLoader;\nimport in.srain.cube.image.ImageLoaderFactory;\nimport in.srain.cube.mints.base.TitleBaseFragment;\nimport in.srain.cube.views.list.ListViewDataAdapter;\nimport in.srain.cube.views.list.ViewHolderBase;\nimport in.srain.cube.views.ptr.PtrDefaultHandler;\nimport in.srain.cube.views.ptr.PtrFrameLayout;\nimport in.srain.cube.views.ptr.demo.R;\nimport in.srain.cube.views.ptr.demo.image.Images;\n\nimport java.util.Arrays;\n\npublic class WithLongPressFragment extends TitleBaseFragment {\n\n    private ImageLoader mImageLoader;\n\n    @Override\n    protected View createView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {\n\n        mImageLoader = ImageLoaderFactory.create(getActivity());\n\n        View view = inflater.inflate(R.layout.fragment_with_long_press, null);\n\n        setHeaderTitle(R.string.ptr_demo_block_with_long_press);\n\n        final PtrFrameLayout ptrFrameLayout = (PtrFrameLayout) view.findViewById(R.id.with_long_press_list_view_frame);\n\n        ListView listView = (ListView) view.findViewById(R.id.with_long_press_list_view);\n        listView.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {\n            @Override\n            public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {\n                Toast.makeText(getContext(), \"Long Pressed: \" + id, Toast.LENGTH_SHORT).show();\n                return true;\n            }\n        });\n\n        final ListViewDataAdapter<String> listViewDataAdapter = new ListViewDataAdapter<String>();\n        listViewDataAdapter.setViewHolderClass(this, ViewHolder.class);\n\n        ptrFrameLayout.setPtrHandler(new PtrDefaultHandler() {\n            @Override\n            public void onRefreshBegin(PtrFrameLayout frame) {\n                ptrFrameLayout.postDelayed(new Runnable() {\n                    @Override\n                    public void run() {\n                        listViewDataAdapter.getDataList().clear();\n                        listViewDataAdapter.getDataList().addAll(Arrays.asList(Images.imageUrls));\n                        listViewDataAdapter.notifyDataSetChanged();\n                        ptrFrameLayout.refreshComplete();\n                    }\n                }, 2000);\n            }\n        });\n        ptrFrameLayout.postDelayed(new Runnable() {\n            @Override\n            public void run() {\n                ptrFrameLayout.autoRefresh();\n            }\n        }, 100);\n        listView.setAdapter(listViewDataAdapter);\n        return view;\n    }\n\n    private class ViewHolder extends ViewHolderBase<String> {\n\n        private CubeImageView mImageView;\n\n        /**\n         * create a view from resource Xml file, and hold the view that may be used in displaying data.\n         *\n         * @param layoutInflater\n         */\n        @Override\n        public View createView(LayoutInflater layoutInflater) {\n            View view = layoutInflater.inflate(R.layout.with_long_press_list_view_item, null);\n            mImageView = (CubeImageView) view.findViewById(R.id.with_long_press_list_image);\n            return view;\n        }\n\n        /**\n         * using the held views to display data\n         *\n         * @param position\n         * @param itemData\n         */\n        @Override\n        public void showData(int position, String itemData) {\n            mImageView.loadImage(mImageLoader, itemData);\n        }\n    }\n}\n"
  },
  {
    "path": "ptr-demo/src/in/srain/cube/views/ptr/demo/ui/activity/PtrDemoHomeActivity.java",
    "content": "package in.srain.cube.views.ptr.demo.ui.activity;\n\nimport android.os.Bundle;\nimport in.srain.cube.mints.base.MintsBaseActivity;\nimport in.srain.cube.views.ptr.demo.R;\nimport in.srain.cube.views.ptr.demo.ui.PtrDemoHomeFragment;\n\npublic class PtrDemoHomeActivity extends MintsBaseActivity {\n\n    @Override\n    protected void onCreate(Bundle bundle) {\n        super.onCreate(bundle);\n        setContentView(R.layout.activity_main);\n        pushFragmentToBackStack(PtrDemoHomeFragment.class, null);\n    }\n\n    @Override\n    protected int getFragmentContainerId() {\n        return R.id.id_fragment;\n    }\n}"
  },
  {
    "path": "ptr-demo/src/in/srain/cube/views/ptr/demo/ui/classic/AutoRefresh.java",
    "content": "package in.srain.cube.views.ptr.demo.ui.classic;\n\nimport in.srain.cube.views.ptr.PtrClassicFrameLayout;\nimport in.srain.cube.views.ptr.demo.R;\n\npublic class AutoRefresh extends WithGridView {\n\n    @Override\n    protected void setupViews(final PtrClassicFrameLayout ptrFrame) {\n        ptrFrame.setLoadingMinTime(3000);\n        setHeaderTitle(R.string.ptr_demo_block_auto_fresh);\n        ptrFrame.postDelayed(new Runnable() {\n            @Override\n            public void run() {\n                ptrFrame.autoRefresh(true);\n            }\n        }, 150);\n    }\n}"
  },
  {
    "path": "ptr-demo/src/in/srain/cube/views/ptr/demo/ui/classic/EvenOnlyATextView.java",
    "content": "package in.srain.cube.views.ptr.demo.ui.classic;\n\nimport android.os.Bundle;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport in.srain.cube.mints.base.TitleBaseFragment;\nimport in.srain.cube.views.ptr.PtrClassicFrameLayout;\nimport in.srain.cube.views.ptr.PtrDefaultHandler;\nimport in.srain.cube.views.ptr.PtrFrameLayout;\nimport in.srain.cube.views.ptr.demo.R;\n\npublic class EvenOnlyATextView extends TitleBaseFragment {\n\n    public View createView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {\n\n        setHeaderTitle(R.string.ptr_demo_block_only_text_view);\n\n        final View contentView = inflater.inflate(R.layout.fragment_classic_header_with_textview, container, false);\n\n        final PtrClassicFrameLayout ptrFrame = (PtrClassicFrameLayout) contentView.findViewById(R.id.fragment_rotate_header_with_text_view_frame);\n        ptrFrame.setLastUpdateTimeRelateObject(this);\n        ptrFrame.setPtrHandler(new PtrDefaultHandler() {\n            @Override\n            public void onRefreshBegin(PtrFrameLayout frame) {\n                frame.postDelayed(new Runnable() {\n                    @Override\n                    public void run() {\n                        ptrFrame.refreshComplete();\n                    }\n                }, 1500);\n            }\n\n            @Override\n            public boolean checkCanDoRefresh(PtrFrameLayout frame, View content, View header) {\n                return true;\n            }\n        });\n        return contentView;\n    }\n\n}\n"
  },
  {
    "path": "ptr-demo/src/in/srain/cube/views/ptr/demo/ui/classic/HideHeader.java",
    "content": "package in.srain.cube.views.ptr.demo.ui.classic;\n\nimport android.view.View;\nimport in.srain.cube.views.ptr.PtrClassicFrameLayout;\nimport in.srain.cube.views.ptr.PtrDefaultHandler;\nimport in.srain.cube.views.ptr.PtrFrameLayout;\nimport in.srain.cube.views.ptr.demo.R;\nimport in.srain.cube.views.ptr.demo.ui.Utils;\n\npublic class HideHeader extends WithTextViewInFrameLayoutFragment {\n\n    @Override\n    protected void setupViews(final PtrClassicFrameLayout ptrFrame) {\n        setHeaderTitle(R.string.ptr_demo_block_hide_header);\n        ptrFrame.setKeepHeaderWhenRefresh(false);\n\n        final View loading = Utils.createSimpleLoadingTip(getContext());\n        mTitleHeaderBar.getRightViewContainer().addView(loading);\n\n        ptrFrame.setPtrHandler(new PtrDefaultHandler() {\n            @Override\n            public void onRefreshBegin(PtrFrameLayout frame) {\n                loading.setVisibility(View.VISIBLE);\n                frame.postDelayed(new Runnable() {\n                    @Override\n                    public void run() {\n                        loading.setVisibility(View.INVISIBLE);\n                        ptrFrame.refreshComplete();\n                    }\n                }, 1500);\n            }\n\n            @Override\n            public boolean checkCanDoRefresh(PtrFrameLayout frame, View content, View header) {\n                return true;\n            }\n        });\n    }\n}"
  },
  {
    "path": "ptr-demo/src/in/srain/cube/views/ptr/demo/ui/classic/KeepHeader.java",
    "content": "package in.srain.cube.views.ptr.demo.ui.classic;\n\nimport in.srain.cube.views.ptr.PtrClassicFrameLayout;\nimport in.srain.cube.views.ptr.demo.R;\n\npublic class KeepHeader extends WithTextViewInFrameLayoutFragment {\n\n    @Override\n    protected void setupViews(PtrClassicFrameLayout ptrFrame) {\n        setHeaderTitle(R.string.ptr_demo_block_keep_header);\n        ptrFrame.setKeepHeaderWhenRefresh(true);\n    }\n}\n"
  },
  {
    "path": "ptr-demo/src/in/srain/cube/views/ptr/demo/ui/classic/PullToRefresh.java",
    "content": "package in.srain.cube.views.ptr.demo.ui.classic;\n\nimport in.srain.cube.views.ptr.PtrClassicFrameLayout;\nimport in.srain.cube.views.ptr.demo.R;\n\npublic class PullToRefresh extends WithTextViewInFrameLayoutFragment {\n\n    @Override\n    protected void setupViews(PtrClassicFrameLayout ptrFrame) {\n        setHeaderTitle(R.string.ptr_demo_block_pull_to_refresh);\n        ptrFrame.setPullToRefresh(true);\n    }\n}\n"
  },
  {
    "path": "ptr-demo/src/in/srain/cube/views/ptr/demo/ui/classic/ReleaseToRefresh.java",
    "content": "package in.srain.cube.views.ptr.demo.ui.classic;\n\nimport in.srain.cube.views.ptr.PtrClassicFrameLayout;\nimport in.srain.cube.views.ptr.demo.R;\n\npublic class ReleaseToRefresh extends WithTextViewInFrameLayoutFragment {\n\n    @Override\n    protected void setupViews(PtrClassicFrameLayout ptrFrame) {\n        setHeaderTitle(R.string.ptr_demo_block_release_to_refresh);\n        ptrFrame.setPullToRefresh(false);\n    }\n}\n"
  },
  {
    "path": "ptr-demo/src/in/srain/cube/views/ptr/demo/ui/classic/WithGridView.java",
    "content": "package in.srain.cube.views.ptr.demo.ui.classic;\n\nimport android.os.Bundle;\nimport android.text.TextUtils;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.AdapterView;\nimport android.widget.GridView;\nimport android.widget.ImageView.ScaleType;\nimport android.widget.LinearLayout;\nimport in.srain.cube.image.CubeImageView;\nimport in.srain.cube.image.ImageLoader;\nimport in.srain.cube.image.ImageLoaderFactory;\nimport in.srain.cube.mints.base.TitleBaseFragment;\nimport in.srain.cube.request.JsonData;\nimport in.srain.cube.request.RequestFinishHandler;\nimport in.srain.cube.util.LocalDisplay;\nimport in.srain.cube.views.list.ListViewDataAdapter;\nimport in.srain.cube.views.list.ViewHolderBase;\nimport in.srain.cube.views.list.ViewHolderCreator;\nimport in.srain.cube.views.ptr.PtrClassicFrameLayout;\nimport in.srain.cube.views.ptr.PtrDefaultHandler;\nimport in.srain.cube.views.ptr.PtrFrameLayout;\nimport in.srain.cube.views.ptr.PtrHandler;\nimport in.srain.cube.views.ptr.demo.R;\nimport in.srain.cube.views.ptr.demo.data.DemoRequestData;\nimport in.srain.cube.views.ptr.demo.ui.MaterialStyleFragment;\n\npublic class WithGridView extends TitleBaseFragment {\n\n    private static final int sGirdImageSize = (LocalDisplay.SCREEN_WIDTH_PIXELS - LocalDisplay.dp2px(12 + 12 + 10)) / 2;\n    private ImageLoader mImageLoader;\n    private ListViewDataAdapter<JsonData> mAdapter;\n    private PtrClassicFrameLayout mPtrFrame;\n\n    @Override\n    public View createView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {\n\n        setHeaderTitle(R.string.ptr_demo_block_grid_view);\n\n        mImageLoader = ImageLoaderFactory.create(getContext());\n\n        final View contentView = inflater.inflate(R.layout.fragment_classic_header_with_gridview, null);\n        final GridView gridListView = (GridView) contentView.findViewById(R.id.rotate_header_grid_view);\n        gridListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {\n            @Override\n            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {\n                if (position >= 0) {\n                    final String url = mAdapter.getItem(position).optString(\"pic\");\n                    if (!TextUtils.isEmpty(url)) {\n                        getContext().pushFragmentToBackStack(MaterialStyleFragment.class, url);\n                    }\n                }\n            }\n        });\n\n        mAdapter = new ListViewDataAdapter<JsonData>(new ViewHolderCreator<JsonData>() {\n            @Override\n            public ViewHolderBase<JsonData> createViewHolder(int position) {\n                return new ViewHolder();\n            }\n        });\n        gridListView.setAdapter(mAdapter);\n\n        mPtrFrame = (PtrClassicFrameLayout) contentView.findViewById(R.id.rotate_header_grid_view_frame);\n        mPtrFrame.setLastUpdateTimeRelateObject(this);\n        mPtrFrame.setPtrHandler(new PtrHandler() {\n            @Override\n            public void onRefreshBegin(PtrFrameLayout frame) {\n                updateData();\n            }\n\n            @Override\n            public boolean checkCanDoRefresh(PtrFrameLayout frame, View content, View header) {\n                return PtrDefaultHandler.checkContentCanBePulledDown(frame, content, header);\n            }\n        });\n        // the following are default settings\n        mPtrFrame.setResistance(1.7f);\n        mPtrFrame.setRatioOfHeaderHeightToRefresh(1.2f);\n        mPtrFrame.setDurationToClose(200);\n        mPtrFrame.setDurationToCloseHeader(1000);\n        // default is false\n        mPtrFrame.setPullToRefresh(false);\n        // default is true\n        mPtrFrame.setKeepHeaderWhenRefresh(true);\n        mPtrFrame.postDelayed(new Runnable() {\n            @Override\n            public void run() {\n                // mPtrFrame.autoRefresh();\n            }\n        }, 100);\n        // updateData();\n        setupViews(mPtrFrame);\n        return contentView;\n    }\n\n    protected void setupViews(final PtrClassicFrameLayout ptrFrame) {\n\n    }\n\n    protected void updateData() {\n\n        DemoRequestData.getImageList(new RequestFinishHandler<JsonData>() {\n            @Override\n            public void onRequestFinish(final JsonData data) {\n                mPtrFrame.postDelayed(new Runnable() {\n                    @Override\n                    public void run() {\n                        mAdapter.getDataList().clear();\n                        mAdapter.getDataList().addAll(data.optJson(\"data\").optJson(\"list\").toArrayList());\n                        mPtrFrame.refreshComplete();\n                        mAdapter.notifyDataSetChanged();\n                    }\n                }, 0);\n            }\n        });\n    }\n\n    private class ViewHolder extends ViewHolderBase<JsonData> {\n\n        private CubeImageView mImageView;\n\n        @Override\n        public View createView(LayoutInflater inflater) {\n            View view = LayoutInflater.from(getActivity()).inflate(R.layout.with_grid_view_item_image_list_grid, null);\n            mImageView = (CubeImageView) view.findViewById(R.id.with_grid_view_item_image);\n            mImageView.setScaleType(ScaleType.CENTER_CROP);\n\n            LinearLayout.LayoutParams lyp = new LinearLayout.LayoutParams(sGirdImageSize, sGirdImageSize);\n            mImageView.setLayoutParams(lyp);\n            return view;\n        }\n\n        @Override\n        public void showData(int position, JsonData itemData) {\n            String url = itemData.optString(\"pic\");\n            mImageView.loadImage(mImageLoader, url);\n        }\n    }\n}"
  },
  {
    "path": "ptr-demo/src/in/srain/cube/views/ptr/demo/ui/classic/WithListView.java",
    "content": "package in.srain.cube.views.ptr.demo.ui.classic;\n\nimport android.os.Bundle;\nimport android.text.TextUtils;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.AdapterView;\nimport android.widget.ImageView;\nimport android.widget.ListView;\nimport in.srain.cube.image.CubeImageView;\nimport in.srain.cube.image.ImageLoader;\nimport in.srain.cube.image.ImageLoaderFactory;\nimport in.srain.cube.mints.base.TitleBaseFragment;\nimport in.srain.cube.request.JsonData;\nimport in.srain.cube.request.RequestFinishHandler;\nimport in.srain.cube.views.list.ListViewDataAdapter;\nimport in.srain.cube.views.list.ViewHolderBase;\nimport in.srain.cube.views.ptr.PtrClassicFrameLayout;\nimport in.srain.cube.views.ptr.PtrDefaultHandler;\nimport in.srain.cube.views.ptr.PtrFrameLayout;\nimport in.srain.cube.views.ptr.PtrHandler;\nimport in.srain.cube.views.ptr.demo.R;\nimport in.srain.cube.views.ptr.demo.data.DemoRequestData;\nimport in.srain.cube.views.ptr.demo.ui.MaterialStyleFragment;\n\npublic class WithListView extends TitleBaseFragment {\n\n    private ImageLoader mImageLoader;\n    private ListViewDataAdapter<JsonData> mAdapter;\n    private PtrClassicFrameLayout mPtrFrame;\n\n    @Override\n    public View createView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {\n\n        setHeaderTitle(R.string.ptr_demo_block_list_view);\n\n        mImageLoader = ImageLoaderFactory.create(getContext());\n\n        final View contentView = inflater.inflate(R.layout.fragment_classic_header_with_list_view, null);\n        final ListView listView = (ListView) contentView.findViewById(R.id.rotate_header_list_view);\n        listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {\n            @Override\n            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {\n                if (position >= 0) {\n                    final String url = mAdapter.getItem(position).optString(\"pic\");\n                    if (!TextUtils.isEmpty(url)) {\n                        getContext().pushFragmentToBackStack(MaterialStyleFragment.class, url);\n                    }\n                }\n            }\n        });\n\n        mAdapter = new ListViewDataAdapter<JsonData>();\n        mAdapter.setViewHolderClass(this, ViewHolder.class);\n        listView.setAdapter(mAdapter);\n\n        mPtrFrame = (PtrClassicFrameLayout) contentView.findViewById(R.id.rotate_header_list_view_frame);\n        mPtrFrame.setLastUpdateTimeRelateObject(this);\n        mPtrFrame.setPtrHandler(new PtrHandler() {\n            @Override\n            public void onRefreshBegin(PtrFrameLayout frame) {\n                updateData();\n            }\n\n            @Override\n            public boolean checkCanDoRefresh(PtrFrameLayout frame, View content, View header) {\n                return PtrDefaultHandler.checkContentCanBePulledDown(frame, content, header);\n            }\n        });\n        // the following are default settings\n        mPtrFrame.setResistance(1.7f);\n        mPtrFrame.setRatioOfHeaderHeightToRefresh(1.2f);\n        mPtrFrame.setDurationToClose(200);\n        mPtrFrame.setDurationToCloseHeader(1000);\n        // default is false\n        mPtrFrame.setPullToRefresh(false);\n        // default is true\n        mPtrFrame.setKeepHeaderWhenRefresh(true);\n        mPtrFrame.postDelayed(new Runnable() {\n            @Override\n            public void run() {\n                mPtrFrame.autoRefresh();\n            }\n        }, 100);\n        return contentView;\n    }\n\n    protected void updateData() {\n\n        DemoRequestData.getImageList(new RequestFinishHandler<JsonData>() {\n            @Override\n            public void onRequestFinish(final JsonData data) {\n                mPtrFrame.postDelayed(new Runnable() {\n                    @Override\n                    public void run() {\n                        mAdapter.getDataList().clear();\n                        mAdapter.getDataList().addAll(data.optJson(\"data\").optJson(\"list\").toArrayList());\n                        mPtrFrame.refreshComplete();\n                        mAdapter.notifyDataSetChanged();\n                    }\n                }, 0);\n            }\n        });\n    }\n\n    private class ViewHolder extends ViewHolderBase<JsonData> {\n\n        private CubeImageView mImageView;\n\n        @Override\n        public View createView(LayoutInflater inflater) {\n            View v = inflater.inflate(R.layout.list_view_item, null);\n            mImageView = (CubeImageView) v.findViewById(R.id.list_view_item_image_view);\n            mImageView.setScaleType(ImageView.ScaleType.CENTER_CROP);\n            return v;\n        }\n\n        @Override\n        public void showData(int position, JsonData itemData) {\n            mImageView.loadImage(mImageLoader, itemData.optString(\"pic\"));\n        }\n    }\n}"
  },
  {
    "path": "ptr-demo/src/in/srain/cube/views/ptr/demo/ui/classic/WithListViewAndEmptyView.java",
    "content": "package in.srain.cube.views.ptr.demo.ui.classic;\n\nimport android.os.Bundle;\nimport android.text.TextUtils;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.AdapterView;\nimport android.widget.ImageView;\nimport android.widget.ListView;\nimport android.widget.TextView;\nimport in.srain.cube.image.CubeImageView;\nimport in.srain.cube.image.ImageLoader;\nimport in.srain.cube.image.ImageLoaderFactory;\nimport in.srain.cube.mints.base.TitleBaseFragment;\nimport in.srain.cube.request.JsonData;\nimport in.srain.cube.request.RequestFinishHandler;\nimport in.srain.cube.views.list.ListViewDataAdapter;\nimport in.srain.cube.views.list.ViewHolderBase;\nimport in.srain.cube.views.ptr.PtrClassicFrameLayout;\nimport in.srain.cube.views.ptr.PtrDefaultHandler;\nimport in.srain.cube.views.ptr.PtrFrameLayout;\nimport in.srain.cube.views.ptr.PtrHandler;\nimport in.srain.cube.views.ptr.demo.R;\nimport in.srain.cube.views.ptr.demo.data.DemoRequestData;\nimport in.srain.cube.views.ptr.demo.ui.MaterialStyleFragment;\n\npublic class WithListViewAndEmptyView extends TitleBaseFragment {\n\n    private ImageLoader mImageLoader;\n    private ListViewDataAdapter<JsonData> mAdapter;\n    private PtrClassicFrameLayout mPtrFrame;\n    private TextView mTextView;\n    private ListView mListView;\n\n    @Override\n    public View createView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {\n\n        setHeaderTitle(R.string.ptr_demo_block_with_list_view_and_empty_view);\n\n        mImageLoader = ImageLoaderFactory.create(getContext());\n\n\n        final View contentView = inflater.inflate(R.layout.fragment_classic_header_with_list_view_and_empty_view, null);\n        mTextView = (TextView) contentView.findViewById(R.id.list_view_with_empty_view_fragment_empty_view);\n        mPtrFrame = (PtrClassicFrameLayout) contentView.findViewById(R.id.list_view_with_empty_view_fragment_ptr_frame);\n\n        mTextView.setOnClickListener(new View.OnClickListener() {\n            @Override\n            public void onClick(View v) {\n                mPtrFrame.setVisibility(View.VISIBLE);\n                mPtrFrame.autoRefresh();\n            }\n        });\n\n        mListView = (ListView) contentView.findViewById(R.id.list_view_with_empty_view_fragment_list_view);\n        mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {\n            @Override\n            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {\n                if (position >= 0) {\n                    final String url = mAdapter.getItem(position).optString(\"pic\");\n                    if (!TextUtils.isEmpty(url)) {\n                        getContext().pushFragmentToBackStack(MaterialStyleFragment.class, url);\n                    }\n                }\n            }\n        });\n\n        // show empty view\n        mPtrFrame.setVisibility(View.INVISIBLE);\n        mTextView.setVisibility(View.VISIBLE);\n\n        mAdapter = new ListViewDataAdapter<JsonData>();\n        mAdapter.setViewHolderClass(this, ViewHolder.class);\n        mListView.setAdapter(mAdapter);\n\n        mPtrFrame.setLastUpdateTimeRelateObject(this);\n        mPtrFrame.setPtrHandler(new PtrHandler() {\n            @Override\n            public boolean checkCanDoRefresh(PtrFrameLayout frame, View content, View header) {\n\n                // here check $mListView instead of $content\n                return PtrDefaultHandler.checkContentCanBePulledDown(frame, mListView, header);\n            }\n\n            @Override\n            public void onRefreshBegin(PtrFrameLayout frame) {\n                updateData();\n            }\n        });\n        // the following are default settings\n        mPtrFrame.setResistance(1.7f);\n        mPtrFrame.setRatioOfHeaderHeightToRefresh(1.2f);\n        mPtrFrame.setDurationToClose(200);\n        mPtrFrame.setDurationToCloseHeader(1000);\n        // default is false\n        mPtrFrame.setPullToRefresh(false);\n        // default is true\n        mPtrFrame.setKeepHeaderWhenRefresh(true);\n        return contentView;\n    }\n\n    protected void updateData() {\n\n        DemoRequestData.getImageList(new RequestFinishHandler<JsonData>() {\n            @Override\n            public void onRequestFinish(final JsonData data) {\n                displayData(data);\n            }\n        });\n    }\n\n    private void displayData(JsonData data) {\n\n        mTextView.setVisibility(View.GONE);\n\n        mAdapter.getDataList().clear();\n        mAdapter.getDataList().addAll(data.optJson(\"data\").optJson(\"list\").toArrayList());\n        mPtrFrame.refreshComplete();\n        mAdapter.notifyDataSetChanged();\n    }\n\n    private class ViewHolder extends ViewHolderBase<JsonData> {\n\n        private CubeImageView mImageView;\n\n        @Override\n        public View createView(LayoutInflater inflater) {\n            View v = inflater.inflate(R.layout.list_view_item, null);\n            mImageView = (CubeImageView) v.findViewById(R.id.list_view_item_image_view);\n            mImageView.setScaleType(ImageView.ScaleType.CENTER_CROP);\n            return v;\n        }\n\n        @Override\n        public void showData(int position, JsonData itemData) {\n            mImageView.loadImage(mImageLoader, itemData.optString(\"pic\"));\n        }\n    }\n}"
  },
  {
    "path": "ptr-demo/src/in/srain/cube/views/ptr/demo/ui/classic/WithScrollView.java",
    "content": "package in.srain.cube.views.ptr.demo.ui.classic;\n\nimport android.os.Bundle;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.ScrollView;\nimport in.srain.cube.mints.base.TitleBaseFragment;\nimport in.srain.cube.views.ptr.PtrClassicFrameLayout;\nimport in.srain.cube.views.ptr.PtrDefaultHandler;\nimport in.srain.cube.views.ptr.PtrFrameLayout;\nimport in.srain.cube.views.ptr.PtrHandler;\nimport in.srain.cube.views.ptr.demo.R;\n\npublic class WithScrollView extends TitleBaseFragment {\n\n    private PtrClassicFrameLayout mPtrFrame;\n    private ScrollView mScrollView;\n\n    @Override\n    public View createView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {\n\n        setHeaderTitle(R.string.ptr_demo_block_scroll_view);\n\n        final View contentView = inflater.inflate(R.layout.fragment_classic_header_with_scroll_view, null);\n        mScrollView = (ScrollView) contentView.findViewById(R.id.rotate_header_scroll_view);\n        mPtrFrame = (PtrClassicFrameLayout) contentView.findViewById(R.id.rotate_header_web_view_frame);\n        mPtrFrame.setLastUpdateTimeRelateObject(this);\n        mPtrFrame.setPtrHandler(new PtrHandler() {\n            @Override\n            public boolean checkCanDoRefresh(PtrFrameLayout frame, View content, View header) {\n                return PtrDefaultHandler.checkContentCanBePulledDown(frame, mScrollView, header);\n            }\n\n            @Override\n            public void onRefreshBegin(PtrFrameLayout frame) {\n                mPtrFrame.postDelayed(new Runnable() {\n                    @Override\n                    public void run() {\n                        mPtrFrame.refreshComplete();\n                    }\n                }, 100);\n            }\n        });\n\n        // the following are default settings\n        mPtrFrame.setResistance(1.7f);\n        mPtrFrame.setRatioOfHeaderHeightToRefresh(1.2f);\n        mPtrFrame.setDurationToClose(200);\n        mPtrFrame.setDurationToCloseHeader(1000);\n        // default is false\n        mPtrFrame.setPullToRefresh(false);\n        // default is true\n        mPtrFrame.setKeepHeaderWhenRefresh(true);\n        mPtrFrame.postDelayed(new Runnable() {\n            @Override\n            public void run() {\n                mPtrFrame.autoRefresh();\n            }\n        }, 100);\n        return contentView;\n    }\n}"
  },
  {
    "path": "ptr-demo/src/in/srain/cube/views/ptr/demo/ui/classic/WithTextViewInFrameLayoutFragment.java",
    "content": "package in.srain.cube.views.ptr.demo.ui.classic;\n\nimport android.os.Bundle;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport in.srain.cube.mints.base.TitleBaseFragment;\nimport in.srain.cube.views.ptr.PtrClassicFrameLayout;\nimport in.srain.cube.views.ptr.PtrFrameLayout;\nimport in.srain.cube.views.ptr.PtrHandler;\nimport in.srain.cube.views.ptr.demo.R;\n\npublic class WithTextViewInFrameLayoutFragment extends TitleBaseFragment {\n\n    @Override\n    public View createView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {\n\n        setHeaderTitle(R.string.ptr_demo_block_frame_layout);\n\n        final View contentView = inflater.inflate(R.layout.fragment_classic_header_with_viewgroup, container, false);\n\n        final PtrClassicFrameLayout ptrFrame = (PtrClassicFrameLayout) contentView.findViewById(R.id.fragment_rotate_header_with_view_group_frame);\n        ptrFrame.setPtrHandler(new PtrHandler() {\n            @Override\n            public void onRefreshBegin(PtrFrameLayout frame) {\n                frame.postDelayed(new Runnable() {\n                    @Override\n                    public void run() {\n                        ptrFrame.refreshComplete();\n                    }\n                }, 1800);\n            }\n\n            @Override\n            public boolean checkCanDoRefresh(PtrFrameLayout frame, View content, View header) {\n                return true;\n            }\n        });\n        ptrFrame.setLastUpdateTimeRelateObject(this);\n\n        // the following are default settings\n        ptrFrame.setResistance(1.7f);\n        ptrFrame.setRatioOfHeaderHeightToRefresh(1.2f);\n        ptrFrame.setDurationToClose(200);\n        ptrFrame.setDurationToCloseHeader(1000);\n        // default is false\n        ptrFrame.setPullToRefresh(false);\n        // default is true\n        ptrFrame.setKeepHeaderWhenRefresh(true);\n\n        // scroll then refresh\n        // comment in base fragment\n        ptrFrame.postDelayed(new Runnable() {\n            @Override\n            public void run() {\n                // ptrFrame.autoRefresh();\n            }\n        }, 150);\n\n        setupViews(ptrFrame);\n\n        return contentView;\n    }\n\n    protected void setupViews(final PtrClassicFrameLayout ptrFrame) {\n\n    }\n}"
  },
  {
    "path": "ptr-demo/src/in/srain/cube/views/ptr/demo/ui/classic/WithWebView.java",
    "content": "package in.srain.cube.views.ptr.demo.ui.classic;\n\nimport android.os.Bundle;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.webkit.WebView;\nimport android.webkit.WebViewClient;\nimport in.srain.cube.mints.base.TitleBaseFragment;\nimport in.srain.cube.views.ptr.PtrClassicFrameLayout;\nimport in.srain.cube.views.ptr.PtrDefaultHandler;\nimport in.srain.cube.views.ptr.PtrFrameLayout;\nimport in.srain.cube.views.ptr.PtrHandler;\nimport in.srain.cube.views.ptr.demo.R;\n\npublic class WithWebView extends TitleBaseFragment {\n\n    private PtrClassicFrameLayout mPtrFrame;\n    private WebView mWebView;\n\n    @Override\n    public View createView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {\n\n        setHeaderTitle(R.string.ptr_demo_block_web_view);\n\n        final View contentView = inflater.inflate(R.layout.fragment_classic_header_with_webview, null);\n        mWebView = (WebView) contentView.findViewById(R.id.rotate_header_web_view);\n        mWebView.setWebViewClient(new WebViewClient() {\n            @Override\n            public void onPageFinished(WebView view, String url) {\n                mPtrFrame.refreshComplete();\n            }\n        });\n        mPtrFrame = (PtrClassicFrameLayout) contentView.findViewById(R.id.rotate_header_web_view_frame);\n        mPtrFrame.setLastUpdateTimeRelateObject(this);\n        mPtrFrame.setPtrHandler(new PtrHandler() {\n            @Override\n            public boolean checkCanDoRefresh(PtrFrameLayout frame, View content, View header) {\n                return PtrDefaultHandler.checkContentCanBePulledDown(frame, mWebView, header);\n            }\n\n            @Override\n            public void onRefreshBegin(PtrFrameLayout frame) {\n                updateData();\n            }\n        });\n        // the following are default settings\n        mPtrFrame.setResistance(1.7f);\n        mPtrFrame.setRatioOfHeaderHeightToRefresh(1.2f);\n        mPtrFrame.setDurationToClose(200);\n        mPtrFrame.setDurationToCloseHeader(1000);\n        // default is false\n        mPtrFrame.setPullToRefresh(false);\n        // default is true\n        mPtrFrame.setKeepHeaderWhenRefresh(true);\n        mPtrFrame.postDelayed(new Runnable() {\n            @Override\n            public void run() {\n                mPtrFrame.autoRefresh();\n            }\n        }, 100);\n        return contentView;\n    }\n\n    private void updateData() {\n        mWebView.loadUrl(\"http://www.liaohuqiu.net/\");\n    }\n}"
  },
  {
    "path": "ptr-demo/src/in/srain/cube/views/ptr/demo/ui/header/RentalsSunDrawable.java",
    "content": "package in.srain.cube.views.ptr.demo.ui.header;\n\nimport android.content.Context;\nimport android.graphics.*;\nimport android.graphics.drawable.Animatable;\nimport android.graphics.drawable.Drawable;\nimport android.view.View;\nimport android.view.animation.Animation;\nimport android.view.animation.Interpolator;\nimport android.view.animation.LinearInterpolator;\nimport android.view.animation.Transformation;\nimport in.srain.cube.views.ptr.demo.R;\nimport in.srain.cube.views.ptr.util.PtrLocalDisplay;\n\npublic class RentalsSunDrawable extends Drawable implements Animatable {\n\n    private static final float SCALE_START_PERCENT = 0.3f;\n    private static final int ANIMATION_DURATION = 1000;\n\n    private final static float SKY_RATIO = 0.65f;\n    private static final float SKY_INITIAL_SCALE = 1.05f;\n\n    private final static float TOWN_RATIO = 0.22f;\n    private static final float TOWN_INITIAL_SCALE = 1.20f;\n    private static final float TOWN_FINAL_SCALE = 1.30f;\n\n    private static final float SUN_FINAL_SCALE = 0.75f;\n    private static final float SUN_INITIAL_ROTATE_GROWTH = 1.2f;\n    private static final float SUN_FINAL_ROTATE_GROWTH = 1.5f;\n\n    private static final Interpolator LINEAR_INTERPOLATOR = new LinearInterpolator();\n\n    private View mParent;\n    private Matrix mMatrix;\n    private Animation mAnimation;\n\n    private int mTop;\n    private int mScreenWidth;\n\n    private int mSkyHeight;\n    private float mSkyTopOffset;\n    private float mSkyMoveOffset;\n\n    private int mTownHeight;\n    private float mTownInitialTopOffset;\n    private float mTownFinalTopOffset;\n    private float mTownMoveOffset;\n\n    private int mSunSize = 100;\n    private float mSunLeftOffset;\n    private float mSunTopOffset;\n\n    private float mPercent = 0.0f;\n    private float mRotate = 0.0f;\n\n    private Bitmap mSky;\n    private Bitmap mSun;\n    private Bitmap mTown;\n\n    private boolean isRefreshing = false;\n\n    private Context mContext;\n    private int mTotalDragDistance;\n\n    public RentalsSunDrawable(Context context, View parent) {\n        mContext = context;\n        mParent = parent;\n\n        mMatrix = new Matrix();\n\n        initiateDimens();\n        createBitmaps();\n        setupAnimations();\n    }\n\n    private Context getContext() {\n        return mContext;\n    }\n\n\n    private void initiateDimens() {\n        PtrLocalDisplay.init(mContext);\n        mTotalDragDistance = PtrLocalDisplay.dp2px(120);\n\n        mScreenWidth = getContext().getResources().getDisplayMetrics().widthPixels;\n        mSkyHeight = (int) (SKY_RATIO * mScreenWidth);\n        mSkyTopOffset = -(mSkyHeight * 0.28f);\n        mSkyMoveOffset = PtrLocalDisplay.designedDP2px(15);\n\n        mTownHeight = (int) (TOWN_RATIO * mScreenWidth);\n        mTownInitialTopOffset = (mTotalDragDistance - mTownHeight * TOWN_INITIAL_SCALE) + mTotalDragDistance * .42f;\n        mTownFinalTopOffset = (mTotalDragDistance - mTownHeight * TOWN_FINAL_SCALE) + mTotalDragDistance * .42f;\n        mTownMoveOffset = PtrLocalDisplay.designedDP2px(10);\n\n        mSunLeftOffset = 0.3f * (float) mScreenWidth;\n        mSunTopOffset = (mTotalDragDistance * 0.5f);\n\n        mTop = 0;\n    }\n\n    private void createBitmaps() {\n        mSky = BitmapFactory.decodeResource(getContext().getResources(), R.drawable.sky);\n        mSky = Bitmap.createScaledBitmap(mSky, mScreenWidth, mSkyHeight, true);\n        mTown = BitmapFactory.decodeResource(getContext().getResources(), R.drawable.buildings);\n        mTown = Bitmap.createScaledBitmap(mTown, mScreenWidth, (int) (mScreenWidth * TOWN_RATIO), true);\n        mSun = BitmapFactory.decodeResource(getContext().getResources(), R.drawable.sun);\n        mSun = Bitmap.createScaledBitmap(mSun, mSunSize, mSunSize, true);\n    }\n\n    public void offsetTopAndBottom(int offset) {\n        mTop = offset;\n        invalidateSelf();\n    }\n\n    @Override\n    public void draw(Canvas canvas) {\n        final int saveCount = canvas.save();\n        canvas.translate(0, mTotalDragDistance - mTop);\n\n        drawSky(canvas);\n        drawSun(canvas);\n        drawTown(canvas);\n\n        canvas.restoreToCount(saveCount);\n    }\n\n    private void drawSky(Canvas canvas) {\n        Matrix matrix = mMatrix;\n        matrix.reset();\n        int y = Math.max(0, mTop - mTotalDragDistance);\n\n        //  0  ~ 1\n        float dragPercent = Math.min(1f, Math.abs(mPercent));\n\n        /** Change skyScale between {@link #SKY_INITIAL_SCALE} and 1.0f depending on {@link #mPercent} */\n        float skyScale;\n        float scalePercentDelta = dragPercent - SCALE_START_PERCENT;\n\n        /** less than {@link SCALE_START_PERCENT} will be {@link SKY_INITIAL_SCALE} */\n        if (scalePercentDelta > 0) {\n            /** will change from 0 ~ 1 **/\n            float scalePercent = scalePercentDelta / (1.0f - SCALE_START_PERCENT);\n            skyScale = SKY_INITIAL_SCALE - (SKY_INITIAL_SCALE - 1.0f) * scalePercent;\n        } else {\n            skyScale = SKY_INITIAL_SCALE;\n        }\n\n        float offsetX = -(mScreenWidth * skyScale - mScreenWidth) / 2.0f;\n\n        float offsetY = y + 50 + mSkyTopOffset // Offset canvas moving, goes lower when goes down\n                - mSkyHeight * (skyScale - 1.0f) / 2 // Offset sky scaling, lower than 0, will go greater when goes down\n                + mSkyMoveOffset * dragPercent; // Give it a little move top -> bottom  // will go greater when goes down\n\n        matrix.postScale(skyScale, skyScale);\n        matrix.postTranslate(offsetX, offsetY);\n        canvas.drawBitmap(mSky, matrix, null);\n    }\n\n    private void drawTown(Canvas canvas) {\n        Matrix matrix = mMatrix;\n        matrix.reset();\n\n        int y = Math.max(0, mTop - mTotalDragDistance);\n        float dragPercent = Math.min(1f, Math.abs(mPercent));\n\n        float townScale;\n        float townTopOffset;\n        float townMoveOffset;\n        float scalePercentDelta = dragPercent - SCALE_START_PERCENT;\n        if (scalePercentDelta > 0) {\n            /**\n             * Change townScale between {@link #TOWN_INITIAL_SCALE} and {@link #TOWN_FINAL_SCALE} depending on {@link #mPercent}\n             * Change townTopOffset between {@link #mTownInitialTopOffset} and {@link #mTownFinalTopOffset} depending on {@link #mPercent}\n             */\n            float scalePercent = scalePercentDelta / (1.0f - SCALE_START_PERCENT);\n            townScale = TOWN_INITIAL_SCALE + (TOWN_FINAL_SCALE - TOWN_INITIAL_SCALE) * scalePercent;\n            townTopOffset = mTownInitialTopOffset - (mTownFinalTopOffset - mTownInitialTopOffset) * scalePercent;\n            townMoveOffset = mTownMoveOffset * (1.0f - scalePercent);\n        } else {\n            float scalePercent = dragPercent / SCALE_START_PERCENT;\n            townScale = TOWN_INITIAL_SCALE;\n            townTopOffset = mTownInitialTopOffset;\n            townMoveOffset = mTownMoveOffset * scalePercent;\n        }\n\n        float offsetX = -(mScreenWidth * townScale - mScreenWidth) / 2.0f;\n        // float offsetY = (1.0f - dragPercent) * mTotalDragDistance // Offset canvas moving\n        float offsetY = y +\n                +townTopOffset\n                - mTownHeight * (townScale - 1.0f) / 2 // Offset town scaling\n                + townMoveOffset; // Give it a little move\n\n        matrix.postScale(townScale, townScale);\n        matrix.postTranslate(offsetX, offsetY);\n\n        canvas.drawBitmap(mTown, matrix, null);\n    }\n\n    private void drawSun(Canvas canvas) {\n        Matrix matrix = mMatrix;\n        matrix.reset();\n\n        float dragPercent = mPercent;\n        if (dragPercent > 1.0f) { // Slow down if pulling over set height\n            dragPercent = (dragPercent + 9.0f) / 10;\n        }\n\n        float sunRadius = (float) mSunSize / 2.0f;\n        float sunRotateGrowth = SUN_INITIAL_ROTATE_GROWTH;\n\n        float offsetX = mSunLeftOffset;\n        float offsetY = mSunTopOffset\n                + (mTotalDragDistance / 2) * (1.0f - dragPercent); // Move the sun up\n\n        float scalePercentDelta = dragPercent - SCALE_START_PERCENT;\n        if (scalePercentDelta > 0) {\n            float scalePercent = scalePercentDelta / (1.0f - SCALE_START_PERCENT);\n            float sunScale = 1.0f - (1.0f - SUN_FINAL_SCALE) * scalePercent;\n            sunRotateGrowth += (SUN_FINAL_ROTATE_GROWTH - SUN_INITIAL_ROTATE_GROWTH) * scalePercent;\n\n            matrix.preTranslate(offsetX + (sunRadius - sunRadius * sunScale), offsetY * (2.0f - sunScale));\n            matrix.preScale(sunScale, sunScale);\n\n            offsetX += sunRadius;\n            offsetY = offsetY * (2.0f - sunScale) + sunRadius * sunScale;\n        } else {\n            matrix.postTranslate(offsetX, offsetY);\n\n            offsetX += sunRadius;\n            offsetY += sunRadius;\n        }\n\n        float r = (isRefreshing ? -360 : 360) * mRotate * (isRefreshing ? 1 : sunRotateGrowth);\n        matrix.postRotate(r, offsetX, offsetY);\n\n        canvas.drawBitmap(mSun, matrix, null);\n    }\n\n    public void setPercent(float percent) {\n        mPercent = percent;\n        setRotate(percent);\n    }\n\n    public void setRotate(float rotate) {\n        mRotate = rotate;\n        mParent.invalidate();\n        invalidateSelf();\n    }\n\n    public void resetOriginals() {\n        setPercent(0);\n        setRotate(0);\n    }\n\n    @Override\n    public void setBounds(int left, int top, int right, int bottom) {\n        super.setBounds(left, top, right, mSkyHeight + top);\n    }\n\n    @Override\n    public void setAlpha(int alpha) {\n\n    }\n\n    @Override\n    public void setColorFilter(ColorFilter colorFilter) {\n\n    }\n\n    @Override\n    public int getOpacity() {\n        return PixelFormat.TRANSLUCENT;\n    }\n\n    @Override\n    public boolean isRunning() {\n        return false;\n    }\n\n    @Override\n    public void start() {\n        mAnimation.reset();\n        isRefreshing = true;\n        mParent.startAnimation(mAnimation);\n    }\n\n    @Override\n    public void stop() {\n        mParent.clearAnimation();\n        isRefreshing = false;\n        resetOriginals();\n    }\n\n    private void setupAnimations() {\n        mAnimation = new Animation() {\n            @Override\n            public void applyTransformation(float interpolatedTime, Transformation t) {\n                setRotate(interpolatedTime);\n            }\n        };\n        mAnimation.setRepeatCount(Animation.INFINITE);\n        mAnimation.setRepeatMode(Animation.RESTART);\n        mAnimation.setInterpolator(LINEAR_INTERPOLATOR);\n        mAnimation.setDuration(ANIMATION_DURATION);\n    }\n\n    public int getTotalDragDistance() {\n        return mTotalDragDistance;\n    }\n}\n"
  },
  {
    "path": "ptr-demo/src/in/srain/cube/views/ptr/demo/ui/header/RentalsSunHeaderView.java",
    "content": "package in.srain.cube.views.ptr.demo.ui.header;\n\nimport android.content.Context;\nimport android.graphics.Canvas;\nimport android.graphics.drawable.Drawable;\nimport android.util.AttributeSet;\nimport android.view.View;\nimport in.srain.cube.views.ptr.PtrFrameLayout;\nimport in.srain.cube.views.ptr.PtrUIHandler;\nimport in.srain.cube.views.ptr.indicator.PtrIndicator;\nimport in.srain.cube.views.ptr.indicator.PtrTensionIndicator;\n\npublic class RentalsSunHeaderView extends View implements PtrUIHandler {\n\n    private RentalsSunDrawable mDrawable;\n    private PtrFrameLayout mPtrFrameLayout;\n    private PtrTensionIndicator mPtrTensionIndicator;\n\n    public RentalsSunHeaderView(Context context, AttributeSet attrs, int defStyleAttr) {\n        super(context, attrs, defStyleAttr);\n        init();\n    }\n\n    public RentalsSunHeaderView(Context context) {\n        super(context);\n        init();\n    }\n\n    public RentalsSunHeaderView(Context context, AttributeSet attrs) {\n        super(context, attrs);\n        init();\n    }\n\n    public void setUp(PtrFrameLayout ptrFrameLayout) {\n        mPtrFrameLayout = ptrFrameLayout;\n        mPtrTensionIndicator = new PtrTensionIndicator();\n        mPtrFrameLayout.setPtrIndicator(mPtrTensionIndicator);\n    }\n\n    private void init() {\n        mDrawable = new RentalsSunDrawable(getContext(), this);\n    }\n\n    @Override\n    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {\n        int height = mDrawable.getTotalDragDistance() * 5 / 4;\n        heightMeasureSpec = MeasureSpec.makeMeasureSpec(height + getPaddingTop() + getPaddingBottom(), MeasureSpec.EXACTLY);\n        super.onMeasure(widthMeasureSpec, heightMeasureSpec);\n    }\n\n    @Override\n    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {\n        int pl = getPaddingLeft();\n        int pt = getPaddingTop();\n        mDrawable.setBounds(pl, pt, pl + right - left, pt + bottom - top);\n    }\n\n    @Override\n    public void onUIReset(PtrFrameLayout frame) {\n        mDrawable.resetOriginals();\n    }\n\n    @Override\n    protected void onDraw(Canvas canvas) {\n        mDrawable.draw(canvas);\n        float percent = mPtrTensionIndicator.getOverDragPercent();\n    }\n\n    @Override\n    public void onUIRefreshPrepare(PtrFrameLayout frame) {\n\n    }\n\n    @Override\n    public void onUIRefreshBegin(PtrFrameLayout frame) {\n        mDrawable.start();\n        float percent = mPtrTensionIndicator.getOverDragPercent();\n        mDrawable.offsetTopAndBottom(mPtrTensionIndicator.getCurrentPosY());\n        mDrawable.setPercent(percent);\n        invalidate();\n    }\n\n    @Override\n    public void onUIRefreshComplete(PtrFrameLayout frame) {\n        float percent = mPtrTensionIndicator.getOverDragPercent();\n        mDrawable.stop();\n        mDrawable.offsetTopAndBottom(mPtrTensionIndicator.getCurrentPosY());\n        mDrawable.setPercent(percent);\n        invalidate();\n    }\n\n    @Override\n    public void onUIPositionChange(PtrFrameLayout frame, boolean isUnderTouch, byte status, PtrIndicator ptrIndicator) {\n        float percent = mPtrTensionIndicator.getOverDragPercent();\n        mDrawable.offsetTopAndBottom(mPtrTensionIndicator.getCurrentPosY());\n        mDrawable.setPercent(percent);\n        invalidate();\n    }\n\n    @Override\n    public void invalidateDrawable(Drawable dr) {\n        if (dr == mDrawable) {\n            invalidate();\n        } else {\n            super.invalidateDrawable(dr);\n        }\n    }\n}\n"
  },
  {
    "path": "ptr-demo/src/in/srain/cube/views/ptr/demo/ui/storehouse/StoreHouseUsingPointList.java",
    "content": "package in.srain.cube.views.ptr.demo.ui.storehouse;\n\nimport android.graphics.Point;\nimport android.os.Bundle;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport in.srain.cube.image.CubeImageView;\nimport in.srain.cube.image.ImageLoader;\nimport in.srain.cube.image.ImageLoaderFactory;\nimport in.srain.cube.mints.base.TitleBaseFragment;\nimport in.srain.cube.util.LocalDisplay;\nimport in.srain.cube.views.ptr.PtrFrameLayout;\nimport in.srain.cube.views.ptr.PtrHandler;\nimport in.srain.cube.views.ptr.demo.R;\nimport in.srain.cube.views.ptr.header.StoreHouseHeader;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n * the point list used here is taken from:\n * https://github.com/cloay/CRefreshLayout\n */\n\npublic class StoreHouseUsingPointList extends TitleBaseFragment {\n\n    @Override\n    protected View createView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {\n        setHeaderTitle(R.string.ptr_demo_storehouse_header_using_point_list);\n\n        View view = inflater.inflate(R.layout.fragment_storehouse_header, null);\n\n        CubeImageView imageView = (CubeImageView) view.findViewById(R.id.store_house_ptr_image);\n        ImageLoader imageLoader = ImageLoaderFactory.create(getContext());\n        String pic = \"http://img5.duitang.com/uploads/item/201406/28/20140628122218_fLQyP.thumb.jpeg\";\n        imageView.loadImage(imageLoader, pic);\n\n        final PtrFrameLayout frame = (PtrFrameLayout) view.findViewById(R.id.store_house_ptr_frame);\n\n        // header\n        final StoreHouseHeader header = new StoreHouseHeader(getContext());\n        header.setPadding(0, LocalDisplay.dp2px(15), 0, 0);\n\n        header.initWithPointList(getPointList());\n\n        frame.setDurationToCloseHeader(3000);\n        frame.setHeaderView(header);\n        frame.addPtrUIHandler(header);\n        frame.postDelayed(new Runnable() {\n            @Override\n            public void run() {\n                frame.autoRefresh(false);\n            }\n        }, 100);\n\n        frame.setPtrHandler(new PtrHandler() {\n            @Override\n            public boolean checkCanDoRefresh(PtrFrameLayout frame, View content, View header) {\n                return true;\n            }\n\n            @Override\n            public void onRefreshBegin(final PtrFrameLayout frame) {\n                frame.postDelayed(new Runnable() {\n                    @Override\n                    public void run() {\n                        frame.refreshComplete();\n                    }\n                }, 2000);\n            }\n        });\n        return view;\n    }\n\n    private ArrayList<float[]> getPointList() {\n        // this point is taken from https://github.com/cloay/CRefreshLayout\n        List<Point> startPoints = new ArrayList<Point>();\n        startPoints.add(new Point(240, 80));\n        startPoints.add(new Point(270, 80));\n        startPoints.add(new Point(265, 103));\n        startPoints.add(new Point(255, 65));\n        startPoints.add(new Point(275, 80));\n        startPoints.add(new Point(275, 80));\n        startPoints.add(new Point(302, 80));\n        startPoints.add(new Point(275, 107));\n\n        startPoints.add(new Point(320, 70));\n        startPoints.add(new Point(313, 80));\n        startPoints.add(new Point(330, 63));\n        startPoints.add(new Point(315, 87));\n        startPoints.add(new Point(330, 80));\n        startPoints.add(new Point(315, 100));\n        startPoints.add(new Point(330, 90));\n        startPoints.add(new Point(315, 110));\n        startPoints.add(new Point(345, 65));\n        startPoints.add(new Point(357, 67));\n        startPoints.add(new Point(363, 103));\n\n        startPoints.add(new Point(375, 80));\n        startPoints.add(new Point(375, 80));\n        startPoints.add(new Point(425, 80));\n        startPoints.add(new Point(380, 95));\n        startPoints.add(new Point(400, 63));\n\n        List<Point> endPoints = new ArrayList<Point>();\n        endPoints.add(new Point(270, 80));\n        endPoints.add(new Point(270, 110));\n        endPoints.add(new Point(270, 110));\n        endPoints.add(new Point(250, 110));\n        endPoints.add(new Point(275, 107));\n        endPoints.add(new Point(302, 80));\n        endPoints.add(new Point(302, 107));\n        endPoints.add(new Point(302, 107));\n\n        endPoints.add(new Point(340, 70));\n        endPoints.add(new Point(360, 80));\n        endPoints.add(new Point(330, 80));\n        endPoints.add(new Point(340, 87));\n        endPoints.add(new Point(315, 100));\n        endPoints.add(new Point(345, 98));\n        endPoints.add(new Point(330, 120));\n        endPoints.add(new Point(345, 108));\n        endPoints.add(new Point(360, 120));\n        endPoints.add(new Point(363, 75));\n        endPoints.add(new Point(345, 117));\n\n        endPoints.add(new Point(380, 95));\n        endPoints.add(new Point(425, 80));\n        endPoints.add(new Point(420, 95));\n        endPoints.add(new Point(420, 95));\n        endPoints.add(new Point(400, 120));\n        ArrayList<float[]> list = new ArrayList<float[]>();\n\n        int offsetX = Integer.MAX_VALUE;\n        int offsetY = Integer.MAX_VALUE;\n\n        for (int i = 0; i < startPoints.size(); i++) {\n            offsetX = Math.min(startPoints.get(i).x, offsetX);\n            offsetY = Math.min(startPoints.get(i).y, offsetY);\n        }\n        for (int i = 0; i < endPoints.size(); i++) {\n            float[] point = new float[4];\n            point[0] = startPoints.get(i).x - offsetX;\n            point[1] = startPoints.get(i).y - offsetY;\n            point[2] = endPoints.get(i).x - offsetX;\n            point[3] = endPoints.get(i).y - offsetY;\n            list.add(point);\n        }\n        return list;\n    }\n}\n"
  },
  {
    "path": "ptr-demo/src/in/srain/cube/views/ptr/demo/ui/storehouse/StoreHouseUsingString.java",
    "content": "package in.srain.cube.views.ptr.demo.ui.storehouse;\n\nimport android.os.Bundle;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport in.srain.cube.image.CubeImageView;\nimport in.srain.cube.image.ImageLoader;\nimport in.srain.cube.image.ImageLoaderFactory;\nimport in.srain.cube.mints.base.TitleBaseFragment;\nimport in.srain.cube.util.LocalDisplay;\nimport in.srain.cube.views.ptr.PtrFrameLayout;\nimport in.srain.cube.views.ptr.PtrHandler;\nimport in.srain.cube.views.ptr.PtrUIHandler;\nimport in.srain.cube.views.ptr.demo.R;\nimport in.srain.cube.views.ptr.header.StoreHouseHeader;\nimport in.srain.cube.views.ptr.indicator.PtrIndicator;\n\npublic class StoreHouseUsingString extends TitleBaseFragment {\n\n    final String[] mStringList = {\"Alibaba\", \"TMALL 11-11\"};\n    private String mTitlePre;\n\n    @Override\n    protected View createView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {\n\n        View view = inflater.inflate(R.layout.fragment_storehouse_header, null);\n        mTitlePre = getString(R.string.ptr_demo_storehouse_header_using_string_in_title);\n\n        CubeImageView imageView = (CubeImageView) view.findViewById(R.id.store_house_ptr_image);\n        ImageLoader imageLoader = ImageLoaderFactory.create(getContext());\n        String pic = \"http://img5.duitang.com/uploads/item/201406/28/20140628122218_fLQyP.thumb.jpeg\";\n        imageView.loadImage(imageLoader, pic);\n\n        final PtrFrameLayout frame = (PtrFrameLayout) view.findViewById(R.id.store_house_ptr_frame);\n\n        // header\n        final StoreHouseHeader header = new StoreHouseHeader(getContext());\n        header.setPadding(0, LocalDisplay.dp2px(15), 0, 0);\n\n        /**\n         * using a string, support: A-Z 0-9 - .\n         * you can add more letters by {@link in.srain.cube.views.ptr.header.StoreHousePath#addChar}\n         */\n        header.initWithString(mStringList[0]);\n        setHeaderTitle(mTitlePre + mStringList[0]);\n\n        // for changing string\n        frame.addPtrUIHandler(new PtrUIHandler() {\n\n            private int mLoadTime = 0;\n\n            @Override\n            public void onUIReset(PtrFrameLayout frame) {\n                mLoadTime++;\n                String string = mStringList[mLoadTime % mStringList.length];\n                header.initWithString(string);\n            }\n\n            @Override\n            public void onUIRefreshPrepare(PtrFrameLayout frame) {\n                String string = mStringList[mLoadTime % mStringList.length];\n                setHeaderTitle(mTitlePre + string);\n            }\n\n            @Override\n            public void onUIRefreshBegin(PtrFrameLayout frame) {\n\n            }\n\n            @Override\n            public void onUIRefreshComplete(PtrFrameLayout frame) {\n\n            }\n\n            @Override\n            public void onUIPositionChange(PtrFrameLayout frame, boolean isUnderTouch, byte status, PtrIndicator ptrIndicator) {\n\n            }\n        });\n\n        frame.setDurationToCloseHeader(3000);\n        frame.setHeaderView(header);\n        frame.addPtrUIHandler(header);\n        frame.postDelayed(new Runnable() {\n            @Override\n            public void run() {\n                frame.autoRefresh(false);\n            }\n        }, 100);\n\n        frame.setPtrHandler(new PtrHandler() {\n            @Override\n            public boolean checkCanDoRefresh(PtrFrameLayout frame, View content, View header) {\n                return true;\n            }\n\n            @Override\n            public void onRefreshBegin(final PtrFrameLayout frame) {\n                frame.postDelayed(new Runnable() {\n                    @Override\n                    public void run() {\n                        frame.refreshComplete();\n                    }\n                }, 2000);\n            }\n        });\n        return view;\n    }\n}\n"
  },
  {
    "path": "ptr-demo/src/in/srain/cube/views/ptr/demo/ui/storehouse/StoreHouseUsingStringArray.java",
    "content": "package in.srain.cube.views.ptr.demo.ui.storehouse;\n\nimport android.os.Bundle;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport in.srain.cube.image.CubeImageView;\nimport in.srain.cube.image.ImageLoader;\nimport in.srain.cube.image.ImageLoaderFactory;\nimport in.srain.cube.mints.base.TitleBaseFragment;\nimport in.srain.cube.util.LocalDisplay;\nimport in.srain.cube.views.ptr.PtrFrameLayout;\nimport in.srain.cube.views.ptr.PtrHandler;\nimport in.srain.cube.views.ptr.PtrUIHandler;\nimport in.srain.cube.views.ptr.demo.R;\nimport in.srain.cube.views.ptr.header.StoreHouseHeader;\nimport in.srain.cube.views.ptr.indicator.PtrIndicator;\n\npublic class StoreHouseUsingStringArray extends TitleBaseFragment {\n\n    private String mTitlePre;\n\n    @Override\n    protected View createView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {\n\n        final View view = inflater.inflate(R.layout.fragment_storehouse_header, null);\n\n        mTitlePre = getString(R.string.ptr_demo_storehouse_header_using_string_array_in_title);\n\n        setHeaderTitle(mTitlePre + \"R.array.storehouse\");\n\n        // loading image\n        CubeImageView imageView = (CubeImageView) view.findViewById(R.id.store_house_ptr_image);\n        ImageLoader imageLoader = ImageLoaderFactory.create(getContext());\n        String pic = \"http://img5.duitang.com/uploads/item/201406/28/20140628122218_fLQyP.thumb.jpeg\";\n        imageView.loadImage(imageLoader, pic);\n\n        final PtrFrameLayout frame = (PtrFrameLayout) view.findViewById(R.id.store_house_ptr_frame);\n        final StoreHouseHeader header = new StoreHouseHeader(getContext());\n        header.setPadding(0, LocalDisplay.dp2px(15), 0, 0);\n\n        // using string array from resource xml file\n        header.initWithStringArray(R.array.storehouse);\n\n        frame.setDurationToCloseHeader(1500);\n        frame.setHeaderView(header);\n        frame.addPtrUIHandler(header);\n        frame.postDelayed(new Runnable() {\n            @Override\n            public void run() {\n                frame.autoRefresh(false);\n            }\n        }, 100);\n\n        // change header after loaded\n        frame.addPtrUIHandler(new PtrUIHandler() {\n\n            private int mLoadTime = 0;\n\n            @Override\n            public void onUIReset(PtrFrameLayout frame) {\n                mLoadTime++;\n                if (mLoadTime % 2 == 0) {\n                    header.setScale(1);\n                    header.initWithStringArray(R.array.storehouse);\n                } else {\n                    header.setScale(0.5f);\n                    header.initWithStringArray(R.array.akta);\n                }\n            }\n\n            @Override\n            public void onUIRefreshPrepare(PtrFrameLayout frame) {\n                if (mLoadTime % 2 == 0) {\n                    setHeaderTitle(mTitlePre + \"R.array.storehouse\");\n                } else {\n                    setHeaderTitle(mTitlePre + \"R.array.akta\");\n                }\n            }\n\n            @Override\n            public void onUIRefreshBegin(PtrFrameLayout frame) {\n\n            }\n\n            @Override\n            public void onUIRefreshComplete(PtrFrameLayout frame) {\n\n            }\n\n            @Override\n            public void onUIPositionChange(PtrFrameLayout frame, boolean isUnderTouch, byte status, PtrIndicator ptrIndicator) {\n\n            }\n        });\n\n        frame.setPtrHandler(new PtrHandler() {\n            @Override\n            public boolean checkCanDoRefresh(PtrFrameLayout frame, View content, View header) {\n                return true;\n            }\n\n            @Override\n            public void onRefreshBegin(final PtrFrameLayout frame) {\n                frame.postDelayed(new Runnable() {\n                    @Override\n                    public void run() {\n                        frame.refreshComplete();\n                    }\n                }, 2000);\n            }\n        });\n        return view;\n    }\n}\n"
  },
  {
    "path": "ptr-demo/src/in/srain/cube/views/ptr/demo/ui/viewpager/ImageListViewHolder.java",
    "content": "package in.srain.cube.views.ptr.demo.ui.viewpager;\n\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.widget.ImageView;\nimport in.srain.cube.image.CubeImageView;\nimport in.srain.cube.image.ImageLoader;\nimport in.srain.cube.request.JsonData;\nimport in.srain.cube.views.list.ViewHolderBase;\nimport in.srain.cube.views.ptr.demo.R;\n\npublic class ImageListViewHolder extends ViewHolderBase<JsonData> {\n\n    private ImageLoader mImageLoader;\n    private CubeImageView mImageView;\n\n    private ImageListViewHolder(ImageLoader imageLoader) {\n        mImageLoader = imageLoader;\n    }\n\n    @Override\n    public View createView(LayoutInflater inflater) {\n        View v = inflater.inflate(R.layout.list_view_item, null);\n        mImageView = (CubeImageView) v.findViewById(R.id.list_view_item_image_view);\n        mImageView.setScaleType(ImageView.ScaleType.CENTER_CROP);\n        return v;\n    }\n\n    @Override\n    public void showData(int position, JsonData itemData) {\n        mImageView.loadImage(mImageLoader, itemData.optString(\"pic\"));\n    }\n}\n"
  },
  {
    "path": "ptr-demo/src/in/srain/cube/views/ptr/demo/ui/viewpager/ViewPagerActivity.java",
    "content": "package in.srain.cube.views.ptr.demo.ui.viewpager;\n\nimport android.os.Bundle;\nimport android.support.v4.app.Fragment;\nimport android.support.v4.app.FragmentManager;\nimport android.support.v4.app.FragmentStatePagerAdapter;\nimport android.support.v4.view.ViewPager;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.AbsListView;\nimport android.widget.TextView;\nimport in.srain.cube.mints.base.TitleBaseActivity;\nimport in.srain.cube.request.JsonData;\nimport in.srain.cube.request.RequestFinishHandler;\nimport in.srain.cube.util.LocalDisplay;\nimport in.srain.cube.views.pager.TabPageIndicator;\nimport in.srain.cube.views.ptr.PtrClassicFrameLayout;\nimport in.srain.cube.views.ptr.PtrFrameLayout;\nimport in.srain.cube.views.ptr.PtrHandler;\nimport in.srain.cube.views.ptr.demo.R;\nimport in.srain.cube.views.ptr.demo.data.DemoRequestData;\n\nimport java.util.ArrayList;\n\npublic class ViewPagerActivity extends TitleBaseActivity {\n\n    private TabPageIndicator mCatTabPageIndicator;\n    private ViewPager mFragmentViewPager;\n    private FragmentViewPagerAdapter mPagerAdapter;\n    private PtrFrameLayout mPtrFrame;\n\n    @Override\n    public void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setHeaderTitle(R.string.ptr_demo_block_with_view_pager);\n        setContentView(R.layout.activity_view_pager);\n        initCateViews();\n    }\n\n    private void initCateViews() {\n\n        int startIndex = 0;\n\n        mCatTabPageIndicator = (TabPageIndicator) findViewById(R.id.view_pager_tab_indicator);\n        mFragmentViewPager = (ViewPager) this.findViewById(R.id.view_pager_view_pager);\n        ArrayList<ViewPagerFragment> list = new ArrayList<ViewPagerFragment>();\n\n        for (int i = 1; i <= 8; i++) {\n            list.add(ViewPagerFragment.create(i));\n        }\n        mPagerAdapter = new FragmentViewPagerAdapter(getSupportFragmentManager(), list);\n        mFragmentViewPager.setAdapter(mPagerAdapter);\n\n        mCatTabPageIndicator.setViewHolderCreator(new TabPageIndicator.ViewHolderCreator() {\n            @Override\n            public TabPageIndicator.ViewHolderBase createViewHolder() {\n                return new HomeCatItemViewHolder();\n            }\n        });\n        mCatTabPageIndicator.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {\n\n            @Override\n            public void onPageSelected(int i) {\n                switchTo(i);\n            }\n        });\n        mCatTabPageIndicator.setViewPager(mFragmentViewPager);\n\n        mPtrFrame = (PtrClassicFrameLayout) findViewById(R.id.view_pager_ptr_frame);\n        mPtrFrame.disableWhenHorizontalMove(true);\n        mPtrFrame.setPtrHandler(new PtrHandler() {\n            @Override\n            public boolean checkCanDoRefresh(PtrFrameLayout frame, View content, View header) {\n                return mPagerAdapter.checkCanDoRefresh();\n            }\n\n            @Override\n            public void onRefreshBegin(PtrFrameLayout frame) {\n                mPagerAdapter.updateData();\n            }\n        });\n        mFragmentViewPager.setCurrentItem(startIndex);\n    }\n\n    @Override\n    protected void onResume() {\n        super.onResume();\n        mCatTabPageIndicator.moveToItem(mFragmentViewPager.getCurrentItem());\n    }\n\n    private void switchTo(int position) {\n        mPagerAdapter.switchTO(position);\n    }\n\n    private class FragmentViewPagerAdapter extends FragmentStatePagerAdapter {\n\n        private final ArrayList<ViewPagerFragment> mViewPagerFragments;\n        private ViewPagerFragment mCurrentFragment;\n\n        public FragmentViewPagerAdapter(FragmentManager fm, ArrayList<ViewPagerFragment> list) {\n            super(fm);\n            mViewPagerFragments = list;\n        }\n\n        @Override\n        public Fragment getItem(int position) {\n            return mViewPagerFragments.get(position);\n        }\n\n        @Override\n        public void destroyItem(ViewGroup container, int position, Object object) {\n        }\n\n        protected void updateData() {\n            final ViewPagerFragment fragment = mCurrentFragment;\n            DemoRequestData.getImageList(new RequestFinishHandler<JsonData>() {\n                @Override\n                public void onRequestFinish(final JsonData data) {\n                    if (fragment == mCurrentFragment) {\n                        fragment.update(data);\n                        mPtrFrame.refreshComplete();\n                    }\n                }\n            });\n        }\n\n        @Override\n        public int getCount() {\n            return mViewPagerFragments.size();\n        }\n\n        public void switchTO(final int position) {\n            int len = mViewPagerFragments.size();\n            for (int i = 0; i < len; i++) {\n                ViewPagerFragment fragment = mViewPagerFragments.get(i);\n                if (i == position) {\n                    mCurrentFragment = fragment;\n                    fragment.show();\n                } else {\n                    fragment.hide();\n                }\n            }\n        }\n\n        public boolean checkCanDoRefresh() {\n            if (mCurrentFragment == null) {\n                return true;\n            }\n            return mCurrentFragment.checkCanDoRefresh();\n        }\n    }\n\n    private class HomeCatItemViewHolder extends TabPageIndicator.ViewHolderBase {\n\n        private TextView mNameView;\n        private View mTagView;\n\n        @Override\n        public View createView(LayoutInflater layoutInflater, int position) {\n            View view = layoutInflater.inflate(R.layout.view_pager_indicator_item, null);\n            view.setLayoutParams(new AbsListView.LayoutParams(LocalDisplay.dp2px(40), -1));\n            mNameView = (TextView) view.findViewById(R.id.view_pager_indicator_name);\n            mTagView = view.findViewById(R.id.view_pager_indicator_tab_current);\n            return view;\n        }\n\n        @Override\n        public void updateView(int position, boolean isCurrent) {\n            mNameView.setText(position + \"\");\n            if (isCurrent) {\n                mTagView.setVisibility(View.VISIBLE);\n            } else {\n                mTagView.setVisibility(View.INVISIBLE);\n            }\n        }\n    }\n}"
  },
  {
    "path": "ptr-demo/src/in/srain/cube/views/ptr/demo/ui/viewpager/ViewPagerFragment.java",
    "content": "package in.srain.cube.views.ptr.demo.ui.viewpager;\n\nimport android.os.Bundle;\nimport android.text.TextUtils;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.AdapterView;\nimport android.widget.ListView;\nimport android.widget.TextView;\nimport in.srain.cube.app.CubeFragment;\nimport in.srain.cube.image.ImageLoader;\nimport in.srain.cube.image.ImageLoaderFactory;\nimport in.srain.cube.request.JsonData;\nimport in.srain.cube.util.CLog;\nimport in.srain.cube.views.list.ListViewDataAdapter;\nimport in.srain.cube.views.ptr.demo.R;\nimport in.srain.cube.views.ptr.demo.ui.MaterialStyleFragment;\n\npublic class ViewPagerFragment extends CubeFragment {\n\n    private int mPage;\n    private ListView mListView;\n    private ImageLoader mImageLoader;\n    private ListViewDataAdapter<JsonData> mAdapter;\n\n    public static ViewPagerFragment create(int page) {\n        ViewPagerFragment fragment = new ViewPagerFragment();\n        fragment.mPage = page;\n        return fragment;\n    }\n\n    @Override\n    protected View createView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {\n        return null;\n    }\n\n    @Override\n    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {\n        mImageLoader = ImageLoaderFactory.create(getContext()).tryToAttachToContainer(getContext());\n        View view = inflater.inflate(R.layout.fragment_view_pager, null);\n        mListView = (ListView) view.findViewById(R.id.view_pager_list_view);\n\n        View headerView = inflater.inflate(R.layout.view_pager_fragment_list_view_header, null);\n        TextView mHeaderTextView = (TextView) headerView.findViewById(R.id.view_pager_fragment_list_view_header_title);\n        mHeaderTextView.setBackgroundColor(0xff4d90fe * mPage / 30);\n        mHeaderTextView.setText(\"Page: \" + mPage);\n\n        mListView.addHeaderView(headerView);\n        mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {\n            @Override\n            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {\n                if (position >= 0) {\n\t\t\t\t\tJsonData js = mAdapter.getItem(position);\n                    final String url = js!=null?js.optString(\"pic\"):null;\n                    if (!TextUtils.isEmpty(url)) {\n                        getContext().pushFragmentToBackStack(MaterialStyleFragment.class, url);\n                    }\n                }\n            }\n        });\n\n        mAdapter = new ListViewDataAdapter<JsonData>();\n        mAdapter.setViewHolderClass(this, ImageListViewHolder.class, mImageLoader);\n        mListView.setAdapter(mAdapter);\n        return view;\n    }\n\n    public void update(JsonData data) {\n        mAdapter.getDataList().clear();\n        mAdapter.getDataList().addAll(data.optJson(\"data\").optJson(\"list\").toArrayList());\n        mAdapter.notifyDataSetChanged();\n    }\n\n    public void show() {\n\n    }\n\n    public void hide() {\n\n    }\n\n    public boolean checkCanDoRefresh() {\n        if (mAdapter.getCount() == 0 || mListView == null) {\n            return true;\n        }\n        CLog.d(\"test\", \"checkCanDoRefresh: %s %s\", mListView.getFirstVisiblePosition(), mListView.getChildAt(0).getTop());\n        return mListView.getFirstVisiblePosition() == 0 && mListView.getChildAt(0).getTop() == 0;\n    }\n\n}\n"
  },
  {
    "path": "ptr-lib/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    package=\"in.srain.cube.views.ptr\"\n    android:versionCode=\"1\"\n    android:versionName=\"1.0\">\n\n    <uses-sdk\n        android:minSdkVersion=\"8\"\n        android:targetSdkVersion=\"16\" />\n\n    <application />\n</manifest>\n"
  },
  {
    "path": "ptr-lib/build.gradle",
    "content": "apply plugin: 'com.android.library'\n\nandroid {\n    compileSdkVersion Integer.parseInt(project.ANDROID_BUILD_SDK_VERSION)\n    buildToolsVersion project.ANDROID_BUILD_TOOLS_VERSION\n\n    defaultConfig {\n        minSdkVersion 8\n        targetSdkVersion Integer.parseInt(project.ANDROID_BUILD_TARGET_SDK_VERSION)\n    }\n\n    lintOptions {\n        abortOnError false\n    }\n\n    sourceSets {\n        main {\n            manifest.srcFile 'AndroidManifest.xml'\n            java.srcDirs = ['src']\n            resources.srcDirs = ['resources']\n            res.srcDirs = ['res']\n            assets.srcDirs = ['assets']\n            // aidl.srcDirs = ['src']\n            // renderscript.srcDirs = ['src']\n        }\n\n        androidTest.setRoot('tests')\n    }\n}\n\ndependencies {\n}\napply from: './gradle-mvn-push.gradle'\n"
  },
  {
    "path": "ptr-lib/checkstyle.xml",
    "content": "<?xml version=\"1.0\"?>\n<!DOCTYPE module PUBLIC\n    \"-//Puppy Crawl//DTD Check Configuration 1.2//EN\"\n    \"http://www.puppycrawl.com/dtds/configuration_1_2.dtd\">\n\n<module name=\"Checker\">\n    <!--module name=\"NewlineAtEndOfFile\"/-->\n    <module name=\"FileLength\"/>\n    <module name=\"FileTabCharacter\"/>\n\n    <!-- Trailing spaces -->\n    <module name=\"RegexpSingleline\">\n        <property name=\"format\" value=\"\\s+$\"/>\n        <property name=\"message\" value=\"Line has trailing spaces.\"/>\n    </module>\n\n    <module name=\"TreeWalker\">\n        <property name=\"cacheFile\" value=\"${checkstyle.cache.file}\"/>\n\n        <!-- Checks for Javadoc comments.                     -->\n        <!-- See http://checkstyle.sf.net/config_javadoc.html -->\n        <!--module name=\"JavadocMethod\"/-->\n        <!--module name=\"JavadocType\"/-->\n        <!--module name=\"JavadocVariable\"/-->\n        <!--module name=\"JavadocStyle\"/-->\n\n\n        <!-- Checks for Naming Conventions.                  -->\n        <!-- See http://checkstyle.sf.net/config_naming.html -->\n        <!--module name=\"ConstantName\"/-->\n        <!--module name=\"LocalFinalVariableName\"/-->\n        <!--module name=\"LocalVariableName\"/-->\n        <module name=\"MemberName\"/>\n        <!--module name=\"MethodName\"/-->\n        <module name=\"PackageName\"/>\n        <!--module name=\"ParameterName\"/-->\n        <!--module name=\"StaticVariableName\"/-->\n        <!--module name=\"TypeName\"/-->\n\n\n        <!-- Checks for imports                              -->\n        <!-- See http://checkstyle.sf.net/config_import.html -->\n        <module name=\"AvoidStarImport\"/>\n        <module name=\"IllegalImport\"/> <!-- defaults to sun.* packages -->\n        <module name=\"RedundantImport\"/>\n        <module name=\"UnusedImports\"/>\n\n\n        <!-- Checks for Size Violations.                    -->\n        <!-- See http://checkstyle.sf.net/config_sizes.html -->\n        <!--module name=\"LineLength\"/-->\n        <!--module name=\"MethodLength\"/-->\n        <!--module name=\"ParameterNumber\"/-->\n\n\n        <!-- Checks for whitespace                               -->\n        <!-- See http://checkstyle.sf.net/config_whitespace.html -->\n        <!--module name=\"EmptyForIteratorPad\"/-->\n        <!--module name=\"MethodParamPad\"/-->\n        <!--module name=\"NoWhitespaceAfter\"/-->\n        <!--module name=\"NoWhitespaceBefore\"/-->\n        <!--module name=\"OperatorWrap\"/-->\n        <!--module name=\"ParenPad\"/-->\n        <!--module name=\"TypecastParenPad\"/-->\n        <!--module name=\"WhitespaceAfter\"/-->\n        <!--module name=\"WhitespaceAround\"/-->\n\n\n        <!-- Modifier Checks                                    -->\n        <!-- See http://checkstyle.sf.net/config_modifiers.html -->\n        <!--module name=\"ModifierOrder\"/-->\n        <!--module name=\"RedundantModifier\"/-->\n\n\n        <!-- Checks for blocks. You know, those {}'s         -->\n        <!-- See http://checkstyle.sf.net/config_blocks.html -->\n        <!--module name=\"AvoidNestedBlocks\"/-->\n        <!--module name=\"EmptyBlock\"/-->\n        <!--module name=\"LeftCurly\"/-->\n        <!--module name=\"NeedBraces\"/-->\n        <!--module name=\"RightCurly\"/-->\n\n\n        <!-- Checks for common coding problems               -->\n        <!-- See http://checkstyle.sf.net/config_coding.html -->\n        <!--module name=\"AvoidInlineConditionals\"/-->\n        <!--module name=\"EmptyStatement\"/-->\n        <!--module name=\"EqualsHashCode\"/-->\n        <!--module name=\"HiddenField\"/-->\n        <!--module name=\"IllegalInstantiation\"/-->\n        <!--module name=\"InnerAssignment\"/-->\n        <!--module name=\"MagicNumber\"/-->\n        <!--module name=\"MissingSwitchDefault\"/-->\n        <module name=\"RedundantThrows\"/>\n        <!--module name=\"SimplifyBooleanExpression\"/-->\n        <!--module name=\"SimplifyBooleanReturn\"/-->\n        <module name=\"StringLiteralEquality\"/>\n        <module name=\"CovariantEquals\"/>\n        <!--module name=\"NoClone\"/-->\n        <module name=\"NoFinalizer\"/>\n        <module name=\"PackageDeclaration\"/>\n        <!--module name=\"FallThrough\"/-->\n\n        <!-- Checks for class design                         -->\n        <!-- See http://checkstyle.sf.net/config_design.html -->\n        <!--module name=\"DesignForExtension\"/-->\n        <!--module name=\"FinalClass\"/-->\n        <!--module name=\"HideUtilityClassConstructor\"/-->\n        <!--module name=\"InterfaceIsType\"/-->\n        <!--module name=\"VisibilityModifier\"/-->\n\n\n        <!-- Miscellaneous other checks.                   -->\n        <!-- See http://checkstyle.sf.net/config_misc.html -->\n        <!--module name=\"ArrayTypeStyle\"/-->\n        <!--module name=\"FinalParameters\"/-->\n        <!--module name=\"TodoComment\"/-->\n        <module name=\"UpperEll\"/>\n    </module>\n</module>\n"
  },
  {
    "path": "ptr-lib/gradle-mvn-push.gradle",
    "content": "apply plugin: 'maven'\napply plugin: 'signing'\n\ndef isReleaseBuild() {\n    return VERSION_NAME.contains(\"SNAPSHOT\") == false\n}\n\ndef getReleaseRepositoryUrl() {\n    return hasProperty('RELEASE_REPOSITORY_URL') ? RELEASE_REPOSITORY_URL\n            : \"https://oss.sonatype.org/service/local/staging/deploy/maven2/\"\n}\n\ndef getSnapshotRepositoryUrl() {\n    return hasProperty('SNAPSHOT_REPOSITORY_URL') ? SNAPSHOT_REPOSITORY_URL\n            : \"https://oss.sonatype.org/content/repositories/snapshots/\"\n}\n\ndef getRepositoryUsername() {\n    return hasProperty('OSS_USERNAME') ? OSS_USERNAME : ''\n}\n\ndef getRepositoryPassword() {\n    return hasProperty('OSS_PWD') ? OSS_PWD : ''\n}\n\nafterEvaluate { project ->\n    uploadArchives {\n        repositories {\n            mavenDeployer {\n                beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) }\n\n                pom.groupId = POM_GROUP\n                pom.artifactId = POM_ARTIFACT_ID\n                pom.version = VERSION_NAME\n\n                repository(url: getReleaseRepositoryUrl()) {\n                    authentication(userName: getRepositoryUsername(), password: getRepositoryPassword())\n                }\n                snapshotRepository(url: getSnapshotRepositoryUrl()) {\n                    authentication(userName: getRepositoryUsername(), password: getRepositoryPassword())\n                }\n\n                pom.project {\n                    name POM_NAME\n                    packaging POM_PACKAGING\n                    description POM_DESCRIPTION\n                    url POM_URL\n\n                    scm {\n                        url POM_SCM_URL\n                        connection POM_SCM_CONNECTION\n                        developerConnection POM_SCM_DEV_CONNECTION\n                    }\n\n                    licenses {\n                        license {\n                            name POM_LICENCE_NAME\n                            url POM_LICENCE_URL\n                            distribution POM_LICENCE_DIST\n                        }\n                    }\n\n                    issueManagement {\n                        system POM_ISSUE_SYSTEM\n                        url POM_ISSUE_URL\n                    }\n\n                    developers {\n                        developer {\n                            id POM_DEVELOPER_ID\n                            name POM_DEVELOPER_NAME\n                        }\n                    }\n                }\n            }\n        }\n    }\n\n    signing {\n        required { isReleaseBuild() && gradle.taskGraph.hasTask(\"uploadArchives\") }\n        sign configurations.archives\n    }\n\n    task apklib(type: Zip) {\n\n        appendix = extension = 'apklib'\n\n        from 'AndroidManifest.xml'\n        into('res') {\n            from 'res'\n        }\n        into('src') {\n            from 'src'\n        }\n    }\n\n    task androidJavadocs(type: Javadoc) {\n        source = android.sourceSets.main.java.srcDirs\n        classpath += project.files(android.getBootClasspath().join(File.pathSeparator))\n    }\n\n    task androidJavadocsJar(type: Jar, dependsOn: androidJavadocs) {\n        classifier = 'javadoc'\n        from androidJavadocs.destinationDir\n    }\n\n    task androidSourcesJar(type: Jar) {\n        classifier = 'sources'\n        from android.sourceSets.main.java.srcDirs\n    }\n\n    artifacts {\n        archives androidSourcesJar\n        archives androidJavadocsJar\n        archives apklib\n    }\n}\n"
  },
  {
    "path": "ptr-lib/gradle.properties",
    "content": "VERSION_NAME=1.0.11\n\nPOM_GROUP=in.srain.cube\nPOM_ARTIFACT_ID=ultra-ptr\nPOM_PACKAGING=aar\n\nPOM_NAME=Android Ultra Pull to Refresh\nPOM_DESCRIPTION=Ultra Pull to Refresh Solution.\n\nPOM_URL=https://github.com/liaohuqiu/android-Ultra-Pull-To-Refresh\nPOM_SCM_URL=https://github.com/liaohuqiu/android-Ultra-Pull-To-Refresh\nPOM_SCM_CONNECTION=scm:https://github.com/liaohuqiu/android-Ultra-Pull-To-Refresh.git\nPOM_SCM_DEV_CONNECTION=scm:https://github.com/liaohuqiu/android-Ultra-Pull-To-Refresh.git\n\nPOM_LICENCE_NAME=MIT\nPOM_LICENCE_URL=http://opensource.org/licenses/MIT\nPOM_LICENCE_DIST=repo\nPOM_DEVELOPER_ID=liaohuqiu\nPOM_DEVELOPER_NAME=liaohuqiu\n\nPOM_ISSUE_SYSTEM=GitHub Issues\nPOM_ISSUE_URL=https://github.com/liaohuqiu/android-Ultra-Pull-To-Refresh/issues\n"
  },
  {
    "path": "ptr-lib/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n    xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n\n    <parent>\n        <groupId>in.srain</groupId>\n        <artifactId>cube-parent-for-oss</artifactId>\n        <version>1.0.1</version>\n    </parent>\n\n    <groupId>in.srain.cube</groupId>\n    <artifactId>ultra-ptr</artifactId>\n    <packaging>aar</packaging>\n    <name>Ultra Pull to Refresh</name>\n    <version>1.0.11</version>\n\n    <description>Ultra Pull to Refresh in Android</description>\n    <url>https://github.com/liaohuqiu/android-Ultra-Pull-To-Refresh</url>\n    <inceptionYear>2014</inceptionYear>\n\n    <scm>\n        <url>https://github.com/liaohuqiu/android-Ultra-Pull-To-Refresh</url>\n        <connection>scm:git:git@github.com:liaohuqiu/android-Ultra-Pull-To-Refresh.git</connection>\n        <developerConnection>scm:git:git@github.com:liaohuqiu/android-Ultra-Pull-To-Refresh.git\n        </developerConnection>\n    </scm>\n\n    <developers>\n        <developer>\n            <name>Huqiu Liao</name>\n            <email>liaohuqiu@gmail.com</email>\n            <id>liaohuqiu</id>\n            <url>http://www.liaohuqiu.net</url>\n            <timezone>+8</timezone>\n            <roles>\n                <role>developer</role>\n            </roles>\n        </developer>\n    </developers>\n\n    <licenses>\n        <license>\n            <name>MIT</name>\n            <url>http://opensource.org/licenses/MIT</url>\n            <distribution>repo</distribution>\n        </license>\n    </licenses>\n\n    <organization>\n        <name>Huqiu Liao</name>\n        <url>http://www.liaohuqiu.net</url>\n    </organization>\n\n    <issueManagement>\n        <system>GitHub Issues</system>\n        <url>https://github.com/liaohuqiu/android-Ultra-Pull-To-Refresh/issues</url>\n    </issueManagement>\n\n    <dependencies>\n        <dependency>\n            <groupId>com.google.android</groupId>\n            <artifactId>android</artifactId>\n            <version>4.1.1.4</version>\n            <scope>provided</scope>\n        </dependency>\n    </dependencies>\n\n    <properties>\n        <android.maven.plugin.version>3.8.2</android.maven.plugin.version>\n        <android.compile.api_level>19</android.compile.api_level>\n    </properties>\n\n    <build>\n        <finalName>${project.artifactId}</finalName>\n        <sourceDirectory>src/</sourceDirectory>\n        <plugins>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n                <configuration>\n                    <source>1.6</source>\n                    <target>1.6</target>\n                    <excludes>\n                        <exclude>target/generated-sources/r/*</exclude>\n                    </excludes>\n                </configuration>\n            </plugin>\n            <!-- compile plugin -->\n            <plugin>\n                <groupId>com.jayway.maven.plugins.android.generation2</groupId>\n                <artifactId>android-maven-plugin</artifactId>\n                <extensions>true</extensions>\n                <version>${android.maven.plugin.version}</version>\n                <configuration>\n                    <sdk>\n                        <platform>${android.compile.api_level}</platform>\n                    </sdk>\n                    <sign>\n                        <debug>false</debug>\n                    </sign>\n                </configuration>\n            </plugin>\n        </plugins>\n    </build>\n</project>\n"
  },
  {
    "path": "ptr-lib/res/layout/cube_ptr_classic_default_header.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\">\n\n    <RelativeLayout\n        android:layout_width=\"fill_parent\"\n        android:layout_height=\"60dp\">\n\n        <LinearLayout\n            android:id=\"@+id/ptr_classic_header_rotate_view_header_text\"\n            android:layout_width=\"150dp\"\n            android:layout_height=\"wrap_content\"\n            android:layout_centerInParent=\"true\"\n            android:gravity=\"center\"\n            android:orientation=\"vertical\">\n\n            <TextView\n                android:id=\"@+id/ptr_classic_header_rotate_view_header_title\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:textColor=\"#666666\"\n                android:textSize=\"12sp\" />\n\n            <TextView\n                android:id=\"@+id/ptr_classic_header_rotate_view_header_last_update\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_marginTop=\"2dp\"\n                android:textColor=\"#999999\"\n                android:textSize=\"10sp\" />\n        </LinearLayout>\n\n        <FrameLayout\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_centerVertical=\"true\"\n            android:layout_marginRight=\"10dp\"\n            android:layout_toLeftOf=\"@+id/ptr_classic_header_rotate_view_header_text\">\n\n            <ImageView\n                android:id=\"@+id/ptr_classic_header_rotate_view\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_gravity=\"center\"\n                android:src=\"@drawable/ptr_rotate_arrow\" />\n\n            <ProgressBar\n                android:id=\"@+id/ptr_classic_header_rotate_view_progressbar\"\n                style=\"@android:style/Widget.ProgressBar.Small\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_gravity=\"center\" />\n        </FrameLayout>\n    </RelativeLayout>\n\n</LinearLayout>\n"
  },
  {
    "path": "ptr-lib/res/layout/cube_ptr_simple_loading.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<ProgressBar\n    style=\"@android:style/Widget.ProgressBar.Small\"\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"wrap_content\"\n    android:layout_height=\"wrap_content\"\n    android:layout_gravity=\"center\" />\n\n"
  },
  {
    "path": "ptr-lib/res/values/cube_ptr_attrs.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n\n    <declare-styleable name=\"PtrFrameLayout\">\n        <!-- Optional. If you put header and content in xml, you can you these to specify them. -->\n        <attr name=\"ptr_header\" format=\"reference\" />\n        <attr name=\"ptr_content\" format=\"reference\" />\n\n        <!-- the resistance when you are moving the frame -->\n        <attr name=\"ptr_resistance\" format=\"float\" />\n\n        <!-- the ration of the height of the header to trigger refresh -->\n        <attr name=\"ptr_ratio_of_header_height_to_refresh\" format=\"float\" />\n\n        <attr name=\"ptr_duration_to_close\" format=\"integer\" />\n        <attr name=\"ptr_duration_to_close_header\" format=\"integer\" />\n\n        <!-- pull to refresh, otherwise release to refresh, default is release to refresh -->\n        <attr name=\"ptr_pull_to_fresh\" format=\"boolean\" />\n\n        <!-- keep header when refreshing-->\n        <attr name=\"ptr_keep_header_when_refresh\" format=\"boolean\" />\n    </declare-styleable>\n\n    <declare-styleable name=\"PtrClassicHeader\">\n        <attr name=\"ptr_rotate_ani_time\" format=\"integer\" />\n    </declare-styleable>\n</resources>"
  },
  {
    "path": "ptr-lib/res/values/cube_ptr_string.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n\n    <string name=\"cube_ptr_pull_down\">Pull Down</string>\n    <string name=\"cube_ptr_pull_down_to_refresh\">Pull Down to Refresh</string>\n    <string name=\"cube_ptr_release_to_refresh\">Release To Refresh</string>\n    <string name=\"cube_ptr_refreshing\">Updating...</string>\n    <string name=\"cube_ptr_refresh_complete\">Updated.</string>\n\n    <string name=\"cube_ptr_last_update\">last update:&#160;</string>\n    <string name=\"cube_ptr_seconds_ago\">&#160;seconds ago</string>\n    <string name=\"cube_ptr_minutes_ago\">&#160;minutes ago</string>\n    <string name=\"cube_ptr_hours_ago\">&#160;hours ago</string>\n\n</resources>"
  },
  {
    "path": "ptr-lib/res/values-zh/cube_ptr_string.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n\n    <string name=\"cube_ptr_pull_down\">下拉</string>\n    <string name=\"cube_ptr_pull_down_to_refresh\">下拉刷新</string>\n    <string name=\"cube_ptr_release_to_refresh\">释放刷新</string>\n    <string name=\"cube_ptr_refreshing\">加载中...</string>\n    <string name=\"cube_ptr_refresh_complete\">更新完成.</string>\n\n    <string name=\"cube_ptr_last_update\">上次更新:&#160;</string>\n    <string name=\"cube_ptr_seconds_ago\">&#160;秒之前</string>\n    <string name=\"cube_ptr_minutes_ago\">&#160;分钟之前</string>\n    <string name=\"cube_ptr_hours_ago\">&#160;小时之前</string>\n\n</resources>"
  },
  {
    "path": "ptr-lib/src/in/srain/cube/views/ptr/PtrClassicDefaultHeader.java",
    "content": "package in.srain.cube.views.ptr;\n\nimport android.content.Context;\nimport android.content.SharedPreferences;\nimport android.content.res.TypedArray;\nimport android.text.TextUtils;\nimport android.util.AttributeSet;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.animation.LinearInterpolator;\nimport android.view.animation.RotateAnimation;\nimport android.widget.FrameLayout;\nimport android.widget.TextView;\nimport in.srain.cube.views.ptr.indicator.PtrIndicator;\n\nimport java.text.SimpleDateFormat;\nimport java.util.Date;\n\npublic class PtrClassicDefaultHeader extends FrameLayout implements PtrUIHandler {\n\n    private final static String KEY_SharedPreferences = \"cube_ptr_classic_last_update\";\n    private static SimpleDateFormat sDataFormat = new SimpleDateFormat(\"yyyy-MM-dd HH:mm:ss\");\n    private int mRotateAniTime = 150;\n    private RotateAnimation mFlipAnimation;\n    private RotateAnimation mReverseFlipAnimation;\n    private TextView mTitleTextView;\n    private View mRotateView;\n    private View mProgressBar;\n    private long mLastUpdateTime = -1;\n    private TextView mLastUpdateTextView;\n    private String mLastUpdateTimeKey;\n    private boolean mShouldShowLastUpdate;\n\n    private LastUpdateTimeUpdater mLastUpdateTimeUpdater = new LastUpdateTimeUpdater();\n\n    public PtrClassicDefaultHeader(Context context) {\n        super(context);\n        initViews(null);\n    }\n\n    public PtrClassicDefaultHeader(Context context, AttributeSet attrs) {\n        super(context, attrs);\n        initViews(attrs);\n    }\n\n    public PtrClassicDefaultHeader(Context context, AttributeSet attrs, int defStyle) {\n        super(context, attrs, defStyle);\n        initViews(attrs);\n    }\n\n    protected void initViews(AttributeSet attrs) {\n        TypedArray arr = getContext().obtainStyledAttributes(attrs, R.styleable.PtrClassicHeader, 0, 0);\n        if (arr != null) {\n            mRotateAniTime = arr.getInt(R.styleable.PtrClassicHeader_ptr_rotate_ani_time, mRotateAniTime);\n        }\n        buildAnimation();\n        View header = LayoutInflater.from(getContext()).inflate(R.layout.cube_ptr_classic_default_header, this);\n\n        mRotateView = header.findViewById(R.id.ptr_classic_header_rotate_view);\n\n        mTitleTextView = (TextView) header.findViewById(R.id.ptr_classic_header_rotate_view_header_title);\n        mLastUpdateTextView = (TextView) header.findViewById(R.id.ptr_classic_header_rotate_view_header_last_update);\n        mProgressBar = header.findViewById(R.id.ptr_classic_header_rotate_view_progressbar);\n\n        resetView();\n    }\n\n    @Override\n    protected void onDetachedFromWindow() {\n        super.onDetachedFromWindow();\n        if (mLastUpdateTimeUpdater != null) {\n            mLastUpdateTimeUpdater.stop();\n        }\n    }\n\n    public void setRotateAniTime(int time) {\n        if (time == mRotateAniTime || time == 0) {\n            return;\n        }\n        mRotateAniTime = time;\n        buildAnimation();\n    }\n\n    /**\n     * Specify the last update time by this key string\n     *\n     * @param key\n     */\n    public void setLastUpdateTimeKey(String key) {\n        if (TextUtils.isEmpty(key)) {\n            return;\n        }\n        mLastUpdateTimeKey = key;\n    }\n\n    /**\n     * Using an object to specify the last update time.\n     *\n     * @param object\n     */\n    public void setLastUpdateTimeRelateObject(Object object) {\n        setLastUpdateTimeKey(object.getClass().getName());\n    }\n\n    private void buildAnimation() {\n        mFlipAnimation = new RotateAnimation(0, -180, RotateAnimation.RELATIVE_TO_SELF, 0.5f, RotateAnimation.RELATIVE_TO_SELF, 0.5f);\n        mFlipAnimation.setInterpolator(new LinearInterpolator());\n        mFlipAnimation.setDuration(mRotateAniTime);\n        mFlipAnimation.setFillAfter(true);\n\n        mReverseFlipAnimation = new RotateAnimation(-180, 0, RotateAnimation.RELATIVE_TO_SELF, 0.5f, RotateAnimation.RELATIVE_TO_SELF, 0.5f);\n        mReverseFlipAnimation.setInterpolator(new LinearInterpolator());\n        mReverseFlipAnimation.setDuration(mRotateAniTime);\n        mReverseFlipAnimation.setFillAfter(true);\n    }\n\n    private void resetView() {\n        hideRotateView();\n        mProgressBar.setVisibility(INVISIBLE);\n    }\n\n    private void hideRotateView() {\n        mRotateView.clearAnimation();\n        mRotateView.setVisibility(INVISIBLE);\n    }\n\n    @Override\n    public void onUIReset(PtrFrameLayout frame) {\n        resetView();\n        mShouldShowLastUpdate = true;\n        tryUpdateLastUpdateTime();\n    }\n\n    @Override\n    public void onUIRefreshPrepare(PtrFrameLayout frame) {\n\n        mShouldShowLastUpdate = true;\n        tryUpdateLastUpdateTime();\n        mLastUpdateTimeUpdater.start();\n\n        mProgressBar.setVisibility(INVISIBLE);\n\n        mRotateView.setVisibility(VISIBLE);\n        mTitleTextView.setVisibility(VISIBLE);\n        if (frame.isPullToRefresh()) {\n            mTitleTextView.setText(getResources().getString(R.string.cube_ptr_pull_down_to_refresh));\n        } else {\n            mTitleTextView.setText(getResources().getString(R.string.cube_ptr_pull_down));\n        }\n    }\n\n    @Override\n    public void onUIRefreshBegin(PtrFrameLayout frame) {\n        mShouldShowLastUpdate = false;\n        hideRotateView();\n        mProgressBar.setVisibility(VISIBLE);\n        mTitleTextView.setVisibility(VISIBLE);\n        mTitleTextView.setText(R.string.cube_ptr_refreshing);\n\n        tryUpdateLastUpdateTime();\n        mLastUpdateTimeUpdater.stop();\n    }\n\n    @Override\n    public void onUIRefreshComplete(PtrFrameLayout frame) {\n\n        hideRotateView();\n        mProgressBar.setVisibility(INVISIBLE);\n\n        mTitleTextView.setVisibility(VISIBLE);\n        mTitleTextView.setText(getResources().getString(R.string.cube_ptr_refresh_complete));\n\n        // update last update time\n        SharedPreferences sharedPreferences = getContext().getSharedPreferences(KEY_SharedPreferences, 0);\n        if (!TextUtils.isEmpty(mLastUpdateTimeKey)) {\n            mLastUpdateTime = new Date().getTime();\n            sharedPreferences.edit().putLong(mLastUpdateTimeKey, mLastUpdateTime).commit();\n        }\n    }\n\n    private void tryUpdateLastUpdateTime() {\n        if (TextUtils.isEmpty(mLastUpdateTimeKey) || !mShouldShowLastUpdate) {\n            mLastUpdateTextView.setVisibility(GONE);\n        } else {\n            String time = getLastUpdateTime();\n            if (TextUtils.isEmpty(time)) {\n                mLastUpdateTextView.setVisibility(GONE);\n            } else {\n                mLastUpdateTextView.setVisibility(VISIBLE);\n                mLastUpdateTextView.setText(time);\n            }\n        }\n    }\n\n    private String getLastUpdateTime() {\n\n        if (mLastUpdateTime == -1 && !TextUtils.isEmpty(mLastUpdateTimeKey)) {\n            mLastUpdateTime = getContext().getSharedPreferences(KEY_SharedPreferences, 0).getLong(mLastUpdateTimeKey, -1);\n        }\n        if (mLastUpdateTime == -1) {\n            return null;\n        }\n        long diffTime = new Date().getTime() - mLastUpdateTime;\n        int seconds = (int) (diffTime / 1000);\n        if (diffTime < 0) {\n            return null;\n        }\n        if (seconds <= 0) {\n            return null;\n        }\n        StringBuilder sb = new StringBuilder();\n        sb.append(getContext().getString(R.string.cube_ptr_last_update));\n\n        if (seconds < 60) {\n            sb.append(seconds + getContext().getString(R.string.cube_ptr_seconds_ago));\n        } else {\n            int minutes = (seconds / 60);\n            if (minutes > 60) {\n                int hours = minutes / 60;\n                if (hours > 24) {\n                    Date date = new Date(mLastUpdateTime);\n                    sb.append(sDataFormat.format(date));\n                } else {\n                    sb.append(hours + getContext().getString(R.string.cube_ptr_hours_ago));\n                }\n\n            } else {\n                sb.append(minutes + getContext().getString(R.string.cube_ptr_minutes_ago));\n            }\n        }\n        return sb.toString();\n    }\n\n    @Override\n    public void onUIPositionChange(PtrFrameLayout frame, boolean isUnderTouch, byte status, PtrIndicator ptrIndicator) {\n\n        final int mOffsetToRefresh = frame.getOffsetToRefresh();\n        final int currentPos = ptrIndicator.getCurrentPosY();\n        final int lastPos = ptrIndicator.getLastPosY();\n\n        if (currentPos < mOffsetToRefresh && lastPos >= mOffsetToRefresh) {\n            if (isUnderTouch && status == PtrFrameLayout.PTR_STATUS_PREPARE) {\n                crossRotateLineFromBottomUnderTouch(frame);\n                if (mRotateView != null) {\n                    mRotateView.clearAnimation();\n                    mRotateView.startAnimation(mReverseFlipAnimation);\n                }\n            }\n        } else if (currentPos > mOffsetToRefresh && lastPos <= mOffsetToRefresh) {\n            if (isUnderTouch && status == PtrFrameLayout.PTR_STATUS_PREPARE) {\n                crossRotateLineFromTopUnderTouch(frame);\n                if (mRotateView != null) {\n                    mRotateView.clearAnimation();\n                    mRotateView.startAnimation(mFlipAnimation);\n                }\n            }\n        }\n    }\n\n    private void crossRotateLineFromTopUnderTouch(PtrFrameLayout frame) {\n        if (!frame.isPullToRefresh()) {\n            mTitleTextView.setVisibility(VISIBLE);\n            mTitleTextView.setText(R.string.cube_ptr_release_to_refresh);\n        }\n    }\n\n    private void crossRotateLineFromBottomUnderTouch(PtrFrameLayout frame) {\n        mTitleTextView.setVisibility(VISIBLE);\n        if (frame.isPullToRefresh()) {\n            mTitleTextView.setText(getResources().getString(R.string.cube_ptr_pull_down_to_refresh));\n        } else {\n            mTitleTextView.setText(getResources().getString(R.string.cube_ptr_pull_down));\n        }\n    }\n\n    private class LastUpdateTimeUpdater implements Runnable {\n\n        private boolean mRunning = false;\n\n        private void start() {\n            if (TextUtils.isEmpty(mLastUpdateTimeKey)) {\n                return;\n            }\n            mRunning = true;\n            run();\n        }\n\n        private void stop() {\n            mRunning = false;\n            removeCallbacks(this);\n        }\n\n        @Override\n        public void run() {\n            tryUpdateLastUpdateTime();\n            if (mRunning) {\n                postDelayed(this, 1000);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "ptr-lib/src/in/srain/cube/views/ptr/PtrClassicFrameLayout.java",
    "content": "package in.srain.cube.views.ptr;\n\nimport android.content.Context;\nimport android.util.AttributeSet;\n\npublic class PtrClassicFrameLayout extends PtrFrameLayout {\n\n    private PtrClassicDefaultHeader mPtrClassicHeader;\n\n    public PtrClassicFrameLayout(Context context) {\n        super(context);\n        initViews();\n    }\n\n    public PtrClassicFrameLayout(Context context, AttributeSet attrs) {\n        super(context, attrs);\n        initViews();\n    }\n\n    public PtrClassicFrameLayout(Context context, AttributeSet attrs, int defStyle) {\n        super(context, attrs, defStyle);\n        initViews();\n    }\n\n    private void initViews() {\n        mPtrClassicHeader = new PtrClassicDefaultHeader(getContext());\n        setHeaderView(mPtrClassicHeader);\n        addPtrUIHandler(mPtrClassicHeader);\n    }\n\n    public PtrClassicDefaultHeader getHeader() {\n        return mPtrClassicHeader;\n    }\n\n    /**\n     * Specify the last update time by this key string\n     *\n     * @param key\n     */\n    public void setLastUpdateTimeKey(String key) {\n        if (mPtrClassicHeader != null) {\n            mPtrClassicHeader.setLastUpdateTimeKey(key);\n        }\n    }\n\n    /**\n     * Using an object to specify the last update time.\n     *\n     * @param object\n     */\n    public void setLastUpdateTimeRelateObject(Object object) {\n        if (mPtrClassicHeader != null) {\n            mPtrClassicHeader.setLastUpdateTimeRelateObject(object);\n        }\n    }\n}\n"
  },
  {
    "path": "ptr-lib/src/in/srain/cube/views/ptr/PtrDefaultHandler.java",
    "content": "package in.srain.cube.views.ptr;\n\nimport android.view.View;\nimport android.widget.AbsListView;\n\npublic abstract class PtrDefaultHandler implements PtrHandler {\n\n    public static boolean canChildScrollUp(View view) {\n        if (android.os.Build.VERSION.SDK_INT < 14) {\n            if (view instanceof AbsListView) {\n                final AbsListView absListView = (AbsListView) view;\n                return absListView.getChildCount() > 0\n                        && (absListView.getFirstVisiblePosition() > 0 || absListView.getChildAt(0)\n                        .getTop() < absListView.getPaddingTop());\n            } else {\n                return view.getScrollY() > 0;\n            }\n        } else {\n            return view.canScrollVertically(-1);\n        }\n    }\n\n    /**\n     * Default implement for check can perform pull to refresh\n     *\n     * @param frame\n     * @param content\n     * @param header\n     * @return\n     */\n    public static boolean checkContentCanBePulledDown(PtrFrameLayout frame, View content, View header) {\n        return !canChildScrollUp(content);\n    }\n\n    @Override\n    public boolean checkCanDoRefresh(PtrFrameLayout frame, View content, View header) {\n        return checkContentCanBePulledDown(frame, content, header);\n    }\n}"
  },
  {
    "path": "ptr-lib/src/in/srain/cube/views/ptr/PtrFrameLayout.java",
    "content": "package in.srain.cube.views.ptr;\n\nimport android.content.Context;\nimport android.content.res.TypedArray;\nimport android.util.AttributeSet;\nimport android.view.*;\nimport android.widget.Scroller;\nimport android.widget.TextView;\nimport in.srain.cube.views.ptr.indicator.PtrIndicator;\nimport in.srain.cube.views.ptr.util.PtrCLog;\n\n/**\n * This layout view for \"Pull to Refresh(Ptr)\" support all of the view, you can contain everything you want.\n * support: pull to refresh / release to refresh / auto refresh / keep header view while refreshing / hide header view while refreshing\n * It defines {@link in.srain.cube.views.ptr.PtrUIHandler}, which allows you customize the UI easily.\n */\npublic class PtrFrameLayout extends ViewGroup {\n\n    // status enum\n    public final static byte PTR_STATUS_INIT = 1;\n    private byte mStatus = PTR_STATUS_INIT;\n    public final static byte PTR_STATUS_PREPARE = 2;\n    public final static byte PTR_STATUS_LOADING = 3;\n    public final static byte PTR_STATUS_COMPLETE = 4;\n    private static final boolean DEBUG_LAYOUT = true;\n    public static boolean DEBUG = false;\n    private static int ID = 1;\n    protected final String LOG_TAG = \"ptr-frame-\" + ++ID;\n    // auto refresh status\n    private final static byte FLAG_AUTO_REFRESH_AT_ONCE = 0x01;\n    private final static byte FLAG_AUTO_REFRESH_BUT_LATER = 0x01 << 1;\n    private final static byte FLAG_ENABLE_NEXT_PTR_AT_ONCE = 0x01 << 2;\n    private final static byte FLAG_PIN_CONTENT = 0x01 << 3;\n    private final static byte MASK_AUTO_REFRESH = 0x03;\n    protected View mContent;\n    // optional config for define header and content in xml file\n    private int mHeaderId = 0;\n    private int mContainerId = 0;\n    // config\n    private int mDurationToClose = 200;\n    private int mDurationToCloseHeader = 1000;\n    private boolean mKeepHeaderWhenRefresh = true;\n    private boolean mPullToRefresh = false;\n    private View mHeaderView;\n    private PtrUIHandlerHolder mPtrUIHandlerHolder = PtrUIHandlerHolder.create();\n    private PtrHandler mPtrHandler;\n    // working parameters\n    private ScrollChecker mScrollChecker;\n    private int mPagingTouchSlop;\n    private int mHeaderHeight;\n    private boolean mDisableWhenHorizontalMove = false;\n    private int mFlag = 0x00;\n\n    // disable when detect moving horizontally\n    private boolean mPreventForHorizontal = false;\n\n    private MotionEvent mLastMoveEvent;\n\n    private PtrUIHandlerHook mRefreshCompleteHook;\n\n    private int mLoadingMinTime = 500;\n    private long mLoadingStartTime = 0;\n    private PtrIndicator mPtrIndicator;\n    private boolean mHasSendCancelEvent = false;\n    private Runnable mPerformRefreshCompleteDelay = new Runnable() {\n        @Override\n        public void run() {\n            performRefreshComplete();\n        }\n    };\n\n    public PtrFrameLayout(Context context) {\n        this(context, null);\n    }\n\n    public PtrFrameLayout(Context context, AttributeSet attrs) {\n        this(context, attrs, 0);\n    }\n\n    public PtrFrameLayout(Context context, AttributeSet attrs, int defStyle) {\n        super(context, attrs, defStyle);\n\n        mPtrIndicator = new PtrIndicator();\n\n        TypedArray arr = context.obtainStyledAttributes(attrs, R.styleable.PtrFrameLayout, 0, 0);\n        if (arr != null) {\n\n            mHeaderId = arr.getResourceId(R.styleable.PtrFrameLayout_ptr_header, mHeaderId);\n            mContainerId = arr.getResourceId(R.styleable.PtrFrameLayout_ptr_content, mContainerId);\n\n            mPtrIndicator.setResistance(\n                    arr.getFloat(R.styleable.PtrFrameLayout_ptr_resistance, mPtrIndicator.getResistance()));\n\n            mDurationToClose = arr.getInt(R.styleable.PtrFrameLayout_ptr_duration_to_close, mDurationToClose);\n            mDurationToCloseHeader = arr.getInt(R.styleable.PtrFrameLayout_ptr_duration_to_close_header, mDurationToCloseHeader);\n\n            float ratio = mPtrIndicator.getRatioOfHeaderToHeightRefresh();\n            ratio = arr.getFloat(R.styleable.PtrFrameLayout_ptr_ratio_of_header_height_to_refresh, ratio);\n            mPtrIndicator.setRatioOfHeaderHeightToRefresh(ratio);\n\n            mKeepHeaderWhenRefresh = arr.getBoolean(R.styleable.PtrFrameLayout_ptr_keep_header_when_refresh, mKeepHeaderWhenRefresh);\n\n            mPullToRefresh = arr.getBoolean(R.styleable.PtrFrameLayout_ptr_pull_to_fresh, mPullToRefresh);\n            arr.recycle();\n        }\n\n        mScrollChecker = new ScrollChecker();\n\n        final ViewConfiguration conf = ViewConfiguration.get(getContext());\n        mPagingTouchSlop = conf.getScaledTouchSlop() * 2;\n    }\n\n    @Override\n    protected void onFinishInflate() {\n        final int childCount = getChildCount();\n        if (childCount > 2) {\n            throw new IllegalStateException(\"PtrFrameLayout can only contains 2 children\");\n        } else if (childCount == 2) {\n            if (mHeaderId != 0 && mHeaderView == null) {\n                mHeaderView = findViewById(mHeaderId);\n            }\n            if (mContainerId != 0 && mContent == null) {\n                mContent = findViewById(mContainerId);\n            }\n\n            // not specify header or content\n            if (mContent == null || mHeaderView == null) {\n\n                View child1 = getChildAt(0);\n                View child2 = getChildAt(1);\n                if (child1 instanceof PtrUIHandler) {\n                    mHeaderView = child1;\n                    mContent = child2;\n                } else if (child2 instanceof PtrUIHandler) {\n                    mHeaderView = child2;\n                    mContent = child1;\n                } else {\n                    // both are not specified\n                    if (mContent == null && mHeaderView == null) {\n                        mHeaderView = child1;\n                        mContent = child2;\n                    }\n                    // only one is specified\n                    else {\n                        if (mHeaderView == null) {\n                            mHeaderView = mContent == child1 ? child2 : child1;\n                        } else {\n                            mContent = mHeaderView == child1 ? child2 : child1;\n                        }\n                    }\n                }\n            }\n        } else if (childCount == 1) {\n            mContent = getChildAt(0);\n        } else {\n            TextView errorView = new TextView(getContext());\n            errorView.setClickable(true);\n            errorView.setTextColor(0xffff6600);\n            errorView.setGravity(Gravity.CENTER);\n            errorView.setTextSize(20);\n            errorView.setText(\"The content view in PtrFrameLayout is empty. Do you forget to specify its id in xml layout file?\");\n            mContent = errorView;\n            addView(mContent);\n        }\n        if (mHeaderView != null) {\n            mHeaderView.bringToFront();\n        }\n        super.onFinishInflate();\n    }\n\n    @Override\n    protected void onDetachedFromWindow() {\n        super.onDetachedFromWindow();\n        if (mScrollChecker != null) {\n            mScrollChecker.destroy();\n        }\n\n        if (mPerformRefreshCompleteDelay != null) {\n            removeCallbacks(mPerformRefreshCompleteDelay);\n        }\n    }\n\n    @Override\n    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {\n        super.onMeasure(widthMeasureSpec, heightMeasureSpec);\n\n        if (isDebug()) {\n            PtrCLog.d(LOG_TAG, \"onMeasure frame: width: %s, height: %s, padding: %s %s %s %s\",\n                    getMeasuredHeight(), getMeasuredWidth(),\n                    getPaddingLeft(), getPaddingRight(), getPaddingTop(), getPaddingBottom());\n\n        }\n\n        if (mHeaderView != null) {\n            measureChildWithMargins(mHeaderView, widthMeasureSpec, 0, heightMeasureSpec, 0);\n            MarginLayoutParams lp = (MarginLayoutParams) mHeaderView.getLayoutParams();\n            mHeaderHeight = mHeaderView.getMeasuredHeight() + lp.topMargin + lp.bottomMargin;\n            mPtrIndicator.setHeaderHeight(mHeaderHeight);\n        }\n\n        if (mContent != null) {\n            measureContentView(mContent, widthMeasureSpec, heightMeasureSpec);\n            if (isDebug()) {\n                ViewGroup.MarginLayoutParams lp = (MarginLayoutParams) mContent.getLayoutParams();\n                PtrCLog.d(LOG_TAG, \"onMeasure content, width: %s, height: %s, margin: %s %s %s %s\",\n                        getMeasuredWidth(), getMeasuredHeight(),\n                        lp.leftMargin, lp.topMargin, lp.rightMargin, lp.bottomMargin);\n                PtrCLog.d(LOG_TAG, \"onMeasure, currentPos: %s, lastPos: %s, top: %s\",\n                        mPtrIndicator.getCurrentPosY(), mPtrIndicator.getLastPosY(), mContent.getTop());\n            }\n        }\n    }\n\n    private void measureContentView(View child,\n                                    int parentWidthMeasureSpec,\n                                    int parentHeightMeasureSpec) {\n        final MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();\n\n        final int childWidthMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec,\n                getPaddingLeft() + getPaddingRight() + lp.leftMargin + lp.rightMargin, lp.width);\n        final int childHeightMeasureSpec = getChildMeasureSpec(parentHeightMeasureSpec,\n                getPaddingTop() + getPaddingBottom() + lp.topMargin, lp.height);\n\n        child.measure(childWidthMeasureSpec, childHeightMeasureSpec);\n    }\n\n    @Override\n    protected void onLayout(boolean flag, int i, int j, int k, int l) {\n        layoutChildren();\n    }\n\n    private void layoutChildren() {\n        int offset = mPtrIndicator.getCurrentPosY();\n        int paddingLeft = getPaddingLeft();\n        int paddingTop = getPaddingTop();\n\n        if (mHeaderView != null) {\n            MarginLayoutParams lp = (MarginLayoutParams) mHeaderView.getLayoutParams();\n            final int left = paddingLeft + lp.leftMargin;\n            // enhance readability(header is layout above screen when first init)\n            final int top = -(mHeaderHeight - paddingTop - lp.topMargin - offset);\n            final int right = left + mHeaderView.getMeasuredWidth();\n            final int bottom = top + mHeaderView.getMeasuredHeight();\n            mHeaderView.layout(left, top, right, bottom);\n            if (isDebug()) {\n                PtrCLog.d(LOG_TAG, \"onLayout header: %s %s %s %s\", left, top, right, bottom);\n            }\n        }\n        if (mContent != null) {\n            if (isPinContent()) {\n                offset = 0;\n            }\n            MarginLayoutParams lp = (MarginLayoutParams) mContent.getLayoutParams();\n            final int left = paddingLeft + lp.leftMargin;\n            final int top = paddingTop + lp.topMargin + offset;\n            final int right = left + mContent.getMeasuredWidth();\n            final int bottom = top + mContent.getMeasuredHeight();\n            if (isDebug()) {\n                PtrCLog.d(LOG_TAG, \"onLayout content: %s %s %s %s\", left, top, right, bottom);\n            }\n            mContent.layout(left, top, right, bottom);\n        }\n    }\n\n    @SuppressWarnings({\"PointlessBooleanExpression\", \"ConstantConditions\"})\n    private boolean isDebug() {\n        return DEBUG && DEBUG_LAYOUT;\n    }\n\n    public boolean dispatchTouchEventSupper(MotionEvent e) {\n        return super.dispatchTouchEvent(e);\n    }\n\n    @Override\n    public boolean dispatchTouchEvent(MotionEvent e) {\n        if (!isEnabled() || mContent == null || mHeaderView == null) {\n            return dispatchTouchEventSupper(e);\n        }\n        int action = e.getAction();\n        switch (action) {\n            case MotionEvent.ACTION_UP:\n            case MotionEvent.ACTION_CANCEL:\n                mPtrIndicator.onRelease();\n                if (mPtrIndicator.hasLeftStartPosition()) {\n                    if (DEBUG) {\n                        PtrCLog.d(LOG_TAG, \"call onRelease when user release\");\n                    }\n                    onRelease(false);\n                    if (mPtrIndicator.hasMovedAfterPressedDown()) {\n                        sendCancelEvent();\n                        return true;\n                    }\n                    return dispatchTouchEventSupper(e);\n                } else {\n                    return dispatchTouchEventSupper(e);\n                }\n\n            case MotionEvent.ACTION_DOWN:\n                mHasSendCancelEvent = false;\n                mPtrIndicator.onPressDown(e.getX(), e.getY());\n\n                mScrollChecker.abortIfWorking();\n\n                mPreventForHorizontal = false;\n                // The cancel event will be sent once the position is moved.\n                // So let the event pass to children.\n                // fix #93, #102\n                dispatchTouchEventSupper(e);\n                return true;\n\n            case MotionEvent.ACTION_MOVE:\n                mLastMoveEvent = e;\n                mPtrIndicator.onMove(e.getX(), e.getY());\n                float offsetX = mPtrIndicator.getOffsetX();\n                float offsetY = mPtrIndicator.getOffsetY();\n\n                if (mDisableWhenHorizontalMove && !mPreventForHorizontal && (Math.abs(offsetX) > mPagingTouchSlop && Math.abs(offsetX) > Math.abs(offsetY))) {\n                    if (mPtrIndicator.isInStartPosition()) {\n                        mPreventForHorizontal = true;\n                    }\n                }\n                if (mPreventForHorizontal) {\n                    return dispatchTouchEventSupper(e);\n                }\n\n                boolean moveDown = offsetY > 0;\n                boolean moveUp = !moveDown;\n                boolean canMoveUp = mPtrIndicator.hasLeftStartPosition();\n\n                if (DEBUG) {\n                    boolean canMoveDown = mPtrHandler != null && mPtrHandler.checkCanDoRefresh(this, mContent, mHeaderView);\n                    PtrCLog.v(LOG_TAG, \"ACTION_MOVE: offsetY:%s, currentPos: %s, moveUp: %s, canMoveUp: %s, moveDown: %s: canMoveDown: %s\", offsetY, mPtrIndicator.getCurrentPosY(), moveUp, canMoveUp, moveDown, canMoveDown);\n                }\n\n                // disable move when header not reach top\n                if (moveDown && mPtrHandler != null && !mPtrHandler.checkCanDoRefresh(this, mContent, mHeaderView)) {\n                    return dispatchTouchEventSupper(e);\n                }\n\n                if ((moveUp && canMoveUp) || moveDown) {\n                    movePos(offsetY);\n                    return true;\n                }\n        }\n        return dispatchTouchEventSupper(e);\n    }\n\n    /**\n     * if deltaY > 0, move the content down\n     *\n     * @param deltaY\n     */\n    private void movePos(float deltaY) {\n        // has reached the top\n        if ((deltaY < 0 && mPtrIndicator.isInStartPosition())) {\n            if (DEBUG) {\n                PtrCLog.e(LOG_TAG, String.format(\"has reached the top\"));\n            }\n            return;\n        }\n\n        int to = mPtrIndicator.getCurrentPosY() + (int) deltaY;\n\n        // over top\n        if (mPtrIndicator.willOverTop(to)) {\n            if (DEBUG) {\n                PtrCLog.e(LOG_TAG, String.format(\"over top\"));\n            }\n            to = PtrIndicator.POS_START;\n        }\n\n        mPtrIndicator.setCurrentPos(to);\n        int change = to - mPtrIndicator.getLastPosY();\n        updatePos(change);\n    }\n\n    private void updatePos(int change) {\n        if (change == 0) {\n            return;\n        }\n\n        boolean isUnderTouch = mPtrIndicator.isUnderTouch();\n\n        // once moved, cancel event will be sent to child\n        if (isUnderTouch && !mHasSendCancelEvent && mPtrIndicator.hasMovedAfterPressedDown()) {\n            mHasSendCancelEvent = true;\n            sendCancelEvent();\n        }\n\n        // leave initiated position or just refresh complete\n        if ((mPtrIndicator.hasJustLeftStartPosition() && mStatus == PTR_STATUS_INIT) ||\n                (mPtrIndicator.goDownCrossFinishPosition() && mStatus == PTR_STATUS_COMPLETE && isEnabledNextPtrAtOnce())) {\n\n            mStatus = PTR_STATUS_PREPARE;\n            mPtrUIHandlerHolder.onUIRefreshPrepare(this);\n            if (DEBUG) {\n                PtrCLog.i(LOG_TAG, \"PtrUIHandler: onUIRefreshPrepare, mFlag %s\", mFlag);\n            }\n        }\n\n        // back to initiated position\n        if (mPtrIndicator.hasJustBackToStartPosition()) {\n            tryToNotifyReset();\n\n            // recover event to children\n            if (isUnderTouch) {\n                sendDownEvent();\n            }\n        }\n\n        // Pull to Refresh\n        if (mStatus == PTR_STATUS_PREPARE) {\n            // reach fresh height while moving from top to bottom\n            if (isUnderTouch && !isAutoRefresh() && mPullToRefresh\n                    && mPtrIndicator.crossRefreshLineFromTopToBottom()) {\n                tryToPerformRefresh();\n            }\n            // reach header height while auto refresh\n            if (performAutoRefreshButLater() && mPtrIndicator.hasJustReachedHeaderHeightFromTopToBottom()) {\n                tryToPerformRefresh();\n            }\n        }\n\n        if (DEBUG) {\n            PtrCLog.v(LOG_TAG, \"updatePos: change: %s, current: %s last: %s, top: %s, headerHeight: %s\",\n                    change, mPtrIndicator.getCurrentPosY(), mPtrIndicator.getLastPosY(), mContent.getTop(), mHeaderHeight);\n        }\n\n        mHeaderView.offsetTopAndBottom(change);\n        if (!isPinContent()) {\n            mContent.offsetTopAndBottom(change);\n        }\n        invalidate();\n\n        if (mPtrUIHandlerHolder.hasHandler()) {\n            mPtrUIHandlerHolder.onUIPositionChange(this, isUnderTouch, mStatus, mPtrIndicator);\n        }\n        onPositionChange(isUnderTouch, mStatus, mPtrIndicator);\n    }\n\n    protected void onPositionChange(boolean isInTouching, byte status, PtrIndicator mPtrIndicator) {\n    }\n\n    @SuppressWarnings(\"unused\")\n    public int getHeaderHeight() {\n        return mHeaderHeight;\n    }\n\n    private void onRelease(boolean stayForLoading) {\n\n        tryToPerformRefresh();\n\n        if (mStatus == PTR_STATUS_LOADING) {\n            // keep header for fresh\n            if (mKeepHeaderWhenRefresh) {\n                // scroll header back\n                if (mPtrIndicator.isOverOffsetToKeepHeaderWhileLoading() && !stayForLoading) {\n                    mScrollChecker.tryToScrollTo(mPtrIndicator.getOffsetToKeepHeaderWhileLoading(), mDurationToClose);\n                } else {\n                    // do nothing\n                }\n            } else {\n                tryScrollBackToTopWhileLoading();\n            }\n        } else {\n            if (mStatus == PTR_STATUS_COMPLETE) {\n                notifyUIRefreshComplete(false);\n            } else {\n                tryScrollBackToTopAbortRefresh();\n            }\n        }\n    }\n\n    /**\n     * please DO REMEMBER resume the hook\n     *\n     * @param hook\n     */\n\n    public void setRefreshCompleteHook(PtrUIHandlerHook hook) {\n        mRefreshCompleteHook = hook;\n        hook.setResumeAction(new Runnable() {\n            @Override\n            public void run() {\n                if (DEBUG) {\n                    PtrCLog.d(LOG_TAG, \"mRefreshCompleteHook resume.\");\n                }\n                notifyUIRefreshComplete(true);\n            }\n        });\n    }\n\n    /**\n     * Scroll back to to if is not under touch\n     */\n    private void tryScrollBackToTop() {\n        if (!mPtrIndicator.isUnderTouch()) {\n            mScrollChecker.tryToScrollTo(PtrIndicator.POS_START, mDurationToCloseHeader);\n        }\n    }\n\n    /**\n     * just make easier to understand\n     */\n    private void tryScrollBackToTopWhileLoading() {\n        tryScrollBackToTop();\n    }\n\n    /**\n     * just make easier to understand\n     */\n    private void tryScrollBackToTopAfterComplete() {\n        tryScrollBackToTop();\n    }\n\n    /**\n     * just make easier to understand\n     */\n    private void tryScrollBackToTopAbortRefresh() {\n        tryScrollBackToTop();\n    }\n\n    private boolean tryToPerformRefresh() {\n        if (mStatus != PTR_STATUS_PREPARE) {\n            return false;\n        }\n\n        //\n        if ((mPtrIndicator.isOverOffsetToKeepHeaderWhileLoading() && isAutoRefresh()) || mPtrIndicator.isOverOffsetToRefresh()) {\n            mStatus = PTR_STATUS_LOADING;\n            performRefresh();\n        }\n        return false;\n    }\n\n    private void performRefresh() {\n        mLoadingStartTime = System.currentTimeMillis();\n        if (mPtrUIHandlerHolder.hasHandler()) {\n            mPtrUIHandlerHolder.onUIRefreshBegin(this);\n            if (DEBUG) {\n                PtrCLog.i(LOG_TAG, \"PtrUIHandler: onUIRefreshBegin\");\n            }\n        }\n        if (mPtrHandler != null) {\n            mPtrHandler.onRefreshBegin(this);\n        }\n    }\n\n    /**\n     * If at the top and not in loading, reset\n     */\n    private boolean tryToNotifyReset() {\n        if ((mStatus == PTR_STATUS_COMPLETE || mStatus == PTR_STATUS_PREPARE) && mPtrIndicator.isInStartPosition()) {\n            if (mPtrUIHandlerHolder.hasHandler()) {\n                mPtrUIHandlerHolder.onUIReset(this);\n                if (DEBUG) {\n                    PtrCLog.i(LOG_TAG, \"PtrUIHandler: onUIReset\");\n                }\n            }\n            mStatus = PTR_STATUS_INIT;\n            clearFlag();\n            return true;\n        }\n        return false;\n    }\n\n    protected void onPtrScrollAbort() {\n        if (mPtrIndicator.hasLeftStartPosition() && isAutoRefresh()) {\n            if (DEBUG) {\n                PtrCLog.d(LOG_TAG, \"call onRelease after scroll abort\");\n            }\n            onRelease(true);\n        }\n    }\n\n    protected void onPtrScrollFinish() {\n        if (mPtrIndicator.hasLeftStartPosition() && isAutoRefresh()) {\n            if (DEBUG) {\n                PtrCLog.d(LOG_TAG, \"call onRelease after scroll finish\");\n            }\n            onRelease(true);\n        }\n    }\n\n    /**\n     * Detect whether is refreshing.\n     *\n     * @return\n     */\n    public boolean isRefreshing() {\n        return mStatus == PTR_STATUS_LOADING;\n    }\n\n    /**\n     * Call this when data is loaded.\n     * The UI will perform complete at once or after a delay, depends on the time elapsed is greater then {@link #mLoadingMinTime} or not.\n     */\n    final public void refreshComplete() {\n        if (DEBUG) {\n            PtrCLog.i(LOG_TAG, \"refreshComplete\");\n        }\n\n        if (mRefreshCompleteHook != null) {\n            mRefreshCompleteHook.reset();\n        }\n\n        int delay = (int) (mLoadingMinTime - (System.currentTimeMillis() - mLoadingStartTime));\n        if (delay <= 0) {\n            if (DEBUG) {\n                PtrCLog.d(LOG_TAG, \"performRefreshComplete at once\");\n            }\n            performRefreshComplete();\n        } else {\n            postDelayed(mPerformRefreshCompleteDelay, delay);\n            if (DEBUG) {\n                PtrCLog.d(LOG_TAG, \"performRefreshComplete after delay: %s\", delay);\n            }\n        }\n    }\n\n    /**\n     * Do refresh complete work when time elapsed is greater than {@link #mLoadingMinTime}\n     */\n    private void performRefreshComplete() {\n        mStatus = PTR_STATUS_COMPLETE;\n\n        // if is auto refresh do nothing, wait scroller stop\n        if (mScrollChecker.mIsRunning && isAutoRefresh()) {\n            // do nothing\n            if (DEBUG) {\n                PtrCLog.d(LOG_TAG, \"performRefreshComplete do nothing, scrolling: %s, auto refresh: %s\",\n                        mScrollChecker.mIsRunning, mFlag);\n            }\n            return;\n        }\n\n        notifyUIRefreshComplete(false);\n    }\n\n    /**\n     * Do real refresh work. If there is a hook, execute the hook first.\n     *\n     * @param ignoreHook\n     */\n    private void notifyUIRefreshComplete(boolean ignoreHook) {\n        /**\n         * After hook operation is done, {@link #notifyUIRefreshComplete} will be call in resume action to ignore hook.\n         */\n        if (mPtrIndicator.hasLeftStartPosition() && !ignoreHook && mRefreshCompleteHook != null) {\n            if (DEBUG) {\n                PtrCLog.d(LOG_TAG, \"notifyUIRefreshComplete mRefreshCompleteHook run.\");\n            }\n\n            mRefreshCompleteHook.takeOver();\n            return;\n        }\n        if (mPtrUIHandlerHolder.hasHandler()) {\n            if (DEBUG) {\n                PtrCLog.i(LOG_TAG, \"PtrUIHandler: onUIRefreshComplete\");\n            }\n            mPtrUIHandlerHolder.onUIRefreshComplete(this);\n        }\n        mPtrIndicator.onUIRefreshComplete();\n        tryScrollBackToTopAfterComplete();\n        tryToNotifyReset();\n    }\n\n    public void autoRefresh() {\n        autoRefresh(true, mDurationToCloseHeader);\n    }\n\n    public void autoRefresh(boolean atOnce) {\n        autoRefresh(atOnce, mDurationToCloseHeader);\n    }\n\n    private void clearFlag() {\n        // remove auto fresh flag\n        mFlag = mFlag & ~MASK_AUTO_REFRESH;\n    }\n\n    public void autoRefresh(boolean atOnce, int duration) {\n\n        if (mStatus != PTR_STATUS_INIT) {\n            return;\n        }\n\n        mFlag |= atOnce ? FLAG_AUTO_REFRESH_AT_ONCE : FLAG_AUTO_REFRESH_BUT_LATER;\n\n        mStatus = PTR_STATUS_PREPARE;\n        if (mPtrUIHandlerHolder.hasHandler()) {\n            mPtrUIHandlerHolder.onUIRefreshPrepare(this);\n            if (DEBUG) {\n                PtrCLog.i(LOG_TAG, \"PtrUIHandler: onUIRefreshPrepare, mFlag %s\", mFlag);\n            }\n        }\n        mScrollChecker.tryToScrollTo(mPtrIndicator.getOffsetToRefresh(), duration);\n        if (atOnce) {\n            mStatus = PTR_STATUS_LOADING;\n            performRefresh();\n        }\n    }\n\n    public boolean isAutoRefresh() {\n        return (mFlag & MASK_AUTO_REFRESH) > 0;\n    }\n\n    private boolean performAutoRefreshButLater() {\n        return (mFlag & MASK_AUTO_REFRESH) == FLAG_AUTO_REFRESH_BUT_LATER;\n    }\n\n    public boolean isEnabledNextPtrAtOnce() {\n        return (mFlag & FLAG_ENABLE_NEXT_PTR_AT_ONCE) > 0;\n    }\n\n    /**\n     * If @param enable has been set to true. The user can perform next PTR at once.\n     *\n     * @param enable\n     */\n    public void setEnabledNextPtrAtOnce(boolean enable) {\n        if (enable) {\n            mFlag = mFlag | FLAG_ENABLE_NEXT_PTR_AT_ONCE;\n        } else {\n            mFlag = mFlag & ~FLAG_ENABLE_NEXT_PTR_AT_ONCE;\n        }\n    }\n\n    public boolean isPinContent() {\n        return (mFlag & FLAG_PIN_CONTENT) > 0;\n    }\n\n    /**\n     * The content view will now move when {@param pinContent} set to true.\n     *\n     * @param pinContent\n     */\n    public void setPinContent(boolean pinContent) {\n        if (pinContent) {\n            mFlag = mFlag | FLAG_PIN_CONTENT;\n        } else {\n            mFlag = mFlag & ~FLAG_PIN_CONTENT;\n        }\n    }\n\n    /**\n     * It's useful when working with viewpager.\n     *\n     * @param disable\n     */\n    public void disableWhenHorizontalMove(boolean disable) {\n        mDisableWhenHorizontalMove = disable;\n    }\n\n    /**\n     * loading will last at least for so long\n     *\n     * @param time\n     */\n    public void setLoadingMinTime(int time) {\n        mLoadingMinTime = time;\n    }\n\n    /**\n     * Not necessary any longer. Once moved, cancel event will be sent to child.\n     *\n     * @param yes\n     */\n    @Deprecated\n    public void setInterceptEventWhileWorking(boolean yes) {\n    }\n\n    @SuppressWarnings({\"unused\"})\n    public View getContentView() {\n        return mContent;\n    }\n\n    public void setPtrHandler(PtrHandler ptrHandler) {\n        mPtrHandler = ptrHandler;\n    }\n\n    public void addPtrUIHandler(PtrUIHandler ptrUIHandler) {\n        PtrUIHandlerHolder.addHandler(mPtrUIHandlerHolder, ptrUIHandler);\n    }\n\n    @SuppressWarnings({\"unused\"})\n    public void removePtrUIHandler(PtrUIHandler ptrUIHandler) {\n        mPtrUIHandlerHolder = PtrUIHandlerHolder.removeHandler(mPtrUIHandlerHolder, ptrUIHandler);\n    }\n\n    public void setPtrIndicator(PtrIndicator slider) {\n        if (mPtrIndicator != null && mPtrIndicator != slider) {\n            slider.convertFrom(mPtrIndicator);\n        }\n        mPtrIndicator = slider;\n    }\n\n    @SuppressWarnings({\"unused\"})\n    public float getResistance() {\n        return mPtrIndicator.getResistance();\n    }\n\n    public void setResistance(float resistance) {\n        mPtrIndicator.setResistance(resistance);\n    }\n\n    @SuppressWarnings({\"unused\"})\n    public float getDurationToClose() {\n        return mDurationToClose;\n    }\n\n    /**\n     * The duration to return back to the refresh position\n     *\n     * @param duration\n     */\n    public void setDurationToClose(int duration) {\n        mDurationToClose = duration;\n    }\n\n    @SuppressWarnings({\"unused\"})\n    public long getDurationToCloseHeader() {\n        return mDurationToCloseHeader;\n    }\n\n    /**\n     * The duration to close time\n     *\n     * @param duration\n     */\n    public void setDurationToCloseHeader(int duration) {\n        mDurationToCloseHeader = duration;\n    }\n\n    public void setRatioOfHeaderHeightToRefresh(float ratio) {\n        mPtrIndicator.setRatioOfHeaderHeightToRefresh(ratio);\n    }\n\n    public int getOffsetToRefresh() {\n        return mPtrIndicator.getOffsetToRefresh();\n    }\n\n    @SuppressWarnings({\"unused\"})\n    public void setOffsetToRefresh(int offset) {\n        mPtrIndicator.setOffsetToRefresh(offset);\n    }\n\n    @SuppressWarnings({\"unused\"})\n    public float getRatioOfHeaderToHeightRefresh() {\n        return mPtrIndicator.getRatioOfHeaderToHeightRefresh();\n    }\n\n    @SuppressWarnings({\"unused\"})\n    public int getOffsetToKeepHeaderWhileLoading() {\n        return mPtrIndicator.getOffsetToKeepHeaderWhileLoading();\n    }\n\n    @SuppressWarnings({\"unused\"})\n    public void setOffsetToKeepHeaderWhileLoading(int offset) {\n        mPtrIndicator.setOffsetToKeepHeaderWhileLoading(offset);\n    }\n\n    @SuppressWarnings({\"unused\"})\n    public boolean isKeepHeaderWhenRefresh() {\n        return mKeepHeaderWhenRefresh;\n    }\n\n    public void setKeepHeaderWhenRefresh(boolean keepOrNot) {\n        mKeepHeaderWhenRefresh = keepOrNot;\n    }\n\n    public boolean isPullToRefresh() {\n        return mPullToRefresh;\n    }\n\n    public void setPullToRefresh(boolean pullToRefresh) {\n        mPullToRefresh = pullToRefresh;\n    }\n\n    @SuppressWarnings({\"unused\"})\n    public View getHeaderView() {\n        return mHeaderView;\n    }\n\n    public void setHeaderView(View header) {\n        if (mHeaderView != null && header != null && mHeaderView != header) {\n            removeView(mHeaderView);\n        }\n        ViewGroup.LayoutParams lp = header.getLayoutParams();\n        if (lp == null) {\n            lp = new LayoutParams(-1, -2);\n            header.setLayoutParams(lp);\n        }\n        mHeaderView = header;\n        addView(header);\n    }\n\n    @Override\n    protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {\n        return p != null && p instanceof LayoutParams;\n    }\n\n    @Override\n    protected ViewGroup.LayoutParams generateDefaultLayoutParams() {\n        return new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);\n    }\n\n    @Override\n    protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {\n        return new LayoutParams(p);\n    }\n\n    @Override\n    public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) {\n        return new LayoutParams(getContext(), attrs);\n    }\n\n    private void sendCancelEvent() {\n        if (DEBUG) {\n            PtrCLog.d(LOG_TAG, \"send cancel event\");\n        }\n        // The ScrollChecker will update position and lead to send cancel event when mLastMoveEvent is null.\n        // fix #104, #80, #92\n        if (mLastMoveEvent == null) {\n            return;\n        }\n        MotionEvent last = mLastMoveEvent;\n        MotionEvent e = MotionEvent.obtain(last.getDownTime(), last.getEventTime() + ViewConfiguration.getLongPressTimeout(), MotionEvent.ACTION_CANCEL, last.getX(), last.getY(), last.getMetaState());\n        dispatchTouchEventSupper(e);\n    }\n\n    private void sendDownEvent() {\n        if (DEBUG) {\n            PtrCLog.d(LOG_TAG, \"send down event\");\n        }\n        final MotionEvent last = mLastMoveEvent;\n        MotionEvent e = MotionEvent.obtain(last.getDownTime(), last.getEventTime(), MotionEvent.ACTION_DOWN, last.getX(), last.getY(), last.getMetaState());\n        dispatchTouchEventSupper(e);\n    }\n\n    public static class LayoutParams extends MarginLayoutParams {\n\n        public LayoutParams(Context c, AttributeSet attrs) {\n            super(c, attrs);\n        }\n\n        public LayoutParams(int width, int height) {\n            super(width, height);\n        }\n\n        @SuppressWarnings({\"unused\"})\n        public LayoutParams(MarginLayoutParams source) {\n            super(source);\n        }\n\n        public LayoutParams(ViewGroup.LayoutParams source) {\n            super(source);\n        }\n    }\n\n    class ScrollChecker implements Runnable {\n\n        private int mLastFlingY;\n        private Scroller mScroller;\n        private boolean mIsRunning = false;\n        private int mStart;\n        private int mTo;\n\n        public ScrollChecker() {\n            mScroller = new Scroller(getContext());\n        }\n\n        public void run() {\n            boolean finish = !mScroller.computeScrollOffset() || mScroller.isFinished();\n            int curY = mScroller.getCurrY();\n            int deltaY = curY - mLastFlingY;\n            if (DEBUG) {\n                if (deltaY != 0) {\n                    PtrCLog.v(LOG_TAG,\n                            \"scroll: %s, start: %s, to: %s, currentPos: %s, current :%s, last: %s, delta: %s\",\n                            finish, mStart, mTo, mPtrIndicator.getCurrentPosY(), curY, mLastFlingY, deltaY);\n                }\n            }\n            if (!finish) {\n                mLastFlingY = curY;\n                movePos(deltaY);\n                post(this);\n            } else {\n                finish();\n            }\n        }\n\n        private void finish() {\n            if (DEBUG) {\n                PtrCLog.v(LOG_TAG, \"finish, currentPos:%s\", mPtrIndicator.getCurrentPosY());\n            }\n            reset();\n            onPtrScrollFinish();\n        }\n\n        private void reset() {\n            mIsRunning = false;\n            mLastFlingY = 0;\n            removeCallbacks(this);\n        }\n\n        private void destroy() {\n            reset();\n            if (!mScroller.isFinished()) {\n                mScroller.forceFinished(true);\n            }\n        }\n\n        public void abortIfWorking() {\n            if (mIsRunning) {\n                if (!mScroller.isFinished()) {\n                    mScroller.forceFinished(true);\n                }\n                onPtrScrollAbort();\n                reset();\n            }\n        }\n\n        public void tryToScrollTo(int to, int duration) {\n            if (mPtrIndicator.isAlreadyHere(to)) {\n                return;\n            }\n            mStart = mPtrIndicator.getCurrentPosY();\n            mTo = to;\n            int distance = to - mStart;\n            if (DEBUG) {\n                PtrCLog.d(LOG_TAG, \"tryToScrollTo: start: %s, distance:%s, to:%s\", mStart, distance, to);\n            }\n            removeCallbacks(this);\n\n            mLastFlingY = 0;\n\n            // fix #47: Scroller should be reused, https://github.com/liaohuqiu/android-Ultra-Pull-To-Refresh/issues/47\n            if (!mScroller.isFinished()) {\n                mScroller.forceFinished(true);\n            }\n            mScroller.startScroll(0, 0, 0, distance, duration);\n            post(this);\n            mIsRunning = true;\n        }\n    }\n}\n"
  },
  {
    "path": "ptr-lib/src/in/srain/cube/views/ptr/PtrHandler.java",
    "content": "package in.srain.cube.views.ptr;\n\nimport android.view.View;\n\npublic interface PtrHandler {\n\n    /**\n     * Check can do refresh or not. For example the content is empty or the first child is in view.\n     * <p/>\n     * {@link in.srain.cube.views.ptr.PtrDefaultHandler#checkContentCanBePulledDown}\n     */\n    public boolean checkCanDoRefresh(final PtrFrameLayout frame, final View content, final View header);\n\n    /**\n     * When refresh begin\n     *\n     * @param frame\n     */\n    public void onRefreshBegin(final PtrFrameLayout frame);\n}"
  },
  {
    "path": "ptr-lib/src/in/srain/cube/views/ptr/PtrUIHandler.java",
    "content": "package in.srain.cube.views.ptr;\n\nimport in.srain.cube.views.ptr.indicator.PtrIndicator;\n\n/**\n *\n */\npublic interface PtrUIHandler {\n\n    /**\n     * When the content view has reached top and refresh has been completed, view will be reset.\n     *\n     * @param frame\n     */\n    public void onUIReset(PtrFrameLayout frame);\n\n    /**\n     * prepare for loading\n     *\n     * @param frame\n     */\n    public void onUIRefreshPrepare(PtrFrameLayout frame);\n\n    /**\n     * perform refreshing UI\n     */\n    public void onUIRefreshBegin(PtrFrameLayout frame);\n\n    /**\n     * perform UI after refresh\n     */\n    public void onUIRefreshComplete(PtrFrameLayout frame);\n\n    public void onUIPositionChange(PtrFrameLayout frame, boolean isUnderTouch, byte status, PtrIndicator ptrIndicator);\n}\n"
  },
  {
    "path": "ptr-lib/src/in/srain/cube/views/ptr/PtrUIHandlerHolder.java",
    "content": "package in.srain.cube.views.ptr;\n\nimport in.srain.cube.views.ptr.indicator.PtrIndicator;\n\n/**\n * A single linked list to wrap PtrUIHandler\n */\nclass PtrUIHandlerHolder implements PtrUIHandler {\n\n    private PtrUIHandler mHandler;\n    private PtrUIHandlerHolder mNext;\n\n    private boolean contains(PtrUIHandler handler) {\n        return mHandler != null && mHandler == handler;\n    }\n\n    private PtrUIHandlerHolder() {\n\n    }\n\n    public boolean hasHandler() {\n        return mHandler != null;\n    }\n\n    private PtrUIHandler getHandler() {\n        return mHandler;\n    }\n\n    public static void addHandler(PtrUIHandlerHolder head, PtrUIHandler handler) {\n\n        if (null == handler) {\n            return;\n        }\n        if (head == null) {\n            return;\n        }\n        if (null == head.mHandler) {\n            head.mHandler = handler;\n            return;\n        }\n\n        PtrUIHandlerHolder current = head;\n        for (; ; current = current.mNext) {\n\n            // duplicated\n            if (current.contains(handler)) {\n                return;\n            }\n            if (current.mNext == null) {\n                break;\n            }\n        }\n\n        PtrUIHandlerHolder newHolder = new PtrUIHandlerHolder();\n        newHolder.mHandler = handler;\n        current.mNext = newHolder;\n    }\n\n    public static PtrUIHandlerHolder create() {\n        return new PtrUIHandlerHolder();\n    }\n\n    public static PtrUIHandlerHolder removeHandler(PtrUIHandlerHolder head, PtrUIHandler handler) {\n        if (head == null || handler == null || null == head.mHandler) {\n            return head;\n        }\n\n        PtrUIHandlerHolder current = head;\n        PtrUIHandlerHolder pre = null;\n        do {\n\n            // delete current: link pre to next, unlink next from current;\n            // pre will no change, current move to next element;\n            if (current.contains(handler)) {\n\n                // current is head\n                if (pre == null) {\n\n                    head = current.mNext;\n                    current.mNext = null;\n\n                    current = head;\n                } else {\n\n                    pre.mNext = current.mNext;\n                    current.mNext = null;\n                    current = pre.mNext;\n                }\n            } else {\n                pre = current;\n                current = current.mNext;\n            }\n\n        } while (current != null);\n\n        if (head == null) {\n            head = new PtrUIHandlerHolder();\n        }\n        return head;\n    }\n\n    @Override\n    public void onUIReset(PtrFrameLayout frame) {\n        PtrUIHandlerHolder current = this;\n        do {\n            final PtrUIHandler handler = current.getHandler();\n            if (null != handler) {\n                handler.onUIReset(frame);\n            }\n        } while ((current = current.mNext) != null);\n    }\n\n    @Override\n    public void onUIRefreshPrepare(PtrFrameLayout frame) {\n        if (!hasHandler()) {\n            return;\n        }\n        PtrUIHandlerHolder current = this;\n        do {\n            final PtrUIHandler handler = current.getHandler();\n            if (null != handler) {\n                handler.onUIRefreshPrepare(frame);\n            }\n        } while ((current = current.mNext) != null);\n    }\n\n    @Override\n    public void onUIRefreshBegin(PtrFrameLayout frame) {\n        PtrUIHandlerHolder current = this;\n        do {\n            final PtrUIHandler handler = current.getHandler();\n            if (null != handler) {\n                handler.onUIRefreshBegin(frame);\n            }\n        } while ((current = current.mNext) != null);\n    }\n\n    @Override\n    public void onUIRefreshComplete(PtrFrameLayout frame) {\n        PtrUIHandlerHolder current = this;\n        do {\n            final PtrUIHandler handler = current.getHandler();\n            if (null != handler) {\n                handler.onUIRefreshComplete(frame);\n            }\n        } while ((current = current.mNext) != null);\n    }\n\n    @Override\n    public void onUIPositionChange(PtrFrameLayout frame, boolean isUnderTouch, byte status, PtrIndicator ptrIndicator) {\n        PtrUIHandlerHolder current = this;\n        do {\n            final PtrUIHandler handler = current.getHandler();\n            if (null != handler) {\n                handler.onUIPositionChange(frame, isUnderTouch, status, ptrIndicator);\n            }\n        } while ((current = current.mNext) != null);\n    }\n}\n"
  },
  {
    "path": "ptr-lib/src/in/srain/cube/views/ptr/PtrUIHandlerHook.java",
    "content": "package in.srain.cube.views.ptr;\n\n/**\n * Run a hook runnable, the runnable will run only once.\n * After the runnable is done, call resume to resume.\n * Once run, call takeover will directory call the resume action\n */\npublic abstract class PtrUIHandlerHook implements Runnable {\n\n    private Runnable mResumeAction;\n    private static final byte STATUS_PREPARE = 0;\n    private static final byte STATUS_IN_HOOK = 1;\n    private static final byte STATUS_RESUMED = 2;\n    private byte mStatus = STATUS_PREPARE;\n\n    public void takeOver() {\n        takeOver(null);\n    }\n\n    public void takeOver(Runnable resumeAction) {\n        if (resumeAction != null) {\n            mResumeAction = resumeAction;\n        }\n        switch (mStatus) {\n            case STATUS_PREPARE:\n                mStatus = STATUS_IN_HOOK;\n                run();\n                break;\n            case STATUS_IN_HOOK:\n                break;\n            case STATUS_RESUMED:\n                resume();\n                break;\n        }\n    }\n\n    public void reset() {\n        mStatus = STATUS_PREPARE;\n    }\n\n    public void resume() {\n        if (mResumeAction != null) {\n            mResumeAction.run();\n        }\n        mStatus = STATUS_RESUMED;\n    }\n\n    /**\n     * Hook should always have a resume action, which is hooked by this hook.\n     *\n     * @param runnable\n     */\n    public void setResumeAction(Runnable runnable) {\n        mResumeAction = runnable;\n    }\n}"
  },
  {
    "path": "ptr-lib/src/in/srain/cube/views/ptr/header/MaterialHeader.java",
    "content": "package in.srain.cube.views.ptr.header;\n\nimport android.content.Context;\nimport android.graphics.Canvas;\nimport android.graphics.Color;\nimport android.graphics.Rect;\nimport android.graphics.drawable.Drawable;\nimport android.util.AttributeSet;\nimport android.view.View;\nimport android.view.animation.Animation;\nimport android.view.animation.Transformation;\nimport in.srain.cube.views.ptr.PtrFrameLayout;\nimport in.srain.cube.views.ptr.PtrUIHandler;\nimport in.srain.cube.views.ptr.PtrUIHandlerHook;\nimport in.srain.cube.views.ptr.indicator.PtrIndicator;\n\npublic class MaterialHeader extends View implements PtrUIHandler {\n\n    private MaterialProgressDrawable mDrawable;\n    private float mScale = 1f;\n    private PtrFrameLayout mPtrFrameLayout;\n\n    private Animation mScaleAnimation = new Animation() {\n        @Override\n        public void applyTransformation(float interpolatedTime, Transformation t) {\n            mScale = 1f - interpolatedTime;\n            mDrawable.setAlpha((int) (255 * mScale));\n            invalidate();\n        }\n    };\n\n    public MaterialHeader(Context context) {\n        super(context);\n        initView();\n    }\n\n    public MaterialHeader(Context context, AttributeSet attrs) {\n        super(context, attrs);\n        initView();\n    }\n\n    public MaterialHeader(Context context, AttributeSet attrs, int defStyleAttr) {\n        super(context, attrs, defStyleAttr);\n        initView();\n    }\n\n    public void setPtrFrameLayout(PtrFrameLayout layout) {\n\n        final PtrUIHandlerHook mPtrUIHandlerHook = new PtrUIHandlerHook() {\n            @Override\n            public void run() {\n                startAnimation(mScaleAnimation);\n            }\n        };\n\n        mScaleAnimation.setDuration(200);\n        mScaleAnimation.setAnimationListener(new Animation.AnimationListener() {\n            @Override\n            public void onAnimationStart(Animation animation) {\n\n            }\n\n            @Override\n            public void onAnimationEnd(Animation animation) {\n                mPtrUIHandlerHook.resume();\n            }\n\n            @Override\n            public void onAnimationRepeat(Animation animation) {\n\n            }\n        });\n\n        mPtrFrameLayout = layout;\n        mPtrFrameLayout.setRefreshCompleteHook(mPtrUIHandlerHook);\n    }\n\n    private void initView() {\n        mDrawable = new MaterialProgressDrawable(getContext(), this);\n        mDrawable.setBackgroundColor(Color.WHITE);\n        mDrawable.setCallback(this);\n    }\n\n    @Override\n    public void invalidateDrawable(Drawable dr) {\n        if (dr == mDrawable) {\n            invalidate();\n        } else {\n            super.invalidateDrawable(dr);\n        }\n    }\n\n    public void setColorSchemeColors(int[] colors) {\n        mDrawable.setColorSchemeColors(colors);\n        invalidate();\n    }\n\n    @Override\n    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {\n        int height = mDrawable.getIntrinsicHeight() + getPaddingTop() + getPaddingBottom();\n        heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);\n        super.onMeasure(widthMeasureSpec, heightMeasureSpec);\n    }\n\n    @Override\n    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {\n        final int size = mDrawable.getIntrinsicHeight();\n        mDrawable.setBounds(0, 0, size, size);\n    }\n\n    @Override\n    protected void onDraw(Canvas canvas) {\n        final int saveCount = canvas.save();\n        Rect rect = mDrawable.getBounds();\n        int l = getPaddingLeft() + (getMeasuredWidth() - mDrawable.getIntrinsicWidth()) / 2;\n        canvas.translate(l, getPaddingTop());\n        canvas.scale(mScale, mScale, rect.exactCenterX(), rect.exactCenterY());\n        mDrawable.draw(canvas);\n        canvas.restoreToCount(saveCount);\n    }\n\n    /**\n     * When the content view has reached top and refresh has been completed, view will be reset.\n     *\n     * @param frame\n     */\n    @Override\n    public void onUIReset(PtrFrameLayout frame) {\n        mScale = 1f;\n        mDrawable.stop();\n    }\n\n    /**\n     * prepare for loading\n     *\n     * @param frame\n     */\n    @Override\n    public void onUIRefreshPrepare(PtrFrameLayout frame) {\n    }\n\n    /**\n     * perform refreshing UI\n     *\n     * @param frame\n     */\n    @Override\n    public void onUIRefreshBegin(PtrFrameLayout frame) {\n        mDrawable.setAlpha(255);\n        mDrawable.start();\n    }\n\n    /**\n     * perform UI after refresh\n     *\n     * @param frame\n     */\n    @Override\n    public void onUIRefreshComplete(PtrFrameLayout frame) {\n        mDrawable.stop();\n    }\n\n    @Override\n    public void onUIPositionChange(PtrFrameLayout frame, boolean isUnderTouch, byte status, PtrIndicator ptrIndicator) {\n\n        float percent = Math.min(1f, ptrIndicator.getCurrentPercent());\n\n        if (status == PtrFrameLayout.PTR_STATUS_PREPARE) {\n            mDrawable.setAlpha((int) (255 * percent));\n            mDrawable.showArrow(true);\n\n            float strokeStart = ((percent) * .8f);\n            mDrawable.setStartEndTrim(0f, Math.min(0.8f, strokeStart));\n            mDrawable.setArrowScale(Math.min(1f, percent));\n\n            // magic\n            float rotation = (-0.25f + .4f * percent + percent * 2) * .5f;\n            mDrawable.setProgressRotation(rotation);\n            invalidate();\n        }\n    }\n}\n"
  },
  {
    "path": "ptr-lib/src/in/srain/cube/views/ptr/header/MaterialProgressDrawable.java",
    "content": "/*\n * Copyright (C) 2014 The Android Open Source Project\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 in.srain.cube.views.ptr.header;\n\nimport android.content.Context;\nimport android.content.res.Resources;\nimport android.graphics.*;\nimport android.graphics.Paint.Style;\nimport android.graphics.drawable.Animatable;\nimport android.graphics.drawable.Drawable;\nimport android.graphics.drawable.ShapeDrawable;\nimport android.graphics.drawable.shapes.OvalShape;\nimport android.os.Build;\nimport android.util.DisplayMetrics;\nimport android.view.View;\nimport android.view.animation.*;\nimport android.view.animation.Interpolator;\nimport in.srain.cube.views.ptr.util.PtrLocalDisplay;\n\nimport java.util.ArrayList;\n\n/**\n * Fancy progress indicator for Material theme.\n * It's taken from {@link android.support.v4.widget}.\n * I've done some slight changes.\n *\n * @hide\n */\npublic class MaterialProgressDrawable extends Drawable implements Animatable {\n\n    // Maps to ProgressBar.Large style\n    public static final int LARGE = 0;\n    // Maps to ProgressBar default style\n    public static final int DEFAULT = 1;\n    private static final Interpolator LINEAR_INTERPOLATOR = new LinearInterpolator();\n    private static final Interpolator END_CURVE_INTERPOLATOR = new EndCurveInterpolator();\n    private static final Interpolator START_CURVE_INTERPOLATOR = new StartCurveInterpolator();\n    private static final Interpolator EASE_INTERPOLATOR = new AccelerateDecelerateInterpolator();\n    // Maps to ProgressBar default style\n    private static final int CIRCLE_DIAMETER = 40;\n    private static final float CENTER_RADIUS = 8.75f; //should add up to 10 when + stroke_width\n    private static final float STROKE_WIDTH = 2.5f;\n    // Maps to ProgressBar.Large style\n    private static final int CIRCLE_DIAMETER_LARGE = 56;\n    private static final float CENTER_RADIUS_LARGE = 12.5f;\n    private static final float STROKE_WIDTH_LARGE = 3f;\n    /**\n     * The duration of a single progress spin in milliseconds.\n     */\n    private static final int ANIMATION_DURATION = 1000 * 80 / 60;\n    /**\n     * The number of points in the progress \"star\".\n     */\n    private static final float NUM_POINTS = 5f;\n    /**\n     * Layout info for the arrowhead in dp\n     */\n    private static final int ARROW_WIDTH = 10;\n    private static final int ARROW_HEIGHT = 5;\n    private static final float ARROW_OFFSET_ANGLE = 5;\n    /**\n     * Layout info for the arrowhead for the large spinner in dp\n     */\n    private static final int ARROW_WIDTH_LARGE = 12;\n    private static final int ARROW_HEIGHT_LARGE = 6;\n    private static final float MAX_PROGRESS_ARC = .8f;\n    private static final int KEY_SHADOW_COLOR = 0x1E000000;\n    private static final int FILL_SHADOW_COLOR = 0x3D000000;\n    private static final float SHADOW_RADIUS = 3.5f;\n    private static final float X_OFFSET = 0f;\n    private static final float Y_OFFSET = 1.75f;\n    private final int[] COLORS = new int[]{\n            0xFFC93437,\n            0xFF375BF1,\n            0xFFF7D23E,\n            0xFF34A350\n    };\n    /**\n     * The list of animators operating on this drawable.\n     */\n    private final ArrayList<Animation> mAnimators = new ArrayList<Animation>();\n    /**\n     * The indicator ring, used to manage animation state.\n     */\n    private final Ring mRing;\n    private final Callback mCallback = new Callback() {\n        @Override\n        public void invalidateDrawable(Drawable d) {\n            invalidateSelf();\n        }\n\n        @Override\n        public void scheduleDrawable(Drawable d, Runnable what, long when) {\n            scheduleSelf(what, when);\n        }\n\n        @Override\n        public void unscheduleDrawable(Drawable d, Runnable what) {\n            unscheduleSelf(what);\n        }\n    };\n    /**\n     * Canvas rotation in degrees.\n     */\n    private float mRotation;\n    private Resources mResources;\n    private View mParent;\n    private Animation mAnimation;\n    private float mRotationCount;\n    private double mWidth;\n    private double mHeight;\n    private Animation mFinishAnimation;\n    private int mBackgroundColor;\n    private ShapeDrawable mShadow;\n\n    public MaterialProgressDrawable(Context context, View parent) {\n        mParent = parent;\n        mResources = context.getResources();\n        mRing = new Ring(mCallback);\n        mRing.setColors(COLORS);\n        updateSizes(DEFAULT);\n        setupAnimators();\n    }\n\n    private void setSizeParameters(double progressCircleWidth, double progressCircleHeight,\n                                   double centerRadius, double strokeWidth, float arrowWidth, float arrowHeight) {\n        final Ring ring = mRing;\n        final DisplayMetrics metrics = mResources.getDisplayMetrics();\n        final float screenDensity = metrics.density;\n        mWidth = progressCircleWidth * screenDensity;\n        mHeight = progressCircleHeight * screenDensity;\n        ring.setStrokeWidth((float) strokeWidth * screenDensity);\n        ring.setCenterRadius(centerRadius * screenDensity);\n        ring.setColorIndex(0);\n        ring.setArrowDimensions(arrowWidth * screenDensity, arrowHeight * screenDensity);\n        ring.setInsets((int) mWidth, (int) mHeight);\n        setUp(mWidth);\n    }\n\n    private void setUp(final double diameter) {\n        PtrLocalDisplay.init(mParent.getContext());\n        final int shadowYOffset = PtrLocalDisplay.dp2px(Y_OFFSET);\n        final int shadowXOffset = PtrLocalDisplay.dp2px(X_OFFSET);\n        int mShadowRadius = PtrLocalDisplay.dp2px(SHADOW_RADIUS);\n        OvalShape oval = new OvalShadow(mShadowRadius, (int) diameter);\n        mShadow = new ShapeDrawable(oval);\n        if (Build.VERSION.SDK_INT >= 11) {\n            mParent.setLayerType(View.LAYER_TYPE_SOFTWARE, mShadow.getPaint());\n        }\n        mShadow.getPaint().setShadowLayer(mShadowRadius, shadowXOffset, shadowYOffset, KEY_SHADOW_COLOR);\n    }\n\n    /**\n     * Set the overall size for the progress spinner. This updates the radius\n     * and stroke width of the ring.\n     *\n     * @param size One of {@link MaterialProgressDrawable#LARGE} or\n     *             {@link MaterialProgressDrawable#DEFAULT}\n     */\n    public void updateSizes(int size) {\n        if (size == LARGE) {\n            setSizeParameters(CIRCLE_DIAMETER_LARGE, CIRCLE_DIAMETER_LARGE, CENTER_RADIUS_LARGE,\n                    STROKE_WIDTH_LARGE, ARROW_WIDTH_LARGE, ARROW_HEIGHT_LARGE);\n        } else {\n            setSizeParameters(CIRCLE_DIAMETER, CIRCLE_DIAMETER, CENTER_RADIUS, STROKE_WIDTH,\n                    ARROW_WIDTH, ARROW_HEIGHT);\n        }\n    }\n\n    /**\n     * @param show Set to true to display the arrowhead on the progress spinner.\n     */\n    public void showArrow(boolean show) {\n        mRing.setShowArrow(show);\n    }\n\n    /**\n     * @param scale Set the scale of the arrowhead for the spinner.\n     */\n    public void setArrowScale(float scale) {\n        mRing.setArrowScale(scale);\n    }\n\n    /**\n     * Set the start and end trim for the progress spinner arc.\n     *\n     * @param startAngle start angle\n     * @param endAngle   end angle\n     */\n    public void setStartEndTrim(float startAngle, float endAngle) {\n        mRing.setStartTrim(startAngle);\n        mRing.setEndTrim(endAngle);\n    }\n\n    /**\n     * Set the amount of rotation to apply to the progress spinner.\n     *\n     * @param rotation Rotation is from [0..1]\n     */\n    public void setProgressRotation(float rotation) {\n        mRing.setRotation(rotation);\n    }\n\n    /**\n     * Update the background color of the circle image view.\n     */\n    public void setBackgroundColor(int color) {\n        mBackgroundColor = color;\n        mRing.setBackgroundColor(color);\n    }\n\n    /**\n     * Set the colors used in the progress animation from color resources.\n     * The first color will also be the color of the bar that grows in response\n     * to a user swipe gesture.\n     *\n     * @param colors\n     */\n    public void setColorSchemeColors(int... colors) {\n        mRing.setColors(colors);\n        mRing.setColorIndex(0);\n    }\n\n    @Override\n    public int getIntrinsicHeight() {\n        return (int) mHeight;\n    }\n\n    @Override\n    public int getIntrinsicWidth() {\n        return (int) mWidth;\n    }\n\n    @Override\n    public void draw(Canvas c) {\n        if (mShadow != null) {\n            mShadow.getPaint().setColor(mBackgroundColor);\n            mShadow.draw(c);\n        }\n\n        final Rect bounds = getBounds();\n        final int saveCount = c.save();\n        c.rotate(mRotation, bounds.exactCenterX(), bounds.exactCenterY());\n        mRing.draw(c, bounds);\n        c.restoreToCount(saveCount);\n    }\n\n    public int getAlpha() {\n        return mRing.getAlpha();\n    }\n\n    @Override\n    public void setAlpha(int alpha) {\n        mRing.setAlpha(alpha);\n    }\n\n    @Override\n    public void setColorFilter(ColorFilter colorFilter) {\n        mRing.setColorFilter(colorFilter);\n    }\n\n    @SuppressWarnings(\"unused\")\n    private float getRotation() {\n        return mRotation;\n    }\n\n    @SuppressWarnings(\"unused\")\n    void setRotation(float rotation) {\n        mRotation = rotation;\n        invalidateSelf();\n    }\n\n    @Override\n    public int getOpacity() {\n        return PixelFormat.TRANSLUCENT;\n    }\n\n    @Override\n    public boolean isRunning() {\n        final ArrayList<Animation> animators = mAnimators;\n        final int N = animators.size();\n        for (int i = 0; i < N; i++) {\n            final Animation animator = animators.get(i);\n            if (animator.hasStarted() && !animator.hasEnded()) {\n                return true;\n            }\n        }\n        return false;\n    }\n\n    @Override\n    public void start() {\n        mAnimation.reset();\n        mRing.storeOriginals();\n        // Already showing some part of the ring\n        if (mRing.getEndTrim() != mRing.getStartTrim()) {\n            mParent.startAnimation(mFinishAnimation);\n        } else {\n            mRing.setColorIndex(0);\n            mRing.resetOriginals();\n            mParent.startAnimation(mAnimation);\n        }\n    }\n\n    @Override\n    public void stop() {\n        mParent.clearAnimation();\n        setRotation(0);\n        mRing.setShowArrow(false);\n        mRing.setColorIndex(0);\n        mRing.resetOriginals();\n    }\n\n    private void setupAnimators() {\n        final Ring ring = mRing;\n        final Animation finishRingAnimation = new Animation() {\n            public void applyTransformation(float interpolatedTime, Transformation t) {\n                // shrink back down and complete a full rotation before starting other circles\n                // Rotation goes between [0..1].\n                float targetRotation = (float) (Math.floor(ring.getStartingRotation()\n                        / MAX_PROGRESS_ARC) + 1f);\n                final float startTrim = ring.getStartingStartTrim()\n                        + (ring.getStartingEndTrim() - ring.getStartingStartTrim())\n                        * interpolatedTime;\n                ring.setStartTrim(startTrim);\n                final float rotation = ring.getStartingRotation()\n                        + ((targetRotation - ring.getStartingRotation()) * interpolatedTime);\n                ring.setRotation(rotation);\n                ring.setArrowScale(1 - interpolatedTime);\n            }\n        };\n        finishRingAnimation.setInterpolator(EASE_INTERPOLATOR);\n        finishRingAnimation.setDuration(ANIMATION_DURATION / 2);\n        finishRingAnimation.setAnimationListener(new Animation.AnimationListener() {\n            @Override\n            public void onAnimationStart(Animation animation) {\n            }\n\n            @Override\n            public void onAnimationEnd(Animation animation) {\n                ring.goToNextColor();\n                ring.storeOriginals();\n                ring.setShowArrow(false);\n                mParent.startAnimation(mAnimation);\n            }\n\n            @Override\n            public void onAnimationRepeat(Animation animation) {\n            }\n        });\n        final Animation animation = new Animation() {\n            @Override\n            public void applyTransformation(float interpolatedTime, Transformation t) {\n                // The minProgressArc is calculated from 0 to create an angle that\n                // matches the stroke width.\n                final float minProgressArc = (float) Math.toRadians(ring.getStrokeWidth()\n                        / (2 * Math.PI * ring.getCenterRadius()));\n                final float startingEndTrim = ring.getStartingEndTrim();\n                final float startingTrim = ring.getStartingStartTrim();\n                final float startingRotation = ring.getStartingRotation();\n                // Offset the minProgressArc to where the endTrim is located.\n                final float minArc = MAX_PROGRESS_ARC - minProgressArc;\n                final float endTrim = startingEndTrim\n                        + (minArc * START_CURVE_INTERPOLATOR.getInterpolation(interpolatedTime));\n                ring.setEndTrim(endTrim);\n                final float startTrim = startingTrim\n                        + (MAX_PROGRESS_ARC * END_CURVE_INTERPOLATOR\n                        .getInterpolation(interpolatedTime));\n                ring.setStartTrim(startTrim);\n                final float rotation = startingRotation + (0.25f * interpolatedTime);\n                ring.setRotation(rotation);\n                float groupRotation = ((720.0f / NUM_POINTS) * interpolatedTime)\n                        + (720.0f * (mRotationCount / NUM_POINTS));\n                setRotation(groupRotation);\n            }\n        };\n        animation.setRepeatCount(Animation.INFINITE);\n        animation.setRepeatMode(Animation.RESTART);\n        animation.setInterpolator(LINEAR_INTERPOLATOR);\n        animation.setDuration(ANIMATION_DURATION);\n        animation.setAnimationListener(new Animation.AnimationListener() {\n            @Override\n            public void onAnimationStart(Animation animation) {\n                mRotationCount = 0;\n            }\n\n            @Override\n            public void onAnimationEnd(Animation animation) {\n                // do nothing\n            }\n\n            @Override\n            public void onAnimationRepeat(Animation animation) {\n                ring.storeOriginals();\n                ring.goToNextColor();\n                ring.setStartTrim(ring.getEndTrim());\n                mRotationCount = (mRotationCount + 1) % (NUM_POINTS);\n            }\n        });\n        mFinishAnimation = finishRingAnimation;\n        mAnimation = animation;\n    }\n\n    private static class Ring {\n        private final RectF mTempBounds = new RectF();\n        private final Paint mArcPaint = new Paint();\n        private final Paint mArrowPaint = new Paint();\n        private final Callback mRingCallback;\n        private final Paint mCirclePaint = new Paint();\n        private float mStartTrim = 0.0f;\n        private float mEndTrim = 0.0f;\n        private float mRotation = 0.0f;\n        private float mStrokeWidth = 5.0f;\n        private float mStrokeInset = 2.5f;\n        private int[] mColors;\n        // mColorIndex represents the offset into the available mColors that the\n        // progress circle should currently display. As the progress circle is\n        // animating, the mColorIndex moves by one to the next available color.\n        private int mColorIndex;\n        private float mStartingStartTrim;\n        private float mStartingEndTrim;\n        private float mStartingRotation;\n        private boolean mShowArrow;\n        private Path mArrow;\n        private float mArrowScale;\n        private double mRingCenterRadius;\n        private int mArrowWidth;\n        private int mArrowHeight;\n        private int mAlpha;\n        private int mBackgroundColor;\n\n        public Ring(Callback callback) {\n            mRingCallback = callback;\n            mArcPaint.setStrokeCap(Paint.Cap.SQUARE);\n            mArcPaint.setAntiAlias(true);\n            mArcPaint.setStyle(Style.STROKE);\n            mArrowPaint.setStyle(Paint.Style.FILL);\n            mArrowPaint.setAntiAlias(true);\n\n            mCirclePaint.setAntiAlias(true);\n        }\n\n        public void setBackgroundColor(int color) {\n            mBackgroundColor = color;\n        }\n\n        /**\n         * Set the dimensions of the arrowhead.\n         *\n         * @param width  Width of the hypotenuse of the arrow head\n         * @param height Height of the arrow point\n         */\n        public void setArrowDimensions(float width, float height) {\n            mArrowWidth = (int) width;\n            mArrowHeight = (int) height;\n        }\n\n        /**\n         * Draw the progress spinner\n         */\n        public void draw(Canvas c, Rect bounds) {\n\n            mCirclePaint.setColor(mBackgroundColor);\n            mCirclePaint.setAlpha(mAlpha);\n\n            c.drawCircle(bounds.exactCenterX(), bounds.exactCenterY(), bounds.width() / 2, mCirclePaint);\n\n            final RectF arcBounds = mTempBounds;\n            arcBounds.set(bounds);\n            arcBounds.inset(mStrokeInset, mStrokeInset);\n            final float startAngle = (mStartTrim + mRotation) * 360;\n            final float endAngle = (mEndTrim + mRotation) * 360;\n            float sweepAngle = endAngle - startAngle;\n            mArcPaint.setColor(mColors[mColorIndex]);\n            mArcPaint.setAlpha(mAlpha);\n            c.drawArc(arcBounds, startAngle, sweepAngle, false, mArcPaint);\n            drawTriangle(c, startAngle, sweepAngle, bounds);\n        }\n\n        private void drawTriangle(Canvas c, float startAngle, float sweepAngle, Rect bounds) {\n            if (mShowArrow) {\n                if (mArrow == null) {\n                    mArrow = new android.graphics.Path();\n                    mArrow.setFillType(android.graphics.Path.FillType.EVEN_ODD);\n                } else {\n                    mArrow.reset();\n                }\n                // Adjust the position of the triangle so that it is inset as\n                // much as the arc, but also centered on the arc.\n                float inset = (int) mStrokeInset / 2 * mArrowScale;\n                float x = (float) (mRingCenterRadius * Math.cos(0) + bounds.exactCenterX());\n                float y = (float) (mRingCenterRadius * Math.sin(0) + bounds.exactCenterY());\n                // Update the path each time. This works around an issue in SKIA\n                // where concatenating a rotation matrix to a scale matrix\n                // ignored a starting negative rotation. This appears to have\n                // been fixed as of API 21.\n                mArrow.moveTo(0, 0);\n                mArrow.lineTo(mArrowWidth * mArrowScale, 0);\n                mArrow.lineTo((mArrowWidth * mArrowScale / 2), (mArrowHeight\n                        * mArrowScale));\n                mArrow.offset(x - inset, y);\n                mArrow.close();\n                // draw a triangle\n                mArrowPaint.setColor(mColors[mColorIndex]);\n                mArrowPaint.setAlpha(mAlpha);\n                c.rotate(startAngle + sweepAngle - ARROW_OFFSET_ANGLE, bounds.exactCenterX(),\n                        bounds.exactCenterY());\n                c.drawPath(mArrow, mArrowPaint);\n            }\n        }\n\n        /**\n         * Set the colors the progress spinner alternates between.\n         *\n         * @param colors Array of integers describing the colors. Must be non-<code>null</code>.\n         */\n        public void setColors(int[] colors) {\n            mColors = colors;\n            // if colors are reset, make sure to reset the color index as well\n            setColorIndex(0);\n        }\n\n        /**\n         * @param index Index into the color array of the color to display in\n         *              the progress spinner.\n         */\n        public void setColorIndex(int index) {\n            mColorIndex = index;\n        }\n\n        /**\n         * Proceed to the next available ring color. This will automatically\n         * wrap back to the beginning of colors.\n         */\n        public void goToNextColor() {\n            mColorIndex = (mColorIndex + 1) % (mColors.length);\n        }\n\n        public void setColorFilter(ColorFilter filter) {\n            mArcPaint.setColorFilter(filter);\n            invalidateSelf();\n        }\n\n        /**\n         * @return Current alpha of the progress spinner and arrowhead.\n         */\n        public int getAlpha() {\n            return mAlpha;\n        }\n\n        /**\n         * @param alpha Set the alpha of the progress spinner and associated arrowhead.\n         */\n        public void setAlpha(int alpha) {\n            mAlpha = alpha;\n        }\n\n        @SuppressWarnings(\"unused\")\n        public float getStrokeWidth() {\n            return mStrokeWidth;\n        }\n\n        /**\n         * @param strokeWidth Set the stroke width of the progress spinner in pixels.\n         */\n        public void setStrokeWidth(float strokeWidth) {\n            mStrokeWidth = strokeWidth;\n            mArcPaint.setStrokeWidth(strokeWidth);\n            invalidateSelf();\n        }\n\n        @SuppressWarnings(\"unused\")\n        public float getStartTrim() {\n            return mStartTrim;\n        }\n\n        @SuppressWarnings(\"unused\")\n        public void setStartTrim(float startTrim) {\n            mStartTrim = startTrim;\n            invalidateSelf();\n        }\n\n        public float getStartingStartTrim() {\n            return mStartingStartTrim;\n        }\n\n        public float getStartingEndTrim() {\n            return mStartingEndTrim;\n        }\n\n        @SuppressWarnings(\"unused\")\n        public float getEndTrim() {\n            return mEndTrim;\n        }\n\n        @SuppressWarnings(\"unused\")\n        public void setEndTrim(float endTrim) {\n            mEndTrim = endTrim;\n            invalidateSelf();\n        }\n\n        @SuppressWarnings(\"unused\")\n        public float getRotation() {\n            return mRotation;\n        }\n\n        @SuppressWarnings(\"unused\")\n        public void setRotation(float rotation) {\n            mRotation = rotation;\n            invalidateSelf();\n        }\n\n        public void setInsets(int width, int height) {\n            final float minEdge = (float) Math.min(width, height);\n            float insets;\n            if (mRingCenterRadius <= 0 || minEdge < 0) {\n                insets = (float) Math.ceil(mStrokeWidth / 2.0f);\n            } else {\n                insets = (float) (minEdge / 2.0f - mRingCenterRadius);\n            }\n            mStrokeInset = insets;\n        }\n\n        @SuppressWarnings(\"unused\")\n        public float getInsets() {\n            return mStrokeInset;\n        }\n\n        public double getCenterRadius() {\n            return mRingCenterRadius;\n        }\n\n        /**\n         * @param centerRadius Inner radius in px of the circle the progress\n         *                     spinner arc traces.\n         */\n        public void setCenterRadius(double centerRadius) {\n            mRingCenterRadius = centerRadius;\n        }\n\n        /**\n         * @param show Set to true to show the arrow head on the progress spinner.\n         */\n        public void setShowArrow(boolean show) {\n            if (mShowArrow != show) {\n                mShowArrow = show;\n                invalidateSelf();\n            }\n        }\n\n        /**\n         * @param scale Set the scale of the arrowhead for the spinner.\n         */\n        public void setArrowScale(float scale) {\n            if (scale != mArrowScale) {\n                mArrowScale = scale;\n                invalidateSelf();\n            }\n        }\n\n        /**\n         * @return The amount the progress spinner is currently rotated, between [0..1].\n         */\n        public float getStartingRotation() {\n            return mStartingRotation;\n        }\n\n        /**\n         * If the start / end trim are offset to begin with, store them so that\n         * animation starts from that offset.\n         */\n        public void storeOriginals() {\n            mStartingStartTrim = mStartTrim;\n            mStartingEndTrim = mEndTrim;\n            mStartingRotation = mRotation;\n        }\n\n        /**\n         * Reset the progress spinner to default rotation, start and end angles.\n         */\n        public void resetOriginals() {\n            mStartingStartTrim = 0;\n            mStartingEndTrim = 0;\n            mStartingRotation = 0;\n            setStartTrim(0);\n            setEndTrim(0);\n            setRotation(0);\n        }\n\n        private void invalidateSelf() {\n            mRingCallback.invalidateDrawable(null);\n        }\n    }\n\n    /**\n     * Squishes the interpolation curve into the second half of the animation.\n     */\n    private static class EndCurveInterpolator extends AccelerateDecelerateInterpolator {\n        @Override\n        public float getInterpolation(float input) {\n            return super.getInterpolation(Math.max(0, (input - 0.5f) * 2.0f));\n        }\n    }\n\n    /**\n     * Squishes the interpolation curve into the first half of the animation.\n     */\n    private static class StartCurveInterpolator extends AccelerateDecelerateInterpolator {\n        @Override\n        public float getInterpolation(float input) {\n            return super.getInterpolation(Math.min(1, input * 2.0f));\n        }\n    }\n\n    /**\n     * Taken from {@link package android.support.v4.widget}\n     */\n    private class OvalShadow extends OvalShape {\n        private RadialGradient mRadialGradient;\n        private int mShadowRadius;\n        private Paint mShadowPaint;\n        private int mCircleDiameter;\n\n        public OvalShadow(int shadowRadius, int circleDiameter) {\n            super();\n            mShadowPaint = new Paint();\n            mShadowRadius = shadowRadius;\n            mCircleDiameter = circleDiameter;\n            mRadialGradient = new RadialGradient(mCircleDiameter / 2, mCircleDiameter / 2,\n                    mShadowRadius, new int[]{\n                    FILL_SHADOW_COLOR, Color.TRANSPARENT\n            }, null, Shader.TileMode.CLAMP);\n            mShadowPaint.setShader(mRadialGradient);\n        }\n\n        @Override\n        public void draw(Canvas canvas, Paint paint) {\n            final int viewWidth = getBounds().width();\n            final int viewHeight = getBounds().height();\n            canvas.drawCircle(viewWidth / 2, viewHeight / 2, (mCircleDiameter / 2 + mShadowRadius),\n                    mShadowPaint);\n            canvas.drawCircle(viewWidth / 2, viewHeight / 2, (mCircleDiameter / 2), paint);\n        }\n    }\n}"
  },
  {
    "path": "ptr-lib/src/in/srain/cube/views/ptr/header/StoreHouseBarItem.java",
    "content": "package in.srain.cube.views.ptr.header;\n\nimport android.graphics.Canvas;\nimport android.graphics.Paint;\nimport android.graphics.PointF;\nimport android.view.animation.Animation;\nimport android.view.animation.Transformation;\n\nimport java.util.Random;\n\n/**\n * Created by srain on 11/6/14.\n */\npublic class StoreHouseBarItem extends Animation {\n\n    public PointF midPoint;\n    public float translationX;\n    public int index;\n\n    private final Paint mPaint = new Paint();\n    private float mFromAlpha = 1.0f;\n    private float mToAlpha = 0.4f;\n    private PointF mCStartPoint;\n    private PointF mCEndPoint;\n\n    public StoreHouseBarItem(int index, PointF start, PointF end, int color, int lineWidth) {\n        this.index = index;\n\n        midPoint = new PointF((start.x + end.x) / 2, (start.y + end.y) / 2);\n\n        mCStartPoint = new PointF(start.x - midPoint.x, start.y - midPoint.y);\n        mCEndPoint = new PointF(end.x - midPoint.x, end.y - midPoint.y);\n\n        setColor(color);\n        setLineWidth(lineWidth);\n        mPaint.setAntiAlias(true);\n        mPaint.setStyle(Paint.Style.STROKE);\n    }\n\n    public void setLineWidth(int width) {\n        mPaint.setStrokeWidth(width);\n    }\n\n    public void setColor(int color) {\n        mPaint.setColor(color);\n    }\n\n    public void resetPosition(int horizontalRandomness) {\n        Random random = new Random();\n        int randomNumber = -random.nextInt(horizontalRandomness) + horizontalRandomness;\n        translationX = randomNumber;\n    }\n\n    @Override\n    protected void applyTransformation(float interpolatedTime, Transformation t) {\n        float alpha = mFromAlpha;\n        alpha = alpha + ((mToAlpha - alpha) * interpolatedTime);\n        setAlpha(alpha);\n    }\n\n    public void start(float fromAlpha, float toAlpha) {\n        mFromAlpha = fromAlpha;\n        mToAlpha = toAlpha;\n        super.start();\n    }\n\n    public void setAlpha(float alpha) {\n        mPaint.setAlpha((int) (alpha * 255));\n    }\n\n    public void draw(Canvas canvas) {\n        canvas.drawLine(mCStartPoint.x, mCStartPoint.y, mCEndPoint.x, mCEndPoint.y, mPaint);\n    }\n}"
  },
  {
    "path": "ptr-lib/src/in/srain/cube/views/ptr/header/StoreHouseHeader.java",
    "content": "package in.srain.cube.views.ptr.header;\n\nimport android.content.Context;\nimport android.graphics.Canvas;\nimport android.graphics.Color;\nimport android.graphics.Matrix;\nimport android.graphics.PointF;\nimport android.util.AttributeSet;\nimport android.view.View;\nimport android.view.animation.Transformation;\nimport in.srain.cube.views.ptr.PtrFrameLayout;\nimport in.srain.cube.views.ptr.PtrUIHandler;\nimport in.srain.cube.views.ptr.indicator.PtrIndicator;\nimport in.srain.cube.views.ptr.util.PtrLocalDisplay;\n\nimport java.util.ArrayList;\n\npublic class StoreHouseHeader extends View implements PtrUIHandler {\n\n    public ArrayList<StoreHouseBarItem> mItemList = new ArrayList<StoreHouseBarItem>();\n\n    private int mLineWidth = -1;\n    private float mScale = 1;\n    private int mDropHeight = -1;\n    private float mInternalAnimationFactor = 0.7f;\n    private int mHorizontalRandomness = -1;\n\n    private float mProgress = 0;\n\n    private int mDrawZoneWidth = 0;\n    private int mDrawZoneHeight = 0;\n    private int mOffsetX = 0;\n    private int mOffsetY = 0;\n    private float mBarDarkAlpha = 0.4f;\n    private float mFromAlpha = 1.0f;\n    private float mToAlpha = 0.4f;\n\n    private int mLoadingAniDuration = 1000;\n    private int mLoadingAniSegDuration = 1000;\n    private int mLoadingAniItemDuration = 400;\n\n    private Transformation mTransformation = new Transformation();\n    private boolean mIsInLoading = false;\n    private AniController mAniController = new AniController();\n    private int mTextColor = Color.WHITE;\n\n    public StoreHouseHeader(Context context) {\n        super(context);\n        initView();\n    }\n\n    public StoreHouseHeader(Context context, AttributeSet attrs) {\n        super(context, attrs);\n        initView();\n    }\n\n    public StoreHouseHeader(Context context, AttributeSet attrs, int defStyleAttr) {\n        super(context, attrs, defStyleAttr);\n        initView();\n    }\n\n    private void initView() {\n        PtrLocalDisplay.init(getContext());\n        mLineWidth = PtrLocalDisplay.dp2px(1);\n        mDropHeight = PtrLocalDisplay.dp2px(40);\n        mHorizontalRandomness = PtrLocalDisplay.SCREEN_WIDTH_PIXELS / 2;\n    }\n\n    private void setProgress(float progress) {\n        mProgress = progress;\n    }\n\n    public int getLoadingAniDuration() {\n        return mLoadingAniDuration;\n    }\n\n    public void setLoadingAniDuration(int duration) {\n        mLoadingAniDuration = duration;\n        mLoadingAniSegDuration = duration;\n    }\n\n    public StoreHouseHeader setLineWidth(int width) {\n        mLineWidth = width;\n        for (int i = 0; i < mItemList.size(); i++) {\n            mItemList.get(i).setLineWidth(width);\n        }\n        return this;\n    }\n\n    public StoreHouseHeader setTextColor(int color) {\n        mTextColor = color;\n        for (int i = 0; i < mItemList.size(); i++) {\n            mItemList.get(i).setColor(color);\n        }\n        return this;\n    }\n\n    public StoreHouseHeader setDropHeight(int height) {\n        mDropHeight = height;\n        return this;\n    }\n\n    @Override\n    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {\n        int height = getTopOffset() + mDrawZoneHeight + getBottomOffset();\n        heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);\n        super.onMeasure(widthMeasureSpec, heightMeasureSpec);\n\n        mOffsetX = (getMeasuredWidth() - mDrawZoneWidth) / 2;\n        mOffsetY = getTopOffset();\n        mDropHeight = getTopOffset();\n    }\n\n    private int getTopOffset() {\n        return getPaddingTop() + PtrLocalDisplay.dp2px(10);\n    }\n\n    private int getBottomOffset() {\n        return getPaddingBottom() + PtrLocalDisplay.dp2px(10);\n    }\n\n    public void initWithString(String str) {\n        initWithString(str, 25);\n    }\n\n    public void initWithString(String str, int fontSize) {\n        ArrayList<float[]> pointList = StoreHousePath.getPath(str, fontSize * 0.01f, 14);\n        initWithPointList(pointList);\n    }\n\n    public void initWithStringArray(int id) {\n        String[] points = getResources().getStringArray(id);\n        ArrayList<float[]> pointList = new ArrayList<float[]>();\n        for (int i = 0; i < points.length; i++) {\n            String[] x = points[i].split(\",\");\n            float[] f = new float[4];\n            for (int j = 0; j < 4; j++) {\n                f[j] = Float.parseFloat(x[j]);\n            }\n            pointList.add(f);\n        }\n        initWithPointList(pointList);\n    }\n\n    public float getScale() {\n        return mScale;\n    }\n\n    public void setScale(float scale) {\n        mScale = scale;\n    }\n\n    public void initWithPointList(ArrayList<float[]> pointList) {\n\n        float drawWidth = 0;\n        float drawHeight = 0;\n        boolean shouldLayout = mItemList.size() > 0;\n        mItemList.clear();\n        for (int i = 0; i < pointList.size(); i++) {\n            float[] line = pointList.get(i);\n            PointF startPoint = new PointF(PtrLocalDisplay.dp2px(line[0]) * mScale, PtrLocalDisplay.dp2px(line[1]) * mScale);\n            PointF endPoint = new PointF(PtrLocalDisplay.dp2px(line[2]) * mScale, PtrLocalDisplay.dp2px(line[3]) * mScale);\n\n            drawWidth = Math.max(drawWidth, startPoint.x);\n            drawWidth = Math.max(drawWidth, endPoint.x);\n\n            drawHeight = Math.max(drawHeight, startPoint.y);\n            drawHeight = Math.max(drawHeight, endPoint.y);\n\n            StoreHouseBarItem item = new StoreHouseBarItem(i, startPoint, endPoint, mTextColor, mLineWidth);\n            item.resetPosition(mHorizontalRandomness);\n            mItemList.add(item);\n        }\n        mDrawZoneWidth = (int) Math.ceil(drawWidth);\n        mDrawZoneHeight = (int) Math.ceil(drawHeight);\n        if (shouldLayout) {\n            requestLayout();\n        }\n    }\n\n    private void beginLoading() {\n        mIsInLoading = true;\n        mAniController.start();\n        invalidate();\n    }\n\n    private void loadFinish() {\n        mIsInLoading = false;\n        mAniController.stop();\n    }\n\n    @Override\n    public void onDraw(Canvas canvas) {\n        super.onDraw(canvas);\n        float progress = mProgress;\n        int c1 = canvas.save();\n        int len = mItemList.size();\n\n        for (int i = 0; i < len; i++) {\n\n            canvas.save();\n            StoreHouseBarItem storeHouseBarItem = mItemList.get(i);\n            float offsetX = mOffsetX + storeHouseBarItem.midPoint.x;\n            float offsetY = mOffsetY + storeHouseBarItem.midPoint.y;\n\n            if (mIsInLoading) {\n                storeHouseBarItem.getTransformation(getDrawingTime(), mTransformation);\n                canvas.translate(offsetX, offsetY);\n            } else {\n\n                if (progress == 0) {\n                    storeHouseBarItem.resetPosition(mHorizontalRandomness);\n                    continue;\n                }\n\n                float startPadding = (1 - mInternalAnimationFactor) * i / len;\n                float endPadding = 1 - mInternalAnimationFactor - startPadding;\n\n                // done\n                if (progress == 1 || progress >= 1 - endPadding) {\n                    canvas.translate(offsetX, offsetY);\n                    storeHouseBarItem.setAlpha(mBarDarkAlpha);\n                } else {\n                    float realProgress;\n                    if (progress <= startPadding) {\n                        realProgress = 0;\n                    } else {\n                        realProgress = Math.min(1, (progress - startPadding) / mInternalAnimationFactor);\n                    }\n                    offsetX += storeHouseBarItem.translationX * (1 - realProgress);\n                    offsetY += -mDropHeight * (1 - realProgress);\n                    Matrix matrix = new Matrix();\n                    matrix.postRotate(360 * realProgress);\n                    matrix.postScale(realProgress, realProgress);\n                    matrix.postTranslate(offsetX, offsetY);\n                    storeHouseBarItem.setAlpha(mBarDarkAlpha * realProgress);\n                    canvas.concat(matrix);\n                }\n            }\n            storeHouseBarItem.draw(canvas);\n            canvas.restore();\n        }\n        if (mIsInLoading) {\n            invalidate();\n        }\n        canvas.restoreToCount(c1);\n    }\n\n    @Override\n    public void onUIReset(PtrFrameLayout frame) {\n        loadFinish();\n        for (int i = 0; i < mItemList.size(); i++) {\n            mItemList.get(i).resetPosition(mHorizontalRandomness);\n\n        }\n    }\n\n    @Override\n    public void onUIRefreshPrepare(PtrFrameLayout frame) {\n\n    }\n\n    @Override\n    public void onUIRefreshBegin(PtrFrameLayout frame) {\n        beginLoading();\n    }\n\n    @Override\n    public void onUIRefreshComplete(PtrFrameLayout frame) {\n        loadFinish();\n    }\n\n    @Override\n    public void onUIPositionChange(PtrFrameLayout frame, boolean isUnderTouch, byte status, PtrIndicator ptrIndicator) {\n\n        float currentPercent = Math.min(1f, ptrIndicator.getCurrentPercent());\n        setProgress(currentPercent);\n        invalidate();\n    }\n\n    private class AniController implements Runnable {\n\n        private int mTick = 0;\n        private int mCountPerSeg = 0;\n        private int mSegCount = 0;\n        private int mInterval = 0;\n        private boolean mRunning = true;\n\n        private void start() {\n            mRunning = true;\n            mTick = 0;\n\n            mInterval = mLoadingAniDuration / mItemList.size();\n            mCountPerSeg = mLoadingAniSegDuration / mInterval;\n            mSegCount = mItemList.size() / mCountPerSeg + 1;\n            run();\n        }\n\n        @Override\n        public void run() {\n\n            int pos = mTick % mCountPerSeg;\n            for (int i = 0; i < mSegCount; i++) {\n\n                int index = i * mCountPerSeg + pos;\n                if (index > mTick) {\n                    continue;\n                }\n\n                index = index % mItemList.size();\n                StoreHouseBarItem item = mItemList.get(index);\n\n                item.setFillAfter(false);\n                item.setFillEnabled(true);\n                item.setFillBefore(false);\n                item.setDuration(mLoadingAniItemDuration);\n                item.start(mFromAlpha, mToAlpha);\n            }\n\n            mTick++;\n            if (mRunning) {\n                postDelayed(this, mInterval);\n            }\n        }\n\n        private void stop() {\n            mRunning = false;\n            removeCallbacks(this);\n        }\n    }\n}"
  },
  {
    "path": "ptr-lib/src/in/srain/cube/views/ptr/header/StoreHousePath.java",
    "content": "package in.srain.cube.views.ptr.header;\n\nimport android.util.SparseArray;\n\nimport java.util.ArrayList;\n\n/**\n * Created by srain on 11/7/14.\n */\npublic class StoreHousePath {\n\n    private static final SparseArray<float[]> sPointList;\n\n    static {\n        sPointList = new SparseArray<float[]>();\n        float[][] LETTERS = new float[][]{\n                new float[]{\n                        // A\n                        24, 0, 1, 22,\n                        1, 22, 1, 72,\n                        24, 0, 47, 22,\n                        47, 22, 47, 72,\n                        1, 48, 47, 48\n                },\n\n                new float[]{\n                        // B\n                        0, 0, 0, 72,\n                        0, 0, 37, 0,\n                        37, 0, 47, 11,\n                        47, 11, 47, 26,\n                        47, 26, 38, 36,\n                        38, 36, 0, 36,\n                        38, 36, 47, 46,\n                        47, 46, 47, 61,\n                        47, 61, 38, 71,\n                        37, 72, 0, 72,\n                },\n\n                new float[]{\n                        // C\n                        47, 0, 0, 0,\n                        0, 0, 0, 72,\n                        0, 72, 47, 72,\n                },\n\n                new float[]{\n                        // D\n                        0, 0, 0, 72,\n                        0, 0, 24, 0,\n                        24, 0, 47, 22,\n                        47, 22, 47, 48,\n                        47, 48, 23, 72,\n                        23, 72, 0, 72,\n                },\n\n                new float[]{\n                        // E\n                        0, 0, 0, 72,\n                        0, 0, 47, 0,\n                        0, 36, 37, 36,\n                        0, 72, 47, 72,\n                },\n\n                new float[]{\n                        // F\n                        0, 0, 0, 72,\n                        0, 0, 47, 0,\n                        0, 36, 37, 36,\n                },\n\n                new float[]{\n                        // G\n                        47, 23, 47, 0,\n                        47, 0, 0, 0,\n                        0, 0, 0, 72,\n                        0, 72, 47, 72,\n                        47, 72, 47, 48,\n                        47, 48, 24, 48,\n                },\n\n                new float[]{\n                        // H\n                        0, 0, 0, 72,\n                        0, 36, 47, 36,\n                        47, 0, 47, 72,\n                },\n\n                new float[]{\n                        // I\n                        0, 0, 47, 0,\n                        24, 0, 24, 72,\n                        0, 72, 47, 72,\n                },\n\n                new float[]{\n                        // J\n                        47, 0, 47, 72,\n                        47, 72, 24, 72,\n                        24, 72, 0, 48,\n                },\n\n                new float[]{\n                        // K\n                        0, 0, 0, 72,\n                        47, 0, 3, 33,\n                        3, 38, 47, 72,\n                },\n\n                new float[]{\n                        // L\n                        0, 0, 0, 72,\n                        0, 72, 47, 72,\n                },\n\n                new float[]{\n                        // M\n                        0, 0, 0, 72,\n                        0, 0, 24, 23,\n                        24, 23, 47, 0,\n                        47, 0, 47, 72,\n                },\n\n                new float[]{\n                        // N\n                        0, 0, 0, 72,\n                        0, 0, 47, 72,\n                        47, 72, 47, 0,\n                },\n\n                new float[]{\n                        // O\n                        0, 0, 0, 72,\n                        0, 72, 47, 72,\n                        47, 72, 47, 0,\n                        47, 0, 0, 0,\n                },\n\n                new float[]{\n                        // P\n                        0, 0, 0, 72,\n                        0, 0, 47, 0,\n                        47, 0, 47, 36,\n                        47, 36, 0, 36,\n                },\n\n                new float[]{\n                        // Q\n                        0, 0, 0, 72,\n                        0, 72, 23, 72,\n                        23, 72, 47, 48,\n                        47, 48, 47, 0,\n                        47, 0, 0, 0,\n                        24, 28, 47, 71,\n                },\n\n                new float[]{\n                        // R\n                        0, 0, 0, 72,\n                        0, 0, 47, 0,\n                        47, 0, 47, 36,\n                        47, 36, 0, 36,\n                        0, 37, 47, 72,\n                },\n\n                new float[]{\n                        // S\n                        47, 0, 0, 0,\n                        0, 0, 0, 36,\n                        0, 36, 47, 36,\n                        47, 36, 47, 72,\n                        47, 72, 0, 72,\n                },\n\n                new float[]{\n                        // T\n                        0, 0, 47, 0,\n                        24, 0, 24, 72,\n                },\n\n                new float[]{\n                        // U\n                        0, 0, 0, 72,\n                        0, 72, 47, 72,\n                        47, 72, 47, 0,\n                },\n\n                new float[]{\n                        // V\n                        0, 0, 24, 72,\n                        24, 72, 47, 0,\n                },\n\n                new float[]{\n                        // W\n                        0, 0, 0, 72,\n                        0, 72, 24, 49,\n                        24, 49, 47, 72,\n                        47, 72, 47, 0\n                },\n\n                new float[]{\n                        // X\n                        0, 0, 47, 72,\n                        47, 0, 0, 72\n                },\n\n                new float[]{\n                        // Y\n                        0, 0, 24, 23,\n                        47, 0, 24, 23,\n                        24, 23, 24, 72\n                },\n\n                new float[]{\n                        // Z\n                        0, 0, 47, 0,\n                        47, 0, 0, 72,\n                        0, 72, 47, 72\n                },\n        };\n        final float[][] NUMBERS = new float[][]{\n                new float[]{\n                        // 0\n                        0, 0, 0, 72,\n                        0, 72, 47, 72,\n                        47, 72, 47, 0,\n                        47, 0, 0, 0,\n                },\n                new float[]{\n                        // 1\n                        24, 0, 24, 72,\n                },\n\n                new float[]{\n                        // 2\n                        0, 0, 47, 0,\n                        47, 0, 47, 36,\n                        47, 36, 0, 36,\n                        0, 36, 0, 72,\n                        0, 72, 47, 72\n                },\n\n                new float[]{\n                        // 3\n                        0, 0, 47, 0,\n                        47, 0, 47, 36,\n                        47, 36, 0, 36,\n                        47, 36, 47, 72,\n                        47, 72, 0, 72,\n                },\n\n                new float[]{\n                        // 4\n                        0, 0, 0, 36,\n                        0, 36, 47, 36,\n                        47, 0, 47, 72,\n                },\n\n                new float[]{\n                        // 5\n                        0, 0, 0, 36,\n                        0, 36, 47, 36,\n                        47, 36, 47, 72,\n                        47, 72, 0, 72,\n                        0, 0, 47, 0\n                },\n\n                new float[]{\n                        // 6\n                        0, 0, 0, 72,\n                        0, 72, 47, 72,\n                        47, 72, 47, 36,\n                        47, 36, 0, 36\n                },\n\n                new float[]{\n                        // 7\n                        0, 0, 47, 0,\n                        47, 0, 47, 72\n                },\n\n                new float[]{\n                        // 8\n                        0, 0, 0, 72,\n                        0, 72, 47, 72,\n                        47, 72, 47, 0,\n                        47, 0, 0, 0,\n                        0, 36, 47, 36\n                },\n\n                new float[]{\n                        // 9\n                        47, 0, 0, 0,\n                        0, 0, 0, 36,\n                        0, 36, 47, 36,\n                        47, 0, 47, 72,\n                }\n        };\n        // A - Z\n        for (int i = 0; i < LETTERS.length; i++) {\n            sPointList.append(i + 65, LETTERS[i]);\n        }\n        // a - z\n        for (int i = 0; i < LETTERS.length; i++) {\n            sPointList.append(i + 65 + 32, LETTERS[i]);\n        }\n        // 0 - 9\n        for (int i = 0; i < NUMBERS.length; i++) {\n            sPointList.append(i + 48, NUMBERS[i]);\n        }\n        // blank\n        addChar(' ', new float[]{});\n        // -\n        addChar('-', new float[]{\n                0, 36, 47, 36\n        });\n        // .\n        addChar('.', new float[]{\n                24, 60, 24, 72\n        });\n    }\n\n    public static void addChar(char c, float[] points) {\n        sPointList.append(c, points);\n    }\n\n    public static ArrayList<float[]> getPath(String str) {\n        return getPath(str, 1, 14);\n    }\n\n    /**\n     * @param str\n     * @param scale\n     * @param gapBetweenLetter\n     * @return ArrayList of float[] {x1, y1, x2, y2}\n     */\n    public static ArrayList<float[]> getPath(String str, float scale, int gapBetweenLetter) {\n        ArrayList<float[]> list = new ArrayList<float[]>();\n        float offsetForWidth = 0;\n        for (int i = 0; i < str.length(); i++) {\n            int pos = str.charAt(i);\n            int key = sPointList.indexOfKey(pos);\n            if (key == -1) {\n                continue;\n            }\n            float[] points = sPointList.get(pos);\n            int pointCount = points.length / 4;\n\n            for (int j = 0; j < pointCount; j++) {\n                float[] line = new float[4];\n                for (int k = 0; k < 4; k++) {\n                    float l = points[j * 4 + k];\n                    // x\n                    if (k % 2 == 0) {\n                        line[k] = (l + offsetForWidth) * scale;\n                    }\n                    // y\n                    else {\n                        line[k] = l * scale;\n                    }\n                }\n                list.add(line);\n            }\n            offsetForWidth += 57 + gapBetweenLetter;\n        }\n        return list;\n    }\n}\n"
  },
  {
    "path": "ptr-lib/src/in/srain/cube/views/ptr/indicator/PtrIndicator.java",
    "content": "package in.srain.cube.views.ptr.indicator;\n\nimport android.graphics.PointF;\n\npublic class PtrIndicator {\n\n    public final static int POS_START = 0;\n    protected int mOffsetToRefresh = 0;\n    private PointF mPtLastMove = new PointF();\n    private float mOffsetX;\n    private float mOffsetY;\n    private int mCurrentPos = 0;\n    private int mLastPos = 0;\n    private int mHeaderHeight;\n    private int mPressedPos = 0;\n\n    private float mRatioOfHeaderHeightToRefresh = 1.2f;\n    private float mResistance = 1.7f;\n    private boolean mIsUnderTouch = false;\n    private int mOffsetToKeepHeaderWhileLoading = -1;\n    // record the refresh complete position\n    private int mRefreshCompleteY = 0;\n\n    public boolean isUnderTouch() {\n        return mIsUnderTouch;\n    }\n\n    public float getResistance() {\n        return mResistance;\n    }\n\n    public void setResistance(float resistance) {\n        mResistance = resistance;\n    }\n\n    public void onRelease() {\n        mIsUnderTouch = false;\n    }\n\n    public void onUIRefreshComplete() {\n        mRefreshCompleteY = mCurrentPos;\n    }\n\n    public boolean goDownCrossFinishPosition() {\n        return mCurrentPos >= mRefreshCompleteY;\n    }\n\n    protected void processOnMove(float currentX, float currentY, float offsetX, float offsetY) {\n        setOffset(offsetX, offsetY / mResistance);\n    }\n\n    public void setRatioOfHeaderHeightToRefresh(float ratio) {\n        mRatioOfHeaderHeightToRefresh = ratio;\n        mOffsetToRefresh = (int) (mHeaderHeight * ratio);\n    }\n\n    public float getRatioOfHeaderToHeightRefresh() {\n        return mRatioOfHeaderHeightToRefresh;\n    }\n\n    public int getOffsetToRefresh() {\n        return mOffsetToRefresh;\n    }\n\n    public void setOffsetToRefresh(int offset) {\n        mRatioOfHeaderHeightToRefresh = mHeaderHeight * 1f / offset;\n        mOffsetToRefresh = offset;\n    }\n\n    public void onPressDown(float x, float y) {\n        mIsUnderTouch = true;\n        mPressedPos = mCurrentPos;\n        mPtLastMove.set(x, y);\n    }\n\n    public final void onMove(float x, float y) {\n        float offsetX = x - mPtLastMove.x;\n        float offsetY = (y - mPtLastMove.y);\n        processOnMove(x, y, offsetX, offsetY);\n        mPtLastMove.set(x, y);\n    }\n\n    protected void setOffset(float x, float y) {\n        mOffsetX = x;\n        mOffsetY = y;\n    }\n\n    public float getOffsetX() {\n        return mOffsetX;\n    }\n\n    public float getOffsetY() {\n        return mOffsetY;\n    }\n\n    public int getLastPosY() {\n        return mLastPos;\n    }\n\n    public int getCurrentPosY() {\n        return mCurrentPos;\n    }\n\n    /**\n     * Update current position before update the UI\n     */\n    public final void setCurrentPos(int current) {\n        mLastPos = mCurrentPos;\n        mCurrentPos = current;\n        onUpdatePos(current, mLastPos);\n    }\n\n    protected void onUpdatePos(int current, int last) {\n\n    }\n\n    public int getHeaderHeight() {\n        return mHeaderHeight;\n    }\n\n    public void setHeaderHeight(int height) {\n        mHeaderHeight = height;\n        updateHeight();\n    }\n\n    protected void updateHeight() {\n        mOffsetToRefresh = (int) (mRatioOfHeaderHeightToRefresh * mHeaderHeight);\n    }\n\n    public void convertFrom(PtrIndicator ptrSlider) {\n        mCurrentPos = ptrSlider.mCurrentPos;\n        mLastPos = ptrSlider.mLastPos;\n        mHeaderHeight = ptrSlider.mHeaderHeight;\n    }\n\n    public boolean hasLeftStartPosition() {\n        return mCurrentPos > POS_START;\n    }\n\n    public boolean hasJustLeftStartPosition() {\n        return mLastPos == POS_START && hasLeftStartPosition();\n    }\n\n    public boolean hasJustBackToStartPosition() {\n        return mLastPos != POS_START && isInStartPosition();\n    }\n\n    public boolean isOverOffsetToRefresh() {\n        return mCurrentPos >= getOffsetToRefresh();\n    }\n\n    public boolean hasMovedAfterPressedDown() {\n        return mCurrentPos != mPressedPos;\n    }\n\n    public boolean isInStartPosition() {\n        return mCurrentPos == POS_START;\n    }\n\n    public boolean crossRefreshLineFromTopToBottom() {\n        return mLastPos < getOffsetToRefresh() && mCurrentPos >= getOffsetToRefresh();\n    }\n\n    public boolean hasJustReachedHeaderHeightFromTopToBottom() {\n        return mLastPos < mHeaderHeight && mCurrentPos >= mHeaderHeight;\n    }\n\n    public boolean isOverOffsetToKeepHeaderWhileLoading() {\n        return mCurrentPos > getOffsetToKeepHeaderWhileLoading();\n    }\n\n    public void setOffsetToKeepHeaderWhileLoading(int offset) {\n        mOffsetToKeepHeaderWhileLoading = offset;\n    }\n\n    public int getOffsetToKeepHeaderWhileLoading() {\n        return mOffsetToKeepHeaderWhileLoading >= 0 ? mOffsetToKeepHeaderWhileLoading : mHeaderHeight;\n    }\n\n    public boolean isAlreadyHere(int to) {\n        return mCurrentPos == to;\n    }\n\n    public float getLastPercent() {\n        final float oldPercent = mHeaderHeight == 0 ? 0 : mLastPos * 1f / mHeaderHeight;\n        return oldPercent;\n    }\n\n    public float getCurrentPercent() {\n        final float currentPercent = mHeaderHeight == 0 ? 0 : mCurrentPos * 1f / mHeaderHeight;\n        return currentPercent;\n    }\n\n    public boolean willOverTop(int to) {\n        return to < POS_START;\n    }\n}\n"
  },
  {
    "path": "ptr-lib/src/in/srain/cube/views/ptr/indicator/PtrTensionIndicator.java",
    "content": "package in.srain.cube.views.ptr.indicator;\n\npublic class PtrTensionIndicator extends PtrIndicator {\n\n    private float DRAG_RATE = 0.5f;\n    private float mDownY;\n    private float mDownPos;\n    private float mOneHeight = 0;\n\n    private float mCurrentDragPercent;\n\n    private int mReleasePos;\n    private float mReleasePercent = -1;\n\n    @Override\n    public void onPressDown(float x, float y) {\n        super.onPressDown(x, y);\n        mDownY = y;\n        mDownPos = getCurrentPosY();\n    }\n\n    @Override\n    public void onRelease() {\n        super.onRelease();\n        mReleasePos = getCurrentPosY();\n        mReleasePercent = mCurrentDragPercent;\n    }\n\n    @Override\n    public void onUIRefreshComplete() {\n        mReleasePos = getCurrentPosY();\n        mReleasePercent = getOverDragPercent();\n    }\n\n    @Override\n    public void setHeaderHeight(int height) {\n        super.setHeaderHeight(height);\n        mOneHeight = height * 4f / 5;\n    }\n\n    @Override\n    protected void processOnMove(float currentX, float currentY, float offsetX, float offsetY) {\n\n        if (currentY < mDownY) {\n            super.processOnMove(currentX, currentY, offsetX, offsetY);\n            return;\n        }\n\n        // distance from top\n        final float scrollTop = (currentY - mDownY) * DRAG_RATE + mDownPos;\n        final float currentDragPercent = scrollTop / mOneHeight;\n\n        if (currentDragPercent < 0) {\n            setOffset(offsetX, 0);\n            return;\n        }\n\n        mCurrentDragPercent = currentDragPercent;\n\n        // 0 ~ 1\n        float boundedDragPercent = Math.min(1f, Math.abs(currentDragPercent));\n        float extraOS = scrollTop - mOneHeight;\n\n        // 0 ~ 2\n        // if extraOS lower than 0, which means scrollTop lower than onHeight, tensionSlingshotPercent will be 0.\n        float tensionSlingshotPercent = Math.max(0, Math.min(extraOS, mOneHeight * 2) / mOneHeight);\n\n        float tensionPercent = (float) ((tensionSlingshotPercent / 4) - Math.pow((tensionSlingshotPercent / 4), 2)) * 2f;\n        float extraMove = (mOneHeight) * tensionPercent / 2;\n        int targetY = (int) ((mOneHeight * boundedDragPercent) + extraMove);\n        int change = targetY - getCurrentPosY();\n\n        setOffset(currentX, change);\n    }\n\n    private float offsetToTarget(float scrollTop) {\n\n        // distance from top\n        final float currentDragPercent = scrollTop / mOneHeight;\n\n        mCurrentDragPercent = currentDragPercent;\n\n        // 0 ~ 1\n        float boundedDragPercent = Math.min(1f, Math.abs(currentDragPercent));\n        float extraOS = scrollTop - mOneHeight;\n\n        // 0 ~ 2\n        // if extraOS lower than 0, which means scrollTop lower than mOneHeight, tensionSlingshotPercent will be 0.\n        float tensionSlingshotPercent = Math.max(0, Math.min(extraOS, mOneHeight * 2) / mOneHeight);\n\n        float tensionPercent = (float) ((tensionSlingshotPercent / 4) - Math.pow((tensionSlingshotPercent / 4), 2)) * 2f;\n        float extraMove = (mOneHeight) * tensionPercent / 2;\n        int targetY = (int) ((mOneHeight * boundedDragPercent) + extraMove);\n\n        return 0;\n    }\n\n    @Override\n    public int getOffsetToKeepHeaderWhileLoading() {\n        return getOffsetToRefresh();\n    }\n\n    @Override\n    public int getOffsetToRefresh() {\n        return (int) mOneHeight;\n    }\n\n    public float getOverDragPercent() {\n        if (isUnderTouch()) {\n            return mCurrentDragPercent;\n        } else {\n            if (mReleasePercent <= 0) {\n                return 1.0f * getCurrentPosY() / getOffsetToKeepHeaderWhileLoading();\n            }\n            // after release\n            return mReleasePercent * getCurrentPosY() / mReleasePos;\n        }\n    }\n}\n"
  },
  {
    "path": "ptr-lib/src/in/srain/cube/views/ptr/util/PtrCLog.java",
    "content": "package in.srain.cube.views.ptr.util;\n\nimport android.util.Log;\n\n/**\n * An encapsulation of {@link Log}, enable log level and print log with parameters.\n *\n * @author http://www.liaohuqiu.net/\n */\npublic class PtrCLog {\n\n    public static final int LEVEL_VERBOSE = 0;\n    public static final int LEVEL_DEBUG = 1;\n    public static final int LEVEL_INFO = 2;\n    public static final int LEVEL_WARNING = 3;\n    public static final int LEVEL_ERROR = 4;\n    public static final int LEVEL_FATAL = 5;\n\n    private static int sLevel = LEVEL_VERBOSE;\n\n    /**\n     * set log level, the level lower than this level will not be logged\n     *\n     * @param level\n     */\n    public static void setLogLevel(int level) {\n        sLevel = level;\n    }\n\n    /**\n     * Send a VERBOSE log message.\n     *\n     * @param tag\n     * @param msg\n     */\n    public static void v(String tag, String msg) {\n        if (sLevel > LEVEL_VERBOSE) {\n            return;\n        }\n        Log.v(tag, msg);\n    }\n\n    /**\n     * Send a VERBOSE log message.\n     *\n     * @param tag\n     * @param msg\n     * @param throwable\n     */\n    public static void v(String tag, String msg, Throwable throwable) {\n        if (sLevel > LEVEL_VERBOSE) {\n            return;\n        }\n        Log.v(tag, msg, throwable);\n    }\n\n    /**\n     * Send a VERBOSE log message.\n     *\n     * @param tag\n     * @param msg\n     * @param args\n     */\n    public static void v(String tag, String msg, Object... args) {\n        if (sLevel > LEVEL_VERBOSE) {\n            return;\n        }\n        if (args.length > 0) {\n            msg = String.format(msg, args);\n        }\n        Log.v(tag, msg);\n    }\n\n    /**\n     * Send a DEBUG log message\n     *\n     * @param tag\n     * @param msg\n     */\n    public static void d(String tag, String msg) {\n        if (sLevel > LEVEL_DEBUG) {\n            return;\n        }\n        Log.d(tag, msg);\n    }\n\n    /**\n     * Send a DEBUG log message\n     *\n     * @param tag\n     * @param msg\n     * @param args\n     */\n    public static void d(String tag, String msg, Object... args) {\n        if (sLevel > LEVEL_DEBUG) {\n            return;\n        }\n        if (args.length > 0) {\n            msg = String.format(msg, args);\n        }\n        Log.d(tag, msg);\n    }\n\n    /**\n     * Send a DEBUG log message\n     *\n     * @param tag\n     * @param msg\n     * @param throwable\n     */\n    public static void d(String tag, String msg, Throwable throwable) {\n        if (sLevel > LEVEL_DEBUG) {\n            return;\n        }\n        Log.d(tag, msg, throwable);\n    }\n\n    /**\n     * Send an INFO log message\n     *\n     * @param tag\n     * @param msg\n     */\n    public static void i(String tag, String msg) {\n        if (sLevel > LEVEL_INFO) {\n            return;\n        }\n        Log.i(tag, msg);\n    }\n\n    /**\n     * Send an INFO log message\n     *\n     * @param tag\n     * @param msg\n     * @param args\n     */\n    public static void i(String tag, String msg, Object... args) {\n        if (sLevel > LEVEL_INFO) {\n            return;\n        }\n        if (args.length > 0) {\n            msg = String.format(msg, args);\n        }\n        Log.i(tag, msg);\n    }\n\n    /**\n     * Send an INFO log message\n     *\n     * @param tag\n     * @param msg\n     */\n    public static void i(String tag, String msg, Throwable throwable) {\n        if (sLevel > LEVEL_INFO) {\n            return;\n        }\n        Log.i(tag, msg, throwable);\n    }\n\n    /**\n     * Send a WARNING log message\n     *\n     * @param tag\n     * @param msg\n     */\n    public static void w(String tag, String msg) {\n        if (sLevel > LEVEL_WARNING) {\n            return;\n        }\n        Log.w(tag, msg);\n    }\n\n    /**\n     * Send a WARNING log message\n     *\n     * @param tag\n     * @param msg\n     * @param args\n     */\n    public static void w(String tag, String msg, Object... args) {\n        if (sLevel > LEVEL_WARNING) {\n            return;\n        }\n        if (args.length > 0) {\n            msg = String.format(msg, args);\n        }\n        Log.w(tag, msg);\n    }\n\n    /**\n     * Send a WARNING log message\n     *\n     * @param tag\n     * @param msg\n     * @param throwable\n     */\n    public static void w(String tag, String msg, Throwable throwable) {\n        if (sLevel > LEVEL_WARNING) {\n            return;\n        }\n        Log.w(tag, msg, throwable);\n    }\n\n    /**\n     * Send an ERROR log message\n     *\n     * @param tag\n     * @param msg\n     */\n    public static void e(String tag, String msg) {\n        if (sLevel > LEVEL_ERROR) {\n            return;\n        }\n        Log.e(tag, msg);\n    }\n\n    /**\n     * Send an ERROR log message\n     *\n     * @param tag\n     * @param msg\n     * @param args\n     */\n    public static void e(String tag, String msg, Object... args) {\n        if (sLevel > LEVEL_ERROR) {\n            return;\n        }\n        if (args.length > 0) {\n            msg = String.format(msg, args);\n        }\n        Log.e(tag, msg);\n    }\n\n    /**\n     * Send an ERROR log message\n     *\n     * @param tag\n     * @param msg\n     * @param throwable\n     */\n    public static void e(String tag, String msg, Throwable throwable) {\n        if (sLevel > LEVEL_ERROR) {\n            return;\n        }\n        Log.e(tag, msg, throwable);\n    }\n\n    /**\n     * Send a FATAL ERROR log message\n     *\n     * @param tag\n     * @param msg\n     */\n    public static void f(String tag, String msg) {\n        if (sLevel > LEVEL_FATAL) {\n            return;\n        }\n        Log.wtf(tag, msg);\n    }\n\n    /**\n     * Send a FATAL ERROR log message\n     *\n     * @param tag\n     * @param msg\n     * @param args\n     */\n    public static void f(String tag, String msg, Object... args) {\n        if (sLevel > LEVEL_FATAL) {\n            return;\n        }\n        if (args.length > 0) {\n            msg = String.format(msg, args);\n        }\n        Log.wtf(tag, msg);\n    }\n\n    /**\n     * Send a FATAL ERROR log message\n     *\n     * @param tag\n     * @param msg\n     * @param throwable\n     */\n    public static void f(String tag, String msg, Throwable throwable) {\n        if (sLevel > LEVEL_FATAL) {\n            return;\n        }\n        Log.wtf(tag, msg, throwable);\n    }\n}\n"
  },
  {
    "path": "ptr-lib/src/in/srain/cube/views/ptr/util/PtrLocalDisplay.java",
    "content": "package in.srain.cube.views.ptr.util;\n\nimport android.content.Context;\nimport android.util.DisplayMetrics;\nimport android.view.View;\nimport android.view.WindowManager;\n\npublic class PtrLocalDisplay {\n\n    public static int SCREEN_WIDTH_PIXELS;\n    public static int SCREEN_HEIGHT_PIXELS;\n    public static float SCREEN_DENSITY;\n    public static int SCREEN_WIDTH_DP;\n    public static int SCREEN_HEIGHT_DP;\n\n    public static void init(Context context) {\n        if (context == null) {\n            return;\n        }\n        DisplayMetrics dm = new DisplayMetrics();\n        WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);\n        wm.getDefaultDisplay().getMetrics(dm);\n        SCREEN_WIDTH_PIXELS = dm.widthPixels;\n        SCREEN_HEIGHT_PIXELS = dm.heightPixels;\n        SCREEN_DENSITY = dm.density;\n        SCREEN_WIDTH_DP = (int) (SCREEN_WIDTH_PIXELS / dm.density);\n        SCREEN_HEIGHT_DP = (int) (SCREEN_HEIGHT_PIXELS / dm.density);\n    }\n\n    public static int dp2px(float dp) {\n        final float scale = SCREEN_DENSITY;\n        return (int) (dp * scale + 0.5f);\n    }\n\n    public static int designedDP2px(float designedDp) {\n        if (SCREEN_WIDTH_DP != 320) {\n            designedDp = designedDp * SCREEN_WIDTH_DP / 320f;\n        }\n        return dp2px(designedDp);\n    }\n\n    public static void setPadding(final View view, float left, float top, float right, float bottom) {\n        view.setPadding(designedDP2px(left), dp2px(top), designedDP2px(right), dp2px(bottom));\n    }\n}\n"
  },
  {
    "path": "publish-to-maven.sh",
    "content": "python update-project.py\n./gradlew clean :ptr-lib:uploadArchives\n"
  },
  {
    "path": "settings.gradle",
    "content": "rootProject.name = 'android-Ultra-Pull-To-Refresh'\n\ninclude ':ptr-lib'\ninclude ':ptr-demo'"
  },
  {
    "path": "template/README-cn.md",
    "content": "###### 欢迎关注我\n\nGitHub: https://github.com/liaohuqiu\n\n微博: http://weibo.com/liaohuqiu\n\n知乎: http://www.zhihu.com/people/liao-hu-qiu\n\n---\n\n# Ultra Pull To Refresh\n\n这是现在已经停止维护的下拉刷新项目的替代方案。继承于ViewGroup可以包含任何View。功能比SwipeRefreshLayout强大。\n\n使用起来非常简单。良好的设计，如果你想定制自己的UI样式，非常简单，就像给ListView加一个Header View那么简单。\n\n支持 `API LEVEL >= 8`。\n\n[APK下载](https://raw.githubusercontent.com/liaohuqiu/android-Ultra-Pull-To-Refresh/master/ptr-demo.apk)\n\n#### 下拉刷新 + 加载更多？\n\n本类库是单纯的下拉刷新。如果你需要用到`加载更多`，看这个项目: https://github.com/liaohuqiu/android-cube-app\n\n#### 使用eclipse的同学请注意, Intellij IDEA / Android Studio 请忽略\n\n**demo可以直接在eclipse中运行, 编译demo项目的同学看这里:  http://www.liaohuqiu.net/cn/posts/compile-ultra-ptr-in-eclipse/**\n\n* 先上两张StoreHouse风格的截图! 感谢 [CBStoreHouseRefreshControl](https://github.com/coolbeet/CBStoreHouseRefreshControl).\n    <div class='row'>\n        <img src='http://srain-github.qiniudn.com/ultra-ptr/store-house-string-array.gif' width=\"300px\" style='border: #f1f1f1 solid 1px'/>\n        <img src='http://srain-github.qiniudn.com/ultra-ptr/store-house-string.gif' width=\"300px\" style='border: #f1f1f1 solid 1px'/>\n    </div>\n\n* 5.0 Material 风格 2014-12-09 新增。**阴影效果，gif图看起来有些失真，看demo吧！**\n    <div class='row'>\n        <img src='http://srain-github.qiniudn.com/ultra-ptr/material-style.gif' width=\"300px\"/>\n    </div>\n\n* **支持所有的View**: \n\n    ListView, GridView, ScrollView, FrameLayout, 甚至 TextView.\n    <div><img src='http://srain-github.qiniudn.com/ultra-ptr/contains-all-of-views.gif' width=\"300px\" style='border: #f1f1f1 solid 1px'/></div>\n\n* 支持各种下拉刷新交互.\n    * 下拉刷新(iOS风格)\n        <div><img src='http://srain-github.qiniudn.com/ultra-ptr/pull-to-refresh.gif' width=\"300px\" style='border: #f1f1f1 solid 1px'/></div>\n\n    * 释放刷新(经典风格)\n        <div><img src='http://srain-github.qiniudn.com/ultra-ptr/release-to-refresh.gif' width=\"300px\" style='border: #f1f1f1 solid 1px'/></div>\n\n    * 刷新时，头部保持(新浪微博)\n\n        <img src='http://srain-github.qiniudn.com/ultra-ptr/keep-header.gif' width=\"300px\"/>\n\n    * 刷新时，头部不保持(微信朋友圈)\n\n        <img src='http://srain-github.qiniudn.com/ultra-ptr/hide-header.gif' width=\"300px\" sytle='border: #f1f1f1 solid 1px'/>\n\n    * 自动刷新，进入界面时自动刷新\n\n        <img src='http://srain-github.qiniudn.com/ultra-ptr/auto-refresh.gif' width=\"300px\" sytle='border: #f1f1f1 solid 1px'/></div>\n\n# 使用方式\n\n#### 中央库依赖\n\n项目已经发布到了Maven中央库，包括`aar`和`apklib`两种格式。在Maven或者Gradle下可如下直接引入:\n\n最新版版本号: `{ptr_lib_version}`, 发布到了: https://oss.sonatype.org/content/repositories/snapshots\n\n在gradle中:\n\n```\nmaven {\n    url 'https://oss.sonatype.org/content/repositories/snapshots'\n}\n```\n\n稳定版: `{ptr_lib_stable_version}`, https://oss.sonatype.org/content/repositories/releases, in gradle:\n\n```\nmavenCentral()\n```\n\n`pom.xml` 文件中\n\n最新版:\n\n```xml\n<dependency>\n    <groupId>in.srain.cube</groupId>\n    <artifactId>ultra-ptr</artifactId>\n    <type>aar</type>\n    <!-- or apklib format, if you want -->\n    <!-- <type>apklib</type> -->\n    <version>{ptr_lib_version}</version>\n</dependency>\n\n稳定版\n\n```xml\n<dependency>\n    <groupId>in.srain.cube</groupId>\n    <artifactId>ultra-ptr</artifactId>\n    <type>aar</type>\n    <!-- or apklib format, if you want -->\n    <!-- <type>apklib</type> -->\n    <version>{ptr_lib_stable_version}</version>\n</dependency>\n```\n\ngradle / Android Studio, 最新版\n\n```\ncompile 'in.srain.cube:ultra-ptr:{ptr_lib_version}'\n```\n\ngradle / Android Studio, 稳定版\n\n```\ncompile 'in.srain.cube:ultra-ptr:{ptr_lib_stable_version}'\n```\n\n#### 配置\n\n有6个参数可配置:\n\n* 阻尼系数\n\n    默认: `1.7f`，越大，感觉下拉时越吃力。\n\n* 触发刷新时移动的位置比例\n\n    默认，`1.2f`，移动达到头部高度1.2倍时可触发刷新操作。\n\n* 回弹延时\n\n    默认 `200ms`，回弹到刷新高度所用时间\n\n* 头部回弹时间\n\n    默认`1000ms`\n\n* 刷新是保持头部\n\n    默认值 `true`.\n\n* 下拉刷新 / 释放刷新\n\n    默认为释放刷新\n\n##### xml中配置示例\n\n```xml\n<in.srain.cube.views.ptr.PtrFrameLayout\n    android:id=\"@+id/store_house_ptr_frame\"\n    xmlns:cube_ptr=\"http://schemas.android.com/apk/res-auto\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n\n    cube_ptr:ptr_resistance=\"1.7\"\n    cube_ptr:ptr_ratio_of_header_height_to_refresh=\"1.2\"\n    cube_ptr:ptr_duration_to_close=\"300\"\n    cube_ptr:ptr_duration_to_close_header=\"2000\"\n    cube_ptr:ptr_keep_header_when_refresh=\"true\"\n    cube_ptr:ptr_pull_to_fresh=\"false\" >\n\n    <LinearLayout\n        android:id=\"@+id/store_house_ptr_image_content\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:background=\"@color/cube_mints_333333\"\n        android:clickable=\"true\"\n        android:padding=\"10dp\">\n\n        <in.srain.cube.image.CubeImageView\n            android:id=\"@+id/store_house_ptr_image\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\" />\n    </LinearLayout>\n\n</in.srain.cube.views.ptr.PtrFrameLayout>\n```\n\n### 也可以在java代码中配置\n\n```java\n// the following are default settings\nmPtrFrame.setResistance(1.7f);\nmPtrFrame.setRatioOfHeaderHeightToRefresh(1.2f);\nmPtrFrame.setDurationToClose(200);\nmPtrFrame.setDurationToCloseHeader(1000);\n// default is false\nmPtrFrame.setPullToRefresh(false);\n// default is true\nmPtrFrame.setKeepHeaderWhenRefresh(true);\n```\n\n### 其他配置\n\n*  刷新时，保持内容不动，仅头部下移, `setPinContent()`\n\n    `Material` 风格时，效果不错，其他风格的头部，效果不好。issue #29\n\n## StoreHouse 风格\n\n* 使用字符串, 支持A-Z, 0-7 以及 `-` `.`\n\n```java\n// header\nfinal StoreHouseHeader header = new StoreHouseHeader(getContext());\nheader.setPadding(0, LocalDisplay.dp2px(15), 0, 0);\n\n/**\n * using a string, support: A-Z 0-9 - .\n * you can add more letters by {@link in.srain.cube.views.ptr.header.StoreHousePath#addChar}\n */\nheader.initWithString('Alibaba');\n```\n\n* 使用资源文件中的路径信息\n\n```java\nheader.initWithStringArray(R.array.storehouse);\n```\n\n资源文件 `res/values/arrays.xml` 内容如下:\n\n```xml\n<resources>\n    <string-array name=\"storehouse\">\n        <item>0,35,12,42,</item>\n        <item>12,42,24,35,</item>\n        <item>24,35,12,28,</item>\n        <item>0,35,12,28,</item>\n        <item>0,21,12,28,</item>\n        <item>12,28,24,21,</item>\n        <item>24,35,24,21,</item>\n        <item>24,21,12,14,</item>\n        <item>0,21,12,14,</item>\n        <item>0,21,0,7,</item>\n        <item>12,14,0,7,</item>\n        <item>12,14,24,7,</item>\n        <item>24,7,12,0,</item>\n        <item>0,7,12,0,</item>\n    </string-array>\n</resources>\n```\n\n# 处理刷新\n\n通过`PtrHandler`，可以检查确定是否可以下来刷新以及在合适的时间刷新数据。\n\n检查是否可以下拉刷新在`PtrDefaultHandler.checkContentCanBePulledDown`中有默认简单的实现，你可以根据实际情况完成这个逻辑。\n\n```\npublic interface PtrHandler {\n\n    /**\n     * 检查是否可以执行下来刷新，比如列表为空或者列表第一项在最上面时。\n     * <p/>\n     * {@link in.srain.cube.views.ptr.PtrDefaultHandler#checkContentCanBePulledDown}\n     */\n    public boolean checkCanDoRefresh(final PtrFrameLayout frame, final View content, final View header);\n\n    /**\n     * 需要加载数据时触发\n     *\n     * @param frame\n     */\n    public void onRefreshBegin(final PtrFrameLayout frame);\n}\n```\n\n例子:\n\n```java\nptrFrame.setPtrHandler(new PtrHandler() {\n    @Override\n    public void onRefreshBegin(PtrFrameLayout frame) {\n        frame.postDelayed(new Runnable() {\n            @Override\n            public void run() {\n                ptrFrame.refreshComplete();\n            }\n        }, 1800);\n    }\n\n    @Override\n    public boolean checkCanDoRefresh(PtrFrameLayout frame, View content, View header) {\n        // 默认实现，根据实际情况做改动\n        return PtrDefaultHandler.checkContentCanBePulledDown(frame, content, header);\n    }\n});\n```\n\n# 常见问题\n\n*  ViewPager滑动冲突: `disableWhenHorizontalMove()`\n\n*  长按LongPressed, `setInterceptEventWhileWorking()`\n\n\n# 联系方式和问题建议\n\n* 微博: http://weibo.com/liaohuqiu\n* QQ 群: \n\n    1. cube系列开源项目使用交流，问题解答: 271918140 (cube-sdk)\n\n        加群前请先阅读群约定: https://github.com/liaohuqiu/qq-tribe-rule\n\n    2. 如果你会通过google解决问题，喜欢独立思考，喜欢和优秀却又温和的人成为朋友，欢迎加入我们在 Slack 上的群组: 我们在 Slack 上的群组: \n    \n        http://join-add1bit.liaohuqiu.net/?channel=git-android-ultra-ptr\n\n* srain@php.net\n* twitter: https://twitter.com/liaohuqiu\n* blog: http://www.liaohuqiu.net\n"
  },
  {
    "path": "template/README.md",
    "content": "###### Welcome to follow me on GitHub or Twitter\n\nGitHub: https://github.com/liaohuqiu\n\nTwitter: https://twitter.com/liaohuqiu\n\n---\n\n[![Build Status](https://travis-ci.org/liaohuqiu/android-Ultra-Pull-To-Refresh.svg?branch=master)](https://travis-ci.org/liaohuqiu/android-Ultra-Pull-To-Refresh)\n[![Android Arsenal](https://img.shields.io/badge/Android%20Arsenal-Ultra%20Pull%20To%20Refresh-brightgreen.svg?style=flat)](https://android-arsenal.com/details/1/1180)\n\n#### [中文版文档](https://github.com/liaohuqiu/android-Ultra-Pull-To-Refresh/blob/master/README-cn.md)\n\nWanna auto-load-more? This will be what you want: https://github.com/liaohuqiu/android-cube-app\n\n# Ultra Pull To Refresh\n\nIt's a replacement for the deprecated pull to refresh solution. It can contain any view you want.\n\nIt's easy to use and more powerful than SwipeRefreshLayout.\n\nIt's well designed, you can customize the UI effect you want as easy as adding a headview to ListView.\n\nSupport `API LEVEL >= 8`, all snapshots are taken from Genymotion, 2.3.7.\n\n[Download APK](https://raw.githubusercontent.com/liaohuqiu/android-Ultra-Pull-To-Refresh/master/ptr-demo.apk)\n\n* StoreHouse Style first! Thanks to [CBStoreHouseRefreshControl](https://github.com/coolbeet/CBStoreHouseRefreshControl).\n    <div class='row'>\n        <img src='http://srain-github.qiniudn.com/ultra-ptr/store-house-string-array.gif' width=\"300px\" style='border: #f1f1f1 solid 1px'/>\n        <img src='http://srain-github.qiniudn.com/ultra-ptr/store-house-string.gif' width=\"300px\" style='border: #f1f1f1 solid 1px'/>\n    </div>\n\n* Material Style, added @ 2014-12-09. **There is a beautiful shadow which looks terrible in gif snapshot. Please Check out the DEMO.**\n    <div class='row'>\n        <img src='http://srain-github.qiniudn.com/ultra-ptr/material-style.gif' width=\"300px\"/>\n    </div>\n\n* **Supports all of the views**: \n    ListView, GridView, ScrollView, FrameLayout, or Even a single TextView.\n    <div><img src='http://srain-github.qiniudn.com/ultra-ptr/contains-all-of-views.gif' width=\"300px\" style='border: #f1f1f1 solid 1px'/></div>\n\n* Supports all of the refresh types.\n    * pull to refresh\n        <div><img src='http://srain-github.qiniudn.com/ultra-ptr/pull-to-refresh.gif' width=\"300px\" style='border: #f1f1f1 solid 1px'/></div>\n    * release to refresh\n        <div><img src='http://srain-github.qiniudn.com/ultra-ptr/release-to-refresh.gif' width=\"300px\" style='border: #f1f1f1 solid 1px'/></div>\n\n    * keep header when refresh \n\n        <img src='http://srain-github.qiniudn.com/ultra-ptr/keep-header.gif' width=\"300px\"/>\n\n    * hide header when refresh\n\n        <img src='http://srain-github.qiniudn.com/ultra-ptr/hide-header.gif' width=\"300px\" sytle='border: #f1f1f1 solid 1px'/>\n\n    * auto refresh\n\n        <img src='http://srain-github.qiniudn.com/ultra-ptr/auto-refresh.gif' width=\"300px\" sytle='border: #f1f1f1 solid 1px'/></div>\n\n# Usage\n\n#### Maven Central\n\nThis project has been pushed to Maven Central, both in `aar` and `apklib`.\n\nThe latest version: `{ptr_lib_version}`, has been published to: https://oss.sonatype.org/content/repositories/snapshots, in gradle:\n\n```\nmaven {\n    url 'https://oss.sonatype.org/content/repositories/snapshots'\n}\n```\n\nThe stable version: `{ptr_lib_stable_version}`, https://oss.sonatype.org/content/repositories/releases, in gradle:\n\n```\nmavenCentral()\n```\n\npom.xml, latest version:\n\n```xml\n<dependency>\n    <groupId>in.srain.cube</groupId>\n    <artifactId>ultra-ptr</artifactId>\n    <type>aar</type>\n    <!-- or apklib format, if you want -->\n    <!-- <type>apklib</type> -->\n    <version>{ptr_lib_version}</version>\n</dependency>\n```\n\npom.xml, stable version:\n\n```xml\n<dependency>\n    <groupId>in.srain.cube</groupId>\n    <artifactId>ultra-ptr</artifactId>\n    <type>aar</type>\n    <!-- or apklib format, if you want -->\n    <!-- <type>apklib</type> -->\n    <version>{ptr_lib_stable_version}</version>\n</dependency>\n```\n\ngradle, latest version:\n\n```\ncompile 'in.srain.cube:ultra-ptr:{ptr_lib_version}'\n```\n\ngradle, stable version:\n\n```\ncompile 'in.srain.cube:ultra-ptr:{ptr_lib_stable_version}'\n```\n\n#### Config\n\nThere are 6 properties:\n\n* Resistence\n\n    This is the resistence while you are moving the frame, default is: `1.7f`.\n\n* Ratio of the Height of the Header to Refresh\n\n    The ratio of the height of the header to trigger refresh, default is: `1.2f`.\n\n* Duration to Close\n\n    The duration for moving from the position you relase the view to the height of header, default is `200ms`.\n\n* Duration to Close Header\n\n    The default value is `1000ms`\n\n* Keep Header while Refreshing\n\n    The default value is `true`.\n\n* Pull to Refresh / Release to Refresh\n\n    The default value is Release to Refresh.\n\n##### Config in xml\n\n```xml\n<in.srain.cube.views.ptr.PtrFrameLayout\n    android:id=\"@+id/store_house_ptr_frame\"\n    xmlns:cube_ptr=\"http://schemas.android.com/apk/res-auto\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n\n    cube_ptr:ptr_resistance=\"1.7\"\n    cube_ptr:ptr_ratio_of_header_height_to_refresh=\"1.2\"\n    cube_ptr:ptr_duration_to_close=\"300\"\n    cube_ptr:ptr_duration_to_close_header=\"2000\"\n    cube_ptr:ptr_keep_header_when_refresh=\"true\"\n    cube_ptr:ptr_pull_to_fresh=\"false\" >\n\n    <LinearLayout\n        android:id=\"@+id/store_house_ptr_image_content\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:background=\"@color/cube_mints_333333\"\n        android:clickable=\"true\"\n        android:padding=\"10dp\">\n\n        <in.srain.cube.image.CubeImageView\n            android:id=\"@+id/store_house_ptr_image\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\" />\n    </LinearLayout>\n\n</in.srain.cube.views.ptr.PtrFrameLayout>\n```\n\n### Or config in java code\n\n```java\n// the following are default settings\nmPtrFrame.setResistance(1.7f);\nmPtrFrame.setRatioOfHeaderHeightToRefresh(1.2f);\nmPtrFrame.setDurationToClose(200);\nmPtrFrame.setDurationToCloseHeader(1000);\n// default is false\nmPtrFrame.setPullToRefresh(false);\n// default is true\nmPtrFrame.setKeepHeaderWhenRefresh(true);\n```\n\n### Other Config\n\n*  `setPinContent`. Pin the content, only the `HeaderView` will be moved. \n\n    This's the the performance of material style in support package v19.\n\n## StoreHouse Style\n\n* Config using string:\n\n```java\n// header\nfinal StoreHouseHeader header = new StoreHouseHeader(getContext());\nheader.setPadding(0, LocalDisplay.dp2px(15), 0, 0);\n\n/**\n * using a string, support: A-Z 0-9 - .\n * you can add more letters by {@link in.srain.cube.views.ptr.header.StoreHousePath#addChar}\n */\nheader.initWithString('Alibaba');\n```\n\n* Config using string array from xml:\n\n```java\nheader.initWithStringArray(R.array.storehouse);\n```\n\nAnd in `res/values/arrays.xml`:\n\n```xml\n<resources>\n    <string-array name=\"storehouse\">\n        <item>0,35,12,42,</item>\n        <item>12,42,24,35,</item>\n        <item>24,35,12,28,</item>\n        <item>0,35,12,28,</item>\n        <item>0,21,12,28,</item>\n        <item>12,28,24,21,</item>\n        <item>24,35,24,21,</item>\n        <item>24,21,12,14,</item>\n        <item>0,21,12,14,</item>\n        <item>0,21,0,7,</item>\n        <item>12,14,0,7,</item>\n        <item>12,14,24,7,</item>\n        <item>24,7,12,0,</item>\n        <item>0,7,12,0,</item>\n    </string-array>\n</resources>\n```\n\n# Process Refresh\n\nThere is a `PtrHandler`, by which you can refresh the data.\n\n```\npublic interface PtrHandler {\n\n    /**\n     * Check can do refresh or not. For example the content is empty or the first child is in view.\n     * <p/>\n     * {@link in.srain.cube.views.ptr.PtrDefaultHandler#checkContentCanBePulledDown}\n     */\n    public boolean checkCanDoRefresh(final PtrFrameLayout frame, final View content, final View header);\n\n    /**\n     * When refresh begin\n     *\n     * @param frame\n     */\n    public void onRefreshBegin(final PtrFrameLayout frame);\n}\n```\n\nAn example:\n\n```java\nptrFrame.setPtrHandler(new PtrHandler() {\n    @Override\n    public void onRefreshBegin(PtrFrameLayout frame) {\n        frame.postDelayed(new Runnable() {\n            @Override\n            public void run() {\n                ptrFrame.refreshComplete();\n            }\n        }, 1800);\n    }\n\n    @Override\n    public boolean checkCanDoRefresh(PtrFrameLayout frame, View content, View header) {\n        return PtrDefaultHandler.checkContentCanBePulledDown(frame, content, header);\n    }\n});\n```\n\n\n# Customize\n\nYou can add a `PtrUIHandler` to `PtrFrameLayout` to implement any UI effect you want.\n\n```java\npublic interface PtrUIHandler {\n\n    /**\n     * When the content view has reached top and refresh has been completed, view will be reset.\n     *\n     * @param frame\n     */\n    public void onUIReset(PtrFrameLayout frame);\n\n    /**\n     * prepare for loading\n     *\n     * @param frame\n     */\n    public void onUIRefreshPrepare(PtrFrameLayout frame);\n\n    /**\n     * perform refreshing UI\n     */\n    public void onUIRefreshBegin(PtrFrameLayout frame);\n\n    /**\n     * perform UI after refresh\n     */\n    public void onUIRefreshComplete(PtrFrameLayout frame);\n\n    public void onUIPositionChange(PtrFrameLayout frame, boolean isUnderTouch, byte status, int oldPosition, int currentPosition, float oldPercent, float currentPercent);\n}\n```\n\n# Q & A\n\n*  work with ViewPager: `disableWhenHorizontalMove()`\n\n*  work with LongPressed, `setInterceptEventWhileWorking()`\n\n# Contact & Help\n\nPlease fell free to contact me if there is any problem when using the library.\n\n* srain@php.net\n* twitter: https://twitter.com/liaohuqiu\n* weibo: http://weibo.com/liaohuqiu\n* blog: http://www.liaohuqiu.net\n\n    1. About how to use cube-sdk / Ultra Ptr: 271918140 (cube-sdk)\n\n        This the rule for our tribes, please read it before you request to join: https://github.com/liaohuqiu/qq-tribe-rule\n\n    2. For those who like thinking independently and are good at solving problem independently. Please join us, we are all here on Slack: \n    \n        http://join-add1bit.liaohuqiu.net/\n"
  },
  {
    "path": "template/ptr-demo/build.gradle",
    "content": "apply plugin: 'com.android.application'\n\nandroid {\n    compileSdkVersion Integer.parseInt(project.ANDROID_BUILD_SDK_VERSION)\n    buildToolsVersion project.ANDROID_BUILD_TOOLS_VERSION\n\n    defaultConfig {\n        applicationId \"in.srain.cube.views.ptr.demo\"\n        minSdkVersion 8\n        targetSdkVersion Integer.parseInt(project.ANDROID_BUILD_TARGET_SDK_VERSION)\n    }\n\n    lintOptions {\n        abortOnError false\n    }\n\n    buildTypes {\n        release {\n            minifyEnabled true\n            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'\n        }\n    }\n\n    sourceSets {\n        main {\n            manifest.srcFile 'AndroidManifest.xml'\n            java.srcDirs = ['src']\n            resources.srcDirs = ['resources']\n            res.srcDirs = ['res']\n            assets.srcDirs = ['assets']\n            // aidl.srcDirs = ['src']\n            // renderscript.srcDirs = ['src']\n        }\n\n        androidTest.setRoot('tests')\n    }\n    dexOptions {\n        preDexLibraries = false\n    }\n}\n\n\ndef EXCLUDE_JAR_LIST = ['cube-sdk', 'support-v4-r7-source', 'ultra-ptr', 'support-annotation', 'ptr-lib']\n\ntask copyLibs << {\n\n    // copy jars\n    copy {\n        from configurations.compile\n        into \"libs\"\n\n        eachFile { file ->\n            println file.name\n            for (name in EXCLUDE_JAR_LIST) {\n                if (file.name.contains(name)) {\n                    file.exclude()\n                    return\n                }\n            }\n        }\n    }\n\n    // copy source\n    copy {\n\n        def sourceList = configurations.compile.incoming.dependencies.collect { dependency ->\n            dependency.artifact { artifact ->\n                artifact.name = dependency.name\n                artifact.type = 'source'\n                artifact.extension = 'jar'\n                artifact.classifier = 'sources'\n            }\n            dependency\n        }\n        from(configurations.detachedConfiguration(sourceList as Dependency[]).resolvedConfiguration.\n                resolvedConfiguration.lenientConfiguration.getFiles(Specs.SATISFIES_ALL)) {\n        }\n\n        into(\"libs\")\n\n        eachFile { file ->\n            println file.name\n            for (name in EXCLUDE_JAR_LIST) {\n                if (file.name.contains(name)) {\n                    file.exclude()\n                    return\n                }\n            }\n        }\n    }\n}\n\ndependencies {\n    compile(project(':ptr-lib')) {\n    }\n    compile 'in.srain.cube:clog:1.0.2'\n    compile 'in.srain.cube:cube-sdk:{cube_sdk_version}@aar'\n    compile 'com.google.android:support-v4:r7'\n}\n"
  },
  {
    "path": "template/ptr-demo/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n    xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n\n    <parent>\n        <groupId>in.srain</groupId>\n        <artifactId>cube-parent-for-oss</artifactId>\n        <version>1.0.1</version>\n    </parent>\n\n    <groupId>in.srain.cube</groupId>\n    <artifactId>ultra-ptr-demo</artifactId>\n    <packaging>apk</packaging>\n    <name>Ultra Pull to Refresh Demo</name>\n    <version>1.0.1</version>\n\n    <dependencies>\n        <dependency>\n            <groupId>com.google.android</groupId>\n            <artifactId>android</artifactId>\n            <version>4.1.1.4</version>\n            <scope>provided</scope>\n        </dependency>\n        <dependency>\n            <groupId>com.google.android</groupId>\n            <artifactId>support-v4</artifactId>\n            <version>r7</version>\n        </dependency>\n        <dependency>\n            <groupId>in.srain.cube</groupId>\n            <artifactId>ultra-ptr</artifactId>\n            <type>aar</type>\n            <version>{ptr_lib_version}</version>\n        </dependency>\n        <dependency>\n            <groupId>in.srain.cube</groupId>\n            <artifactId>cube-sdk</artifactId>\n            <type>aar</type>\n            <version>{cube_sdk_version}</version>\n        </dependency>\n    </dependencies>\n\n    <properties>\n        <android_maven_plugin_version>3.8.2</android_maven_plugin_version>\n        <android_compile_api_level>16</android_compile_api_level>\n    </properties>\n\n    <build>\n        <finalName>${project.artifactId}</finalName>\n        <sourceDirectory>src/</sourceDirectory>\n        <plugins>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n                <configuration>\n                    <source>1.6</source>\n                    <target>1.6</target>\n                </configuration>\n            </plugin>\n            <!-- compile plugin -->\n            <plugin>\n                <groupId>com.jayway.maven.plugins.android.generation2</groupId>\n                <artifactId>android-maven-plugin</artifactId>\n                <extensions>true</extensions>\n                <version>${android_maven_plugin_version}</version>\n                <configuration>\n                    <sdk>\n                        <platform>${android_compile_api_level}</platform>\n                    </sdk>\n                    <sign>\n                        <debug>false</debug>\n                    </sign>\n                </configuration>\n            </plugin>\n        </plugins>\n    </build>\n</project>\n"
  },
  {
    "path": "template/ptr-lib/gradle.properties",
    "content": "VERSION_NAME={ptr_lib_version}\n\nPOM_GROUP=in.srain.cube\nPOM_ARTIFACT_ID=ultra-ptr\nPOM_PACKAGING=aar\n\nPOM_NAME=Android Ultra Pull to Refresh\nPOM_DESCRIPTION=Ultra Pull to Refresh Solution.\n\nPOM_URL=https://github.com/liaohuqiu/android-Ultra-Pull-To-Refresh\nPOM_SCM_URL=https://github.com/liaohuqiu/android-Ultra-Pull-To-Refresh\nPOM_SCM_CONNECTION=scm:https://github.com/liaohuqiu/android-Ultra-Pull-To-Refresh.git\nPOM_SCM_DEV_CONNECTION=scm:https://github.com/liaohuqiu/android-Ultra-Pull-To-Refresh.git\n\nPOM_LICENCE_NAME=MIT\nPOM_LICENCE_URL=http://opensource.org/licenses/MIT\nPOM_LICENCE_DIST=repo\nPOM_DEVELOPER_ID=liaohuqiu\nPOM_DEVELOPER_NAME=liaohuqiu\n\nPOM_ISSUE_SYSTEM=GitHub Issues\nPOM_ISSUE_URL=https://github.com/liaohuqiu/android-Ultra-Pull-To-Refresh/issues\n"
  },
  {
    "path": "template/ptr-lib/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n    xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n\n    <parent>\n        <groupId>in.srain</groupId>\n        <artifactId>cube-parent-for-oss</artifactId>\n        <version>1.0.1</version>\n    </parent>\n\n    <groupId>in.srain.cube</groupId>\n    <artifactId>ultra-ptr</artifactId>\n    <packaging>aar</packaging>\n    <name>Ultra Pull to Refresh</name>\n    <version>{ptr_lib_version}</version>\n\n    <description>Ultra Pull to Refresh in Android</description>\n    <url>https://github.com/liaohuqiu/android-Ultra-Pull-To-Refresh</url>\n    <inceptionYear>2014</inceptionYear>\n\n    <scm>\n        <url>https://github.com/liaohuqiu/android-Ultra-Pull-To-Refresh</url>\n        <connection>scm:git:git@github.com:liaohuqiu/android-Ultra-Pull-To-Refresh.git</connection>\n        <developerConnection>scm:git:git@github.com:liaohuqiu/android-Ultra-Pull-To-Refresh.git\n        </developerConnection>\n    </scm>\n\n    <developers>\n        <developer>\n            <name>Huqiu Liao</name>\n            <email>liaohuqiu@gmail.com</email>\n            <id>liaohuqiu</id>\n            <url>http://www.liaohuqiu.net</url>\n            <timezone>+8</timezone>\n            <roles>\n                <role>developer</role>\n            </roles>\n        </developer>\n    </developers>\n\n    <licenses>\n        <license>\n            <name>MIT</name>\n            <url>http://opensource.org/licenses/MIT</url>\n            <distribution>repo</distribution>\n        </license>\n    </licenses>\n\n    <organization>\n        <name>Huqiu Liao</name>\n        <url>http://www.liaohuqiu.net</url>\n    </organization>\n\n    <issueManagement>\n        <system>GitHub Issues</system>\n        <url>https://github.com/liaohuqiu/android-Ultra-Pull-To-Refresh/issues</url>\n    </issueManagement>\n\n    <dependencies>\n        <dependency>\n            <groupId>com.google.android</groupId>\n            <artifactId>android</artifactId>\n            <version>4.1.1.4</version>\n            <scope>provided</scope>\n        </dependency>\n    </dependencies>\n\n    <properties>\n        <android.maven.plugin.version>3.8.2</android.maven.plugin.version>\n        <android.compile.api_level>19</android.compile.api_level>\n    </properties>\n\n    <build>\n        <finalName>${project.artifactId}</finalName>\n        <sourceDirectory>src/</sourceDirectory>\n        <plugins>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n                <configuration>\n                    <source>1.6</source>\n                    <target>1.6</target>\n                    <excludes>\n                        <exclude>target/generated-sources/r/*</exclude>\n                    </excludes>\n                </configuration>\n            </plugin>\n            <!-- compile plugin -->\n            <plugin>\n                <groupId>com.jayway.maven.plugins.android.generation2</groupId>\n                <artifactId>android-maven-plugin</artifactId>\n                <extensions>true</extensions>\n                <version>${android.maven.plugin.version}</version>\n                <configuration>\n                    <sdk>\n                        <platform>${android.compile.api_level}</platform>\n                    </sdk>\n                    <sign>\n                        <debug>false</debug>\n                    </sign>\n                </configuration>\n            </plugin>\n        </plugins>\n    </build>\n</project>\n"
  },
  {
    "path": "update-project.py",
    "content": "import os\nvars = {\n        'ptr_lib_version': '1.0.11',\n        'ptr_lib_stable_version': '1.0.11',\n        'cube_sdk_version': '1.0.44.39-SNAPSHOT'\n        }\n\nfiles = [\n        'README.md',\n        'README-cn.md',\n        'ptr-lib/pom.xml',\n        'ptr-lib/gradle.properties',\n        'ptr-demo/pom.xml',\n        'ptr-demo/build.gradle',\n        ]\n\ncurrent_dir = os.path.dirname(os.path.realpath(__file__))\nprint current_dir\nsrc_dir = current_dir + '/template/'\ndst_dir = current_dir + '/'\n\ndef update_var_for_file(file, vars):\n    src_file = src_dir + file\n    dst_file = dst_dir + file\n    print \"update_var_for_file: %s => %s\" % (src_file, dst_file)\n    infile = open(src_file)\n    outfile = open(dst_file, 'w')\n\n    for line in infile:\n        for src, target in vars.iteritems():\n            line = line.replace(src, target)\n        outfile.write(line)\n    infile.close()\n    outfile.close()\n\nreal_vars = {}\nfor src, target in vars.iteritems():\n    real_vars['{' + src + '}'] = target\n\nfor f in files:\n    update_var_for_file(f, real_vars)\n"
  }
]