[
  {
    "path": ".github/workflows/gradle-wrapper-validation.yml",
    "content": "name: \"Validate Gradle Wrapper\"\non: [push, pull_request]\n\njobs:\n  validation:\n    name: \"Validation\"\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v2\n      - uses: gradle/wrapper-validation-action@v1\n"
  },
  {
    "path": ".gitignore",
    "content": "# Android generated\nbin/\ngen/\n\n# Ant\nbuild.xml\nlocal.properties\n\n# Maven\ntarget/\npom.xml.*\nrelease.properties\n\n# Eclipse\n.classpath\n.project\n.externalToolBuilders/\n\n# IntelliJ\n*.iml\n*.ipr\n*.iws\n.idea/\nout/\n\n# Mac \n.DS_Store\n\n# Ignore gradle files\n.gradle/\nbuild/\n\n# Private\nsigning.properties"
  },
  {
    "path": ".travis.yml",
    "content": "sudo: false\nlanguage: android\nandroid:\n  components:\n    - platform-tools\n    - tools\n    - build-tools-28.0.3\n    - android-28\n    - extra\n"
  },
  {
    "path": "CHANGELOG.md",
    "content": "Change Log\n===\n\nv1.9.5 *(27.11.2015)*\n---\n * **New API:**\n   * `ImageLoader.displayImage(..., ImageSize targetImageSize, ...)`\n * CircleBitmapDisplayer\n * Better rendering of scaled images.\n * Fixed bugs:\n   * inPurgeable and inInputShareable causes file descriptor leak on KitKat ([#1020](https://github.com/nostra13/Android-Universal-Image-Loader/issues/1020))\n   * markSupported() ([#1026](https://github.com/nostra13/Android-Universal-Image-Loader/issues/1026))\n\nv1.9.4 *(29.05.2015)*\n---\n * **New API:**\n   * `ImageLoader.setDefaultLoadingListener(ImageLoadingListener)`\n * \"Disc -> Disk\" migration (deleted DiscCacheAware, MemoryCacheAware)\n * Video thumbnails support (`file://...`)\n * Fixed 0-length files problem\n\nv1.9.3 *(06.09.2014)*\n---\n * Introduced `ImageScaleType.NONE_SAFE`\n * Video thumbnails support (`content://...`)\n * Animated drawables support (for `.showImageOnLoading()`, `.showImageOnFail()`, `.showImageForEmptyUri()`)\n * Fixed bugs:\n   * `loadImageSync(...)` bug ([#636](https://github.com/nostra13/Android-Universal-Image-Loader/issues/636))\n   * NPE if no free space while init disk cache\n   * \"Bitmap too large ...\" for all ImageScaleTypes\n   * contacts photo considering\n\nv1.9.2 *(24.05.2014)*\n---\n * New Disk cache API (preparing renaming `disc` -> `disk`)\n * ImageLoader can be called out of the Main thread. Callback will be delivered on separate thread.\n * Prevented broken image files (#511)\n * Interrupt non-actual tasks\n * `LruDiscCache` is default limited cache\n * Renaming: `ImageNonViewAware` -> `NonViewAware`. Extracted `ViewAware` from `ImageViewAware`.\n * Introduced `DiskCache` and `MemoryCache` interfaces instead of deprecated `DiscCacheAware` and `MemoryCacheAware`.\n * Removed `LimitedDiscCache`, `TotalSizeLimitedDiscCache`, `FileCountLimitedDiscCache`. Use `LruDisckCache` instead.\n\nv1.9.1 *(27.12.2013)*\n---\n * **Changed API:**\n   * `BitmapDisplayer.display(...) : Bitmap` -> `BitmapDisplayer.display(...) : void`\n * **New API:**\n   * Added possibility to listen image loading progress by listener - `ImageLoadingProgressListener`\n * Non-actual downloads are interrupted (if loaded less than 75%)\n * Re-designed `RoundedBitmapDisplayer`. Added `RoundedVignetteBitmapDisplayer`.\n   **NOTE:** New `RoundedBitmapDisplayer`'s behaviour can vary from old one. Also consider [\"RoundedImageView\" project](https://github.com/vinc3m1/RoundedImageView) for usage if new `RoundedBitmapDisplayer` doesn't work for you.\n * Maximum GL texture size is considered while decode images ([#281](https://github.com/nostra13/Android-Universal-Image-Loader/issues/281))\n * `loadImage(...)` call cancels previous task for the same image URI ([#475](https://github.com/nostra13/Android-Universal-Image-Loader/issues/475))\n * Fixed StrictMode warning `Explicit termination method 'close' not called` ([#482](https://github.com/nostra13/Android-Universal-Image-Loader/issues/482))\n * `LruMemoryCache` is default memory cache for Android < 2.3 too.\n\nv1.9.0 *(27.11.2013)*\n---\n * **Changed API:**\n   * `BitmapDisplayer.display(..., ImageView, ...)` -> `BitmapDisplayer.display(..., ImageAware, ...)`\n * **New API:**\n   * `ImageAware`\n   * `ImageLoader.displayImage(..., ImageAware, ...)`\n   * `ImageLoader.loadImageSync(...) : Bitmap` for synchronous loading of image\n   * `DisplayImageOptions.considerExifParams(boolean)`\n   * `DisplayImageOptions.showImageOnLoading(...)` (instead of `.showStubImage(...)`)\n * `ImageLoader` can process any view (or any other object) which implements `ImageAware` interface. E.g. `ImageViewAware` is adapter of `ImageView` for `ImageAware`\n * EXIF parameters of image are not considered by default anymore. Use new API to enable it.\n * Optimized image loading (prevented double-request on image loading, reuse existing stream)\n * Fixed bugs:\n   * `loadImage(...)` bug (frequent `onLoadingCancelled()`) ([#356](https://github.com/nostra13/Android-Universal-Image-Loader/issues/356))\n   * Prevented NPE if `Context.getCacheDir()` returns `null` ([#392](https://github.com/nostra13/Android-Universal-Image-Loader/issues/392))\n\nv1.8.6 *(25.07.2013)*\n---\n * **Changed API:** `ImageLoaderConfiguration.enableLogging()` -> `ImageLoaderConfiguration.writeDebugLogs()`\n * **Fixed memory leak** ([#263](https://github.com/nostra13/Android-Universal-Image-Loader/issues/263))\n * Added the bug of `loadImage(...)` method (`onLoadingCancelled()` is fired always) :) \n\nv1.8.5 *(30.06.2013)*\n---\n * **Changed API:** `ImageLoaderConfiguration.discCacheExtraOptions(...)` -> `ImageLoaderConfiguration.discCacheExtraOptions(..., BitmapProcessor)` ([#314](https://github.com/nostra13/Android-Universal-Image-Loader/issues/314))\n * **New API:**\n   * `ImageLoaderConfiguration.memoryCacheSizePercentage(int)` ([#279](https://github.com/nostra13/Android-Universal-Image-Loader/issues/279))\n   * `DisplayImageOptions.cacheInMemory(boolean)`, `.cacheOnDisc(boolean)`, `.resetViewBeforeLoading(boolean)` ([#252](https://github.com/nostra13/Android-Universal-Image-Loader/issues/252))\n * Added `LoadedFrom` flag to `BitmapDisplayer.display(..., LoadedFrom)` about image source  ([#149](https://github.com/nostra13/Android-Universal-Image-Loader/issues/149), [#239](https://github.com/nostra13/Android-Universal-Image-Loader/issues/239))\n * Added `L.disableLogging()` and `L.enableLogging()` to off/on logs completely ([#270](https://github.com/nostra13/Android-Universal-Image-Loader/issues/270))\n * Prevent image decoding if image is reused ([#247](https://github.com/nostra13/Android-Universal-Image-Loader/issues/247))\n * Not set cache dir on SD card if no appropriate permission ([#311](https://github.com/nostra13/Android-Universal-Image-Loader/issues/311))\n * Increased buffer size for image downloads (8 KB -> 32 KB) ([#249](https://github.com/nostra13/Android-Universal-Image-Loader/issues/249))\n * Fixed bugs:\n   * Prevent recycling of cached in memory images ([#259](https://github.com/nostra13/Android-Universal-Image-Loader/issues/259))\n   * ConcurrentModificationException in `LruMemoryCache` ([#265](https://github.com/nostra13/Android-Universal-Image-Loader/issues/265))\n   * File counting if cached files disappeared `LimitedDiscCache` ([#316](https://github.com/nostra13/Android-Universal-Image-Loader/issues/316))    \n   * NPE for ImageView without LayoutParams ([#272](https://github.com/nostra13/Android-Universal-Image-Loader/issues/272))\n   * NPE in `LoadAndDisplayImageTask` ([#271](https://github.com/nostra13/Android-Universal-Image-Loader/issues/271))\n   * NPE in ImageLoaderEngine ([#301](https://github.com/nostra13/Android-Universal-Image-Loader/issues/301))\n   * RoundedBitmapDisplayer doesn't display round corner correctly for CENTER_CROP ([#315](https://github.com/nostra13/Android-Universal-Image-Loader/issues/315))\n\nv1.8.4 *(13.04.2013)*\n---\n * Travis CI, added Unit tests ([#189](https://github.com/nostra13/Android-Universal-Image-Loader/issues/189))\n * **New API:** `DisplayImageOptions.handler(Handler)` ([#231](https://github.com/nostra13/Android-Universal-Image-Loader/issues/231))\n * Fixed bugs:\n   * `ConcurrentModificationException` in `BaseMemoryCache` ([#229](https://github.com/nostra13/Android-Universal-Image-Loader/issues/229))\n   * `NullPointerException` in `LimitedDiscCache` ([#234](https://github.com/nostra13/Android-Universal-Image-Loader/issues/234))\n   * `NullPointerException` in `LruMemoryCache` ([#233](https://github.com/nostra13/Android-Universal-Image-Loader/issues/233))\n * Improved work with Strings on UI thread ([#244](https://github.com/nostra13/Android-Universal-Image-Loader/issues/244))\n\nv1.8.3 *(31.03.2013)*\n---\n * Android 2.0+ support\n * Added EXIF orientation support ([#172](https://github.com/nostra13/Android-Universal-Image-Loader/issues/172))\n * **New API:** \n   * `ImageLoaderConfiguration.imageDecoder(ImageDecoder)`\n   * `DisplayImageOptions.decodingOptions(BitmapFactory.Options)`\n * Handled disc cache non-availability\n * Use `LruMemoryCache` as default memory cache for API >= 9, `LRULimitedMemoryCache` - for API < 9. Default memory cache size - 1/8 of available app memory.\n * Improved `LimitedDiscCache` and `FuzzyKeyMemoryCache` performance\n * Fixed bugs:\n    * `.denyCacheImageMultipleSizesInMemory` doesn't work if own memory cache is set\n\t* `java.lang.NoSuchMethodError` in sample app ([#206](https://github.com/nostra13/Android-Universal-Image-Loader/issues/206))\n\nv1.8.2 *(13.03.2013)*\n---\n * **Changed API:**\n   * `ImageDownloader.getStream***(URI, ...)` -> `ImageDownloader.getStream***(String, ...)`\n   * Made `FailReason` as a class instead of enum. Can be used in switches: `FailReason.getType()`\n   * Removed `ImageLoader.offOutOfMemoryHandling()`. ImageLoader doesn't handle OutOfMemoryError by default anymore (but still catches it for callbacks).\n * **New API:**\n   * `ImageLoader.taskExecutor(Executor)` and `ImageLoader.taskExecutorForCachedImages(Executor)` ([#187](https://github.com/nostra13/Android-Universal-Image-Loader/issues/187))\n   * `ImageLoader.destroy()`\n * Handled SD card unmount ([#170](https://github.com/nostra13/Android-Universal-Image-Loader/issues/170))\n * Added `Scheme` class\n * Fixed bugs:\n   * problem of loading of local files with encoded symbols in path ([#179](https://github.com/nostra13/Android-Universal-Image-Loader/issues/179))\n   * minor mistake in `getImageSizeScaleTo()` method ([#200](https://github.com/nostra13/Android-Universal-Image-Loader/issues/200))\n   * possible concurrency issue in memory caches ([#116](https://github.com/nostra13/Android-Universal-Image-Loader/issues/116))\n   * wrong visibility of methods `ImageLoader.denyNetworkDownloads(boolean)` and `ImageLoader.handleSlowNetworks(boolean)` \n\nv1.8.1 *(08.03.2013)*\n---\n * **Changed API:**\n   * `ImageLoader.denyNetworkDownloads()` -> `ImageLoader.denyNetworkDownloads(true)`\n   * `ImageLoader.allowNetworkDownloads()` -> `ImageLoader.denyNetworkDownloads(false)`\n * **New API:** \n   * `ImageLoader.denyNetworkDownloads(boolean)`\n   * `ImageLoader.handleSlowNetwork(boolean)`. `FlushedInsputStream` isn't used for downloads by default.\n * Handled HTTP(S) redirects\n * Added `LruMemoryCache` (based on Android's LruCache), uses only strong references.\n * Fixed `DisplayImageOptions.cloneFrom(...)` ([#173](https://github.com/nostra13/Android-Universal-Image-Loader/issues/173))\n * Fixed ConcurrentModification issue in `MemoryCacheUtil. findCacheKeysForImageUri(...)` ([#174](https://github.com/nostra13/Android-Universal-Image-Loader/issues/174))\n * Fixed issue \"Disc Cache can't find image by URI with special/local UTF-8 characters\"\n * Improved calculation of target image size to scale (consider measured View width and height)\n\nv1.8.0 *(10.02.2013)*\n---\n * **Changed API:**\n   * Signatures:\n     * `ImageLoader.loadImage(Context, ...)` -> `ImageLoader.loadImage(...)`\n     * `ImageDownloader.getStream(URI)` -> `ImageDownloader.getStream(URI, Object)` ([#150](https://github.com/nostra13/Android-Universal-Image-Loader/issues/150))\n\t * `ImageLoadingListener.onLoading***(...)` -> `ImageLoadingListener.onLoading***(String, View, ...)` ([#130](https://github.com/nostra13/Android-Universal-Image-Loader/issues/130))\n     * Constructor `PauseOnScrollListener(...)` -> `PauseOnScrollListener(ImageLoader, ...)`\n   * `ImageDownloader` became interface, `URLConnectionImageDownloader` + `ExtendedImageDownloader` -> `BaseImageDownloader`\n   * Renaming: `FileUtil` -> `IoUtil`\n   * Removed deprecated `ImageScaleType.POWER_OF_2` and `ImageScaleType.EXACT` \n * Support of \"content://\", \"assets://\", \"drawable://\" URI schemes out of the box ([#162](https://github.com/nostra13/Android-Universal-Image-Loader/issues/162))\n * **New API:** \n   * `DisplayImageOptions.showImageOnFail(int)`\n   * `DisplayImageOptions.preProcessor(BitmapProcessor)` and `DisplayImageOptions.postProcessor(BitmapProcessor)` ([#151](https://github.com/nostra13/Android-Universal-Image-Loader/issues/151))\n   * `DisplayImageOptions.extraForDownloader(Object)`, allows to pass auxiliary object which will be passed to `ImageDownloader.getStream(URI, Object)` ([#150](https://github.com/nostra13/Android-Universal-Image-Loader/issues/150))\n   * `ImageLoader.denyNetworkDownloads()` and `ImageLoader.allowNetworkDownloads()` ([#148](https://github.com/nostra13/Android-Universal-Image-Loader/issues/148))\n   * `FailReason.UNSUPPORTED_URI_SCHEME` and `FailReason.NETWORK_DENIED`\n   * `ImageScaleType.NONE`\n * Added `DiscCacheUtil`\n * Prepared ImageLoader to be extandable for creation of multiple instances ([#158](https://github.com/nostra13/Android-Universal-Image-Loader/issues/158))\n * Fixed bug \"Images aren't loaded after \"Clear Cache\" in app info\" ([#168](https://github.com/nostra13/Android-Universal-Image-Loader/issues/168))\n * Switched to Apache 2.0 license\n\nv1.7.1 *(31.01.2013)*\n---\n * Avoid I/O operations on the main thread, prevented ANR ([#129](https://github.com/nostra13/Android-Universal-Image-Loader/issues/129), [#154](https://github.com/nostra13/Android-Universal-Image-Loader/issues/154))\n * Correctly handled every ImageView's scale type in `RoundedBitmapDisplayer` ([#70](https://github.com/nostra13/Android-Universal-Image-Loader/issues/70))\n * Prevented slow precaching modified date in LimitedAgeDiscCache constructor (for large number of images in cache) ([#141](https://github.com/nostra13/Android-Universal-Image-Loader/issues/141))\n * **New API:** `ImageLoader.isInited()` method. Throw IllegalStateException on `displayImage(...)`, `loadImage(...)`, `getMemoryCache()`, `clearMemoryCache()`, `getDiscCache()`, `clearDiscCache()` calls if ImageLoader isn't inited with config.\n * Closed OutputStream after Bitmap compressing ([#115](https://github.com/nostra13/Android-Universal-Image-Loader/issues/115))\n * Sample: Refactored resources\n\nv1.7.0 *(27.11.2012)*\n---\n * Maven support\n * **New API:** \n   * `ImageLoader.pause()` and `ImageLoader.resume()` ([#106](https://github.com/nostra13/Android-Universal-Image-Loader/issues/106))\n   * `PauseOnScrollListener` (instead of `OnScrollSmartOptions`) for convenient pause/resume ImageLoader on scroll/fling in list views ([#106](https://github.com/nostra13/Android-Universal-Image-Loader/issues/106))\n * Prevented consuming of lot of memory by cacheKeysForImageViews ([#108](https://github.com/nostra13/Android-Universal-Image-Loader/issues/108))\n\nv1.6.4 *(20.11.2012)*\n---\n * **New API:** \n   * `DisplayImageOptions.bitmapConfig(Bitmap.Config)` ([#101](https://github.com/nostra13/Android-Universal-Image-Loader/issues/101))\n   * `DisplayImageOptions.delayBeforeLoading(int)` ([#103](https://github.com/nostra13/Android-Universal-Image-Loader/issues/103))\n   * `OnScrollSmartOptions` for convenient control of loading delay on fling in ListViews, GridViews\n * Added `FadeInBitmapDisplayer`\n * Prevented recycling of using Bitmap ([#101](https://github.com/nostra13/Android-Universal-Image-Loader/issues/101))\n\nv1.6.3 *(03.11.2012)*\n---\n * **New API:** `ImageLoaderConfiguration.tasksProcessingOrder(QueueProcessingType)` ([#89](https://github.com/nostra13/Android-Universal-Image-Loader/issues/89))\n * Added `MemoryCacheUtil` for work with memory cache\n * Fixed calculation of size the original image is needed scale to ([#93](https://github.com/nostra13/Android-Universal-Image-Loader/issues/93))\n * Allowed to create multiple `ImageLoader` instances ([#92](https://github.com/nostra13/Android-Universal-Image-Loader/issues/92))\n\nv1.6.2 *(28.10.2012)*\n---\n * Prevented showing wrong bitmap in reused view ([#85](https://github.com/nostra13/Android-Universal-Image-Loader/issues/85))\n * Fixed bug \"double displaying\" if image is cached in memory\n * Prevented \"MissingFormatWidthException\" ([#88](https://github.com/nostra13/Android-Universal-Image-Loader/issues/88))\n\nv1.6.1 *(02.10.2012)*\n---\n * **Changed API:** Renaming:\n   * `ImageScaleType.POWER_OF_2` -> `IN_SAMPLE_POWER_OF_2`\n   * `ImageScaleType.EXACT` -> `IN_SAMPLE_INT`\n * **New API:** `ImageScaleType.EXACTLY` and `ImageScaleType.EXACTLY_STRETCHED`\n * Prevented `ImageLoadingListener` callbacks firing and displaying image in view after ImageLoader was stopped\n * Fixed bug of calculation of original image scale for decoding\n\nv1.6.0 *(29.09.2012)*\n---\n * **New API:** `ImageLoader.loadImage(...)` which loads image, decodes it to Bitmap and returns Bitmap in callback ([#51](https://github.com/nostra13/Android-Universal-Image-Loader/issues/51))\n * Avoided unnecessary image downloads ([#44](https://github.com/nostra13/Android-Universal-Image-Loader/issues/44))\n\nv1.5.6 *(20.09.2012)*\n---\n * **Changed API:** Changed `FileNameGenerator` to interface (instead of abstract class)\n * **New API:** `BitmapDisplayer` and `DisplayImageOptions.displayer(...)`\n * Multithread displaying of cached images (instead of single-thread)\n * Correctly handle UTF-8 symbols and spaces in image URL ([#31](https://github.com/nostra13/Android-Universal-Image-Loader/issues/31))\n\nv1.5.5 *(18.08.2012)*\n---\n * **Changed API:**\n   * Removed `DisplayImageOptions.transform()`\n   * Changed `FileNameGenerator` to abstract class (instead of interface)\n * Fire `ImageLoadingListener` callbacks if image URI is null\n"
  },
  {
    "path": "LICENSE",
    "content": "                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright [yyyy] [name of copyright owner]\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."
  },
  {
    "path": "README.md",
    "content": "# ![Logo](https://github.com/nostra13/Android-Universal-Image-Loader/raw/master/sample/src/main/res/drawable-mdpi/ic_launcher.png) Universal Image Loader [![Build Status](https://travis-ci.org/nostra13/Android-Universal-Image-Loader.svg?branch=master)](https://travis-ci.org/nostra13/Android-Universal-Image-Loader) [![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.nostra13.universalimageloader/universal-image-loader/badge.svg)](https://maven-badges.herokuapp.com/maven-central/com.nostra13.universalimageloader/universal-image-loader)\n\nThe great ancestor of modern image-loading libraries :)  \nUIL aims to provide a powerful, flexible and highly customizable instrument for image loading, caching and displaying. It provides a lot of configuration options and good control over the image loading and caching process.\n\n![Screenshot](https://github.com/nostra13/Android-Universal-Image-Loader/raw/master/UniversalImageLoader.png)\n\n## Project News \n * Really have no time for development... so I stop project maintaining since Nov 27 :(\n * UIL [27.11.2011 - 27.11.2015]\n * Thanks to all developers for your support :)\n\n## Features\n * Multi-thread image loading (async or sync)\n * Wide customization of ImageLoader's configuration (thread executors, downloader, decoder, memory and disk cache, display image options, etc.)\n * Many customization options for every display image call (stub images, caching switch, decoding options, Bitmap processing and displaying, etc.)\n * Image caching in memory and/or on disk (device's file system or SD card)\n * Listening loading process (including downloading progress)\n\nAndroid 4.1+ support\n\n## Downloads\n * **[universal-image-loader-1.9.5.jar](https://github.com/nostra13/Android-Universal-Image-Loader/raw/master/downloads/universal-image-loader-1.9.5.jar)**\n * [<img src=\"https://play.google.com/intl/en_us/badges/images/apps/en-play-badge.png\" height=\"45px\" />](https://play.google.com/store/apps/details?id=com.nostra13.universalimageloader.sample) [![QR Code](https://lh3.ggpht.com/csXEddxiLgQ6FxckefjQnP1PVugbaAYOdcuTa3vVtGV1PlWbFu2dYggoH8rI1w2RdEz1=w50)](http://chart.apis.google.com/chart?chs=300x300&cht=qr&chld=|1&chl=https%3A%2F%2Fplay.google.com%2Fstore%2Fapps%2Fdetails%3Fid%3Dcom.nostra13.universalimageloader.sample) [<img src=\"https://www.javatpoint.com/fullformpages/images/apk.png\" height=\"45px\" />](https://github.com/nostra13/Android-Universal-Image-Loader/raw/master/downloads/universal-image-loader-sample-1.9.5.apk)\n\n## [Documentation](https://github.com/nostra13/Android-Universal-Image-Loader/wiki)\n * **[Quick Setup](https://github.com/nostra13/Android-Universal-Image-Loader/wiki/Quick-Setup)**\n * **[Configuration](https://github.com/nostra13/Android-Universal-Image-Loader/wiki/Configuration)**\n * **[Display Options](https://github.com/nostra13/Android-Universal-Image-Loader/wiki/Display-Options)**\n * [Useful Info](https://github.com/nostra13/Android-Universal-Image-Loader/wiki/Useful-Info) - Read it before asking a question\n * [User Support](https://github.com/nostra13/Android-Universal-Image-Loader/wiki/User-Support) - Read it before creating new issue\n * [Sample project](https://github.com/nostra13/Android-Universal-Image-Loader/tree/master/sample) - Learn it to understand the right way of library usage\n * [ChangeLog](https://github.com/nostra13/Android-Universal-Image-Loader/blob/master/CHANGELOG.md) - Info about API changes is here\n\n## Usage\n\n### Dependency\n\n```\nimplementation 'com.nostra13.universalimageloader:universal-image-loader:1.9.5'\n```\n\n### Acceptable URIs examples\n``` java\n\"http://site.com/image.png\" // from Web\n\"file:///mnt/sdcard/image.png\" // from SD card\n\"file:///mnt/sdcard/video.mp4\" // from SD card (video thumbnail)\n\"content://media/external/images/media/13\" // from content provider\n\"content://media/external/video/media/13\" // from content provider (video thumbnail)\n\"assets://image.png\" // from assets\n\"drawable://\" + R.drawable.img // from drawables (non-9patch images)\n```\n**NOTE:** Use `drawable://` only if you really need it! Always **consider the native way** to load drawables - `ImageView.setImageResource(...)` instead of using of `ImageLoader`.\n\n### Simple\n``` java\nImageLoader imageLoader = ImageLoader.getInstance(); // Get singleton instance\n```\n``` java\n// Load image, decode it to Bitmap and display Bitmap in ImageView (or any other view \n//\twhich implements ImageAware interface)\nimageLoader.displayImage(imageUri, imageView);\n```\n``` java\n// Load image, decode it to Bitmap and return Bitmap to callback\nimageLoader.loadImage(imageUri, new SimpleImageLoadingListener() {\n\t@Override\n\tpublic void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) {\n\t\t// Do whatever you want with Bitmap\n\t}\n});\n```\n``` java\n// Load image, decode it to Bitmap and return Bitmap synchronously\nBitmap bmp = imageLoader.loadImageSync(imageUri);\n```\n\n### Complete\n``` java\n// Load image, decode it to Bitmap and display Bitmap in ImageView (or any other view \n//\twhich implements ImageAware interface)\nimageLoader.displayImage(imageUri, imageView, options, new ImageLoadingListener() {\n\t@Override\n\tpublic void onLoadingStarted(String imageUri, View view) {\n\t\t...\n\t}\n\t@Override\n\tpublic void onLoadingFailed(String imageUri, View view, FailReason failReason) {\n\t\t...\n\t}\n\t@Override\n\tpublic void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) {\n\t\t...\n\t}\n\t@Override\n\tpublic void onLoadingCancelled(String imageUri, View view) {\n\t\t...\n\t}\n}, new ImageLoadingProgressListener() {\n\t@Override\n\tpublic void onProgressUpdate(String imageUri, View view, int current, int total) {\n\t\t...\n\t}\n});\n```\n``` java\n// Load image, decode it to Bitmap and return Bitmap to callback\nImageSize targetSize = new ImageSize(80, 50); // result Bitmap will be fit to this size\nimageLoader.loadImage(imageUri, targetSize, options, new SimpleImageLoadingListener() {\n\t@Override\n\tpublic void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) {\n\t\t// Do whatever you want with Bitmap\n\t}\n});\n```\n``` java\n// Load image, decode it to Bitmap and return Bitmap synchronously\nImageSize targetSize = new ImageSize(80, 50); // result Bitmap will be fit to this size\nBitmap bmp = imageLoader.loadImageSync(imageUri, targetSize, options);\n```\n\n## Load & Display Task Flow\n![Task Flow](https://github.com/nostra13/Android-Universal-Image-Loader/raw/master/wiki/UIL_Flow.png)\n\n\n## Applications using Universal Image Loader\n**[MediaHouse, UPnP/DLNA Browser](https://play.google.com/store/apps/details?id=com.dbapp.android.mediahouse)** | **[Prezzi Benzina (AndroidFuel)](https://play.google.com/store/apps/details?id=org.vernazza.androidfuel)** | **[ROM Toolbox Lite](https://play.google.com/store/apps/details?id=com.jrummy.liberty.toolbox)**, [Pro](https://play.google.com/store/apps/details?id=com.jrummy.liberty.toolboxpro) | [Stadium Astro](https://play.google.com/store/apps/details?id=com.astro.stadium.activities) | [Chef Astro](https://play.google.com/store/apps/details?id=com.sencha.test) | [Sporee - Live Soccer Scores](https://play.google.com/store/apps/details?id=com.sporee.android) | **[EyeEm - Photo Filter Camera](https://play.google.com/store/apps/details?id=com.baseapp.eyeem)** | **[Topface - meeting is easy](https://play.google.com/store/apps/details?id=com.topface.topface)** | **[reddit is fun](https://play.google.com/store/apps/details?id=com.andrewshu.android.reddit)** | **[Diaro - personal diary](https://play.google.com/store/apps/details?id=com.pixelcrater.Diaro)** | **[Meetup](https://play.google.com/store/apps/details?id=com.meetup)** | [Vingle - Magazines by Fans](https://play.google.com/store/apps/details?id=com.vingle.android) | [Anime Music Radio](https://play.google.com/store/apps/details?id=com.maxxt.animeradio) | [WidgetLocker Theme Viewer](https://play.google.com/store/apps/details?id=com.companionfree.WLThemeViewer) | [ShortBlogger for Tumblr](https://play.google.com/store/apps/details?id=com.luckydroid.tumblelog) | [SnapDish Food Camera](https://play.google.com/store/apps/details?id=com.vuzz.snapdish) | **[Twitch](https://play.google.com/store/apps/details?id=tv.twitch.android.viewer)** | [TVShow Time, TV show guide](https://play.google.com/store/apps/details?id=com.tozelabs.tvshowtime) | [Planning Center Services](https://play.google.com/store/apps/details?id=com.ministrycentered.PlanningCenter) | **[Lapse It](https://play.google.com/store/apps/details?id=com.ui.LapseIt)** | [My Cloud Player for SoundCloud](https://play.google.com/store/apps/details?id=com.mycloudplayers.mycloudplayer) | **[SoundTracking](https://play.google.com/store/apps/details?id=com.schematiclabs.soundtracking)** | [LoopLR Social Video](https://play.google.com/store/apps/details?id=com.looplr) | [Hír24](https://play.google.com/store/apps/details?id=hu.sanomamedia.hir24) | **[Immobilien Scout24](https://play.google.com/store/apps/details?id=de.is24.android)** | **[Lieferheld - Pizza Pasta Sushi](https://play.google.com/store/apps/details?id=de.lieferheld.android)** | [Loocator: free sex datings](https://play.google.com/store/apps/details?id=com.ivicode.loocator) | [벨팡-개편 이벤트,컬러링,벨소리,무료,최신가요,링투유](https://play.google.com/store/apps/details?id=com.mediahubs.www) | [Streambels AirPlay/DLNA Player](https://play.google.com/store/apps/details?id=com.tuxera.streambels) | [Ship Mate - All Cruise Lines](https://play.google.com/store/apps/details?id=shipmate.carnival) | [Disk & Storage Analyzer](https://play.google.com/store/apps/details?id=com.mobile_infographics_tools.mydrive) | [糗事百科](https://play.google.com/store/apps/details?id=qsbk.app) | [Balance BY](https://play.google.com/store/apps/details?id=com.vladyud.balance) | **[Anti Theft Alarm - Security](https://play.google.com/store/apps/details?id=br.com.verde.alarme)** | **[XiiaLive™ - Internet Radio](https://play.google.com/store/apps/details?id=com.android.DroidLiveLite)** | **[Bandsintown Concerts](https://play.google.com/store/apps/details?id=com.bandsintown)** | **[Save As Web Archive](https://play.google.com/store/apps/details?id=jp.fuukiemonster.webmemo)** | [MCPE STORE -Download MCPE file](https://play.google.com/store/apps/details?id=com.newidea.mcpestore) | **[All-In-One Toolbox (29 Tools)](http://aiotoolbox.com/)** | [Zaim](https://play.google.com/store/apps/details?id=net.zaim.android) | **[Calculator Plus Free](https://play.google.com/store/apps/details?id=com.digitalchemy.calculator.freedecimal)** | [Truedialer by Truecaller](https://play.google.com/store/apps/details?id=com.truecaller.phoneapp) | [DoggCatcher Podcast Player](https://play.google.com/store/apps/details?id=com.snoggdoggler.android.applications.doggcatcher.v1_0) | [PingTools Network Utilities](https://play.google.com/store/apps/details?id=ua.com.streamsoft.pingtools) | [The Traveler](https://play.google.com/store/apps/details?id=edu.bsu.android.apps.traveler) | [minube: travel photo album](https://play.google.com/store/apps/details?id=com.minube.app) | [Wear Store for Wear Apps](https://play.google.com/store/apps/details?id=goko.ws2) | [Cast Store for Chromecast Apps](https://play.google.com/store/apps/details?id=goko.gcs) | [WebMoney Keeper](https://play.google.com/store/apps/details?id=com.webmoney.my)\n\n## Donation\nYou can support the project and thank the author for his hard work :)\n\n* **PayPal** - nostra.uil[at]gmail[dot]com\n\n## Alternative libraries\n\n * [Fresco](https://github.com/facebook/fresco)\n * [Glide](https://github.com/bumptech/glide)\n * [Picasso](https://github.com/square/picasso)\n * [Volley : ImageLoader](https://android.googlesource.com/platform/frameworks/volley/)\n"
  },
  {
    "path": "build.gradle",
    "content": "// Top-level build file where you can add configuration options common to all sub-projects/modules.\n\nbuildscript {\n    repositories {\n        google()\n        jcenter()\n    }\n    dependencies {\n        classpath 'com.android.tools.build:gradle:3.6.2'\n    }\n}\n\nallprojects {\n    repositories {\n        google()\n        jcenter()\n    }\n}\n\nif (JavaVersion.current().isJava8Compatible()) {\n    allprojects {\n        tasks.withType(Javadoc) {\n            options.addStringOption('Xdoclint:none', '-quiet')\n        }\n    }\n}\n"
  },
  {
    "path": "gradle/maven_push.gradle",
    "content": "/*\n * Copyright 2013 Chris Banes\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\napply 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('NEXUS_USERNAME') ? NEXUS_USERNAME : \"\"\n}\n\ndef getRepositoryPassword() {\n    return hasProperty('NEXUS_PASSWORD') ? NEXUS_PASSWORD : \"\"\n}\n\nafterEvaluate { project ->\n    uploadArchives {\n        repositories {\n            mavenDeployer {\n                beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) }\n\n                pom.groupId = 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                    developers {\n                        developer {\n                            id POM_DEVELOPER_ID\n                            name POM_DEVELOPER_NAME\n                        }\n                    }\n                }\n            }\n        }\n    }\n\n    task installArchives(type: Upload) {\n        description \"Installs the artifacts to the local Maven repository.\"\n        configuration = configurations['archives']\n        repositories {\n            mavenDeployer {\n                pom.groupId = GROUP\n                pom.artifactId = POM_ARTIFACT_ID\n                pom.version = VERSION_NAME\n\n                repository url: \"file://${System.properties['user.home']}/.m2/repository\"\n            }\n        }\n    }\n\n    signing {\n        required { isReleaseBuild() && gradle.taskGraph.hasTask(\"uploadArchives\") }\n        sign configurations.archives\n    }\n\n    task androidJavadocs(type: Javadoc) {\n        source = android.sourceSets.main.java.srcDirs\n\t    options {\n            encoding = \"UTF-8\"\n\t    }\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    }\n}\n"
  },
  {
    "path": "gradle/wrapper/gradle-wrapper.properties",
    "content": "#Tue Apr 23 15:38:19 MSK 2019\ndistributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\nzipStoreBase=GRADLE_USER_HOME\nzipStorePath=wrapper/dists\ndistributionUrl=https\\://services.gradle.org/distributions/gradle-5.6.4-all.zip\n"
  },
  {
    "path": "gradle.properties",
    "content": "org.gradle.daemon=true\n\nVERSION_NAME=1.9.5\nVERSION_COE=40\nGROUP=com.nostra13.universalimageloader\n\nPOM_DESCRIPTION=Powerful and flexible instrument for asynchronous image loading, caching and displaying on Android\nPOM_URL=https://github.com/nostra13/Android-Universal-Image-Loader\nPOM_SCM_URL=https://github.com/nostra13/Android-Universal-Image-Loader\nPOM_SCM_CONNECTION=scm:git@github.com:nostra13/Android-Universal-Image-Loader.git\nPOM_SCM_DEV_CONNECTION=scm:git@github.com:nostra13/Android-Universal-Image-Loader.git\nPOM_LICENCE_NAME=The Apache Software License, Version 2.0\nPOM_LICENCE_URL=http://www.apache.org/licenses/LICENSE-2.0.txt\nPOM_LICENCE_DIST=repo\nPOM_DEVELOPER_ID=nostra13\nPOM_DEVELOPER_NAME=Sergey Tarasevich\n\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\n@rem ##########################################################################\n@rem\n@rem  Gradle startup script for Windows\n@rem\n@rem ##########################################################################\n\n@rem Set local scope for the variables with windows NT shell\nif \"%OS%\"==\"Windows_NT\" setlocal\n\n@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\nset DEFAULT_JVM_OPTS=\n\nset DIRNAME=%~dp0\nif \"%DIRNAME%\" == \"\" set DIRNAME=.\nset APP_BASE_NAME=%~n0\nset APP_HOME=%DIRNAME%\n\n@rem Find java.exe\nif defined JAVA_HOME goto findJavaFromJavaHome\n\nset JAVA_EXE=java.exe\n%JAVA_EXE% -version >NUL 2>&1\nif \"%ERRORLEVEL%\" == \"0\" goto init\n\necho.\necho ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\necho.\necho Please set the JAVA_HOME variable in your environment to match the\necho location of your Java installation.\n\ngoto fail\n\n:findJavaFromJavaHome\nset JAVA_HOME=%JAVA_HOME:\"=%\nset JAVA_EXE=%JAVA_HOME%/bin/java.exe\n\nif exist \"%JAVA_EXE%\" goto init\n\necho.\necho ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%\necho.\necho Please set the JAVA_HOME variable in your environment to match the\necho location of your Java installation.\n\ngoto fail\n\n:init\n@rem Get command-line arguments, handling Windowz variants\n\nif not \"%OS%\" == \"Windows_NT\" goto win9xME_args\nif \"%@eval[2+2]\" == \"4\" goto 4NT_args\n\n:win9xME_args\n@rem Slurp the command line arguments.\nset CMD_LINE_ARGS=\nset _SKIP=2\n\n:win9xME_args_slurp\nif \"x%~1\" == \"x\" goto execute\n\nset CMD_LINE_ARGS=%*\ngoto execute\n\n:4NT_args\n@rem Get arguments from the 4NT Shell from JP Software\nset CMD_LINE_ARGS=%$\n\n:execute\n@rem Setup the command line\n\nset CLASSPATH=%APP_HOME%\\gradle\\wrapper\\gradle-wrapper.jar\n\n@rem Execute Gradle\n\"%JAVA_EXE%\" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% \"-Dorg.gradle.appname=%APP_BASE_NAME%\" -classpath \"%CLASSPATH%\" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%\n\n:end\n@rem End local scope for the variables with windows NT shell\nif \"%ERRORLEVEL%\"==\"0\" goto mainEnd\n\n:fail\nrem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of\nrem the _cmd.exe /c_ return code!\nif  not \"\" == \"%GRADLE_EXIT_CONSOLE%\" exit 1\nexit /b 1\n\n:mainEnd\nif \"%OS%\"==\"Windows_NT\" endlocal\n\n:omega\n"
  },
  {
    "path": "library/build.gradle",
    "content": "apply plugin: 'com.android.library'\n\nandroid {\n    compileSdkVersion 28\n    buildToolsVersion \"28.0.3\"\n\n    defaultConfig {\n        minSdkVersion 16\n        targetSdkVersion 28\n        versionCode 40\n        versionName \"1.9.5\"\n    }\n\n    compileOptions {\n        sourceCompatibility JavaVersion.VERSION_1_8\n        targetCompatibility JavaVersion.VERSION_1_8\n    }\n}\n\ndependencies {\n    testImplementation 'junit:junit:4.12'\n    testImplementation 'org.robolectric:robolectric:3.0-rc3'\n    testImplementation 'com.squareup.assertj:assertj-android:1.0.0'\n}\n\n\n// build a jar with source files\ntask sourcesJar(type: Jar) {\n    from android.sourceSets.main.java.srcDirs\n    classifier = 'sources'\n}\nartifacts {\n    archives sourcesJar\n}\n\n// Build a jar file in addition to the default aar file\nandroid.libraryVariants.all { variant ->\n    def name = variant.buildType.name\n    def task = project.tasks.create \"jar${name.capitalize()}\", Jar\n    task.dependsOn variant.javaCompile\n    task.from variant.javaCompile.destinationDir\n    artifacts.add('archives', task);\n}\n\napply from: '../gradle/maven_push.gradle'\n"
  },
  {
    "path": "library/gradle.properties",
    "content": "POM_NAME=Universal Image Loader Library\nPOM_ARTIFACT_ID=universal-image-loader\nPOM_PACKAGING=jar\n"
  },
  {
    "path": "library/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 use,\n# \"ant.properties\", and override values to adapt the script to your\n# project structure.\n\n# Project target.\ntarget=android-21\nandroid.library=true\n"
  },
  {
    "path": "library/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n          package=\"com.nostra13.universalimageloader\"/>\n"
  },
  {
    "path": "library/src/main/java/com/nostra13/universalimageloader/cache/disc/DiskCache.java",
    "content": "/*******************************************************************************\n * Copyright 2014 Sergey Tarasevich\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *******************************************************************************/\npackage com.nostra13.universalimageloader.cache.disc;\n\nimport android.graphics.Bitmap;\nimport com.nostra13.universalimageloader.utils.IoUtils;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.InputStream;\n\n/**\n * Interface for disk cache\n *\n * @author Sergey Tarasevich (nostra13[at]gmail[dot]com)\n * @since 1.9.2\n */\npublic interface DiskCache {\n\t/**\n\t * Returns root directory of disk cache\n\t *\n\t * @return Root directory of disk cache\n\t */\n\tFile getDirectory();\n\n\t/**\n\t * Returns file of cached image\n\t *\n\t * @param imageUri Original image URI\n\t * @return File of cached image or <b>null</b> if image wasn't cached\n\t */\n\tFile get(String imageUri);\n\n\t/**\n\t * Saves image stream in disk cache.\n\t * Incoming image stream shouldn't be closed in this method.\n\t *\n\t * @param imageUri    Original image URI\n\t * @param imageStream Input stream of image (shouldn't be closed in this method)\n\t * @param listener    Listener for saving progress, can be ignored if you don't use\n\t *                    {@linkplain com.nostra13.universalimageloader.core.listener.ImageLoadingProgressListener\n\t *                    progress listener} in ImageLoader calls\n\t * @return <b>true</b> - if image was saved successfully; <b>false</b> - if image wasn't saved in disk cache.\n\t * @throws java.io.IOException\n\t */\n\tboolean save(String imageUri, InputStream imageStream, IoUtils.CopyListener listener) throws IOException;\n\n\t/**\n\t * Saves image bitmap in disk cache.\n\t *\n\t * @param imageUri Original image URI\n\t * @param bitmap   Image bitmap\n\t * @return <b>true</b> - if bitmap was saved successfully; <b>false</b> - if bitmap wasn't saved in disk cache.\n\t * @throws IOException\n\t */\n\tboolean save(String imageUri, Bitmap bitmap) throws IOException;\n\n\t/**\n\t * Removes image file associated with incoming URI\n\t *\n\t * @param imageUri Image URI\n\t * @return <b>true</b> - if image file is deleted successfully; <b>false</b> - if image file doesn't exist for\n\t * incoming URI or image file can't be deleted.\n\t */\n\tboolean remove(String imageUri);\n\n\t/** Closes disk cache, releases resources. */\n\tvoid close();\n\n\t/** Clears disk cache. */\n\tvoid clear();\n}\n"
  },
  {
    "path": "library/src/main/java/com/nostra13/universalimageloader/cache/disc/impl/BaseDiskCache.java",
    "content": "/*******************************************************************************\n * Copyright 2011-2014 Sergey Tarasevich\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *******************************************************************************/\npackage com.nostra13.universalimageloader.cache.disc.impl;\n\nimport android.graphics.Bitmap;\nimport com.nostra13.universalimageloader.cache.disc.DiskCache;\nimport com.nostra13.universalimageloader.cache.disc.naming.FileNameGenerator;\nimport com.nostra13.universalimageloader.core.DefaultConfigurationFactory;\nimport com.nostra13.universalimageloader.utils.IoUtils;\n\nimport java.io.BufferedOutputStream;\nimport java.io.File;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\n\n/**\n * Base disk cache.\n *\n * @author Sergey Tarasevich (nostra13[at]gmail[dot]com)\n * @see FileNameGenerator\n * @since 1.0.0\n */\npublic abstract class BaseDiskCache implements DiskCache {\n\t/** {@value} */\n\tpublic static final int DEFAULT_BUFFER_SIZE = 32 * 1024; // 32 Kb\n\t/** {@value} */\n\tpublic static final Bitmap.CompressFormat DEFAULT_COMPRESS_FORMAT = Bitmap.CompressFormat.PNG;\n\t/** {@value} */\n\tpublic static final int DEFAULT_COMPRESS_QUALITY = 100;\n\n\tprivate static final String ERROR_ARG_NULL = \" argument must be not null\";\n\tprivate static final String TEMP_IMAGE_POSTFIX = \".tmp\";\n\n\tprotected final File cacheDir;\n\tprotected final File reserveCacheDir;\n\n\tprotected final FileNameGenerator fileNameGenerator;\n\n\tprotected int bufferSize = DEFAULT_BUFFER_SIZE;\n\n\tprotected Bitmap.CompressFormat compressFormat = DEFAULT_COMPRESS_FORMAT;\n\tprotected int compressQuality = DEFAULT_COMPRESS_QUALITY;\n\n\t/** @param cacheDir Directory for file caching */\n\tpublic BaseDiskCache(File cacheDir) {\n\t\tthis(cacheDir, null);\n\t}\n\n\t/**\n\t * @param cacheDir        Directory for file caching\n\t * @param reserveCacheDir null-ok; Reserve directory for file caching. It's used when the primary directory isn't available.\n\t */\n\tpublic BaseDiskCache(File cacheDir, File reserveCacheDir) {\n\t\tthis(cacheDir, reserveCacheDir, DefaultConfigurationFactory.createFileNameGenerator());\n\t}\n\n\t/**\n\t * @param cacheDir          Directory for file caching\n\t * @param reserveCacheDir   null-ok; Reserve directory for file caching. It's used when the primary directory isn't available.\n\t * @param fileNameGenerator {@linkplain com.nostra13.universalimageloader.cache.disc.naming.FileNameGenerator\n\t *                          Name generator} for cached files\n\t */\n\tpublic BaseDiskCache(File cacheDir, File reserveCacheDir, FileNameGenerator fileNameGenerator) {\n\t\tif (cacheDir == null) {\n\t\t\tthrow new IllegalArgumentException(\"cacheDir\" + ERROR_ARG_NULL);\n\t\t}\n\t\tif (fileNameGenerator == null) {\n\t\t\tthrow new IllegalArgumentException(\"fileNameGenerator\" + ERROR_ARG_NULL);\n\t\t}\n\n\t\tthis.cacheDir = cacheDir;\n\t\tthis.reserveCacheDir = reserveCacheDir;\n\t\tthis.fileNameGenerator = fileNameGenerator;\n\t}\n\n\t@Override\n\tpublic File getDirectory() {\n\t\treturn cacheDir;\n\t}\n\n\t@Override\n\tpublic File get(String imageUri) {\n\t\treturn getFile(imageUri);\n\t}\n\n\t@Override\n\tpublic boolean save(String imageUri, InputStream imageStream, IoUtils.CopyListener listener) throws IOException {\n\t\tFile imageFile = getFile(imageUri);\n\t\tFile tmpFile = new File(imageFile.getAbsolutePath() + TEMP_IMAGE_POSTFIX);\n\t\tboolean loaded = false;\n\t\ttry {\n\t\t\tOutputStream os = new BufferedOutputStream(new FileOutputStream(tmpFile), bufferSize);\n\t\t\ttry {\n\t\t\t\tloaded = IoUtils.copyStream(imageStream, os, listener, bufferSize);\n\t\t\t} finally {\n\t\t\t\tIoUtils.closeSilently(os);\n\t\t\t}\n\t\t} finally {\n\t\t\tif (loaded && !tmpFile.renameTo(imageFile)) {\n\t\t\t\tloaded = false;\n\t\t\t}\n\t\t\tif (!loaded) {\n\t\t\t\ttmpFile.delete();\n\t\t\t}\n\t\t}\n\t\treturn loaded;\n\t}\n\n\t@Override\n\tpublic boolean save(String imageUri, Bitmap bitmap) throws IOException {\n\t\tFile imageFile = getFile(imageUri);\n\t\tFile tmpFile = new File(imageFile.getAbsolutePath() + TEMP_IMAGE_POSTFIX);\n\t\tOutputStream os = new BufferedOutputStream(new FileOutputStream(tmpFile), bufferSize);\n\t\tboolean savedSuccessfully = false;\n\t\ttry {\n\t\t\tsavedSuccessfully = bitmap.compress(compressFormat, compressQuality, os);\n\t\t} finally {\n\t\t\tIoUtils.closeSilently(os);\n\t\t\tif (savedSuccessfully && !tmpFile.renameTo(imageFile)) {\n\t\t\t\tsavedSuccessfully = false;\n\t\t\t}\n\t\t\tif (!savedSuccessfully) {\n\t\t\t\ttmpFile.delete();\n\t\t\t}\n\t\t}\n\t\tbitmap.recycle();\n\t\treturn savedSuccessfully;\n\t}\n\n\t@Override\n\tpublic boolean remove(String imageUri) {\n\t\treturn getFile(imageUri).delete();\n\t}\n\n\t@Override\n\tpublic void close() {\n\t\t// Nothing to do\n\t}\n\n\t@Override\n\tpublic void clear() {\n\t\tFile[] files = cacheDir.listFiles();\n\t\tif (files != null) {\n\t\t\tfor (File f : files) {\n\t\t\t\tf.delete();\n\t\t\t}\n\t\t}\n\t}\n\n\t/** Returns file object (not null) for incoming image URI. File object can reference to non-existing file. */\n\tprotected File getFile(String imageUri) {\n\t\tString fileName = fileNameGenerator.generate(imageUri);\n\t\tFile dir = cacheDir;\n\t\tif (!cacheDir.exists() && !cacheDir.mkdirs()) {\n\t\t\tif (reserveCacheDir != null && (reserveCacheDir.exists() || reserveCacheDir.mkdirs())) {\n\t\t\t\tdir = reserveCacheDir;\n\t\t\t}\n\t\t}\n\t\treturn new File(dir, fileName);\n\t}\n\n\tpublic void setBufferSize(int bufferSize) {\n\t\tthis.bufferSize = bufferSize;\n\t}\n\n\tpublic void setCompressFormat(Bitmap.CompressFormat compressFormat) {\n\t\tthis.compressFormat = compressFormat;\n\t}\n\n\tpublic void setCompressQuality(int compressQuality) {\n\t\tthis.compressQuality = compressQuality;\n\t}\n}"
  },
  {
    "path": "library/src/main/java/com/nostra13/universalimageloader/cache/disc/impl/LimitedAgeDiskCache.java",
    "content": "/*******************************************************************************\n * Copyright 2011-2014 Sergey Tarasevich\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *******************************************************************************/\npackage com.nostra13.universalimageloader.cache.disc.impl;\n\nimport android.graphics.Bitmap;\nimport com.nostra13.universalimageloader.cache.disc.naming.FileNameGenerator;\nimport com.nostra13.universalimageloader.core.DefaultConfigurationFactory;\nimport com.nostra13.universalimageloader.utils.IoUtils;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.Map;\n\n/**\n * Cache which deletes files which were loaded more than defined time. Cache size is unlimited.\n *\n * @author Sergey Tarasevich (nostra13[at]gmail[dot]com)\n * @since 1.3.1\n */\npublic class LimitedAgeDiskCache extends BaseDiskCache {\n\n\tprivate final long maxFileAge;\n\n\tprivate final Map<File, Long> loadingDates = Collections.synchronizedMap(new HashMap<File, Long>());\n\n\t/**\n\t * @param cacheDir Directory for file caching\n\t * @param maxAge   Max file age (in seconds). If file age will exceed this value then it'll be removed on next\n\t *                 treatment (and therefore be reloaded).\n\t */\n\tpublic LimitedAgeDiskCache(File cacheDir, long maxAge) {\n\t\tthis(cacheDir, null, DefaultConfigurationFactory.createFileNameGenerator(), maxAge);\n\t}\n\n\t/**\n\t * @param cacheDir Directory for file caching\n\t * @param maxAge   Max file age (in seconds). If file age will exceed this value then it'll be removed on next\n\t *                 treatment (and therefore be reloaded).\n\t */\n\tpublic LimitedAgeDiskCache(File cacheDir, File reserveCacheDir, long maxAge) {\n\t\tthis(cacheDir, reserveCacheDir, DefaultConfigurationFactory.createFileNameGenerator(), maxAge);\n\t}\n\n\t/**\n\t * @param cacheDir          Directory for file caching\n\t * @param reserveCacheDir   null-ok; Reserve directory for file caching. It's used when the primary directory isn't available.\n\t * @param fileNameGenerator Name generator for cached files\n\t * @param maxAge            Max file age (in seconds). If file age will exceed this value then it'll be removed on next\n\t *                          treatment (and therefore be reloaded).\n\t */\n\tpublic LimitedAgeDiskCache(File cacheDir, File reserveCacheDir, FileNameGenerator fileNameGenerator, long maxAge) {\n\t\tsuper(cacheDir, reserveCacheDir, fileNameGenerator);\n\t\tthis.maxFileAge = maxAge * 1000; // to milliseconds\n\t}\n\n\t@Override\n\tpublic File get(String imageUri) {\n\t\tFile file = super.get(imageUri);\n\t\tif (file != null && file.exists()) {\n\t\t\tboolean cached;\n\t\t\tLong loadingDate = loadingDates.get(file);\n\t\t\tif (loadingDate == null) {\n\t\t\t\tcached = false;\n\t\t\t\tloadingDate = file.lastModified();\n\t\t\t} else {\n\t\t\t\tcached = true;\n\t\t\t}\n\n\t\t\tif (System.currentTimeMillis() - loadingDate > maxFileAge) {\n\t\t\t\tfile.delete();\n\t\t\t\tloadingDates.remove(file);\n\t\t\t} else if (!cached) {\n\t\t\t\tloadingDates.put(file, loadingDate);\n\t\t\t}\n\t\t}\n\t\treturn file;\n\t}\n\n\t@Override\n\tpublic boolean save(String imageUri, InputStream imageStream, IoUtils.CopyListener listener) throws IOException {\n\t\tboolean saved = super.save(imageUri, imageStream, listener);\n\t\trememberUsage(imageUri);\n\t\treturn saved;\n\t}\n\n\t@Override\n\tpublic boolean save(String imageUri, Bitmap bitmap) throws IOException {\n\t\tboolean saved = super.save(imageUri, bitmap);\n\t\trememberUsage(imageUri);\n\t\treturn saved;\n\t}\n\n\t@Override\n\tpublic boolean remove(String imageUri) {\n\t\tloadingDates.remove(getFile(imageUri));\n\t\treturn super.remove(imageUri);\n\t}\n\n\t@Override\n\tpublic void clear() {\n\t\tsuper.clear();\n\t\tloadingDates.clear();\n\t}\n\n\tprivate void rememberUsage(String imageUri) {\n\t\tFile file = getFile(imageUri);\n\t\tlong currentTime = System.currentTimeMillis();\n\t\tfile.setLastModified(currentTime);\n\t\tloadingDates.put(file, currentTime);\n\t}\n}"
  },
  {
    "path": "library/src/main/java/com/nostra13/universalimageloader/cache/disc/impl/UnlimitedDiskCache.java",
    "content": "/*******************************************************************************\n * Copyright 2011-2014 Sergey Tarasevich\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *******************************************************************************/\npackage com.nostra13.universalimageloader.cache.disc.impl;\n\nimport com.nostra13.universalimageloader.cache.disc.naming.FileNameGenerator;\n\nimport java.io.File;\n\n/**\n * Default implementation of {@linkplain com.nostra13.universalimageloader.cache.disc.DiskCache disk cache}.\n * Cache size is unlimited.\n *\n * @author Sergey Tarasevich (nostra13[at]gmail[dot]com)\n * @since 1.0.0\n */\npublic class UnlimitedDiskCache extends BaseDiskCache {\n\t/** @param cacheDir Directory for file caching */\n\tpublic UnlimitedDiskCache(File cacheDir) {\n\t\tsuper(cacheDir);\n\t}\n\n\t/**\n\t * @param cacheDir        Directory for file caching\n\t * @param reserveCacheDir null-ok; Reserve directory for file caching. It's used when the primary directory isn't available.\n\t */\n\tpublic UnlimitedDiskCache(File cacheDir, File reserveCacheDir) {\n\t\tsuper(cacheDir, reserveCacheDir);\n\t}\n\n\t/**\n\t * @param cacheDir          Directory for file caching\n\t * @param reserveCacheDir   null-ok; Reserve directory for file caching. It's used when the primary directory isn't available.\n\t * @param fileNameGenerator {@linkplain com.nostra13.universalimageloader.cache.disc.naming.FileNameGenerator\n\t *                          Name generator} for cached files\n\t */\n\tpublic UnlimitedDiskCache(File cacheDir, File reserveCacheDir, FileNameGenerator fileNameGenerator) {\n\t\tsuper(cacheDir, reserveCacheDir, fileNameGenerator);\n\t}\n}\n"
  },
  {
    "path": "library/src/main/java/com/nostra13/universalimageloader/cache/disc/impl/ext/DiskLruCache.java",
    "content": "/*\n * Copyright (C) 2011 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 com.nostra13.universalimageloader.cache.disc.impl.ext;\n\nimport java.io.BufferedWriter;\nimport java.io.Closeable;\nimport java.io.EOFException;\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.FileNotFoundException;\nimport java.io.FileOutputStream;\nimport java.io.FilterOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.InputStreamReader;\nimport java.io.OutputStream;\nimport java.io.OutputStreamWriter;\nimport java.io.Writer;\nimport java.util.ArrayList;\nimport java.util.Iterator;\nimport java.util.LinkedHashMap;\nimport java.util.Map;\nimport java.util.concurrent.Callable;\nimport java.util.concurrent.LinkedBlockingQueue;\nimport java.util.concurrent.ThreadPoolExecutor;\nimport java.util.concurrent.TimeUnit;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\n/**\n * A cache that uses a bounded amount of space on a filesystem. Each cache\n * entry has a string key and a fixed number of values. Each key must match\n * the regex <strong>[a-z0-9_-]{1,64}</strong>. Values are byte sequences,\n * accessible as streams or files. Each value must be between {@code 0} and\n * {@code Integer.MAX_VALUE} bytes in length.\n *\n * <p>The cache stores its data in a directory on the filesystem. This\n * directory must be exclusive to the cache; the cache may delete or overwrite\n * files from its directory. It is an error for multiple processes to use the\n * same cache directory at the same time.\n *\n * <p>This cache limits the number of bytes that it will store on the\n * filesystem. When the number of stored bytes exceeds the limit, the cache will\n * remove entries in the background until the limit is satisfied. The limit is\n * not strict: the cache may temporarily exceed it while waiting for files to be\n * deleted. The limit does not include filesystem overhead or the cache\n * journal so space-sensitive applications should set a conservative limit.\n *\n * <p>Clients call {@link #edit} to create or update the values of an entry. An\n * entry may have only one editor at one time; if a value is not available to be\n * edited then {@link #edit} will return null.\n * <ul>\n * <li>When an entry is being <strong>created</strong> it is necessary to\n * supply a full set of values; the empty value should be used as a\n * placeholder if necessary.\n * <li>When an entry is being <strong>edited</strong>, it is not necessary\n * to supply data for every value; values default to their previous\n * value.\n * </ul>\n * Every {@link #edit} call must be matched by a call to {@link Editor#commit}\n * or {@link Editor#abort}. Committing is atomic: a read observes the full set\n * of values as they were before or after the commit, but never a mix of values.\n *\n * <p>Clients call {@link #get} to read a snapshot of an entry. The read will\n * observe the value at the time that {@link #get} was called. Updates and\n * removals after the call do not impact ongoing reads.\n *\n * <p>This class is tolerant of some I/O errors. If files are missing from the\n * filesystem, the corresponding entries will be dropped from the cache. If\n * an error occurs while writing a cache value, the edit will fail silently.\n * Callers should handle other problems by catching {@code IOException} and\n * responding appropriately.\n */\nfinal class DiskLruCache implements Closeable {\n\tstatic final String JOURNAL_FILE = \"journal\";\n\tstatic final String JOURNAL_FILE_TEMP = \"journal.tmp\";\n\tstatic final String JOURNAL_FILE_BACKUP = \"journal.bkp\";\n\tstatic final String MAGIC = \"libcore.io.DiskLruCache\";\n\tstatic final String VERSION_1 = \"1\";\n\tstatic final long ANY_SEQUENCE_NUMBER = -1;\n\tstatic final Pattern LEGAL_KEY_PATTERN = Pattern.compile(\"[a-z0-9_-]{1,64}\");\n\tprivate static final String CLEAN = \"CLEAN\";\n\tprivate static final String DIRTY = \"DIRTY\";\n\tprivate static final String REMOVE = \"REMOVE\";\n\tprivate static final String READ = \"READ\";\n\n    /*\n     * This cache uses a journal file named \"journal\". A typical journal file\n     * looks like this:\n     *     libcore.io.DiskLruCache\n     *     1\n     *     100\n     *     2\n     *\n     *     CLEAN 3400330d1dfc7f3f7f4b8d4d803dfcf6 832 21054\n     *     DIRTY 335c4c6028171cfddfbaae1a9c313c52\n     *     CLEAN 335c4c6028171cfddfbaae1a9c313c52 3934 2342\n     *     REMOVE 335c4c6028171cfddfbaae1a9c313c52\n     *     DIRTY 1ab96a171faeeee38496d8b330771a7a\n     *     CLEAN 1ab96a171faeeee38496d8b330771a7a 1600 234\n     *     READ 335c4c6028171cfddfbaae1a9c313c52\n     *     READ 3400330d1dfc7f3f7f4b8d4d803dfcf6\n     *\n     * The first five lines of the journal form its header. They are the\n     * constant string \"libcore.io.DiskLruCache\", the disk cache's version,\n     * the application's version, the value count, and a blank line.\n     *\n     * Each of the subsequent lines in the file is a record of the state of a\n     * cache entry. Each line contains space-separated values: a state, a key,\n     * and optional state-specific values.\n     *   o DIRTY lines track that an entry is actively being created or updated.\n     *     Every successful DIRTY action should be followed by a CLEAN or REMOVE\n     *     action. DIRTY lines without a matching CLEAN or REMOVE indicate that\n     *     temporary files may need to be deleted.\n     *   o CLEAN lines track a cache entry that has been successfully published\n     *     and may be read. A publish line is followed by the lengths of each of\n     *     its values.\n     *   o READ lines track accesses for LRU.\n     *   o REMOVE lines track entries that have been deleted.\n     *\n     * The journal file is appended to as cache operations occur. The journal may\n     * occasionally be compacted by dropping redundant lines. A temporary file named\n     * \"journal.tmp\" will be used during compaction; that file should be deleted if\n     * it exists when the cache is opened.\n     */\n\n\tprivate final File directory;\n\tprivate final File journalFile;\n\tprivate final File journalFileTmp;\n\tprivate final File journalFileBackup;\n\tprivate final int appVersion;\n\tprivate long maxSize;\n\tprivate int maxFileCount;\n\tprivate final int valueCount;\n\tprivate long size = 0;\n\tprivate int fileCount = 0;\n\tprivate Writer journalWriter;\n\tprivate final LinkedHashMap<String, Entry> lruEntries =\n\t\t\tnew LinkedHashMap<String, Entry>(0, 0.75f, true);\n\tprivate int redundantOpCount;\n\n\t/**\n\t * To differentiate between old and current snapshots, each entry is given\n\t * a sequence number each time an edit is committed. A snapshot is stale if\n\t * its sequence number is not equal to its entry's sequence number.\n\t */\n\tprivate long nextSequenceNumber = 0;\n\n\t/** This cache uses a single background thread to evict entries. */\n\tfinal ThreadPoolExecutor executorService =\n\t\t\tnew ThreadPoolExecutor(0, 1, 60L, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());\n\tprivate final Callable<Void> cleanupCallable = new Callable<Void>() {\n\t\tpublic Void call() throws Exception {\n\t\t\tsynchronized (DiskLruCache.this) {\n\t\t\t\tif (journalWriter == null) {\n\t\t\t\t\treturn null; // Closed.\n\t\t\t\t}\n\t\t\t\ttrimToSize();\n\t\t\t\ttrimToFileCount();\n\t\t\t\tif (journalRebuildRequired()) {\n\t\t\t\t\trebuildJournal();\n\t\t\t\t\tredundantOpCount = 0;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn null;\n\t\t}\n\t};\n\n\tprivate DiskLruCache(File directory, int appVersion, int valueCount, long maxSize, int maxFileCount) {\n\t\tthis.directory = directory;\n\t\tthis.appVersion = appVersion;\n\t\tthis.journalFile = new File(directory, JOURNAL_FILE);\n\t\tthis.journalFileTmp = new File(directory, JOURNAL_FILE_TEMP);\n\t\tthis.journalFileBackup = new File(directory, JOURNAL_FILE_BACKUP);\n\t\tthis.valueCount = valueCount;\n\t\tthis.maxSize = maxSize;\n\t\tthis.maxFileCount = maxFileCount;\n\t}\n\n\t/**\n\t * Opens the cache in {@code directory}, creating a cache if none exists\n\t * there.\n\t *\n\t * @param directory a writable directory\n\t * @param valueCount the number of values per cache entry. Must be positive.\n\t * @param maxSize the maximum number of bytes this cache should use to store\n\t * @param maxFileCount the maximum file count this cache should store\n\t * @throws IOException if reading or writing the cache directory fails\n\t */\n\tpublic static DiskLruCache open(File directory, int appVersion, int valueCount, long maxSize, int maxFileCount)\n\t\t\tthrows IOException {\n\t\tif (maxSize <= 0) {\n\t\t\tthrow new IllegalArgumentException(\"maxSize <= 0\");\n\t\t}\n\t\tif (maxFileCount <= 0) {\n\t\t\tthrow new IllegalArgumentException(\"maxFileCount <= 0\");\n\t\t}\n\t\tif (valueCount <= 0) {\n\t\t\tthrow new IllegalArgumentException(\"valueCount <= 0\");\n\t\t}\n\n\t\t// If a bkp file exists, use it instead.\n\t\tFile backupFile = new File(directory, JOURNAL_FILE_BACKUP);\n\t\tif (backupFile.exists()) {\n\t\t\tFile journalFile = new File(directory, JOURNAL_FILE);\n\t\t\t// If journal file also exists just delete backup file.\n\t\t\tif (journalFile.exists()) {\n\t\t\t\tbackupFile.delete();\n\t\t\t} else {\n\t\t\t\trenameTo(backupFile, journalFile, false);\n\t\t\t}\n\t\t}\n\n\t\t// Prefer to pick up where we left off.\n\t\tDiskLruCache cache = new DiskLruCache(directory, appVersion, valueCount, maxSize, maxFileCount);\n\t\tif (cache.journalFile.exists()) {\n\t\t\ttry {\n\t\t\t\tcache.readJournal();\n\t\t\t\tcache.processJournal();\n\t\t\t\tcache.journalWriter = new BufferedWriter(\n\t\t\t\t\t\tnew OutputStreamWriter(new FileOutputStream(cache.journalFile, true), Util.US_ASCII));\n\t\t\t\treturn cache;\n\t\t\t} catch (IOException journalIsCorrupt) {\n\t\t\t\tSystem.out\n\t\t\t\t\t\t.println(\"DiskLruCache \"\n\t\t\t\t\t\t\t\t+ directory\n\t\t\t\t\t\t\t\t+ \" is corrupt: \"\n\t\t\t\t\t\t\t\t+ journalIsCorrupt.getMessage()\n\t\t\t\t\t\t\t\t+ \", removing\");\n\t\t\t\tcache.delete();\n\t\t\t}\n\t\t}\n\n\t\t// Create a new empty cache.\n\t\tdirectory.mkdirs();\n\t\tcache = new DiskLruCache(directory, appVersion, valueCount, maxSize, maxFileCount);\n\t\tcache.rebuildJournal();\n\t\treturn cache;\n\t}\n\n\tprivate void readJournal() throws IOException {\n\t\tStrictLineReader reader = new StrictLineReader(new FileInputStream(journalFile), Util.US_ASCII);\n\t\ttry {\n\t\t\tString magic = reader.readLine();\n\t\t\tString version = reader.readLine();\n\t\t\tString appVersionString = reader.readLine();\n\t\t\tString valueCountString = reader.readLine();\n\t\t\tString blank = reader.readLine();\n\t\t\tif (!MAGIC.equals(magic)\n\t\t\t\t\t|| !VERSION_1.equals(version)\n\t\t\t\t\t|| !Integer.toString(appVersion).equals(appVersionString)\n\t\t\t\t\t|| !Integer.toString(valueCount).equals(valueCountString)\n\t\t\t\t\t|| !\"\".equals(blank)) {\n\t\t\t\tthrow new IOException(\"unexpected journal header: [\" + magic + \", \" + version + \", \"\n\t\t\t\t\t\t+ valueCountString + \", \" + blank + \"]\");\n\t\t\t}\n\n\t\t\tint lineCount = 0;\n\t\t\twhile (true) {\n\t\t\t\ttry {\n\t\t\t\t\treadJournalLine(reader.readLine());\n\t\t\t\t\tlineCount++;\n\t\t\t\t} catch (EOFException endOfJournal) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tredundantOpCount = lineCount - lruEntries.size();\n\t\t} finally {\n\t\t\tUtil.closeQuietly(reader);\n\t\t}\n\t}\n\n\tprivate void readJournalLine(String line) throws IOException {\n\t\tint firstSpace = line.indexOf(' ');\n\t\tif (firstSpace == -1) {\n\t\t\tthrow new IOException(\"unexpected journal line: \" + line);\n\t\t}\n\n\t\tint keyBegin = firstSpace + 1;\n\t\tint secondSpace = line.indexOf(' ', keyBegin);\n\t\tfinal String key;\n\t\tif (secondSpace == -1) {\n\t\t\tkey = line.substring(keyBegin);\n\t\t\tif (firstSpace == REMOVE.length() && line.startsWith(REMOVE)) {\n\t\t\t\tlruEntries.remove(key);\n\t\t\t\treturn;\n\t\t\t}\n\t\t} else {\n\t\t\tkey = line.substring(keyBegin, secondSpace);\n\t\t}\n\n\t\tEntry entry = lruEntries.get(key);\n\t\tif (entry == null) {\n\t\t\tentry = new Entry(key);\n\t\t\tlruEntries.put(key, entry);\n\t\t}\n\n\t\tif (secondSpace != -1 && firstSpace == CLEAN.length() && line.startsWith(CLEAN)) {\n\t\t\tString[] parts = line.substring(secondSpace + 1).split(\" \");\n\t\t\tentry.readable = true;\n\t\t\tentry.currentEditor = null;\n\t\t\tentry.setLengths(parts);\n\t\t} else if (secondSpace == -1 && firstSpace == DIRTY.length() && line.startsWith(DIRTY)) {\n\t\t\tentry.currentEditor = new Editor(entry);\n\t\t} else if (secondSpace == -1 && firstSpace == READ.length() && line.startsWith(READ)) {\n\t\t\t// This work was already done by calling lruEntries.get().\n\t\t} else {\n\t\t\tthrow new IOException(\"unexpected journal line: \" + line);\n\t\t}\n\t}\n\n\t/**\n\t * Computes the initial size and collects garbage as a part of opening the\n\t * cache. Dirty entries are assumed to be inconsistent and will be deleted.\n\t */\n\tprivate void processJournal() throws IOException {\n\t\tdeleteIfExists(journalFileTmp);\n\t\tfor (Iterator<Entry> i = lruEntries.values().iterator(); i.hasNext(); ) {\n\t\t\tEntry entry = i.next();\n\t\t\tif (entry.currentEditor == null) {\n\t\t\t\tfor (int t = 0; t < valueCount; t++) {\n\t\t\t\t\tsize += entry.lengths[t];\n\t\t\t\t\tfileCount++;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tentry.currentEditor = null;\n\t\t\t\tfor (int t = 0; t < valueCount; t++) {\n\t\t\t\t\tdeleteIfExists(entry.getCleanFile(t));\n\t\t\t\t\tdeleteIfExists(entry.getDirtyFile(t));\n\t\t\t\t}\n\t\t\t\ti.remove();\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Creates a new journal that omits redundant information. This replaces the\n\t * current journal if it exists.\n\t */\n\tprivate synchronized void rebuildJournal() throws IOException {\n\t\tif (journalWriter != null) {\n\t\t\tjournalWriter.close();\n\t\t}\n\n\t\tWriter writer = new BufferedWriter(\n\t\t\t\tnew OutputStreamWriter(new FileOutputStream(journalFileTmp), Util.US_ASCII));\n\t\ttry {\n\t\t\twriter.write(MAGIC);\n\t\t\twriter.write(\"\\n\");\n\t\t\twriter.write(VERSION_1);\n\t\t\twriter.write(\"\\n\");\n\t\t\twriter.write(Integer.toString(appVersion));\n\t\t\twriter.write(\"\\n\");\n\t\t\twriter.write(Integer.toString(valueCount));\n\t\t\twriter.write(\"\\n\");\n\t\t\twriter.write(\"\\n\");\n\n\t\t\tfor (Entry entry : lruEntries.values()) {\n\t\t\t\tif (entry.currentEditor != null) {\n\t\t\t\t\twriter.write(DIRTY + ' ' + entry.key + '\\n');\n\t\t\t\t} else {\n\t\t\t\t\twriter.write(CLEAN + ' ' + entry.key + entry.getLengths() + '\\n');\n\t\t\t\t}\n\t\t\t}\n\t\t} finally {\n\t\t\twriter.close();\n\t\t}\n\n\t\tif (journalFile.exists()) {\n\t\t\trenameTo(journalFile, journalFileBackup, true);\n\t\t}\n\t\trenameTo(journalFileTmp, journalFile, false);\n\t\tjournalFileBackup.delete();\n\n\t\tjournalWriter = new BufferedWriter(\n\t\t\t\tnew OutputStreamWriter(new FileOutputStream(journalFile, true), Util.US_ASCII));\n\t}\n\n\tprivate static void deleteIfExists(File file) throws IOException {\n\t\tif (file.exists() && !file.delete()) {\n\t\t\tthrow new IOException();\n\t\t}\n\t}\n\n\tprivate static void renameTo(File from, File to, boolean deleteDestination) throws IOException {\n\t\tif (deleteDestination) {\n\t\t\tdeleteIfExists(to);\n\t\t}\n\t\tif (!from.renameTo(to)) {\n\t\t\tthrow new IOException();\n\t\t}\n\t}\n\n\t/**\n\t * Returns a snapshot of the entry named {@code key}, or null if it doesn't\n\t * exist is not currently readable. If a value is returned, it is moved to\n\t * the head of the LRU queue.\n\t */\n\tpublic synchronized Snapshot get(String key) throws IOException {\n\t\tcheckNotClosed();\n\t\tvalidateKey(key);\n\t\tEntry entry = lruEntries.get(key);\n\t\tif (entry == null) {\n\t\t\treturn null;\n\t\t}\n\n\t\tif (!entry.readable) {\n\t\t\treturn null;\n\t\t}\n\n\t\t// Open all streams eagerly to guarantee that we see a single published\n\t\t// snapshot. If we opened streams lazily then the streams could come\n\t\t// from different edits.\n\t\tFile[] files = new File[valueCount];\n\t\tInputStream[] ins = new InputStream[valueCount];\n\t\ttry {\n\t\t\tFile file;\n\t\t\tfor (int i = 0; i < valueCount; i++) {\n\t\t\t\tfile = entry.getCleanFile(i);\n\t\t\t\tfiles[i] = file;\n\t\t\t\tins[i] = new FileInputStream(file);\n\t\t\t}\n\t\t} catch (FileNotFoundException e) {\n\t\t\t// A file must have been deleted manually!\n\t\t\tfor (int i = 0; i < valueCount; i++) {\n\t\t\t\tif (ins[i] != null) {\n\t\t\t\t\tUtil.closeQuietly(ins[i]);\n\t\t\t\t} else {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn null;\n\t\t}\n\n\t\tredundantOpCount++;\n\t\tjournalWriter.append(READ + ' ' + key + '\\n');\n\t\tif (journalRebuildRequired()) {\n\t\t\texecutorService.submit(cleanupCallable);\n\t\t}\n\n\t\treturn new Snapshot(key, entry.sequenceNumber, files, ins, entry.lengths);\n\t}\n\n\t/**\n\t * Returns an editor for the entry named {@code key}, or null if another\n\t * edit is in progress.\n\t */\n\tpublic Editor edit(String key) throws IOException {\n\t\treturn edit(key, ANY_SEQUENCE_NUMBER);\n\t}\n\n\tprivate synchronized Editor edit(String key, long expectedSequenceNumber) throws IOException {\n\t\tcheckNotClosed();\n\t\tvalidateKey(key);\n\t\tEntry entry = lruEntries.get(key);\n\t\tif (expectedSequenceNumber != ANY_SEQUENCE_NUMBER && (entry == null\n\t\t\t\t|| entry.sequenceNumber != expectedSequenceNumber)) {\n\t\t\treturn null; // Snapshot is stale.\n\t\t}\n\t\tif (entry == null) {\n\t\t\tentry = new Entry(key);\n\t\t\tlruEntries.put(key, entry);\n\t\t} else if (entry.currentEditor != null) {\n\t\t\treturn null; // Another edit is in progress.\n\t\t}\n\n\t\tEditor editor = new Editor(entry);\n\t\tentry.currentEditor = editor;\n\n\t\t// Flush the journal before creating files to prevent file leaks.\n\t\tjournalWriter.write(DIRTY + ' ' + key + '\\n');\n\t\tjournalWriter.flush();\n\t\treturn editor;\n\t}\n\n\t/** Returns the directory where this cache stores its data. */\n\tpublic File getDirectory() {\n\t\treturn directory;\n\t}\n\n\t/**\n\t * Returns the maximum number of bytes that this cache should use to store\n\t * its data.\n\t */\n\tpublic synchronized long getMaxSize() {\n\t\treturn maxSize;\n\t}\n\n\t/** Returns the maximum number of files that this cache should store */\n\tpublic synchronized int getMaxFileCount() {\n\t\treturn maxFileCount;\n\t}\n\n\t/**\n\t * Changes the maximum number of bytes the cache can store and queues a job\n\t * to trim the existing store, if necessary.\n\t */\n\tpublic synchronized void setMaxSize(long maxSize) {\n\t\tthis.maxSize = maxSize;\n\t\texecutorService.submit(cleanupCallable);\n\t}\n\n\t/**\n\t * Returns the number of bytes currently being used to store the values in\n\t * this cache. This may be greater than the max size if a background\n\t * deletion is pending.\n\t */\n\tpublic synchronized long size() {\n\t\treturn size;\n\t}\n\n\t/**\n\t * Returns the number of files currently being used to store the values in\n\t * this cache. This may be greater than the max file count if a background\n\t * deletion is pending.\n\t */\n\tpublic synchronized long fileCount() {\n\t\treturn fileCount;\n\t}\n\n\tprivate synchronized void completeEdit(Editor editor, boolean success) throws IOException {\n\t\tEntry entry = editor.entry;\n\t\tif (entry.currentEditor != editor) {\n\t\t\tthrow new IllegalStateException();\n\t\t}\n\n\t\t// If this edit is creating the entry for the first time, every index must have a value.\n\t\tif (success && !entry.readable) {\n\t\t\tfor (int i = 0; i < valueCount; i++) {\n\t\t\t\tif (!editor.written[i]) {\n\t\t\t\t\teditor.abort();\n\t\t\t\t\tthrow new IllegalStateException(\"Newly created entry didn't create value for index \" + i);\n\t\t\t\t}\n\t\t\t\tif (!entry.getDirtyFile(i).exists()) {\n\t\t\t\t\teditor.abort();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tfor (int i = 0; i < valueCount; i++) {\n\t\t\tFile dirty = entry.getDirtyFile(i);\n\t\t\tif (success) {\n\t\t\t\tif (dirty.exists()) {\n\t\t\t\t\tFile clean = entry.getCleanFile(i);\n\t\t\t\t\tdirty.renameTo(clean);\n\t\t\t\t\tlong oldLength = entry.lengths[i];\n\t\t\t\t\tlong newLength = clean.length();\n\t\t\t\t\tentry.lengths[i] = newLength;\n\t\t\t\t\tsize = size - oldLength + newLength;\n\t\t\t\t\tfileCount++;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tdeleteIfExists(dirty);\n\t\t\t}\n\t\t}\n\n\t\tredundantOpCount++;\n\t\tentry.currentEditor = null;\n\t\tif (entry.readable | success) {\n\t\t\tentry.readable = true;\n\t\t\tjournalWriter.write(CLEAN + ' ' + entry.key + entry.getLengths() + '\\n');\n\t\t\tif (success) {\n\t\t\t\tentry.sequenceNumber = nextSequenceNumber++;\n\t\t\t}\n\t\t} else {\n\t\t\tlruEntries.remove(entry.key);\n\t\t\tjournalWriter.write(REMOVE + ' ' + entry.key + '\\n');\n\t\t}\n\t\tjournalWriter.flush();\n\n\t\tif (size > maxSize || fileCount > maxFileCount || journalRebuildRequired()) {\n\t\t\texecutorService.submit(cleanupCallable);\n\t\t}\n\t}\n\n\t/**\n\t * We only rebuild the journal when it will halve the size of the journal\n\t * and eliminate at least 2000 ops.\n\t */\n\tprivate boolean journalRebuildRequired() {\n\t\tfinal int redundantOpCompactThreshold = 2000;\n\t\treturn redundantOpCount >= redundantOpCompactThreshold //\n\t\t\t\t&& redundantOpCount >= lruEntries.size();\n\t}\n\n\t/**\n\t * Drops the entry for {@code key} if it exists and can be removed. Entries\n\t * actively being edited cannot be removed.\n\t *\n\t * @return true if an entry was removed.\n\t */\n\tpublic synchronized boolean remove(String key) throws IOException {\n\t\tcheckNotClosed();\n\t\tvalidateKey(key);\n\t\tEntry entry = lruEntries.get(key);\n\t\tif (entry == null || entry.currentEditor != null) {\n\t\t\treturn false;\n\t\t}\n\n\t\tfor (int i = 0; i < valueCount; i++) {\n\t\t\tFile file = entry.getCleanFile(i);\n\t\t\tif (file.exists() && !file.delete()) {\n\t\t\t\tthrow new IOException(\"failed to delete \" + file);\n\t\t\t}\n\t\t\tsize -= entry.lengths[i];\n\t\t\tfileCount--;\n\t\t\tentry.lengths[i] = 0;\n\t\t}\n\n\t\tredundantOpCount++;\n\t\tjournalWriter.append(REMOVE + ' ' + key + '\\n');\n\t\tlruEntries.remove(key);\n\n\t\tif (journalRebuildRequired()) {\n\t\t\texecutorService.submit(cleanupCallable);\n\t\t}\n\n\t\treturn true;\n\t}\n\n\t/** Returns true if this cache has been closed. */\n\tpublic synchronized boolean isClosed() {\n\t\treturn journalWriter == null;\n\t}\n\n\tprivate void checkNotClosed() {\n\t\tif (journalWriter == null) {\n\t\t\tthrow new IllegalStateException(\"cache is closed\");\n\t\t}\n\t}\n\n\t/** Force buffered operations to the filesystem. */\n\tpublic synchronized void flush() throws IOException {\n\t\tcheckNotClosed();\n\t\ttrimToSize();\n\t\ttrimToFileCount();\n\t\tjournalWriter.flush();\n\t}\n\n\t/** Closes this cache. Stored values will remain on the filesystem. */\n\tpublic synchronized void close() throws IOException {\n\t\tif (journalWriter == null) {\n\t\t\treturn; // Already closed.\n\t\t}\n\t\tfor (Entry entry : new ArrayList<Entry>(lruEntries.values())) {\n\t\t\tif (entry.currentEditor != null) {\n\t\t\t\tentry.currentEditor.abort();\n\t\t\t}\n\t\t}\n\t\ttrimToSize();\n\t\ttrimToFileCount();\n\t\tjournalWriter.close();\n\t\tjournalWriter = null;\n\t}\n\n\tprivate void trimToSize() throws IOException {\n\t\twhile (size > maxSize) {\n\t\t\tMap.Entry<String, Entry> toEvict = lruEntries.entrySet().iterator().next();\n\t\t\tremove(toEvict.getKey());\n\t\t}\n\t}\n\n\tprivate void trimToFileCount() throws IOException {\n\t\twhile (fileCount > maxFileCount) {\n\t\t\tMap.Entry<String, Entry> toEvict = lruEntries.entrySet().iterator().next();\n\t\t\tremove(toEvict.getKey());\n\t\t}\n\t}\n\n\t/**\n\t * Closes the cache and deletes all of its stored values. This will delete\n\t * all files in the cache directory including files that weren't created by\n\t * the cache.\n\t */\n\tpublic void delete() throws IOException {\n\t\tclose();\n\t\tUtil.deleteContents(directory);\n\t}\n\n\tprivate void validateKey(String key) {\n\t\tMatcher matcher = LEGAL_KEY_PATTERN.matcher(key);\n\t\tif (!matcher.matches()) {\n\t\t\tthrow new IllegalArgumentException(\"keys must match regex [a-z0-9_-]{1,64}: \\\"\" + key + \"\\\"\");\n\t\t}\n\t}\n\n\tprivate static String inputStreamToString(InputStream in) throws IOException {\n\t\treturn Util.readFully(new InputStreamReader(in, Util.UTF_8));\n\t}\n\n\t/** A snapshot of the values for an entry. */\n\tpublic final class Snapshot implements Closeable {\n\t\tprivate final String key;\n\t\tprivate final long sequenceNumber;\n\t\tprivate File[] files;\n\t\tprivate final InputStream[] ins;\n\t\tprivate final long[] lengths;\n\n\t\tprivate Snapshot(String key, long sequenceNumber, File[] files, InputStream[] ins, long[] lengths) {\n\t\t\tthis.key = key;\n\t\t\tthis.sequenceNumber = sequenceNumber;\n\t\t\tthis.files = files;\n\t\t\tthis.ins = ins;\n\t\t\tthis.lengths = lengths;\n\t\t}\n\n\t\t/**\n\t\t * Returns an editor for this snapshot's entry, or null if either the\n\t\t * entry has changed since this snapshot was created or if another edit\n\t\t * is in progress.\n\t\t */\n\t\tpublic Editor edit() throws IOException {\n\t\t\treturn DiskLruCache.this.edit(key, sequenceNumber);\n\t\t}\n\n\t\t/** Returns file with the value for {@code index}. */\n\t\tpublic File getFile(int index) {\n\t\t\treturn files[index];\n\t\t}\n\n\t\t/** Returns the unbuffered stream with the value for {@code index}. */\n\t\tpublic InputStream getInputStream(int index) {\n\t\t\treturn ins[index];\n\t\t}\n\n\t\t/** Returns the string value for {@code index}. */\n\t\tpublic String getString(int index) throws IOException {\n\t\t\treturn inputStreamToString(getInputStream(index));\n\t\t}\n\n\t\t/** Returns the byte length of the value for {@code index}. */\n\t\tpublic long getLength(int index) {\n\t\t\treturn lengths[index];\n\t\t}\n\n\t\tpublic void close() {\n\t\t\tfor (InputStream in : ins) {\n\t\t\t\tUtil.closeQuietly(in);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate static final OutputStream NULL_OUTPUT_STREAM = new OutputStream() {\n\t\t@Override\n\t\tpublic void write(int b) throws IOException {\n\t\t\t// Eat all writes silently. Nom nom.\n\t\t}\n\t};\n\n\t/** Edits the values for an entry. */\n\tpublic final class Editor {\n\t\tprivate final Entry entry;\n\t\tprivate final boolean[] written;\n\t\tprivate boolean hasErrors;\n\t\tprivate boolean committed;\n\n\t\tprivate Editor(Entry entry) {\n\t\t\tthis.entry = entry;\n\t\t\tthis.written = (entry.readable) ? null : new boolean[valueCount];\n\t\t}\n\n\t\t/**\n\t\t * Returns an unbuffered input stream to read the last committed value,\n\t\t * or null if no value has been committed.\n\t\t */\n\t\tpublic InputStream newInputStream(int index) throws IOException {\n\t\t\tsynchronized (DiskLruCache.this) {\n\t\t\t\tif (entry.currentEditor != this) {\n\t\t\t\t\tthrow new IllegalStateException();\n\t\t\t\t}\n\t\t\t\tif (!entry.readable) {\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\t\t\t\ttry {\n\t\t\t\t\treturn new FileInputStream(entry.getCleanFile(index));\n\t\t\t\t} catch (FileNotFoundException e) {\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t/**\n\t\t * Returns the last committed value as a string, or null if no value\n\t\t * has been committed.\n\t\t */\n\t\tpublic String getString(int index) throws IOException {\n\t\t\tInputStream in = newInputStream(index);\n\t\t\treturn in != null ? inputStreamToString(in) : null;\n\t\t}\n\n\t\t/**\n\t\t * Returns a new unbuffered output stream to write the value at\n\t\t * {@code index}. If the underlying output stream encounters errors\n\t\t * when writing to the filesystem, this edit will be aborted when\n\t\t * {@link #commit} is called. The returned output stream does not throw\n\t\t * IOExceptions.\n\t\t */\n\t\tpublic OutputStream newOutputStream(int index) throws IOException {\n\t\t\tsynchronized (DiskLruCache.this) {\n\t\t\t\tif (entry.currentEditor != this) {\n\t\t\t\t\tthrow new IllegalStateException();\n\t\t\t\t}\n\t\t\t\tif (!entry.readable) {\n\t\t\t\t\twritten[index] = true;\n\t\t\t\t}\n\t\t\t\tFile dirtyFile = entry.getDirtyFile(index);\n\t\t\t\tFileOutputStream outputStream;\n\t\t\t\ttry {\n\t\t\t\t\toutputStream = new FileOutputStream(dirtyFile);\n\t\t\t\t} catch (FileNotFoundException e) {\n\t\t\t\t\t// Attempt to recreate the cache directory.\n\t\t\t\t\tdirectory.mkdirs();\n\t\t\t\t\ttry {\n\t\t\t\t\t\toutputStream = new FileOutputStream(dirtyFile);\n\t\t\t\t\t} catch (FileNotFoundException e2) {\n\t\t\t\t\t\t// We are unable to recover. Silently eat the writes.\n\t\t\t\t\t\treturn NULL_OUTPUT_STREAM;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn new FaultHidingOutputStream(outputStream);\n\t\t\t}\n\t\t}\n\n\t\t/** Sets the value at {@code index} to {@code value}. */\n\t\tpublic void set(int index, String value) throws IOException {\n\t\t\tWriter writer = null;\n\t\t\ttry {\n\t\t\t\twriter = new OutputStreamWriter(newOutputStream(index), Util.UTF_8);\n\t\t\t\twriter.write(value);\n\t\t\t} finally {\n\t\t\t\tUtil.closeQuietly(writer);\n\t\t\t}\n\t\t}\n\n\t\t/**\n\t\t * Commits this edit so it is visible to readers.  This releases the\n\t\t * edit lock so another edit may be started on the same key.\n\t\t */\n\t\tpublic void commit() throws IOException {\n\t\t\tif (hasErrors) {\n\t\t\t\tcompleteEdit(this, false);\n\t\t\t\tremove(entry.key); // The previous entry is stale.\n\t\t\t} else {\n\t\t\t\tcompleteEdit(this, true);\n\t\t\t}\n\t\t\tcommitted = true;\n\t\t}\n\n\t\t/**\n\t\t * Aborts this edit. This releases the edit lock so another edit may be\n\t\t * started on the same key.\n\t\t */\n\t\tpublic void abort() throws IOException {\n\t\t\tcompleteEdit(this, false);\n\t\t}\n\n\t\tpublic void abortUnlessCommitted() {\n\t\t\tif (!committed) {\n\t\t\t\ttry {\n\t\t\t\t\tabort();\n\t\t\t\t} catch (IOException ignored) {\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tprivate class FaultHidingOutputStream extends FilterOutputStream {\n\t\t\tprivate FaultHidingOutputStream(OutputStream out) {\n\t\t\t\tsuper(out);\n\t\t\t}\n\n\t\t\t@Override public void write(int oneByte) {\n\t\t\t\ttry {\n\t\t\t\t\tout.write(oneByte);\n\t\t\t\t} catch (IOException e) {\n\t\t\t\t\thasErrors = true;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t@Override public void write(byte[] buffer, int offset, int length) {\n\t\t\t\ttry {\n\t\t\t\t\tout.write(buffer, offset, length);\n\t\t\t\t} catch (IOException e) {\n\t\t\t\t\thasErrors = true;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t@Override public void close() {\n\t\t\t\ttry {\n\t\t\t\t\tout.close();\n\t\t\t\t} catch (IOException e) {\n\t\t\t\t\thasErrors = true;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t@Override public void flush() {\n\t\t\t\ttry {\n\t\t\t\t\tout.flush();\n\t\t\t\t} catch (IOException e) {\n\t\t\t\t\thasErrors = true;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate final class Entry {\n\t\tprivate final String key;\n\n\t\t/** Lengths of this entry's files. */\n\t\tprivate final long[] lengths;\n\n\t\t/** True if this entry has ever been published. */\n\t\tprivate boolean readable;\n\n\t\t/** The ongoing edit or null if this entry is not being edited. */\n\t\tprivate Editor currentEditor;\n\n\t\t/** The sequence number of the most recently committed edit to this entry. */\n\t\tprivate long sequenceNumber;\n\n\t\tprivate Entry(String key) {\n\t\t\tthis.key = key;\n\t\t\tthis.lengths = new long[valueCount];\n\t\t}\n\n\t\tpublic String getLengths() throws IOException {\n\t\t\tStringBuilder result = new StringBuilder();\n\t\t\tfor (long size : lengths) {\n\t\t\t\tresult.append(' ').append(size);\n\t\t\t}\n\t\t\treturn result.toString();\n\t\t}\n\n\t\t/** Set lengths using decimal numbers like \"10123\". */\n\t\tprivate void setLengths(String[] strings) throws IOException {\n\t\t\tif (strings.length != valueCount) {\n\t\t\t\tthrow invalidLengths(strings);\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tfor (int i = 0; i < strings.length; i++) {\n\t\t\t\t\tlengths[i] = Long.parseLong(strings[i]);\n\t\t\t\t}\n\t\t\t} catch (NumberFormatException e) {\n\t\t\t\tthrow invalidLengths(strings);\n\t\t\t}\n\t\t}\n\n\t\tprivate IOException invalidLengths(String[] strings) throws IOException {\n\t\t\tthrow new IOException(\"unexpected journal line: \" + java.util.Arrays.toString(strings));\n\t\t}\n\n\t\tpublic File getCleanFile(int i) {\n\t\t\treturn new File(directory, key + \".\" + i);\n\t\t}\n\n\t\tpublic File getDirtyFile(int i) {\n\t\t\treturn new File(directory, key + \".\" + i + \".tmp\");\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "library/src/main/java/com/nostra13/universalimageloader/cache/disc/impl/ext/LruDiskCache.java",
    "content": "/*******************************************************************************\n * Copyright 2014 Sergey Tarasevich\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *******************************************************************************/\npackage com.nostra13.universalimageloader.cache.disc.impl.ext;\n\nimport android.graphics.Bitmap;\nimport com.nostra13.universalimageloader.cache.disc.DiskCache;\nimport com.nostra13.universalimageloader.cache.disc.naming.FileNameGenerator;\nimport com.nostra13.universalimageloader.utils.IoUtils;\nimport com.nostra13.universalimageloader.utils.L;\n\nimport java.io.BufferedOutputStream;\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\n\n/**\n * Disk cache based on \"Least-Recently Used\" principle. Adapter pattern, adapts\n * {@link com.nostra13.universalimageloader.cache.disc.impl.ext.DiskLruCache DiskLruCache} to\n * {@link com.nostra13.universalimageloader.cache.disc.DiskCache DiskCache}\n *\n * @author Sergey Tarasevich (nostra13[at]gmail[dot]com)\n * @see FileNameGenerator\n * @since 1.9.2\n */\npublic class LruDiskCache implements DiskCache {\n\t/** {@value */\n\tpublic static final int DEFAULT_BUFFER_SIZE = 32 * 1024; // 32 Kb\n\t/** {@value */\n\tpublic static final Bitmap.CompressFormat DEFAULT_COMPRESS_FORMAT = Bitmap.CompressFormat.PNG;\n\t/** {@value */\n\tpublic static final int DEFAULT_COMPRESS_QUALITY = 100;\n\n\tprivate static final String ERROR_ARG_NULL = \" argument must be not null\";\n\tprivate static final String ERROR_ARG_NEGATIVE = \" argument must be positive number\";\n\n\tprotected DiskLruCache cache;\n\tprivate File reserveCacheDir;\n\n\tprotected final FileNameGenerator fileNameGenerator;\n\n\tprotected int bufferSize = DEFAULT_BUFFER_SIZE;\n\n\tprotected Bitmap.CompressFormat compressFormat = DEFAULT_COMPRESS_FORMAT;\n\tprotected int compressQuality = DEFAULT_COMPRESS_QUALITY;\n\n\t/**\n\t * @param cacheDir          Directory for file caching\n\t * @param fileNameGenerator {@linkplain com.nostra13.universalimageloader.cache.disc.naming.FileNameGenerator\n\t *                          Name generator} for cached files. Generated names must match the regex\n\t *                          <strong>[a-z0-9_-]{1,64}</strong>\n\t * @param cacheMaxSize      Max cache size in bytes. <b>0</b> means cache size is unlimited.\n\t * @throws IOException if cache can't be initialized (e.g. \"No space left on device\")\n\t */\n\tpublic LruDiskCache(File cacheDir, FileNameGenerator fileNameGenerator, long cacheMaxSize) throws IOException {\n\t\tthis(cacheDir, null, fileNameGenerator, cacheMaxSize, 0);\n\t}\n\n\t/**\n\t * @param cacheDir          Directory for file caching\n\t * @param reserveCacheDir   null-ok; Reserve directory for file caching. It's used when the primary directory isn't available.\n\t * @param fileNameGenerator {@linkplain com.nostra13.universalimageloader.cache.disc.naming.FileNameGenerator\n\t *                          Name generator} for cached files. Generated names must match the regex\n\t *                          <strong>[a-z0-9_-]{1,64}</strong>\n\t * @param cacheMaxSize      Max cache size in bytes. <b>0</b> means cache size is unlimited.\n\t * @param cacheMaxFileCount Max file count in cache. <b>0</b> means file count is unlimited.\n\t * @throws IOException if cache can't be initialized (e.g. \"No space left on device\")\n\t */\n\tpublic LruDiskCache(File cacheDir, File reserveCacheDir, FileNameGenerator fileNameGenerator, long cacheMaxSize,\n\t\t\tint cacheMaxFileCount) throws IOException {\n\t\tif (cacheDir == null) {\n\t\t\tthrow new IllegalArgumentException(\"cacheDir\" + ERROR_ARG_NULL);\n\t\t}\n\t\tif (cacheMaxSize < 0) {\n\t\t\tthrow new IllegalArgumentException(\"cacheMaxSize\" + ERROR_ARG_NEGATIVE);\n\t\t}\n\t\tif (cacheMaxFileCount < 0) {\n\t\t\tthrow new IllegalArgumentException(\"cacheMaxFileCount\" + ERROR_ARG_NEGATIVE);\n\t\t}\n\t\tif (fileNameGenerator == null) {\n\t\t\tthrow new IllegalArgumentException(\"fileNameGenerator\" + ERROR_ARG_NULL);\n\t\t}\n\n\t\tif (cacheMaxSize == 0) {\n\t\t\tcacheMaxSize = Long.MAX_VALUE;\n\t\t}\n\t\tif (cacheMaxFileCount == 0) {\n\t\t\tcacheMaxFileCount = Integer.MAX_VALUE;\n\t\t}\n\n\t\tthis.reserveCacheDir = reserveCacheDir;\n\t\tthis.fileNameGenerator = fileNameGenerator;\n\t\tinitCache(cacheDir, reserveCacheDir, cacheMaxSize, cacheMaxFileCount);\n\t}\n\n\tprivate void initCache(File cacheDir, File reserveCacheDir, long cacheMaxSize, int cacheMaxFileCount)\n\t\t\tthrows IOException {\n\t\ttry {\n\t\t\tcache = DiskLruCache.open(cacheDir, 1, 1, cacheMaxSize, cacheMaxFileCount);\n\t\t} catch (IOException e) {\n\t\t\tL.e(e);\n\t\t\tif (reserveCacheDir != null) {\n\t\t\t\tinitCache(reserveCacheDir, null, cacheMaxSize, cacheMaxFileCount);\n\t\t\t}\n\t\t\tif (cache == null) {\n\t\t\t\tthrow e; //new RuntimeException(\"Can't initialize disk cache\", e);\n\t\t\t}\n\t\t}\n\t}\n\n\t@Override\n\tpublic File getDirectory() {\n\t\treturn cache.getDirectory();\n\t}\n\n\t@Override\n\tpublic File get(String imageUri) {\n\t\tDiskLruCache.Snapshot snapshot = null;\n\t\ttry {\n\t\t\tsnapshot = cache.get(getKey(imageUri));\n\t\t\treturn snapshot == null ? null : snapshot.getFile(0);\n\t\t} catch (IOException e) {\n\t\t\tL.e(e);\n\t\t\treturn null;\n\t\t} finally {\n\t\t\tif (snapshot != null) {\n\t\t\t\tsnapshot.close();\n\t\t\t}\n\t\t}\n\t}\n\n\t@Override\n\tpublic boolean save(String imageUri, InputStream imageStream, IoUtils.CopyListener listener) throws IOException {\n\t\tDiskLruCache.Editor editor = cache.edit(getKey(imageUri));\n\t\tif (editor == null) {\n\t\t\treturn false;\n\t\t}\n\n\t\tOutputStream os = new BufferedOutputStream(editor.newOutputStream(0), bufferSize);\n\t\tboolean copied = false;\n\t\ttry {\n\t\t\tcopied = IoUtils.copyStream(imageStream, os, listener, bufferSize);\n\t\t} finally {\n\t\t\tIoUtils.closeSilently(os);\n\t\t\tif (copied) {\n\t\t\t\teditor.commit();\n\t\t\t} else {\n\t\t\t\teditor.abort();\n\t\t\t}\n\t\t}\n\t\treturn copied;\n\t}\n\n\t@Override\n\tpublic boolean save(String imageUri, Bitmap bitmap) throws IOException {\n\t\tDiskLruCache.Editor editor = cache.edit(getKey(imageUri));\n\t\tif (editor == null) {\n\t\t\treturn false;\n\t\t}\n\n\t\tOutputStream os = new BufferedOutputStream(editor.newOutputStream(0), bufferSize);\n\t\tboolean savedSuccessfully = false;\n\t\ttry {\n\t\t\tsavedSuccessfully = bitmap.compress(compressFormat, compressQuality, os);\n\t\t} finally {\n\t\t\tIoUtils.closeSilently(os);\n\t\t}\n\t\tif (savedSuccessfully) {\n\t\t\teditor.commit();\n\t\t} else {\n\t\t\teditor.abort();\n\t\t}\n\t\treturn savedSuccessfully;\n\t}\n\n\t@Override\n\tpublic boolean remove(String imageUri) {\n\t\ttry {\n\t\t\treturn cache.remove(getKey(imageUri));\n\t\t} catch (IOException e) {\n\t\t\tL.e(e);\n\t\t\treturn false;\n\t\t}\n\t}\n\n\t@Override\n\tpublic void close() {\n\t\ttry {\n\t\t\tcache.close();\n\t\t} catch (IOException e) {\n\t\t\tL.e(e);\n\t\t}\n\t\tcache = null;\n\t}\n\n\t@Override\n\tpublic void clear() {\n\t\ttry {\n\t\t\tcache.delete();\n\t\t} catch (IOException e) {\n\t\t\tL.e(e);\n\t\t}\n\t\ttry {\n\t\t\tinitCache(cache.getDirectory(), reserveCacheDir, cache.getMaxSize(), cache.getMaxFileCount());\n\t\t} catch (IOException e) {\n\t\t\tL.e(e);\n\t\t}\n\t}\n\n\tprivate String getKey(String imageUri) {\n\t\treturn fileNameGenerator.generate(imageUri);\n\t}\n\n\tpublic void setBufferSize(int bufferSize) {\n\t\tthis.bufferSize = bufferSize;\n\t}\n\n\tpublic void setCompressFormat(Bitmap.CompressFormat compressFormat) {\n\t\tthis.compressFormat = compressFormat;\n\t}\n\n\tpublic void setCompressQuality(int compressQuality) {\n\t\tthis.compressQuality = compressQuality;\n\t}\n}\n"
  },
  {
    "path": "library/src/main/java/com/nostra13/universalimageloader/cache/disc/impl/ext/StrictLineReader.java",
    "content": "/*\n * Copyright (C) 2012 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 com.nostra13.universalimageloader.cache.disc.impl.ext;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.Closeable;\nimport java.io.EOFException;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.UnsupportedEncodingException;\nimport java.nio.charset.Charset;\n\n/**\n * Buffers input from an {@link InputStream} for reading lines.\n *\n * <p>This class is used for buffered reading of lines. For purposes of this class, a line ends\n * with \"\\n\" or \"\\r\\n\". End of input is reported by throwing {@code EOFException}. Unterminated\n * line at end of input is invalid and will be ignored, the caller may use {@code\n * hasUnterminatedLine()} to detect it after catching the {@code EOFException}.\n *\n * <p>This class is intended for reading input that strictly consists of lines, such as line-based\n * cache entries or cache journal. Unlike the {@link java.io.BufferedReader} which in conjunction\n * with {@link java.io.InputStreamReader} provides similar functionality, this class uses different\n * end-of-input reporting and a more restrictive definition of a line.\n *\n * <p>This class supports only charsets that encode '\\r' and '\\n' as a single byte with value 13\n * and 10, respectively, and the representation of no other character contains these values.\n * We currently check in constructor that the charset is one of US-ASCII, UTF-8 and ISO-8859-1.\n * The default charset is US_ASCII.\n */\nclass StrictLineReader implements Closeable {\n\tprivate static final byte CR = (byte) '\\r';\n\tprivate static final byte LF = (byte) '\\n';\n\n\tprivate final InputStream in;\n\tprivate final Charset charset;\n\n\t/*\n\t   * Buffered data is stored in {@code buf}. As long as no exception occurs, 0 <= pos <= end\n\t   * and the data in the range [pos, end) is buffered for reading. At end of input, if there is\n\t   * an unterminated line, we set end == -1, otherwise end == pos. If the underlying\n\t   * {@code InputStream} throws an {@code IOException}, end may remain as either pos or -1.\n\t   */\n\tprivate byte[] buf;\n\tprivate int pos;\n\tprivate int end;\n\n\t/**\n\t * Constructs a new {@code LineReader} with the specified charset and the default capacity.\n\t *\n\t * @param in the {@code InputStream} to read data from.\n\t * @param charset the charset used to decode data. Only US-ASCII, UTF-8 and ISO-8859-1 are\n\t * supported.\n\t * @throws NullPointerException if {@code in} or {@code charset} is null.\n\t * @throws IllegalArgumentException if the specified charset is not supported.\n\t */\n\tpublic StrictLineReader(InputStream in, Charset charset) {\n\t\tthis(in, 8192, charset);\n\t}\n\n\t/**\n\t * Constructs a new {@code LineReader} with the specified capacity and charset.\n\t *\n\t * @param in the {@code InputStream} to read data from.\n\t * @param capacity the capacity of the buffer.\n\t * @param charset the charset used to decode data. Only US-ASCII, UTF-8 and ISO-8859-1 are\n\t * supported.\n\t * @throws NullPointerException if {@code in} or {@code charset} is null.\n\t * @throws IllegalArgumentException if {@code capacity} is negative or zero\n\t * or the specified charset is not supported.\n\t */\n\tpublic StrictLineReader(InputStream in, int capacity, Charset charset) {\n\t\tif (in == null || charset == null) {\n\t\t\tthrow new NullPointerException();\n\t\t}\n\t\tif (capacity < 0) {\n\t\t\tthrow new IllegalArgumentException(\"capacity <= 0\");\n\t\t}\n\t\tif (!(charset.equals(Util.US_ASCII))) {\n\t\t\tthrow new IllegalArgumentException(\"Unsupported encoding\");\n\t\t}\n\n\t\tthis.in = in;\n\t\tthis.charset = charset;\n\t\tbuf = new byte[capacity];\n\t}\n\n\t/**\n\t * Closes the reader by closing the underlying {@code InputStream} and\n\t * marking this reader as closed.\n\t *\n\t * @throws IOException for errors when closing the underlying {@code InputStream}.\n\t */\n\tpublic void close() throws IOException {\n\t\tsynchronized (in) {\n\t\t\tif (buf != null) {\n\t\t\t\tbuf = null;\n\t\t\t\tin.close();\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Reads the next line. A line ends with {@code \"\\n\"} or {@code \"\\r\\n\"},\n\t * this end of line marker is not included in the result.\n\t *\n\t * @return the next line from the input.\n\t * @throws IOException for underlying {@code InputStream} errors.\n\t * @throws EOFException for the end of source stream.\n\t */\n\tpublic String readLine() throws IOException {\n\t\tsynchronized (in) {\n\t\t\tif (buf == null) {\n\t\t\t\tthrow new IOException(\"LineReader is closed\");\n\t\t\t}\n\n\t\t\t// Read more data if we are at the end of the buffered data.\n\t\t\t// Though it's an error to read after an exception, we will let {@code fillBuf()}\n\t\t\t// throw again if that happens; thus we need to handle end == -1 as well as end == pos.\n\t\t\tif (pos >= end) {\n\t\t\t\tfillBuf();\n\t\t\t}\n\t\t\t// Try to find LF in the buffered data and return the line if successful.\n\t\t\tfor (int i = pos; i != end; ++i) {\n\t\t\t\tif (buf[i] == LF) {\n\t\t\t\t\tint lineEnd = (i != pos && buf[i - 1] == CR) ? i - 1 : i;\n\t\t\t\t\tString res = new String(buf, pos, lineEnd - pos, charset.name());\n\t\t\t\t\tpos = i + 1;\n\t\t\t\t\treturn res;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Let's anticipate up to 80 characters on top of those already read.\n\t\t\tByteArrayOutputStream out = new ByteArrayOutputStream(end - pos + 80) {\n\t\t\t\t@Override\n\t\t\t\tpublic String toString() {\n\t\t\t\t\tint length = (count > 0 && buf[count - 1] == CR) ? count - 1 : count;\n\t\t\t\t\ttry {\n\t\t\t\t\t\treturn new String(buf, 0, length, charset.name());\n\t\t\t\t\t} catch (UnsupportedEncodingException e) {\n\t\t\t\t\t\tthrow new AssertionError(e); // Since we control the charset this will never happen.\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t};\n\n\t\t\twhile (true) {\n\t\t\t\tout.write(buf, pos, end - pos);\n\t\t\t\t// Mark unterminated line in case fillBuf throws EOFException or IOException.\n\t\t\t\tend = -1;\n\t\t\t\tfillBuf();\n\t\t\t\t// Try to find LF in the buffered data and return the line if successful.\n\t\t\t\tfor (int i = pos; i != end; ++i) {\n\t\t\t\t\tif (buf[i] == LF) {\n\t\t\t\t\t\tif (i != pos) {\n\t\t\t\t\t\t\tout.write(buf, pos, i - pos);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tpos = i + 1;\n\t\t\t\t\t\treturn out.toString();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Reads new input data into the buffer. Call only with pos == end or end == -1,\n\t * depending on the desired outcome if the function throws.\n\t */\n\tprivate void fillBuf() throws IOException {\n\t\tint result = in.read(buf, 0, buf.length);\n\t\tif (result == -1) {\n\t\t\tthrow new EOFException();\n\t\t}\n\t\tpos = 0;\n\t\tend = result;\n\t}\n}\n\n"
  },
  {
    "path": "library/src/main/java/com/nostra13/universalimageloader/cache/disc/impl/ext/Util.java",
    "content": "/*\n * Copyright (C) 2010 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 com.nostra13.universalimageloader.cache.disc.impl.ext;\n\nimport java.io.Closeable;\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.Reader;\nimport java.io.StringWriter;\nimport java.nio.charset.Charset;\n\n/** Junk drawer of utility methods. */\nfinal class Util {\n\tstatic final Charset US_ASCII = Charset.forName(\"US-ASCII\");\n\tstatic final Charset UTF_8 = Charset.forName(\"UTF-8\");\n\n\tprivate Util() {\n\t}\n\n\tstatic String readFully(Reader reader) throws IOException {\n\t\ttry {\n\t\t\tStringWriter writer = new StringWriter();\n\t\t\tchar[] buffer = new char[1024];\n\t\t\tint count;\n\t\t\twhile ((count = reader.read(buffer)) != -1) {\n\t\t\t\twriter.write(buffer, 0, count);\n\t\t\t}\n\t\t\treturn writer.toString();\n\t\t} finally {\n\t\t\treader.close();\n\t\t}\n\t}\n\n\t/**\n\t * Deletes the contents of {@code dir}. Throws an IOException if any file\n\t * could not be deleted, or if {@code dir} is not a readable directory.\n\t */\n\tstatic void deleteContents(File dir) throws IOException {\n\t\tFile[] files = dir.listFiles();\n\t\tif (files == null) {\n\t\t\tthrow new IOException(\"not a readable directory: \" + dir);\n\t\t}\n\t\tfor (File file : files) {\n\t\t\tif (file.isDirectory()) {\n\t\t\t\tdeleteContents(file);\n\t\t\t}\n\t\t\tif (!file.delete()) {\n\t\t\t\tthrow new IOException(\"failed to delete file: \" + file);\n\t\t\t}\n\t\t}\n\t}\n\n\tstatic void closeQuietly(/*Auto*/Closeable closeable) {\n\t\tif (closeable != null) {\n\t\t\ttry {\n\t\t\t\tcloseable.close();\n\t\t\t} catch (RuntimeException rethrown) {\n\t\t\t\tthrow rethrown;\n\t\t\t} catch (Exception ignored) {\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "library/src/main/java/com/nostra13/universalimageloader/cache/disc/naming/FileNameGenerator.java",
    "content": "/*******************************************************************************\n * Copyright 2011-2013 Sergey Tarasevich\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *******************************************************************************/\npackage com.nostra13.universalimageloader.cache.disc.naming;\n\n/**\n * Generates names for files at disk cache\n *\n * @author Sergey Tarasevich (nostra13[at]gmail[dot]com)\n * @since 1.3.1\n */\npublic interface FileNameGenerator {\n\n\t/** Generates unique file name for image defined by URI */\n\tString generate(String imageUri);\n}\n"
  },
  {
    "path": "library/src/main/java/com/nostra13/universalimageloader/cache/disc/naming/HashCodeFileNameGenerator.java",
    "content": "/*******************************************************************************\n * Copyright 2011-2013 Sergey Tarasevich\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *******************************************************************************/\npackage com.nostra13.universalimageloader.cache.disc.naming;\n\n/**\n * Names image file as image URI {@linkplain String#hashCode() hashcode}\n *\n * @author Sergey Tarasevich (nostra13[at]gmail[dot]com)\n * @since 1.3.1\n */\npublic class HashCodeFileNameGenerator implements FileNameGenerator {\n\t@Override\n\tpublic String generate(String imageUri) {\n\t\treturn String.valueOf(imageUri.hashCode());\n\t}\n}\n"
  },
  {
    "path": "library/src/main/java/com/nostra13/universalimageloader/cache/disc/naming/Md5FileNameGenerator.java",
    "content": "/*******************************************************************************\n * Copyright 2011-2013 Sergey Tarasevich\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *******************************************************************************/\npackage com.nostra13.universalimageloader.cache.disc.naming;\n\nimport com.nostra13.universalimageloader.utils.L;\n\nimport java.math.BigInteger;\nimport java.security.MessageDigest;\nimport java.security.NoSuchAlgorithmException;\n\n/**\n * Names image file as MD5 hash of image URI\n *\n * @author Sergey Tarasevich (nostra13[at]gmail[dot]com)\n * @since 1.4.0\n */\npublic class Md5FileNameGenerator implements FileNameGenerator {\n\n\tprivate static final String HASH_ALGORITHM = \"MD5\";\n\tprivate static final int RADIX = 10 + 26; // 10 digits + 26 letters\n\n\t@Override\n\tpublic String generate(String imageUri) {\n\t\tbyte[] md5 = getMD5(imageUri.getBytes());\n\t\tBigInteger bi = new BigInteger(md5).abs();\n\t\treturn bi.toString(RADIX);\n\t}\n\n\tprivate byte[] getMD5(byte[] data) {\n\t\tbyte[] hash = null;\n\t\ttry {\n\t\t\tMessageDigest digest = MessageDigest.getInstance(HASH_ALGORITHM);\n\t\t\tdigest.update(data);\n\t\t\thash = digest.digest();\n\t\t} catch (NoSuchAlgorithmException e) {\n\t\t\tL.e(e);\n\t\t}\n\t\treturn hash;\n\t}\n}\n"
  },
  {
    "path": "library/src/main/java/com/nostra13/universalimageloader/cache/memory/BaseMemoryCache.java",
    "content": "/*******************************************************************************\n * Copyright 2011-2014 Sergey Tarasevich\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *******************************************************************************/\npackage com.nostra13.universalimageloader.cache.memory;\n\nimport android.graphics.Bitmap;\n\nimport java.lang.ref.Reference;\nimport java.util.*;\n\n/**\n * Base memory cache. Implements common functionality for memory cache. Provides object references (\n * {@linkplain Reference not strong}) storing.\n *\n * @author Sergey Tarasevich (nostra13[at]gmail[dot]com)\n * @since 1.0.0\n */\npublic abstract class BaseMemoryCache implements MemoryCache {\n\n\t/** Stores not strong references to objects */\n\tprivate final Map<String, Reference<Bitmap>> softMap = Collections.synchronizedMap(new HashMap<String, Reference<Bitmap>>());\n\n\t@Override\n\tpublic Bitmap get(String key) {\n\t\tBitmap result = null;\n\t\tReference<Bitmap> reference = softMap.get(key);\n\t\tif (reference != null) {\n\t\t\tresult = reference.get();\n\t\t}\n\t\treturn result;\n\t}\n\n\t@Override\n\tpublic boolean put(String key, Bitmap value) {\n\t\tsoftMap.put(key, createReference(value));\n\t\treturn true;\n\t}\n\n\t@Override\n\tpublic Bitmap remove(String key) {\n\t\tReference<Bitmap> bmpRef = softMap.remove(key);\n\t\treturn bmpRef == null ? null : bmpRef.get();\n\t}\n\n\t@Override\n\tpublic Collection<String> keys() {\n\t\tsynchronized (softMap) {\n\t\t\treturn new HashSet<String>(softMap.keySet());\n\t\t}\n\t}\n\n\t@Override\n\tpublic void clear() {\n\t\tsoftMap.clear();\n\t}\n\n\t/** Creates {@linkplain Reference not strong} reference of value */\n\tprotected abstract Reference<Bitmap> createReference(Bitmap value);\n}\n"
  },
  {
    "path": "library/src/main/java/com/nostra13/universalimageloader/cache/memory/LimitedMemoryCache.java",
    "content": "/*******************************************************************************\n * Copyright 2011-2014 Sergey Tarasevich\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *******************************************************************************/\npackage com.nostra13.universalimageloader.cache.memory;\n\nimport android.graphics.Bitmap;\n\nimport com.nostra13.universalimageloader.utils.L;\n\nimport java.util.Collections;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.concurrent.atomic.AtomicInteger;\n\n/**\n * Limited cache. Provides object storing. Size of all stored bitmaps will not to exceed size limit (\n * {@link #getSizeLimit()}).<br />\n * <br />\n * <b>NOTE:</b> This cache uses strong and weak references for stored Bitmaps. Strong references - for limited count of\n * Bitmaps (depends on cache size), weak references - for all other cached Bitmaps.\n *\n * @author Sergey Tarasevich (nostra13[at]gmail[dot]com)\n * @see BaseMemoryCache\n * @since 1.0.0\n */\npublic abstract class LimitedMemoryCache extends BaseMemoryCache {\n\n\tprivate static final int MAX_NORMAL_CACHE_SIZE_IN_MB = 16;\n\tprivate static final int MAX_NORMAL_CACHE_SIZE = MAX_NORMAL_CACHE_SIZE_IN_MB * 1024 * 1024;\n\n\tprivate final int sizeLimit;\n\n\tprivate final AtomicInteger cacheSize;\n\n\t/**\n\t * Contains strong references to stored objects. Each next object is added last. If hard cache size will exceed\n\t * limit then first object is deleted (but it continue exist at {@link #softMap} and can be collected by GC at any\n\t * time)\n\t */\n\tprivate final List<Bitmap> hardCache = Collections.synchronizedList(new LinkedList<Bitmap>());\n\n\t/** @param sizeLimit Maximum size for cache (in bytes) */\n\tpublic LimitedMemoryCache(int sizeLimit) {\n\t\tthis.sizeLimit = sizeLimit;\n\t\tcacheSize = new AtomicInteger();\n\t\tif (sizeLimit > MAX_NORMAL_CACHE_SIZE) {\n\t\t\tL.w(\"You set too large memory cache size (more than %1$d Mb)\", MAX_NORMAL_CACHE_SIZE_IN_MB);\n\t\t}\n\t}\n\n\t@Override\n\tpublic boolean put(String key, Bitmap value) {\n\t\tboolean putSuccessfully = false;\n\t\t// Try to add value to hard cache\n\t\tint valueSize = getSize(value);\n\t\tint sizeLimit = getSizeLimit();\n\t\tint curCacheSize = cacheSize.get();\n\t\tif (valueSize < sizeLimit) {\n\t\t\twhile (curCacheSize + valueSize > sizeLimit) {\n\t\t\t\tBitmap removedValue = removeNext();\n\t\t\t\tif (hardCache.remove(removedValue)) {\n\t\t\t\t\tcurCacheSize = cacheSize.addAndGet(-getSize(removedValue));\n\t\t\t\t}\n\t\t\t}\n\t\t\thardCache.add(value);\n\t\t\tcacheSize.addAndGet(valueSize);\n\n\t\t\tputSuccessfully = true;\n\t\t}\n\t\t// Add value to soft cache\n\t\tsuper.put(key, value);\n\t\treturn putSuccessfully;\n\t}\n\n\t@Override\n\tpublic Bitmap remove(String key) {\n\t\tBitmap value = super.get(key);\n\t\tif (value != null) {\n\t\t\tif (hardCache.remove(value)) {\n\t\t\t\tcacheSize.addAndGet(-getSize(value));\n\t\t\t}\n\t\t}\n\t\treturn super.remove(key);\n\t}\n\n\t@Override\n\tpublic void clear() {\n\t\thardCache.clear();\n\t\tcacheSize.set(0);\n\t\tsuper.clear();\n\t}\n\n\tprotected int getSizeLimit() {\n\t\treturn sizeLimit;\n\t}\n\n\tprotected abstract int getSize(Bitmap value);\n\n\tprotected abstract Bitmap removeNext();\n}\n"
  },
  {
    "path": "library/src/main/java/com/nostra13/universalimageloader/cache/memory/MemoryCache.java",
    "content": "/*******************************************************************************\n * Copyright 2014 Sergey Tarasevich\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *******************************************************************************/\npackage com.nostra13.universalimageloader.cache.memory;\n\nimport android.graphics.Bitmap;\n\nimport java.util.Collection;\n\n/**\n * Interface for memory cache\n *\n * @author Sergey Tarasevich (nostra13[at]gmail[dot]com)\n * @since 1.9.2\n */\npublic interface MemoryCache {\n\t/**\n\t * Puts value into cache by key\n\t *\n\t * @return <b>true</b> - if value was put into cache successfully, <b>false</b> - if value was <b>not</b> put into\n\t * cache\n\t */\n\tboolean put(String key, Bitmap value);\n\n\t/** Returns value by key. If there is no value for key then null will be returned. */\n\tBitmap get(String key);\n\n\t/** Removes item by key */\n\tBitmap remove(String key);\n\n\t/** Returns all keys of cache */\n\tCollection<String> keys();\n\n\t/** Remove all items from cache */\n\tvoid clear();\n}\n"
  },
  {
    "path": "library/src/main/java/com/nostra13/universalimageloader/cache/memory/impl/FIFOLimitedMemoryCache.java",
    "content": "/*******************************************************************************\n * Copyright 2011-2014 Sergey Tarasevich\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *******************************************************************************/\npackage com.nostra13.universalimageloader.cache.memory.impl;\n\nimport android.graphics.Bitmap;\nimport com.nostra13.universalimageloader.cache.memory.LimitedMemoryCache;\n\nimport java.lang.ref.Reference;\nimport java.lang.ref.WeakReference;\nimport java.util.Collections;\nimport java.util.LinkedList;\nimport java.util.List;\n\n/**\n * Limited {@link Bitmap bitmap} cache. Provides {@link Bitmap bitmaps} storing. Size of all stored bitmaps will not to\n * exceed size limit. When cache reaches limit size then cache clearing is processed by FIFO principle.<br />\n * <br />\n * <b>NOTE:</b> This cache uses strong and weak references for stored Bitmaps. Strong references - for limited count of\n * Bitmaps (depends on cache size), weak references - for all other cached Bitmaps.\n *\n * @author Sergey Tarasevich (nostra13[at]gmail[dot]com)\n * @since 1.0.0\n */\npublic class FIFOLimitedMemoryCache extends LimitedMemoryCache {\n\n\tprivate final List<Bitmap> queue = Collections.synchronizedList(new LinkedList<Bitmap>());\n\n\tpublic FIFOLimitedMemoryCache(int sizeLimit) {\n\t\tsuper(sizeLimit);\n\t}\n\n\t@Override\n\tpublic boolean put(String key, Bitmap value) {\n\t\tif (super.put(key, value)) {\n\t\t\tqueue.add(value);\n\t\t\treturn true;\n\t\t} else {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\t@Override\n\tpublic Bitmap remove(String key) {\n\t\tBitmap value = super.get(key);\n\t\tif (value != null) {\n\t\t\tqueue.remove(value);\n\t\t}\n\t\treturn super.remove(key);\n\t}\n\n\t@Override\n\tpublic void clear() {\n\t\tqueue.clear();\n\t\tsuper.clear();\n\t}\n\n\t@Override\n\tprotected int getSize(Bitmap value) {\n\t\treturn value.getRowBytes() * value.getHeight();\n\t}\n\n\t@Override\n\tprotected Bitmap removeNext() {\n\t\treturn queue.remove(0);\n\t}\n\n\t@Override\n\tprotected Reference<Bitmap> createReference(Bitmap value) {\n\t\treturn new WeakReference<Bitmap>(value);\n\t}\n}\n"
  },
  {
    "path": "library/src/main/java/com/nostra13/universalimageloader/cache/memory/impl/FuzzyKeyMemoryCache.java",
    "content": "/*******************************************************************************\n * Copyright 2011-2014 Sergey Tarasevich\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *******************************************************************************/\npackage com.nostra13.universalimageloader.cache.memory.impl;\n\nimport android.graphics.Bitmap;\n\nimport com.nostra13.universalimageloader.cache.memory.MemoryCache;\n\nimport java.util.Collection;\nimport java.util.Comparator;\n\n/**\n * Decorator for {@link MemoryCache}. Provides special feature for cache: some different keys are considered as\n * equals (using {@link Comparator comparator}). And when you try to put some value into cache by key so entries with\n * \"equals\" keys will be removed from cache before.<br />\n * <b>NOTE:</b> Used for internal needs. Normally you don't need to use this class.\n *\n * @author Sergey Tarasevich (nostra13[at]gmail[dot]com)\n * @since 1.0.0\n */\npublic class FuzzyKeyMemoryCache implements MemoryCache {\n\n\tprivate final MemoryCache cache;\n\tprivate final Comparator<String> keyComparator;\n\n\tpublic FuzzyKeyMemoryCache(MemoryCache cache, Comparator<String> keyComparator) {\n\t\tthis.cache = cache;\n\t\tthis.keyComparator = keyComparator;\n\t}\n\n\t@Override\n\tpublic boolean put(String key, Bitmap value) {\n\t\t// Search equal key and remove this entry\n\t\tsynchronized (cache) {\n\t\t\tString keyToRemove = null;\n\t\t\tfor (String cacheKey : cache.keys()) {\n\t\t\t\tif (keyComparator.compare(key, cacheKey) == 0) {\n\t\t\t\t\tkeyToRemove = cacheKey;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (keyToRemove != null) {\n\t\t\t\tcache.remove(keyToRemove);\n\t\t\t}\n\t\t}\n\t\treturn cache.put(key, value);\n\t}\n\n\t@Override\n\tpublic Bitmap get(String key) {\n\t\treturn cache.get(key);\n\t}\n\n\t@Override\n\tpublic Bitmap remove(String key) {\n\t\treturn cache.remove(key);\n\t}\n\n\t@Override\n\tpublic void clear() {\n\t\tcache.clear();\n\t}\n\n\t@Override\n\tpublic Collection<String> keys() {\n\t\treturn cache.keys();\n\t}\n}\n"
  },
  {
    "path": "library/src/main/java/com/nostra13/universalimageloader/cache/memory/impl/LRULimitedMemoryCache.java",
    "content": "/*******************************************************************************\n * Copyright 2011-2014 Sergey Tarasevich\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *******************************************************************************/\npackage com.nostra13.universalimageloader.cache.memory.impl;\n\nimport android.graphics.Bitmap;\nimport com.nostra13.universalimageloader.cache.memory.LimitedMemoryCache;\n\nimport java.lang.ref.Reference;\nimport java.lang.ref.WeakReference;\nimport java.util.Collections;\nimport java.util.Iterator;\nimport java.util.LinkedHashMap;\nimport java.util.Map;\nimport java.util.Map.Entry;\n\n/**\n * Limited {@link Bitmap bitmap} cache. Provides {@link Bitmap bitmaps} storing. Size of all stored bitmaps will not to\n * exceed size limit. When cache reaches limit size then the least recently used bitmap is deleted from cache.<br />\n * <br />\n * <b>NOTE:</b> This cache uses strong and weak references for stored Bitmaps. Strong references - for limited count of\n * Bitmaps (depends on cache size), weak references - for all other cached Bitmaps.\n *\n * @author Sergey Tarasevich (nostra13[at]gmail[dot]com)\n * @since 1.3.0\n */\npublic class LRULimitedMemoryCache extends LimitedMemoryCache {\n\n\tprivate static final int INITIAL_CAPACITY = 10;\n\tprivate static final float LOAD_FACTOR = 1.1f;\n\n\t/** Cache providing Least-Recently-Used logic */\n\tprivate final Map<String, Bitmap> lruCache = Collections.synchronizedMap(new LinkedHashMap<String, Bitmap>(INITIAL_CAPACITY, LOAD_FACTOR, true));\n\n\t/** @param maxSize Maximum sum of the sizes of the Bitmaps in this cache */\n\tpublic LRULimitedMemoryCache(int maxSize) {\n\t\tsuper(maxSize);\n\t}\n\n\t@Override\n\tpublic boolean put(String key, Bitmap value) {\n\t\tif (super.put(key, value)) {\n\t\t\tlruCache.put(key, value);\n\t\t\treturn true;\n\t\t} else {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\t@Override\n\tpublic Bitmap get(String key) {\n\t\tlruCache.get(key); // call \"get\" for LRU logic\n\t\treturn super.get(key);\n\t}\n\n\t@Override\n\tpublic Bitmap remove(String key) {\n\t\tlruCache.remove(key);\n\t\treturn super.remove(key);\n\t}\n\n\t@Override\n\tpublic void clear() {\n\t\tlruCache.clear();\n\t\tsuper.clear();\n\t}\n\n\t@Override\n\tprotected int getSize(Bitmap value) {\n\t\treturn value.getRowBytes() * value.getHeight();\n\t}\n\n\t@Override\n\tprotected Bitmap removeNext() {\n\t\tBitmap mostLongUsedValue = null;\n\t\tsynchronized (lruCache) {\n\t\t\tIterator<Entry<String, Bitmap>> it = lruCache.entrySet().iterator();\n\t\t\tif (it.hasNext()) {\n\t\t\t\tEntry<String, Bitmap> entry = it.next();\n\t\t\t\tmostLongUsedValue = entry.getValue();\n\t\t\t\tit.remove();\n\t\t\t}\n\t\t}\n\t\treturn mostLongUsedValue;\n\t}\n\n\t@Override\n\tprotected Reference<Bitmap> createReference(Bitmap value) {\n\t\treturn new WeakReference<Bitmap>(value);\n\t}\n}\n"
  },
  {
    "path": "library/src/main/java/com/nostra13/universalimageloader/cache/memory/impl/LargestLimitedMemoryCache.java",
    "content": "/*******************************************************************************\n * Copyright 2011-2014 Sergey Tarasevich\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *******************************************************************************/\npackage com.nostra13.universalimageloader.cache.memory.impl;\n\nimport android.graphics.Bitmap;\nimport com.nostra13.universalimageloader.cache.memory.LimitedMemoryCache;\n\nimport java.lang.ref.Reference;\nimport java.lang.ref.WeakReference;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.Map.Entry;\nimport java.util.Set;\n\n/**\n * Limited {@link Bitmap bitmap} cache. Provides {@link Bitmap bitmaps} storing. Size of all stored bitmaps will not to\n * exceed size limit. When cache reaches limit size then the bitmap which has the largest size is deleted from\n * cache.<br />\n * <br />\n * <b>NOTE:</b> This cache uses strong and weak references for stored Bitmaps. Strong references - for limited count of\n * Bitmaps (depends on cache size), weak references - for all other cached Bitmaps.\n *\n * @author Sergey Tarasevich (nostra13[at]gmail[dot]com)\n * @since 1.0.0\n */\npublic class LargestLimitedMemoryCache extends LimitedMemoryCache {\n\t/**\n\t * Contains strong references to stored objects (keys) and sizes of the objects. If hard cache\n\t * size will exceed limit then object with the largest size is deleted (but it continue exist at\n\t * {@link #softMap} and can be collected by GC at any time)\n\t */\n\tprivate final Map<Bitmap, Integer> valueSizes = Collections.synchronizedMap(new HashMap<Bitmap, Integer>());\n\n\tpublic LargestLimitedMemoryCache(int sizeLimit) {\n\t\tsuper(sizeLimit);\n\t}\n\n\t@Override\n\tpublic boolean put(String key, Bitmap value) {\n\t\tif (super.put(key, value)) {\n\t\t\tvalueSizes.put(value, getSize(value));\n\t\t\treturn true;\n\t\t} else {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\t@Override\n\tpublic Bitmap remove(String key) {\n\t\tBitmap value = super.get(key);\n\t\tif (value != null) {\n\t\t\tvalueSizes.remove(value);\n\t\t}\n\t\treturn super.remove(key);\n\t}\n\n\t@Override\n\tpublic void clear() {\n\t\tvalueSizes.clear();\n\t\tsuper.clear();\n\t}\n\n\t@Override\n\tprotected int getSize(Bitmap value) {\n\t\treturn value.getRowBytes() * value.getHeight();\n\t}\n\n\t@Override\n\tprotected Bitmap removeNext() {\n\t\tInteger maxSize = null;\n\t\tBitmap largestValue = null;\n\t\tSet<Entry<Bitmap, Integer>> entries = valueSizes.entrySet();\n\t\tsynchronized (valueSizes) {\n\t\t\tfor (Entry<Bitmap, Integer> entry : entries) {\n\t\t\t\tif (largestValue == null) {\n\t\t\t\t\tlargestValue = entry.getKey();\n\t\t\t\t\tmaxSize = entry.getValue();\n\t\t\t\t} else {\n\t\t\t\t\tInteger size = entry.getValue();\n\t\t\t\t\tif (size > maxSize) {\n\t\t\t\t\t\tmaxSize = size;\n\t\t\t\t\t\tlargestValue = entry.getKey();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tvalueSizes.remove(largestValue);\n\t\treturn largestValue;\n\t}\n\n\t@Override\n\tprotected Reference<Bitmap> createReference(Bitmap value) {\n\t\treturn new WeakReference<Bitmap>(value);\n\t}\n}\n"
  },
  {
    "path": "library/src/main/java/com/nostra13/universalimageloader/cache/memory/impl/LimitedAgeMemoryCache.java",
    "content": "/*******************************************************************************\n * Copyright 2011-2014 Sergey Tarasevich\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *******************************************************************************/\npackage com.nostra13.universalimageloader.cache.memory.impl;\n\nimport android.graphics.Bitmap;\n\nimport com.nostra13.universalimageloader.cache.memory.MemoryCache;\n\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.Map;\n\n/**\n * Decorator for {@link MemoryCache}. Provides special feature for cache: if some cached object age exceeds defined\n * value then this object will be removed from cache.\n *\n * @author Sergey Tarasevich (nostra13[at]gmail[dot]com)\n * @see MemoryCache\n * @since 1.3.1\n */\npublic class LimitedAgeMemoryCache implements MemoryCache {\n\n\tprivate final MemoryCache cache;\n\n\tprivate final long maxAge;\n\tprivate final Map<String, Long> loadingDates = Collections.synchronizedMap(new HashMap<String, Long>());\n\n\t/**\n\t * @param cache  Wrapped memory cache\n\t * @param maxAge Max object age <b>(in seconds)</b>. If object age will exceed this value then it'll be removed from\n\t *               cache on next treatment (and therefore be reloaded).\n\t */\n\tpublic LimitedAgeMemoryCache(MemoryCache cache, long maxAge) {\n\t\tthis.cache = cache;\n\t\tthis.maxAge = maxAge * 1000; // to milliseconds\n\t}\n\n\t@Override\n\tpublic boolean put(String key, Bitmap value) {\n\t\tboolean putSuccesfully = cache.put(key, value);\n\t\tif (putSuccesfully) {\n\t\t\tloadingDates.put(key, System.currentTimeMillis());\n\t\t}\n\t\treturn putSuccesfully;\n\t}\n\n\t@Override\n\tpublic Bitmap get(String key) {\n\t\tLong loadingDate = loadingDates.get(key);\n\t\tif (loadingDate != null && System.currentTimeMillis() - loadingDate > maxAge) {\n\t\t\tcache.remove(key);\n\t\t\tloadingDates.remove(key);\n\t\t}\n\n\t\treturn cache.get(key);\n\t}\n\n\t@Override\n\tpublic Bitmap remove(String key) {\n\t\tloadingDates.remove(key);\n\t\treturn cache.remove(key);\n\t}\n\n\t@Override\n\tpublic Collection<String> keys() {\n\t\treturn cache.keys();\n\t}\n\n\t@Override\n\tpublic void clear() {\n\t\tcache.clear();\n\t\tloadingDates.clear();\n\t}\n}\n"
  },
  {
    "path": "library/src/main/java/com/nostra13/universalimageloader/cache/memory/impl/LruMemoryCache.java",
    "content": "package com.nostra13.universalimageloader.cache.memory.impl;\n\nimport android.graphics.Bitmap;\n\nimport com.nostra13.universalimageloader.cache.memory.MemoryCache;\n\nimport java.util.Collection;\nimport java.util.HashSet;\nimport java.util.LinkedHashMap;\nimport java.util.Map;\n\n/**\n * A cache that holds strong references to a limited number of Bitmaps. Each time a Bitmap is accessed, it is moved to\n * the head of a queue. When a Bitmap is added to a full cache, the Bitmap at the end of that queue is evicted and may\n * become eligible for garbage collection.<br />\n * <br />\n * <b>NOTE:</b> This cache uses only strong references for stored Bitmaps.\n *\n * @author Sergey Tarasevich (nostra13[at]gmail[dot]com)\n * @since 1.8.1\n */\npublic class LruMemoryCache implements MemoryCache {\n\n\tprivate final LinkedHashMap<String, Bitmap> map;\n\n\tprivate final int maxSize;\n\t/** Size of this cache in bytes */\n\tprivate int size;\n\n\t/** @param maxSize Maximum sum of the sizes of the Bitmaps in this cache */\n\tpublic LruMemoryCache(int maxSize) {\n\t\tif (maxSize <= 0) {\n\t\t\tthrow new IllegalArgumentException(\"maxSize <= 0\");\n\t\t}\n\t\tthis.maxSize = maxSize;\n\t\tthis.map = new LinkedHashMap<String, Bitmap>(0, 0.75f, true);\n\t}\n\n\t/**\n\t * Returns the Bitmap for {@code key} if it exists in the cache. If a Bitmap was returned, it is moved to the head\n\t * of the queue. This returns null if a Bitmap is not cached.\n\t */\n\t@Override\n\tpublic final Bitmap get(String key) {\n\t\tif (key == null) {\n\t\t\tthrow new NullPointerException(\"key == null\");\n\t\t}\n\n\t\tsynchronized (this) {\n\t\t\treturn map.get(key);\n\t\t}\n\t}\n\n\t/** Caches {@code Bitmap} for {@code key}. The Bitmap is moved to the head of the queue. */\n\t@Override\n\tpublic final boolean put(String key, Bitmap value) {\n\t\tif (key == null || value == null) {\n\t\t\tthrow new NullPointerException(\"key == null || value == null\");\n\t\t}\n\n\t\tsynchronized (this) {\n\t\t\tsize += sizeOf(key, value);\n\t\t\tBitmap previous = map.put(key, value);\n\t\t\tif (previous != null) {\n\t\t\t\tsize -= sizeOf(key, previous);\n\t\t\t}\n\t\t}\n\n\t\ttrimToSize(maxSize);\n\t\treturn true;\n\t}\n\n\t/**\n\t * Remove the eldest entries until the total of remaining entries is at or below the requested size.\n\t *\n\t * @param maxSize the maximum size of the cache before returning. May be -1 to evict even 0-sized elements.\n\t */\n\tprivate void trimToSize(int maxSize) {\n\t\twhile (true) {\n\t\t\tString key;\n\t\t\tBitmap value;\n\t\t\tsynchronized (this) {\n\t\t\t\tif (size < 0 || (map.isEmpty() && size != 0)) {\n\t\t\t\t\tthrow new IllegalStateException(getClass().getName() + \".sizeOf() is reporting inconsistent results!\");\n\t\t\t\t}\n\n\t\t\t\tif (size <= maxSize || map.isEmpty()) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tMap.Entry<String, Bitmap> toEvict = map.entrySet().iterator().next();\n\t\t\t\tif (toEvict == null) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tkey = toEvict.getKey();\n\t\t\t\tvalue = toEvict.getValue();\n\t\t\t\tmap.remove(key);\n\t\t\t\tsize -= sizeOf(key, value);\n\t\t\t}\n\t\t}\n\t}\n\n\t/** Removes the entry for {@code key} if it exists. */\n\t@Override\n\tpublic final Bitmap remove(String key) {\n\t\tif (key == null) {\n\t\t\tthrow new NullPointerException(\"key == null\");\n\t\t}\n\n\t\tsynchronized (this) {\n\t\t\tBitmap previous = map.remove(key);\n\t\t\tif (previous != null) {\n\t\t\t\tsize -= sizeOf(key, previous);\n\t\t\t}\n\t\t\treturn previous;\n\t\t}\n\t}\n\n\t@Override\n\tpublic Collection<String> keys() {\n\t\tsynchronized (this) {\n\t\t\treturn new HashSet<String>(map.keySet());\n\t\t}\n\t}\n\n\t@Override\n\tpublic void clear() {\n\t\ttrimToSize(-1); // -1 will evict 0-sized elements\n\t}\n\n\t/**\n\t * Returns the size {@code Bitmap} in bytes.\n\t * <p/>\n\t * An entry's size must not change while it is in the cache.\n\t */\n\tprivate int sizeOf(String key, Bitmap value) {\n\t\treturn value.getRowBytes() * value.getHeight();\n\t}\n\n\t@Override\n\tpublic synchronized final String toString() {\n\t\treturn String.format(\"LruCache[maxSize=%d]\", maxSize);\n\t}\n}"
  },
  {
    "path": "library/src/main/java/com/nostra13/universalimageloader/cache/memory/impl/UsingFreqLimitedMemoryCache.java",
    "content": "/*******************************************************************************\n * Copyright 2011-2014 Sergey Tarasevich\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *******************************************************************************/\npackage com.nostra13.universalimageloader.cache.memory.impl;\n\nimport android.graphics.Bitmap;\nimport com.nostra13.universalimageloader.cache.memory.LimitedMemoryCache;\n\nimport java.lang.ref.Reference;\nimport java.lang.ref.WeakReference;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.Map.Entry;\nimport java.util.Set;\n\n/**\n * Limited {@link Bitmap bitmap} cache. Provides {@link Bitmap bitmaps} storing. Size of all stored bitmaps will not to\n * exceed size limit. When cache reaches limit size then the bitmap which used the least frequently is deleted from\n * cache.<br />\n * <br />\n * <b>NOTE:</b> This cache uses strong and weak references for stored Bitmaps. Strong references - for limited count of\n * Bitmaps (depends on cache size), weak references - for all other cached Bitmaps.\n *\n * @author Sergey Tarasevich (nostra13[at]gmail[dot]com)\n * @since 1.0.0\n */\npublic class UsingFreqLimitedMemoryCache extends LimitedMemoryCache {\n\t/**\n\t * Contains strong references to stored objects (keys) and last object usage date (in milliseconds). If hard cache\n\t * size will exceed limit then object with the least frequently usage is deleted (but it continue exist at\n\t * {@link #softMap} and can be collected by GC at any time)\n\t */\n\tprivate final Map<Bitmap, Integer> usingCounts = Collections.synchronizedMap(new HashMap<Bitmap, Integer>());\n\n\tpublic UsingFreqLimitedMemoryCache(int sizeLimit) {\n\t\tsuper(sizeLimit);\n\t}\n\n\t@Override\n\tpublic boolean put(String key, Bitmap value) {\n\t\tif (super.put(key, value)) {\n\t\t\tusingCounts.put(value, 0);\n\t\t\treturn true;\n\t\t} else {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\t@Override\n\tpublic Bitmap get(String key) {\n\t\tBitmap value = super.get(key);\n\t\t// Increment usage count for value if value is contained in hardCahe\n\t\tif (value != null) {\n\t\t\tInteger usageCount = usingCounts.get(value);\n\t\t\tif (usageCount != null) {\n\t\t\t\tusingCounts.put(value, usageCount + 1);\n\t\t\t}\n\t\t}\n\t\treturn value;\n\t}\n\n\t@Override\n\tpublic Bitmap remove(String key) {\n\t\tBitmap value = super.get(key);\n\t\tif (value != null) {\n\t\t\tusingCounts.remove(value);\n\t\t}\n\t\treturn super.remove(key);\n\t}\n\n\t@Override\n\tpublic void clear() {\n\t\tusingCounts.clear();\n\t\tsuper.clear();\n\t}\n\n\t@Override\n\tprotected int getSize(Bitmap value) {\n\t\treturn value.getRowBytes() * value.getHeight();\n\t}\n\n\t@Override\n\tprotected Bitmap removeNext() {\n\t\tInteger minUsageCount = null;\n\t\tBitmap leastUsedValue = null;\n\t\tSet<Entry<Bitmap, Integer>> entries = usingCounts.entrySet();\n\t\tsynchronized (usingCounts) {\n\t\t\tfor (Entry<Bitmap, Integer> entry : entries) {\n\t\t\t\tif (leastUsedValue == null) {\n\t\t\t\t\tleastUsedValue = entry.getKey();\n\t\t\t\t\tminUsageCount = entry.getValue();\n\t\t\t\t} else {\n\t\t\t\t\tInteger lastValueUsage = entry.getValue();\n\t\t\t\t\tif (lastValueUsage < minUsageCount) {\n\t\t\t\t\t\tminUsageCount = lastValueUsage;\n\t\t\t\t\t\tleastUsedValue = entry.getKey();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tusingCounts.remove(leastUsedValue);\n\t\treturn leastUsedValue;\n\t}\n\n\t@Override\n\tprotected Reference<Bitmap> createReference(Bitmap value) {\n\t\treturn new WeakReference<Bitmap>(value);\n\t}\n}\n"
  },
  {
    "path": "library/src/main/java/com/nostra13/universalimageloader/cache/memory/impl/WeakMemoryCache.java",
    "content": "/*******************************************************************************\n * Copyright 2011-2014 Sergey Tarasevich\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *******************************************************************************/\npackage com.nostra13.universalimageloader.cache.memory.impl;\n\nimport android.graphics.Bitmap;\nimport com.nostra13.universalimageloader.cache.memory.BaseMemoryCache;\n\nimport java.lang.ref.Reference;\nimport java.lang.ref.WeakReference;\n\n/**\n * Memory cache with {@linkplain WeakReference weak references} to {@linkplain android.graphics.Bitmap bitmaps}<br />\n * <br />\n * <b>NOTE:</b> This cache uses only weak references for stored Bitmaps.\n *\n * @author Sergey Tarasevich (nostra13[at]gmail[dot]com)\n * @since 1.5.3\n */\npublic class WeakMemoryCache extends BaseMemoryCache {\n\t@Override\n\tprotected Reference<Bitmap> createReference(Bitmap value) {\n\t\treturn new WeakReference<Bitmap>(value);\n\t}\n}\n"
  },
  {
    "path": "library/src/main/java/com/nostra13/universalimageloader/core/DefaultConfigurationFactory.java",
    "content": "/*******************************************************************************\n * Copyright 2011-2014 Sergey Tarasevich\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *******************************************************************************/\npackage com.nostra13.universalimageloader.core;\n\nimport android.annotation.TargetApi;\nimport android.app.ActivityManager;\nimport android.content.Context;\nimport android.content.pm.ApplicationInfo;\nimport android.os.Build;\nimport com.nostra13.universalimageloader.cache.disc.DiskCache;\nimport com.nostra13.universalimageloader.cache.disc.impl.UnlimitedDiskCache;\nimport com.nostra13.universalimageloader.cache.disc.impl.ext.LruDiskCache;\nimport com.nostra13.universalimageloader.cache.disc.naming.FileNameGenerator;\nimport com.nostra13.universalimageloader.cache.disc.naming.HashCodeFileNameGenerator;\nimport com.nostra13.universalimageloader.cache.memory.MemoryCache;\nimport com.nostra13.universalimageloader.cache.memory.impl.LruMemoryCache;\nimport com.nostra13.universalimageloader.core.assist.QueueProcessingType;\nimport com.nostra13.universalimageloader.core.assist.deque.LIFOLinkedBlockingDeque;\nimport com.nostra13.universalimageloader.core.decode.BaseImageDecoder;\nimport com.nostra13.universalimageloader.core.decode.ImageDecoder;\nimport com.nostra13.universalimageloader.core.display.BitmapDisplayer;\nimport com.nostra13.universalimageloader.core.display.SimpleBitmapDisplayer;\nimport com.nostra13.universalimageloader.core.download.BaseImageDownloader;\nimport com.nostra13.universalimageloader.core.download.ImageDownloader;\nimport com.nostra13.universalimageloader.utils.L;\nimport com.nostra13.universalimageloader.utils.StorageUtils;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.util.concurrent.BlockingQueue;\nimport java.util.concurrent.Executor;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.LinkedBlockingQueue;\nimport java.util.concurrent.ThreadFactory;\nimport java.util.concurrent.ThreadPoolExecutor;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.atomic.AtomicInteger;\n\n/**\n * Factory for providing of default options for {@linkplain ImageLoaderConfiguration configuration}\n *\n * @author Sergey Tarasevich (nostra13[at]gmail[dot]com)\n * @since 1.5.6\n */\npublic class DefaultConfigurationFactory {\n\n\t/** Creates default implementation of task executor */\n\tpublic static Executor createExecutor(int threadPoolSize, int threadPriority,\n\t\t\tQueueProcessingType tasksProcessingType) {\n\t\tboolean lifo = tasksProcessingType == QueueProcessingType.LIFO;\n\t\tBlockingQueue<Runnable> taskQueue =\n\t\t\t\tlifo ? new LIFOLinkedBlockingDeque<Runnable>() : new LinkedBlockingQueue<Runnable>();\n\t\treturn new ThreadPoolExecutor(threadPoolSize, threadPoolSize, 0L, TimeUnit.MILLISECONDS, taskQueue,\n\t\t\t\tcreateThreadFactory(threadPriority, \"uil-pool-\"));\n\t}\n\n\t/** Creates default implementation of task distributor */\n\tpublic static Executor createTaskDistributor() {\n\t\treturn Executors.newCachedThreadPool(createThreadFactory(Thread.NORM_PRIORITY, \"uil-pool-d-\"));\n\t}\n\n\t/** Creates {@linkplain HashCodeFileNameGenerator default implementation} of FileNameGenerator */\n\tpublic static FileNameGenerator createFileNameGenerator() {\n\t\treturn new HashCodeFileNameGenerator();\n\t}\n\n\t/**\n\t * Creates default implementation of {@link DiskCache} depends on incoming parameters\n\t */\n\tpublic static DiskCache createDiskCache(Context context, FileNameGenerator diskCacheFileNameGenerator,\n\t\t\tlong diskCacheSize, int diskCacheFileCount) {\n\t\tFile reserveCacheDir = createReserveDiskCacheDir(context);\n\t\tif (diskCacheSize > 0 || diskCacheFileCount > 0) {\n\t\t\tFile individualCacheDir = StorageUtils.getIndividualCacheDirectory(context);\n\t\t\ttry {\n\t\t\t\treturn new LruDiskCache(individualCacheDir, reserveCacheDir, diskCacheFileNameGenerator, diskCacheSize,\n\t\t\t\t\t\tdiskCacheFileCount);\n\t\t\t} catch (IOException e) {\n\t\t\t\tL.e(e);\n\t\t\t\t// continue and create unlimited cache\n\t\t\t}\n\t\t}\n\t\tFile cacheDir = StorageUtils.getCacheDirectory(context);\n\t\treturn new UnlimitedDiskCache(cacheDir, reserveCacheDir, diskCacheFileNameGenerator);\n\t}\n\n\t/** Creates reserve disk cache folder which will be used if primary disk cache folder becomes unavailable */\n\tprivate static File createReserveDiskCacheDir(Context context) {\n\t\tFile cacheDir = StorageUtils.getCacheDirectory(context, false);\n\t\tFile individualDir = new File(cacheDir, \"uil-images\");\n\t\tif (individualDir.exists() || individualDir.mkdir()) {\n\t\t\tcacheDir = individualDir;\n\t\t}\n\t\treturn cacheDir;\n\t}\n\n\t/**\n\t * Creates default implementation of {@link MemoryCache} - {@link LruMemoryCache}<br />\n\t * Default cache size = 1/8 of available app memory.\n\t */\n\tpublic static MemoryCache createMemoryCache(Context context, int memoryCacheSize) {\n\t\tif (memoryCacheSize == 0) {\n\t\t\tActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);\n\t\t\tint memoryClass = am.getMemoryClass();\n\t\t\tif (hasHoneycomb() && isLargeHeap(context)) {\n\t\t\t\tmemoryClass = getLargeMemoryClass(am);\n\t\t\t}\n\t\t\tmemoryCacheSize = 1024 * 1024 * memoryClass / 8;\n\t\t}\n\t\treturn new LruMemoryCache(memoryCacheSize);\n\t}\n\n\tprivate static boolean hasHoneycomb() {\n\t\treturn Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB;\n\t}\n\n\t@TargetApi(Build.VERSION_CODES.HONEYCOMB)\n\tprivate static boolean isLargeHeap(Context context) {\n\t\treturn (context.getApplicationInfo().flags & ApplicationInfo.FLAG_LARGE_HEAP) != 0;\n\t}\n\n\t@TargetApi(Build.VERSION_CODES.HONEYCOMB)\n\tprivate static int getLargeMemoryClass(ActivityManager am) {\n\t\treturn am.getLargeMemoryClass();\n\t}\n\n\t/** Creates default implementation of {@link ImageDownloader} - {@link BaseImageDownloader} */\n\tpublic static ImageDownloader createImageDownloader(Context context) {\n\t\treturn new BaseImageDownloader(context);\n\t}\n\n\t/** Creates default implementation of {@link ImageDecoder} - {@link BaseImageDecoder} */\n\tpublic static ImageDecoder createImageDecoder(boolean loggingEnabled) {\n\t\treturn new BaseImageDecoder(loggingEnabled);\n\t}\n\n\t/** Creates default implementation of {@link BitmapDisplayer} - {@link SimpleBitmapDisplayer} */\n\tpublic static BitmapDisplayer createBitmapDisplayer() {\n\t\treturn new SimpleBitmapDisplayer();\n\t}\n\n\t/** Creates default implementation of {@linkplain ThreadFactory thread factory} for task executor */\n\tprivate static ThreadFactory createThreadFactory(int threadPriority, String threadNamePrefix) {\n\t\treturn new DefaultThreadFactory(threadPriority, threadNamePrefix);\n\t}\n\n\tprivate static class DefaultThreadFactory implements ThreadFactory {\n\n\t\tprivate static final AtomicInteger poolNumber = new AtomicInteger(1);\n\n\t\tprivate final ThreadGroup group;\n\t\tprivate final AtomicInteger threadNumber = new AtomicInteger(1);\n\t\tprivate final String namePrefix;\n\t\tprivate final int threadPriority;\n\n\t\tDefaultThreadFactory(int threadPriority, String threadNamePrefix) {\n\t\t\tthis.threadPriority = threadPriority;\n\t\t\tgroup = Thread.currentThread().getThreadGroup();\n\t\t\tnamePrefix = threadNamePrefix + poolNumber.getAndIncrement() + \"-thread-\";\n\t\t}\n\n\t\t@Override\n\t\tpublic Thread newThread(Runnable r) {\n\t\t\tThread t = new Thread(group, r, namePrefix + threadNumber.getAndIncrement(), 0);\n\t\t\tif (t.isDaemon()) t.setDaemon(false);\n\t\t\tt.setPriority(threadPriority);\n\t\t\treturn t;\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "library/src/main/java/com/nostra13/universalimageloader/core/DisplayBitmapTask.java",
    "content": "/*******************************************************************************\n * Copyright 2011-2014 Sergey Tarasevich\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *******************************************************************************/\npackage com.nostra13.universalimageloader.core;\n\nimport android.graphics.Bitmap;\nimport com.nostra13.universalimageloader.core.assist.LoadedFrom;\nimport com.nostra13.universalimageloader.core.display.BitmapDisplayer;\nimport com.nostra13.universalimageloader.core.imageaware.ImageAware;\nimport com.nostra13.universalimageloader.core.listener.ImageLoadingListener;\nimport com.nostra13.universalimageloader.utils.L;\n\n/**\n * Displays bitmap in {@link com.nostra13.universalimageloader.core.imageaware.ImageAware}. Must be called on UI thread.\n *\n * @author Sergey Tarasevich (nostra13[at]gmail[dot]com)\n * @see ImageLoadingListener\n * @see BitmapDisplayer\n * @since 1.3.1\n */\nfinal class DisplayBitmapTask implements Runnable {\n\n\tprivate static final String LOG_DISPLAY_IMAGE_IN_IMAGEAWARE = \"Display image in ImageAware (loaded from %1$s) [%2$s]\";\n\tprivate static final String LOG_TASK_CANCELLED_IMAGEAWARE_REUSED = \"ImageAware is reused for another image. Task is cancelled. [%s]\";\n\tprivate static final String LOG_TASK_CANCELLED_IMAGEAWARE_COLLECTED = \"ImageAware was collected by GC. Task is cancelled. [%s]\";\n\n\tprivate final Bitmap bitmap;\n\tprivate final String imageUri;\n\tprivate final ImageAware imageAware;\n\tprivate final String memoryCacheKey;\n\tprivate final BitmapDisplayer displayer;\n\tprivate final ImageLoadingListener listener;\n\tprivate final ImageLoaderEngine engine;\n\tprivate final LoadedFrom loadedFrom;\n\n\tpublic DisplayBitmapTask(Bitmap bitmap, ImageLoadingInfo imageLoadingInfo, ImageLoaderEngine engine,\n\t\t\tLoadedFrom loadedFrom) {\n\t\tthis.bitmap = bitmap;\n\t\timageUri = imageLoadingInfo.uri;\n\t\timageAware = imageLoadingInfo.imageAware;\n\t\tmemoryCacheKey = imageLoadingInfo.memoryCacheKey;\n\t\tdisplayer = imageLoadingInfo.options.getDisplayer();\n\t\tlistener = imageLoadingInfo.listener;\n\t\tthis.engine = engine;\n\t\tthis.loadedFrom = loadedFrom;\n\t}\n\n\t@Override\n\tpublic void run() {\n\t\tif (imageAware.isCollected()) {\n\t\t\tL.d(LOG_TASK_CANCELLED_IMAGEAWARE_COLLECTED, memoryCacheKey);\n\t\t\tlistener.onLoadingCancelled(imageUri, imageAware.getWrappedView());\n\t\t} else if (isViewWasReused()) {\n\t\t\tL.d(LOG_TASK_CANCELLED_IMAGEAWARE_REUSED, memoryCacheKey);\n\t\t\tlistener.onLoadingCancelled(imageUri, imageAware.getWrappedView());\n\t\t} else {\n\t\t\tL.d(LOG_DISPLAY_IMAGE_IN_IMAGEAWARE, loadedFrom, memoryCacheKey);\n\t\t\tdisplayer.display(bitmap, imageAware, loadedFrom);\n\t\t\tengine.cancelDisplayTaskFor(imageAware);\n\t\t\tlistener.onLoadingComplete(imageUri, imageAware.getWrappedView(), bitmap);\n\t\t}\n\t}\n\n\t/** Checks whether memory cache key (image URI) for current ImageAware is actual */\n\tprivate boolean isViewWasReused() {\n\t\tString currentCacheKey = engine.getLoadingUriForView(imageAware);\n\t\treturn !memoryCacheKey.equals(currentCacheKey);\n\t}\n}\n"
  },
  {
    "path": "library/src/main/java/com/nostra13/universalimageloader/core/DisplayImageOptions.java",
    "content": "/*******************************************************************************\n * Copyright 2011-2014 Sergey Tarasevich\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *******************************************************************************/\npackage com.nostra13.universalimageloader.core;\n\nimport android.content.res.Resources;\nimport android.graphics.Bitmap;\nimport android.graphics.BitmapFactory.Options;\nimport android.graphics.drawable.Drawable;\nimport android.os.Handler;\nimport com.nostra13.universalimageloader.core.listener.ImageLoadingListener;\nimport com.nostra13.universalimageloader.core.assist.ImageScaleType;\nimport com.nostra13.universalimageloader.core.display.BitmapDisplayer;\nimport com.nostra13.universalimageloader.core.display.SimpleBitmapDisplayer;\nimport com.nostra13.universalimageloader.core.download.ImageDownloader;\nimport com.nostra13.universalimageloader.core.process.BitmapProcessor;\n\n/**\n * Contains options for image display. Defines:\n * <ul>\n * <li>whether stub image will be displayed in {@link com.nostra13.universalimageloader.core.imageaware.ImageAware\n * image aware view} during image loading</li>\n * <li>whether stub image will be displayed in {@link com.nostra13.universalimageloader.core.imageaware.ImageAware\n * image aware view} if empty URI is passed</li>\n * <li>whether stub image will be displayed in {@link com.nostra13.universalimageloader.core.imageaware.ImageAware\n * image aware view} if image loading fails</li>\n * <li>whether {@link com.nostra13.universalimageloader.core.imageaware.ImageAware image aware view} should be reset\n * before image loading start</li>\n * <li>whether loaded image will be cached in memory</li>\n * <li>whether loaded image will be cached on disk</li>\n * <li>image scale type</li>\n * <li>decoding options (including bitmap decoding configuration)</li>\n * <li>delay before loading of image</li>\n * <li>whether consider EXIF parameters of image</li>\n * <li>auxiliary object which will be passed to {@link ImageDownloader#getStream(String, Object) ImageDownloader}</li>\n * <li>pre-processor for image Bitmap (before caching in memory)</li>\n * <li>post-processor for image Bitmap (after caching in memory, before displaying)</li>\n * <li>how decoded {@link Bitmap} will be displayed</li>\n * </ul>\n * <p/>\n * You can create instance:\n * <ul>\n * <li>with {@link Builder}:<br />\n * <b>i.e.</b> :\n * <code>new {@link DisplayImageOptions}.Builder().{@link Builder#cacheInMemory() cacheInMemory()}.\n * {@link Builder#showImageOnLoading(int) showImageOnLoading()}.{@link Builder#build() build()}</code><br />\n * </li>\n * <li>or by static method: {@link #createSimple()}</li> <br />\n *\n * @author Sergey Tarasevich (nostra13[at]gmail[dot]com)\n * @since 1.0.0\n */\npublic final class DisplayImageOptions {\n\n\tprivate final int imageResOnLoading;\n\tprivate final int imageResForEmptyUri;\n\tprivate final int imageResOnFail;\n\tprivate final Drawable imageOnLoading;\n\tprivate final Drawable imageForEmptyUri;\n\tprivate final Drawable imageOnFail;\n\tprivate final boolean resetViewBeforeLoading;\n\tprivate final boolean cacheInMemory;\n\tprivate final boolean cacheOnDisk;\n\tprivate final ImageScaleType imageScaleType;\n\tprivate final Options decodingOptions;\n\tprivate final int delayBeforeLoading;\n\tprivate final boolean considerExifParams;\n\tprivate final Object extraForDownloader;\n\tprivate final BitmapProcessor preProcessor;\n\tprivate final BitmapProcessor postProcessor;\n\tprivate final BitmapDisplayer displayer;\n\tprivate final Handler handler;\n\tprivate final boolean isSyncLoading;\n\n\tprivate DisplayImageOptions(Builder builder) {\n\t\timageResOnLoading = builder.imageResOnLoading;\n\t\timageResForEmptyUri = builder.imageResForEmptyUri;\n\t\timageResOnFail = builder.imageResOnFail;\n\t\timageOnLoading = builder.imageOnLoading;\n\t\timageForEmptyUri = builder.imageForEmptyUri;\n\t\timageOnFail = builder.imageOnFail;\n\t\tresetViewBeforeLoading = builder.resetViewBeforeLoading;\n\t\tcacheInMemory = builder.cacheInMemory;\n\t\tcacheOnDisk = builder.cacheOnDisk;\n\t\timageScaleType = builder.imageScaleType;\n\t\tdecodingOptions = builder.decodingOptions;\n\t\tdelayBeforeLoading = builder.delayBeforeLoading;\n\t\tconsiderExifParams = builder.considerExifParams;\n\t\textraForDownloader = builder.extraForDownloader;\n\t\tpreProcessor = builder.preProcessor;\n\t\tpostProcessor = builder.postProcessor;\n\t\tdisplayer = builder.displayer;\n\t\thandler = builder.handler;\n\t\tisSyncLoading = builder.isSyncLoading;\n\t}\n\n\tpublic boolean shouldShowImageOnLoading() {\n\t\treturn imageOnLoading != null || imageResOnLoading != 0;\n\t}\n\n\tpublic boolean shouldShowImageForEmptyUri() {\n\t\treturn imageForEmptyUri != null || imageResForEmptyUri != 0;\n\t}\n\n\tpublic boolean shouldShowImageOnFail() {\n\t\treturn imageOnFail != null || imageResOnFail != 0;\n\t}\n\n\tpublic boolean shouldPreProcess() {\n\t\treturn preProcessor != null;\n\t}\n\n\tpublic boolean shouldPostProcess() {\n\t\treturn postProcessor != null;\n\t}\n\n\tpublic boolean shouldDelayBeforeLoading() {\n\t\treturn delayBeforeLoading > 0;\n\t}\n\n\tpublic Drawable getImageOnLoading(Resources res) {\n\t\treturn imageResOnLoading != 0 ? res.getDrawable(imageResOnLoading) : imageOnLoading;\n\t}\n\n\tpublic Drawable getImageForEmptyUri(Resources res) {\n\t\treturn imageResForEmptyUri != 0 ? res.getDrawable(imageResForEmptyUri) : imageForEmptyUri;\n\t}\n\n\tpublic Drawable getImageOnFail(Resources res) {\n\t\treturn imageResOnFail != 0 ? res.getDrawable(imageResOnFail) : imageOnFail;\n\t}\n\n\tpublic boolean isResetViewBeforeLoading() {\n\t\treturn resetViewBeforeLoading;\n\t}\n\n\tpublic boolean isCacheInMemory() {\n\t\treturn cacheInMemory;\n\t}\n\n\tpublic boolean isCacheOnDisk() {\n\t\treturn cacheOnDisk;\n\t}\n\n\tpublic ImageScaleType getImageScaleType() {\n\t\treturn imageScaleType;\n\t}\n\n\tpublic Options getDecodingOptions() {\n\t\treturn decodingOptions;\n\t}\n\n\tpublic int getDelayBeforeLoading() {\n\t\treturn delayBeforeLoading;\n\t}\n\n\tpublic boolean isConsiderExifParams() {\n\t\treturn considerExifParams;\n\t}\n\n\tpublic Object getExtraForDownloader() {\n\t\treturn extraForDownloader;\n\t}\n\n\tpublic BitmapProcessor getPreProcessor() {\n\t\treturn preProcessor;\n\t}\n\n\tpublic BitmapProcessor getPostProcessor() {\n\t\treturn postProcessor;\n\t}\n\n\tpublic BitmapDisplayer getDisplayer() {\n\t\treturn displayer;\n\t}\n\n\tpublic Handler getHandler() {\n\t\treturn handler;\n\t}\n\n\tboolean isSyncLoading() {\n\t\treturn isSyncLoading;\n\t}\n\n\t/**\n\t * Builder for {@link DisplayImageOptions}\n\t *\n\t * @author Sergey Tarasevich (nostra13[at]gmail[dot]com)\n\t */\n\tpublic static class Builder {\n\t\tprivate int imageResOnLoading = 0;\n\t\tprivate int imageResForEmptyUri = 0;\n\t\tprivate int imageResOnFail = 0;\n\t\tprivate Drawable imageOnLoading = null;\n\t\tprivate Drawable imageForEmptyUri = null;\n\t\tprivate Drawable imageOnFail = null;\n\t\tprivate boolean resetViewBeforeLoading = false;\n\t\tprivate boolean cacheInMemory = false;\n\t\tprivate boolean cacheOnDisk = false;\n\t\tprivate ImageScaleType imageScaleType = ImageScaleType.IN_SAMPLE_POWER_OF_2;\n\t\tprivate Options decodingOptions = new Options();\n\t\tprivate int delayBeforeLoading = 0;\n\t\tprivate boolean considerExifParams = false;\n\t\tprivate Object extraForDownloader = null;\n\t\tprivate BitmapProcessor preProcessor = null;\n\t\tprivate BitmapProcessor postProcessor = null;\n\t\tprivate BitmapDisplayer displayer = DefaultConfigurationFactory.createBitmapDisplayer();\n\t\tprivate Handler handler = null;\n\t\tprivate boolean isSyncLoading = false;\n\n\t\t/**\n\t\t * Stub image will be displayed in {@link com.nostra13.universalimageloader.core.imageaware.ImageAware\n\t\t * image aware view} during image loading\n\t\t *\n\t\t * @param imageRes Stub image resource\n\t\t * @deprecated Use {@link #showImageOnLoading(int)} instead\n\t\t */\n\t\t@Deprecated\n\t\tpublic Builder showStubImage(int imageRes) {\n\t\t\timageResOnLoading = imageRes;\n\t\t\treturn this;\n\t\t}\n\n\t\t/**\n\t\t * Incoming image will be displayed in {@link com.nostra13.universalimageloader.core.imageaware.ImageAware\n\t\t * image aware view} during image loading\n\t\t *\n\t\t * @param imageRes Image resource\n\t\t */\n\t\tpublic Builder showImageOnLoading(int imageRes) {\n\t\t\timageResOnLoading = imageRes;\n\t\t\treturn this;\n\t\t}\n\n\t\t/**\n\t\t * Incoming drawable will be displayed in {@link com.nostra13.universalimageloader.core.imageaware.ImageAware\n\t\t * image aware view} during image loading.\n\t\t * This option will be ignored if {@link DisplayImageOptions.Builder#showImageOnLoading(int)} is set.\n\t\t */\n\t\tpublic Builder showImageOnLoading(Drawable drawable) {\n\t\t\timageOnLoading = drawable;\n\t\t\treturn this;\n\t\t}\n\n\t\t/**\n\t\t * Incoming image will be displayed in {@link com.nostra13.universalimageloader.core.imageaware.ImageAware\n\t\t * image aware view} if empty URI (null or empty\n\t\t * string) will be passed to <b>ImageLoader.displayImage(...)</b> method.\n\t\t *\n\t\t * @param imageRes Image resource\n\t\t */\n\t\tpublic Builder showImageForEmptyUri(int imageRes) {\n\t\t\timageResForEmptyUri = imageRes;\n\t\t\treturn this;\n\t\t}\n\n\t\t/**\n\t\t * Incoming drawable will be displayed in {@link com.nostra13.universalimageloader.core.imageaware.ImageAware\n\t\t * image aware view} if empty URI (null or empty\n\t\t * string) will be passed to <b>ImageLoader.displayImage(...)</b> method.\n\t\t * This option will be ignored if {@link DisplayImageOptions.Builder#showImageForEmptyUri(int)} is set.\n\t\t */\n\t\tpublic Builder showImageForEmptyUri(Drawable drawable) {\n\t\t\timageForEmptyUri = drawable;\n\t\t\treturn this;\n\t\t}\n\n\t\t/**\n\t\t * Incoming image will be displayed in {@link com.nostra13.universalimageloader.core.imageaware.ImageAware\n\t\t * image aware view} if some error occurs during\n\t\t * requested image loading/decoding.\n\t\t *\n\t\t * @param imageRes Image resource\n\t\t */\n\t\tpublic Builder showImageOnFail(int imageRes) {\n\t\t\timageResOnFail = imageRes;\n\t\t\treturn this;\n\t\t}\n\n\t\t/**\n\t\t * Incoming drawable will be displayed in {@link com.nostra13.universalimageloader.core.imageaware.ImageAware\n\t\t * image aware view} if some error occurs during\n\t\t * requested image loading/decoding.\n\t\t * This option will be ignored if {@link DisplayImageOptions.Builder#showImageOnFail(int)} is set.\n\t\t */\n\t\tpublic Builder showImageOnFail(Drawable drawable) {\n\t\t\timageOnFail = drawable;\n\t\t\treturn this;\n\t\t}\n\n\t\t/**\n\t\t * {@link com.nostra13.universalimageloader.core.imageaware.ImageAware\n\t\t * image aware view} will be reset (set <b>null</b>) before image loading start\n\t\t *\n\t\t * @deprecated Use {@link #resetViewBeforeLoading(boolean) resetViewBeforeLoading(true)} instead\n\t\t */\n\t\tpublic Builder resetViewBeforeLoading() {\n\t\t\tresetViewBeforeLoading = true;\n\t\t\treturn this;\n\t\t}\n\n\t\t/**\n\t\t * Sets whether {@link com.nostra13.universalimageloader.core.imageaware.ImageAware\n\t\t * image aware view} will be reset (set <b>null</b>) before image loading start\n\t\t */\n\t\tpublic Builder resetViewBeforeLoading(boolean resetViewBeforeLoading) {\n\t\t\tthis.resetViewBeforeLoading = resetViewBeforeLoading;\n\t\t\treturn this;\n\t\t}\n\n\t\t/**\n\t\t * Loaded image will be cached in memory\n\t\t *\n\t\t * @deprecated Use {@link #cacheInMemory(boolean) cacheInMemory(true)} instead\n\t\t */\n\t\t@Deprecated\n\t\tpublic Builder cacheInMemory() {\n\t\t\tcacheInMemory = true;\n\t\t\treturn this;\n\t\t}\n\n\t\t/** Sets whether loaded image will be cached in memory */\n\t\tpublic Builder cacheInMemory(boolean cacheInMemory) {\n\t\t\tthis.cacheInMemory = cacheInMemory;\n\t\t\treturn this;\n\t\t}\n\n\t\t/**\n\t\t * Loaded image will be cached on disk\n\t\t *\n\t\t * @deprecated Use {@link #cacheOnDisk(boolean) cacheOnDisk(true)} instead\n\t\t */\n\t\t@Deprecated\n\t\tpublic Builder cacheOnDisc() {\n\t\t\treturn cacheOnDisk(true);\n\t\t}\n\n\t\t/**\n\t\t * Sets whether loaded image will be cached on disk\n\t\t *\n\t\t * @deprecated Use {@link #cacheOnDisk(boolean)} instead\n\t\t */\n\t\t@Deprecated\n\t\tpublic Builder cacheOnDisc(boolean cacheOnDisk) {\n\t\t\treturn cacheOnDisk(cacheOnDisk);\n\t\t}\n\n\t\t/** Sets whether loaded image will be cached on disk */\n\t\tpublic Builder cacheOnDisk(boolean cacheOnDisk) {\n\t\t\tthis.cacheOnDisk = cacheOnDisk;\n\t\t\treturn this;\n\t\t}\n\n\t\t/**\n\t\t * Sets {@linkplain ImageScaleType scale type} for decoding image. This parameter is used while define scale\n\t\t * size for decoding image to Bitmap. Default value - {@link ImageScaleType#IN_SAMPLE_POWER_OF_2}\n\t\t */\n\t\tpublic Builder imageScaleType(ImageScaleType imageScaleType) {\n\t\t\tthis.imageScaleType = imageScaleType;\n\t\t\treturn this;\n\t\t}\n\n\t\t/** Sets {@link Bitmap.Config bitmap config} for image decoding. Default value - {@link Bitmap.Config#ARGB_8888} */\n\t\tpublic Builder bitmapConfig(Bitmap.Config bitmapConfig) {\n\t\t\tif (bitmapConfig == null) throw new IllegalArgumentException(\"bitmapConfig can't be null\");\n\t\t\tdecodingOptions.inPreferredConfig = bitmapConfig;\n\t\t\treturn this;\n\t\t}\n\n\t\t/**\n\t\t * Sets options for image decoding.<br />\n\t\t * <b>NOTE:</b> {@link Options#inSampleSize} of incoming options will <b>NOT</b> be considered. Library\n\t\t * calculate the most appropriate sample size itself according yo {@link #imageScaleType(ImageScaleType)}\n\t\t * options.<br />\n\t\t * <b>NOTE:</b> This option overlaps {@link #bitmapConfig(android.graphics.Bitmap.Config) bitmapConfig()}\n\t\t * option.\n\t\t */\n\t\tpublic Builder decodingOptions(Options decodingOptions) {\n\t\t\tif (decodingOptions == null) throw new IllegalArgumentException(\"decodingOptions can't be null\");\n\t\t\tthis.decodingOptions = decodingOptions;\n\t\t\treturn this;\n\t\t}\n\n\t\t/** Sets delay time before starting loading task. Default - no delay. */\n\t\tpublic Builder delayBeforeLoading(int delayInMillis) {\n\t\t\tthis.delayBeforeLoading = delayInMillis;\n\t\t\treturn this;\n\t\t}\n\n\t\t/** Sets auxiliary object which will be passed to {@link ImageDownloader#getStream(String, Object)} */\n\t\tpublic Builder extraForDownloader(Object extra) {\n\t\t\tthis.extraForDownloader = extra;\n\t\t\treturn this;\n\t\t}\n\n\t\t/** Sets whether ImageLoader will consider EXIF parameters of JPEG image (rotate, flip) */\n\t\tpublic Builder considerExifParams(boolean considerExifParams) {\n\t\t\tthis.considerExifParams = considerExifParams;\n\t\t\treturn this;\n\t\t}\n\n\t\t/**\n\t\t * Sets bitmap processor which will be process bitmaps before they will be cached in memory. So memory cache\n\t\t * will contain bitmap processed by incoming preProcessor.<br />\n\t\t * Image will be pre-processed even if caching in memory is disabled.\n\t\t */\n\t\tpublic Builder preProcessor(BitmapProcessor preProcessor) {\n\t\t\tthis.preProcessor = preProcessor;\n\t\t\treturn this;\n\t\t}\n\n\t\t/**\n\t\t * Sets bitmap processor which will be process bitmaps before they will be displayed in\n\t\t * {@link com.nostra13.universalimageloader.core.imageaware.ImageAware image aware view} but\n\t\t * after they'll have been saved in memory cache.\n\t\t */\n\t\tpublic Builder postProcessor(BitmapProcessor postProcessor) {\n\t\t\tthis.postProcessor = postProcessor;\n\t\t\treturn this;\n\t\t}\n\n\t\t/**\n\t\t * Sets custom {@link BitmapDisplayer displayer} for image loading task. Default value -\n\t\t * {@link DefaultConfigurationFactory#createBitmapDisplayer()}\n\t\t */\n\t\tpublic Builder displayer(BitmapDisplayer displayer) {\n\t\t\tif (displayer == null) throw new IllegalArgumentException(\"displayer can't be null\");\n\t\t\tthis.displayer = displayer;\n\t\t\treturn this;\n\t\t}\n\n\t\tBuilder syncLoading(boolean isSyncLoading) {\n\t\t\tthis.isSyncLoading = isSyncLoading;\n\t\t\treturn this;\n\t\t}\n\n\t\t/**\n\t\t * Sets custom {@linkplain Handler handler} for displaying images and firing {@linkplain ImageLoadingListener\n\t\t * listener} events.\n\t\t */\n\t\tpublic Builder handler(Handler handler) {\n\t\t\tthis.handler = handler;\n\t\t\treturn this;\n\t\t}\n\n\t\t/** Sets all options equal to incoming options */\n\t\tpublic Builder cloneFrom(DisplayImageOptions options) {\n\t\t\timageResOnLoading = options.imageResOnLoading;\n\t\t\timageResForEmptyUri = options.imageResForEmptyUri;\n\t\t\timageResOnFail = options.imageResOnFail;\n\t\t\timageOnLoading = options.imageOnLoading;\n\t\t\timageForEmptyUri = options.imageForEmptyUri;\n\t\t\timageOnFail = options.imageOnFail;\n\t\t\tresetViewBeforeLoading = options.resetViewBeforeLoading;\n\t\t\tcacheInMemory = options.cacheInMemory;\n\t\t\tcacheOnDisk = options.cacheOnDisk;\n\t\t\timageScaleType = options.imageScaleType;\n\t\t\tdecodingOptions = options.decodingOptions;\n\t\t\tdelayBeforeLoading = options.delayBeforeLoading;\n\t\t\tconsiderExifParams = options.considerExifParams;\n\t\t\textraForDownloader = options.extraForDownloader;\n\t\t\tpreProcessor = options.preProcessor;\n\t\t\tpostProcessor = options.postProcessor;\n\t\t\tdisplayer = options.displayer;\n\t\t\thandler = options.handler;\n\t\t\tisSyncLoading = options.isSyncLoading;\n\t\t\treturn this;\n\t\t}\n\n\t\t/** Builds configured {@link DisplayImageOptions} object */\n\t\tpublic DisplayImageOptions build() {\n\t\t\treturn new DisplayImageOptions(this);\n\t\t}\n\t}\n\n\t/**\n\t * Creates options appropriate for single displaying:\n\t * <ul>\n\t * <li>View will <b>not</b> be reset before loading</li>\n\t * <li>Loaded image will <b>not</b> be cached in memory</li>\n\t * <li>Loaded image will <b>not</b> be cached on disk</li>\n\t * <li>{@link ImageScaleType#IN_SAMPLE_POWER_OF_2} decoding type will be used</li>\n\t * <li>{@link Bitmap.Config#ARGB_8888} bitmap config will be used for image decoding</li>\n\t * <li>{@link SimpleBitmapDisplayer} will be used for image displaying</li>\n\t * </ul>\n\t * <p/>\n\t * These option are appropriate for simple single-use image (from drawables or from Internet) displaying.\n\t */\n\tpublic static DisplayImageOptions createSimple() {\n\t\treturn new Builder().build();\n\t}\n}\n"
  },
  {
    "path": "library/src/main/java/com/nostra13/universalimageloader/core/ImageLoader.java",
    "content": "/*******************************************************************************\n * Copyright 2011-2014 Sergey Tarasevich\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *******************************************************************************/\npackage com.nostra13.universalimageloader.core;\n\nimport android.graphics.Bitmap;\nimport android.os.Handler;\nimport android.os.Looper;\nimport android.text.TextUtils;\nimport android.view.View;\nimport android.widget.ImageView;\n\nimport com.nostra13.universalimageloader.cache.disc.DiskCache;\nimport com.nostra13.universalimageloader.cache.memory.MemoryCache;\nimport com.nostra13.universalimageloader.core.assist.FailReason;\nimport com.nostra13.universalimageloader.core.assist.FlushedInputStream;\nimport com.nostra13.universalimageloader.core.assist.ImageSize;\nimport com.nostra13.universalimageloader.core.assist.LoadedFrom;\nimport com.nostra13.universalimageloader.core.assist.ViewScaleType;\nimport com.nostra13.universalimageloader.core.imageaware.ImageAware;\nimport com.nostra13.universalimageloader.core.imageaware.ImageViewAware;\nimport com.nostra13.universalimageloader.core.imageaware.NonViewAware;\nimport com.nostra13.universalimageloader.core.listener.ImageLoadingListener;\nimport com.nostra13.universalimageloader.core.listener.ImageLoadingProgressListener;\nimport com.nostra13.universalimageloader.core.listener.SimpleImageLoadingListener;\nimport com.nostra13.universalimageloader.utils.ImageSizeUtils;\nimport com.nostra13.universalimageloader.utils.L;\nimport com.nostra13.universalimageloader.utils.MemoryCacheUtils;\n\n/**\n * Singletone for image loading and displaying at {@link ImageView ImageViews}<br />\n * <b>NOTE:</b> {@link #init(ImageLoaderConfiguration)} method must be called before any other method.\n *\n * @author Sergey Tarasevich (nostra13[at]gmail[dot]com)\n * @since 1.0.0\n */\npublic class ImageLoader {\n\n\tpublic static final String TAG = ImageLoader.class.getSimpleName();\n\n\tstatic final String LOG_INIT_CONFIG = \"Initialize ImageLoader with configuration\";\n\tstatic final String LOG_DESTROY = \"Destroy ImageLoader\";\n\tstatic final String LOG_LOAD_IMAGE_FROM_MEMORY_CACHE = \"Load image from memory cache [%s]\";\n\n\tprivate static final String WARNING_RE_INIT_CONFIG = \"Try to initialize ImageLoader which had already been initialized before. \" + \"To re-init ImageLoader with new configuration call ImageLoader.destroy() at first.\";\n\tprivate static final String ERROR_WRONG_ARGUMENTS = \"Wrong arguments were passed to displayImage() method (ImageView reference must not be null)\";\n\tprivate static final String ERROR_NOT_INIT = \"ImageLoader must be init with configuration before using\";\n\tprivate static final String ERROR_INIT_CONFIG_WITH_NULL = \"ImageLoader configuration can not be initialized with null\";\n\n\tprivate ImageLoaderConfiguration configuration;\n\tprivate ImageLoaderEngine engine;\n\n\tprivate ImageLoadingListener defaultListener = new SimpleImageLoadingListener();\n\n\tprivate volatile static ImageLoader instance;\n\n\t/** Returns singleton class instance */\n\tpublic static ImageLoader getInstance() {\n\t\tif (instance == null) {\n\t\t\tsynchronized (ImageLoader.class) {\n\t\t\t\tif (instance == null) {\n\t\t\t\t\tinstance = new ImageLoader();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn instance;\n\t}\n\n\tprotected ImageLoader() {\n\t}\n\n\t/**\n\t * Initializes ImageLoader instance with configuration.<br />\n\t * If configurations was set before ( {@link #isInited()} == true) then this method does nothing.<br />\n\t * To force initialization with new configuration you should {@linkplain #destroy() destroy ImageLoader} at first.\n\t *\n\t * @param configuration {@linkplain ImageLoaderConfiguration ImageLoader configuration}\n\t * @throws IllegalArgumentException if <b>configuration</b> parameter is null\n\t */\n\tpublic synchronized void init(ImageLoaderConfiguration configuration) {\n\t\tif (configuration == null) {\n\t\t\tthrow new IllegalArgumentException(ERROR_INIT_CONFIG_WITH_NULL);\n\t\t}\n\t\tif (this.configuration == null) {\n\t\t\tL.d(LOG_INIT_CONFIG);\n\t\t\tengine = new ImageLoaderEngine(configuration);\n\t\t\tthis.configuration = configuration;\n\t\t} else {\n\t\t\tL.w(WARNING_RE_INIT_CONFIG);\n\t\t}\n\t}\n\n\t/**\n\t * Returns <b>true</b> - if ImageLoader {@linkplain #init(ImageLoaderConfiguration) is initialized with\n\t * configuration}; <b>false</b> - otherwise\n\t */\n\tpublic boolean isInited() {\n\t\treturn configuration != null;\n\t}\n\n\t/**\n\t * Adds display image task to execution pool. Image will be set to ImageAware when it's turn. <br/>\n\t * Default {@linkplain DisplayImageOptions display image options} from {@linkplain ImageLoaderConfiguration\n\t * configuration} will be used.<br />\n\t * <b>NOTE:</b> {@link #init(ImageLoaderConfiguration)} method must be called before this method call\n\t *\n\t * @param uri        Image URI (i.e. \"http://site.com/image.png\", \"file:///mnt/sdcard/image.png\")\n\t * @param imageAware {@linkplain com.nostra13.universalimageloader.core.imageaware.ImageAware Image aware view}\n\t *                   which should display image\n\t * @throws IllegalStateException    if {@link #init(ImageLoaderConfiguration)} method wasn't called before\n\t * @throws IllegalArgumentException if passed <b>imageAware</b> is null\n\t */\n\tpublic void displayImage(String uri, ImageAware imageAware) {\n\t\tdisplayImage(uri, imageAware, null, null, null);\n\t}\n\n\t/**\n\t * Adds display image task to execution pool. Image will be set to ImageAware when it's turn.<br />\n\t * Default {@linkplain DisplayImageOptions display image options} from {@linkplain ImageLoaderConfiguration\n\t * configuration} will be used.<br />\n\t * <b>NOTE:</b> {@link #init(ImageLoaderConfiguration)} method must be called before this method call\n\t *\n\t * @param uri        Image URI (i.e. \"http://site.com/image.png\", \"file:///mnt/sdcard/image.png\")\n\t * @param imageAware {@linkplain com.nostra13.universalimageloader.core.imageaware.ImageAware Image aware view}\n\t *                   which should display image\n\t * @param listener   {@linkplain ImageLoadingListener Listener} for image loading process. Listener fires events on\n\t *                   UI thread if this method is called on UI thread.\n\t * @throws IllegalStateException    if {@link #init(ImageLoaderConfiguration)} method wasn't called before\n\t * @throws IllegalArgumentException if passed <b>imageAware</b> is null\n\t */\n\tpublic void displayImage(String uri, ImageAware imageAware, ImageLoadingListener listener) {\n\t\tdisplayImage(uri, imageAware, null, listener, null);\n\t}\n\n\t/**\n\t * Adds display image task to execution pool. Image will be set to ImageAware when it's turn.<br />\n\t * <b>NOTE:</b> {@link #init(ImageLoaderConfiguration)} method must be called before this method call\n\t *\n\t * @param uri        Image URI (i.e. \"http://site.com/image.png\", \"file:///mnt/sdcard/image.png\")\n\t * @param imageAware {@linkplain com.nostra13.universalimageloader.core.imageaware.ImageAware Image aware view}\n\t *                   which should display image\n\t * @param options    {@linkplain com.nostra13.universalimageloader.core.DisplayImageOptions Options} for image\n\t *                   decoding and displaying. If <b>null</b> - default display image options\n\t *                   {@linkplain ImageLoaderConfiguration.Builder#defaultDisplayImageOptions(DisplayImageOptions)\n\t *                   from configuration} will be used.\n\t * @throws IllegalStateException    if {@link #init(ImageLoaderConfiguration)} method wasn't called before\n\t * @throws IllegalArgumentException if passed <b>imageAware</b> is null\n\t */\n\tpublic void displayImage(String uri, ImageAware imageAware, DisplayImageOptions options) {\n\t\tdisplayImage(uri, imageAware, options, null, null);\n\t}\n\n\t/**\n\t * Adds display image task to execution pool. Image will be set to ImageAware when it's turn.<br />\n\t * <b>NOTE:</b> {@link #init(ImageLoaderConfiguration)} method must be called before this method call\n\t *\n\t * @param uri        Image URI (i.e. \"http://site.com/image.png\", \"file:///mnt/sdcard/image.png\")\n\t * @param imageAware {@linkplain com.nostra13.universalimageloader.core.imageaware.ImageAware Image aware view}\n\t *                   which should display image\n\t * @param options    {@linkplain com.nostra13.universalimageloader.core.DisplayImageOptions Options} for image\n\t *                   decoding and displaying. If <b>null</b> - default display image options\n\t *                   {@linkplain ImageLoaderConfiguration.Builder#defaultDisplayImageOptions(DisplayImageOptions)\n\t *                   from configuration} will be used.\n\t * @param listener   {@linkplain ImageLoadingListener Listener} for image loading process. Listener fires events on\n\t *                   UI thread if this method is called on UI thread.\n\t * @throws IllegalStateException    if {@link #init(ImageLoaderConfiguration)} method wasn't called before\n\t * @throws IllegalArgumentException if passed <b>imageAware</b> is null\n\t */\n\tpublic void displayImage(String uri, ImageAware imageAware, DisplayImageOptions options,\n\t\t\tImageLoadingListener listener) {\n\t\tdisplayImage(uri, imageAware, options, listener, null);\n\t}\n\n\t/**\n\t * Adds display image task to execution pool. Image will be set to ImageAware when it's turn.<br />\n\t * <b>NOTE:</b> {@link #init(ImageLoaderConfiguration)} method must be called before this method call\n\t *\n\t * @param uri              Image URI (i.e. \"http://site.com/image.png\", \"file:///mnt/sdcard/image.png\")\n\t * @param imageAware       {@linkplain com.nostra13.universalimageloader.core.imageaware.ImageAware Image aware view}\n\t *                         which should display image\n\t * @param options          {@linkplain com.nostra13.universalimageloader.core.DisplayImageOptions Options} for image\n\t *                         decoding and displaying. If <b>null</b> - default display image options\n\t *                         {@linkplain ImageLoaderConfiguration.Builder#defaultDisplayImageOptions(DisplayImageOptions)\n\t *                         from configuration} will be used.\n\t * @param listener         {@linkplain ImageLoadingListener Listener} for image loading process. Listener fires\n\t *                         events on UI thread if this method is called on UI thread.\n\t * @param progressListener {@linkplain com.nostra13.universalimageloader.core.listener.ImageLoadingProgressListener\n\t *                         Listener} for image loading progress. Listener fires events on UI thread if this method\n\t *                         is called on UI thread. Caching on disk should be enabled in\n\t *                         {@linkplain com.nostra13.universalimageloader.core.DisplayImageOptions options} to make\n\t *                         this listener work.\n\t * @throws IllegalStateException    if {@link #init(ImageLoaderConfiguration)} method wasn't called before\n\t * @throws IllegalArgumentException if passed <b>imageAware</b> is null\n\t */\n\tpublic void displayImage(String uri, ImageAware imageAware, DisplayImageOptions options,\n\t\t\tImageLoadingListener listener, ImageLoadingProgressListener progressListener) {\n\t\tdisplayImage(uri, imageAware, options, null, listener, progressListener);\n\t}\n\n\t/**\n\t * Adds display image task to execution pool. Image will be set to ImageAware when it's turn.<br />\n\t * <b>NOTE:</b> {@link #init(ImageLoaderConfiguration)} method must be called before this method call\n\t *\n\t * @param uri              Image URI (i.e. \"http://site.com/image.png\", \"file:///mnt/sdcard/image.png\")\n\t * @param imageAware       {@linkplain com.nostra13.universalimageloader.core.imageaware.ImageAware Image aware view}\n\t *                         which should display image\n\t * @param options          {@linkplain com.nostra13.universalimageloader.core.DisplayImageOptions Options} for image\n\t *                         decoding and displaying. If <b>null</b> - default display image options\n\t *                         {@linkplain ImageLoaderConfiguration.Builder#defaultDisplayImageOptions(DisplayImageOptions)\n\t *                         from configuration} will be used.\n\t * @param targetSize       {@linkplain ImageSize} Image target size. If <b>null</b> - size will depend on the view\n\t * @param listener         {@linkplain ImageLoadingListener Listener} for image loading process. Listener fires\n\t *                         events on UI thread if this method is called on UI thread.\n\t * @param progressListener {@linkplain com.nostra13.universalimageloader.core.listener.ImageLoadingProgressListener\n\t *                         Listener} for image loading progress. Listener fires events on UI thread if this method\n\t *                         is called on UI thread. Caching on disk should be enabled in\n\t *                         {@linkplain com.nostra13.universalimageloader.core.DisplayImageOptions options} to make\n\t *                         this listener work.\n\t * @throws IllegalStateException    if {@link #init(ImageLoaderConfiguration)} method wasn't called before\n\t * @throws IllegalArgumentException if passed <b>imageAware</b> is null\n\t */\n\tpublic void displayImage(String uri, ImageAware imageAware, DisplayImageOptions options,\n\t\t\tImageSize targetSize, ImageLoadingListener listener, ImageLoadingProgressListener progressListener) {\n\t\tcheckConfiguration();\n\t\tif (imageAware == null) {\n\t\t\tthrow new IllegalArgumentException(ERROR_WRONG_ARGUMENTS);\n\t\t}\n\t\tif (listener == null) {\n\t\t\tlistener = defaultListener;\n\t\t}\n\t\tif (options == null) {\n\t\t\toptions = configuration.defaultDisplayImageOptions;\n\t\t}\n\n\t\tif (TextUtils.isEmpty(uri)) {\n\t\t\tengine.cancelDisplayTaskFor(imageAware);\n\t\t\tlistener.onLoadingStarted(uri, imageAware.getWrappedView());\n\t\t\tif (options.shouldShowImageForEmptyUri()) {\n\t\t\t\timageAware.setImageDrawable(options.getImageForEmptyUri(configuration.resources));\n\t\t\t} else {\n\t\t\t\timageAware.setImageDrawable(null);\n\t\t\t}\n\t\t\tlistener.onLoadingComplete(uri, imageAware.getWrappedView(), null);\n\t\t\treturn;\n\t\t}\n\n\t\tif (targetSize == null) {\n\t\t\ttargetSize = ImageSizeUtils.defineTargetSizeForView(imageAware, configuration.getMaxImageSize());\n\t\t}\n\t\tString memoryCacheKey = MemoryCacheUtils.generateKey(uri, targetSize);\n\t\tengine.prepareDisplayTaskFor(imageAware, memoryCacheKey);\n\n\t\tlistener.onLoadingStarted(uri, imageAware.getWrappedView());\n\n\t\tBitmap bmp = configuration.memoryCache.get(memoryCacheKey);\n\t\tif (bmp != null && !bmp.isRecycled()) {\n\t\t\tL.d(LOG_LOAD_IMAGE_FROM_MEMORY_CACHE, memoryCacheKey);\n\n\t\t\tif (options.shouldPostProcess()) {\n\t\t\t\tImageLoadingInfo imageLoadingInfo = new ImageLoadingInfo(uri, imageAware, targetSize, memoryCacheKey,\n\t\t\t\t\t\toptions, listener, progressListener, engine.getLockForUri(uri));\n\t\t\t\tProcessAndDisplayImageTask displayTask = new ProcessAndDisplayImageTask(engine, bmp, imageLoadingInfo,\n\t\t\t\t\t\tdefineHandler(options));\n\t\t\t\tif (options.isSyncLoading()) {\n\t\t\t\t\tdisplayTask.run();\n\t\t\t\t} else {\n\t\t\t\t\tengine.submit(displayTask);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\toptions.getDisplayer().display(bmp, imageAware, LoadedFrom.MEMORY_CACHE);\n\t\t\t\tlistener.onLoadingComplete(uri, imageAware.getWrappedView(), bmp);\n\t\t\t}\n\t\t} else {\n\t\t\tif (options.shouldShowImageOnLoading()) {\n\t\t\t\timageAware.setImageDrawable(options.getImageOnLoading(configuration.resources));\n\t\t\t} else if (options.isResetViewBeforeLoading()) {\n\t\t\t\timageAware.setImageDrawable(null);\n\t\t\t}\n\n\t\t\tImageLoadingInfo imageLoadingInfo = new ImageLoadingInfo(uri, imageAware, targetSize, memoryCacheKey,\n\t\t\t\t\toptions, listener, progressListener, engine.getLockForUri(uri));\n\t\t\tLoadAndDisplayImageTask displayTask = new LoadAndDisplayImageTask(engine, imageLoadingInfo,\n\t\t\t\t\tdefineHandler(options));\n\t\t\tif (options.isSyncLoading()) {\n\t\t\t\tdisplayTask.run();\n\t\t\t} else {\n\t\t\t\tengine.submit(displayTask);\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Adds display image task to execution pool. Image will be set to ImageView when it's turn. <br/>\n\t * Default {@linkplain DisplayImageOptions display image options} from {@linkplain ImageLoaderConfiguration\n\t * configuration} will be used.<br />\n\t * <b>NOTE:</b> {@link #init(ImageLoaderConfiguration)} method must be called before this method call\n\t *\n\t * @param uri       Image URI (i.e. \"http://site.com/image.png\", \"file:///mnt/sdcard/image.png\")\n\t * @param imageView {@link ImageView} which should display image\n\t * @throws IllegalStateException    if {@link #init(ImageLoaderConfiguration)} method wasn't called before\n\t * @throws IllegalArgumentException if passed <b>imageView</b> is null\n\t */\n\tpublic void displayImage(String uri, ImageView imageView) {\n\t\tdisplayImage(uri, new ImageViewAware(imageView), null, null, null);\n\t}\n\n\t/**\n\t * Adds display image task to execution pool. Image will be set to ImageView when it's turn. <br/>\n\t * Default {@linkplain DisplayImageOptions display image options} from {@linkplain ImageLoaderConfiguration\n\t * configuration} will be used.<br />\n\t * <b>NOTE:</b> {@link #init(ImageLoaderConfiguration)} method must be called before this method call\n\t *\n\t * @param uri       Image URI (i.e. \"http://site.com/image.png\", \"file:///mnt/sdcard/image.png\")\n\t * @param imageView {@link ImageView} which should display image\n\t * @throws IllegalStateException    if {@link #init(ImageLoaderConfiguration)} method wasn't called before\n\t * @throws IllegalArgumentException if passed <b>imageView</b> is null\n\t */\n\tpublic void displayImage(String uri, ImageView imageView, ImageSize targetImageSize) {\n\t\tdisplayImage(uri, new ImageViewAware(imageView), null, targetImageSize, null, null);\n\t}\n\n\t/**\n\t * Adds display image task to execution pool. Image will be set to ImageView when it's turn.<br />\n\t * <b>NOTE:</b> {@link #init(ImageLoaderConfiguration)} method must be called before this method call\n\t *\n\t * @param uri       Image URI (i.e. \"http://site.com/image.png\", \"file:///mnt/sdcard/image.png\")\n\t * @param imageView {@link ImageView} which should display image\n\t * @param options   {@linkplain com.nostra13.universalimageloader.core.DisplayImageOptions Options} for image\n\t *                  decoding and displaying. If <b>null</b> - default display image options\n\t *                  {@linkplain ImageLoaderConfiguration.Builder#defaultDisplayImageOptions(DisplayImageOptions)\n\t *                  from configuration} will be used.\n\t * @throws IllegalStateException    if {@link #init(ImageLoaderConfiguration)} method wasn't called before\n\t * @throws IllegalArgumentException if passed <b>imageView</b> is null\n\t */\n\tpublic void displayImage(String uri, ImageView imageView, DisplayImageOptions options) {\n\t\tdisplayImage(uri, new ImageViewAware(imageView), options, null, null);\n\t}\n\n\t/**\n\t * Adds display image task to execution pool. Image will be set to ImageView when it's turn.<br />\n\t * Default {@linkplain DisplayImageOptions display image options} from {@linkplain ImageLoaderConfiguration\n\t * configuration} will be used.<br />\n\t * <b>NOTE:</b> {@link #init(ImageLoaderConfiguration)} method must be called before this method call\n\t *\n\t * @param uri       Image URI (i.e. \"http://site.com/image.png\", \"file:///mnt/sdcard/image.png\")\n\t * @param imageView {@link ImageView} which should display image\n\t * @param listener  {@linkplain ImageLoadingListener Listener} for image loading process. Listener fires events on\n\t *                  UI thread if this method is called on UI thread.\n\t * @throws IllegalStateException    if {@link #init(ImageLoaderConfiguration)} method wasn't called before\n\t * @throws IllegalArgumentException if passed <b>imageView</b> is null\n\t */\n\tpublic void displayImage(String uri, ImageView imageView, ImageLoadingListener listener) {\n\t\tdisplayImage(uri, new ImageViewAware(imageView), null, listener, null);\n\t}\n\n\t/**\n\t * Adds display image task to execution pool. Image will be set to ImageView when it's turn.<br />\n\t * <b>NOTE:</b> {@link #init(ImageLoaderConfiguration)} method must be called before this method call\n\t *\n\t * @param uri       Image URI (i.e. \"http://site.com/image.png\", \"file:///mnt/sdcard/image.png\")\n\t * @param imageView {@link ImageView} which should display image\n\t * @param options   {@linkplain com.nostra13.universalimageloader.core.DisplayImageOptions Options} for image\n\t *                  decoding and displaying. If <b>null</b> - default display image options\n\t *                  {@linkplain ImageLoaderConfiguration.Builder#defaultDisplayImageOptions(DisplayImageOptions)\n\t *                  from configuration} will be used.\n\t * @param listener  {@linkplain ImageLoadingListener Listener} for image loading process. Listener fires events on\n\t *                  UI thread if this method is called on UI thread.\n\t * @throws IllegalStateException    if {@link #init(ImageLoaderConfiguration)} method wasn't called before\n\t * @throws IllegalArgumentException if passed <b>imageView</b> is null\n\t */\n\tpublic void displayImage(String uri, ImageView imageView, DisplayImageOptions options,\n\t\t\tImageLoadingListener listener) {\n\t\tdisplayImage(uri, imageView, options, listener, null);\n\t}\n\n\t/**\n\t * Adds display image task to execution pool. Image will be set to ImageView when it's turn.<br />\n\t * <b>NOTE:</b> {@link #init(ImageLoaderConfiguration)} method must be called before this method call\n\t *\n\t * @param uri              Image URI (i.e. \"http://site.com/image.png\", \"file:///mnt/sdcard/image.png\")\n\t * @param imageView        {@link ImageView} which should display image\n\t * @param options          {@linkplain com.nostra13.universalimageloader.core.DisplayImageOptions Options} for image\n\t *                         decoding and displaying. If <b>null</b> - default display image options\n\t *                         {@linkplain ImageLoaderConfiguration.Builder#defaultDisplayImageOptions(DisplayImageOptions)\n\t *                         from configuration} will be used.\n\t * @param listener         {@linkplain ImageLoadingListener Listener} for image loading process. Listener fires\n\t *                         events on UI thread if this method is called on UI thread.\n\t * @param progressListener {@linkplain com.nostra13.universalimageloader.core.listener.ImageLoadingProgressListener\n\t *                         Listener} for image loading progress. Listener fires events on UI thread if this method\n\t *                         is called on UI thread. Caching on disk should be enabled in\n\t *                         {@linkplain com.nostra13.universalimageloader.core.DisplayImageOptions options} to make\n\t *                         this listener work.\n\t * @throws IllegalStateException    if {@link #init(ImageLoaderConfiguration)} method wasn't called before\n\t * @throws IllegalArgumentException if passed <b>imageView</b> is null\n\t */\n\tpublic void displayImage(String uri, ImageView imageView, DisplayImageOptions options,\n\t\t\tImageLoadingListener listener, ImageLoadingProgressListener progressListener) {\n\t\tdisplayImage(uri, new ImageViewAware(imageView), options, listener, progressListener);\n\t}\n\n\t/**\n\t * Adds load image task to execution pool. Image will be returned with\n\t * {@link ImageLoadingListener#onLoadingComplete(String, android.view.View, android.graphics.Bitmap)} callback}.\n\t * <br />\n\t * <b>NOTE:</b> {@link #init(ImageLoaderConfiguration)} method must be called before this method call\n\t *\n\t * @param uri      Image URI (i.e. \"http://site.com/image.png\", \"file:///mnt/sdcard/image.png\")\n\t * @param listener {@linkplain ImageLoadingListener Listener} for image loading process. Listener fires events on UI\n\t *                 thread if this method is called on UI thread.\n\t * @throws IllegalStateException if {@link #init(ImageLoaderConfiguration)} method wasn't called before\n\t */\n\tpublic void loadImage(String uri, ImageLoadingListener listener) {\n\t\tloadImage(uri, null, null, listener, null);\n\t}\n\n\t/**\n\t * Adds load image task to execution pool. Image will be returned with\n\t * {@link ImageLoadingListener#onLoadingComplete(String, android.view.View, android.graphics.Bitmap)} callback}.\n\t * <br />\n\t * <b>NOTE:</b> {@link #init(ImageLoaderConfiguration)} method must be called before this method call\n\t *\n\t * @param uri             Image URI (i.e. \"http://site.com/image.png\", \"file:///mnt/sdcard/image.png\")\n\t * @param targetImageSize Minimal size for {@link Bitmap} which will be returned in\n\t *                        {@linkplain ImageLoadingListener#onLoadingComplete(String, android.view.View,\n\t *                        android.graphics.Bitmap)} callback}. Downloaded image will be decoded\n\t *                        and scaled to {@link Bitmap} of the size which is <b>equal or larger</b> (usually a bit\n\t *                        larger) than incoming targetImageSize.\n\t * @param listener        {@linkplain ImageLoadingListener Listener} for image loading process. Listener fires\n\t *                        events on UI thread if this method is called on UI thread.\n\t * @throws IllegalStateException if {@link #init(ImageLoaderConfiguration)} method wasn't called before\n\t */\n\tpublic void loadImage(String uri, ImageSize targetImageSize, ImageLoadingListener listener) {\n\t\tloadImage(uri, targetImageSize, null, listener, null);\n\t}\n\n\t/**\n\t * Adds load image task to execution pool. Image will be returned with\n\t * {@link ImageLoadingListener#onLoadingComplete(String, android.view.View, android.graphics.Bitmap)} callback}.\n\t * <br />\n\t * <b>NOTE:</b> {@link #init(ImageLoaderConfiguration)} method must be called before this method call\n\t *\n\t * @param uri      Image URI (i.e. \"http://site.com/image.png\", \"file:///mnt/sdcard/image.png\")\n\t * @param options  {@linkplain com.nostra13.universalimageloader.core.DisplayImageOptions Options} for image\n\t *                 decoding and displaying. If <b>null</b> - default display image options\n\t *                 {@linkplain ImageLoaderConfiguration.Builder#defaultDisplayImageOptions(DisplayImageOptions) from\n\t *                 configuration} will be used.<br />\n\t * @param listener {@linkplain ImageLoadingListener Listener} for image loading process. Listener fires events on UI\n\t *                 thread if this method is called on UI thread.\n\t * @throws IllegalStateException if {@link #init(ImageLoaderConfiguration)} method wasn't called before\n\t */\n\tpublic void loadImage(String uri, DisplayImageOptions options, ImageLoadingListener listener) {\n\t\tloadImage(uri, null, options, listener, null);\n\t}\n\n\t/**\n\t * Adds load image task to execution pool. Image will be returned with\n\t * {@link ImageLoadingListener#onLoadingComplete(String, android.view.View, android.graphics.Bitmap)} callback}.\n\t * <br />\n\t * <b>NOTE:</b> {@link #init(ImageLoaderConfiguration)} method must be called before this method call\n\t *\n\t * @param uri             Image URI (i.e. \"http://site.com/image.png\", \"file:///mnt/sdcard/image.png\")\n\t * @param targetImageSize Minimal size for {@link Bitmap} which will be returned in\n\t *                        {@linkplain ImageLoadingListener#onLoadingComplete(String, android.view.View,\n\t *                        android.graphics.Bitmap)} callback}. Downloaded image will be decoded\n\t *                        and scaled to {@link Bitmap} of the size which is <b>equal or larger</b> (usually a bit\n\t *                        larger) than incoming targetImageSize.\n\t * @param options         {@linkplain com.nostra13.universalimageloader.core.DisplayImageOptions Options} for image\n\t *                        decoding and displaying. If <b>null</b> - default display image options\n\t *                        {@linkplain ImageLoaderConfiguration.Builder#defaultDisplayImageOptions(DisplayImageOptions)\n\t *                        from configuration} will be used.<br />\n\t * @param listener        {@linkplain ImageLoadingListener Listener} for image loading process. Listener fires\n\t *                        events on UI thread if this method is called on UI thread.\n\t * @throws IllegalStateException if {@link #init(ImageLoaderConfiguration)} method wasn't called before\n\t */\n\tpublic void loadImage(String uri, ImageSize targetImageSize, DisplayImageOptions options,\n\t\t\tImageLoadingListener listener) {\n\t\tloadImage(uri, targetImageSize, options, listener, null);\n\t}\n\n\t/**\n\t * Adds load image task to execution pool. Image will be returned with\n\t * {@link ImageLoadingListener#onLoadingComplete(String, android.view.View, android.graphics.Bitmap)} callback}.\n\t * <br />\n\t * <b>NOTE:</b> {@link #init(ImageLoaderConfiguration)} method must be called before this method call\n\t *\n\t * @param uri              Image URI (i.e. \"http://site.com/image.png\", \"file:///mnt/sdcard/image.png\")\n\t * @param targetImageSize  Minimal size for {@link Bitmap} which will be returned in\n\t *                         {@linkplain ImageLoadingListener#onLoadingComplete(String, android.view.View,\n\t *                         android.graphics.Bitmap)} callback}. Downloaded image will be decoded\n\t *                         and scaled to {@link Bitmap} of the size which is <b>equal or larger</b> (usually a bit\n\t *                         larger) than incoming targetImageSize.\n\t * @param options          {@linkplain com.nostra13.universalimageloader.core.DisplayImageOptions Options} for image\n\t *                         decoding and displaying. If <b>null</b> - default display image options\n\t *                         {@linkplain ImageLoaderConfiguration.Builder#defaultDisplayImageOptions(DisplayImageOptions)\n\t *                         from configuration} will be used.<br />\n\t * @param listener         {@linkplain ImageLoadingListener Listener} for image loading process. Listener fires\n\t *                         events on UI thread if this method is called on UI thread.\n\t * @param progressListener {@linkplain com.nostra13.universalimageloader.core.listener.ImageLoadingProgressListener\n\t *                         Listener} for image loading progress. Listener fires events on UI thread if this method\n\t *                         is called on UI thread. Caching on disk should be enabled in\n\t *                         {@linkplain com.nostra13.universalimageloader.core.DisplayImageOptions options} to make\n\t *                         this listener work.\n\t * @throws IllegalStateException if {@link #init(ImageLoaderConfiguration)} method wasn't called before\n\t */\n\tpublic void loadImage(String uri, ImageSize targetImageSize, DisplayImageOptions options,\n\t\t\tImageLoadingListener listener, ImageLoadingProgressListener progressListener) {\n\t\tcheckConfiguration();\n\t\tif (targetImageSize == null) {\n\t\t\ttargetImageSize = configuration.getMaxImageSize();\n\t\t}\n\t\tif (options == null) {\n\t\t\toptions = configuration.defaultDisplayImageOptions;\n\t\t}\n\n\t\tNonViewAware imageAware = new NonViewAware(uri, targetImageSize, ViewScaleType.CROP);\n\t\tdisplayImage(uri, imageAware, options, listener, progressListener);\n\t}\n\n\t/**\n\t * Loads and decodes image synchronously.<br />\n\t * Default display image options\n\t * {@linkplain ImageLoaderConfiguration.Builder#defaultDisplayImageOptions(DisplayImageOptions) from\n\t * configuration} will be used.<br />\n\t * <b>NOTE:</b> {@link #init(ImageLoaderConfiguration)} method must be called before this method call\n\t *\n\t * @param uri Image URI (i.e. \"http://site.com/image.png\", \"file:///mnt/sdcard/image.png\")\n\t * @return Result image Bitmap. Can be <b>null</b> if image loading/decoding was failed or cancelled.\n\t * @throws IllegalStateException if {@link #init(ImageLoaderConfiguration)} method wasn't called before\n\t */\n\tpublic Bitmap loadImageSync(String uri) {\n\t\treturn loadImageSync(uri, null, null);\n\t}\n\n\t/**\n\t * Loads and decodes image synchronously.<br />\n\t * <b>NOTE:</b> {@link #init(ImageLoaderConfiguration)} method must be called before this method call\n\t *\n\t * @param uri     Image URI (i.e. \"http://site.com/image.png\", \"file:///mnt/sdcard/image.png\")\n\t * @param options {@linkplain com.nostra13.universalimageloader.core.DisplayImageOptions Options} for image\n\t *                decoding and scaling. If <b>null</b> - default display image options\n\t *                {@linkplain ImageLoaderConfiguration.Builder#defaultDisplayImageOptions(DisplayImageOptions) from\n\t *                configuration} will be used.\n\t * @return Result image Bitmap. Can be <b>null</b> if image loading/decoding was failed or cancelled.\n\t * @throws IllegalStateException if {@link #init(ImageLoaderConfiguration)} method wasn't called before\n\t */\n\tpublic Bitmap loadImageSync(String uri, DisplayImageOptions options) {\n\t\treturn loadImageSync(uri, null, options);\n\t}\n\n\t/**\n\t * Loads and decodes image synchronously.<br />\n\t * Default display image options\n\t * {@linkplain ImageLoaderConfiguration.Builder#defaultDisplayImageOptions(DisplayImageOptions) from\n\t * configuration} will be used.<br />\n\t * <b>NOTE:</b> {@link #init(ImageLoaderConfiguration)} method must be called before this method call\n\t *\n\t * @param uri             Image URI (i.e. \"http://site.com/image.png\", \"file:///mnt/sdcard/image.png\")\n\t * @param targetImageSize Minimal size for {@link Bitmap} which will be returned. Downloaded image will be decoded\n\t *                        and scaled to {@link Bitmap} of the size which is <b>equal or larger</b> (usually a bit\n\t *                        larger) than incoming targetImageSize.\n\t * @return Result image Bitmap. Can be <b>null</b> if image loading/decoding was failed or cancelled.\n\t * @throws IllegalStateException if {@link #init(ImageLoaderConfiguration)} method wasn't called before\n\t */\n\tpublic Bitmap loadImageSync(String uri, ImageSize targetImageSize) {\n\t\treturn loadImageSync(uri, targetImageSize, null);\n\t}\n\n\t/**\n\t * Loads and decodes image synchronously.<br />\n\t * <b>NOTE:</b> {@link #init(ImageLoaderConfiguration)} method must be called before this method call\n\t *\n\t * @param uri             Image URI (i.e. \"http://site.com/image.png\", \"file:///mnt/sdcard/image.png\")\n\t * @param targetImageSize Minimal size for {@link Bitmap} which will be returned. Downloaded image will be decoded\n\t *                        and scaled to {@link Bitmap} of the size which is <b>equal or larger</b> (usually a bit\n\t *                        larger) than incoming targetImageSize.\n\t * @param options         {@linkplain com.nostra13.universalimageloader.core.DisplayImageOptions Options} for image\n\t *                        decoding and scaling. If <b>null</b> - default display image options\n\t *                        {@linkplain ImageLoaderConfiguration.Builder#defaultDisplayImageOptions(DisplayImageOptions)\n\t *                        from configuration} will be used.\n\t * @return Result image Bitmap. Can be <b>null</b> if image loading/decoding was failed or cancelled.\n\t * @throws IllegalStateException if {@link #init(ImageLoaderConfiguration)} method wasn't called before\n\t */\n\tpublic Bitmap loadImageSync(String uri, ImageSize targetImageSize, DisplayImageOptions options) {\n\t\tif (options == null) {\n\t\t\toptions = configuration.defaultDisplayImageOptions;\n\t\t}\n\t\toptions = new DisplayImageOptions.Builder().cloneFrom(options).syncLoading(true).build();\n\n\t\tSyncImageLoadingListener listener = new SyncImageLoadingListener();\n\t\tloadImage(uri, targetImageSize, options, listener);\n\t\treturn listener.getLoadedBitmap();\n\t}\n\n\t/**\n\t * Checks if ImageLoader's configuration was initialized\n\t *\n\t * @throws IllegalStateException if configuration wasn't initialized\n\t */\n\tprivate void checkConfiguration() {\n\t\tif (configuration == null) {\n\t\t\tthrow new IllegalStateException(ERROR_NOT_INIT);\n\t\t}\n\t}\n\n\t/** Sets a default loading listener for all display and loading tasks. */\n\tpublic void setDefaultLoadingListener(ImageLoadingListener listener) {\n\t\tdefaultListener = listener == null ? new SimpleImageLoadingListener() : listener;\n\t}\n\n\t/**\n\t * Returns memory cache\n\t *\n\t * @throws IllegalStateException if {@link #init(ImageLoaderConfiguration)} method wasn't called before\n\t */\n\tpublic MemoryCache getMemoryCache() {\n\t\tcheckConfiguration();\n\t\treturn configuration.memoryCache;\n\t}\n\n\t/**\n\t * Clears memory cache\n\t *\n\t * @throws IllegalStateException if {@link #init(ImageLoaderConfiguration)} method wasn't called before\n\t */\n\tpublic void clearMemoryCache() {\n\t\tcheckConfiguration();\n\t\tconfiguration.memoryCache.clear();\n\t}\n\n\t/**\n\t * Returns disk cache\n\t *\n\t * @throws IllegalStateException if {@link #init(ImageLoaderConfiguration)} method wasn't called before\n\t * @deprecated Use {@link #getDiskCache()} instead\n\t */\n\t@Deprecated\n\tpublic DiskCache getDiscCache() {\n\t\treturn getDiskCache();\n\t}\n\n\t/**\n\t * Returns disk cache\n\t *\n\t * @throws IllegalStateException if {@link #init(ImageLoaderConfiguration)} method wasn't called before\n\t */\n\tpublic DiskCache getDiskCache() {\n\t\tcheckConfiguration();\n\t\treturn configuration.diskCache;\n\t}\n\n\t/**\n\t * Clears disk cache.\n\t *\n\t * @throws IllegalStateException if {@link #init(ImageLoaderConfiguration)} method wasn't called before\n\t * @deprecated Use {@link #clearDiskCache()} instead\n\t */\n\t@Deprecated\n\tpublic void clearDiscCache() {\n\t\tclearDiskCache();\n\t}\n\n\t/**\n\t * Clears disk cache.\n\t *\n\t * @throws IllegalStateException if {@link #init(ImageLoaderConfiguration)} method wasn't called before\n\t */\n\tpublic void clearDiskCache() {\n\t\tcheckConfiguration();\n\t\tconfiguration.diskCache.clear();\n\t}\n\n\t/**\n\t * Returns URI of image which is loading at this moment into passed\n\t * {@link com.nostra13.universalimageloader.core.imageaware.ImageAware ImageAware}\n\t */\n\tpublic String getLoadingUriForView(ImageAware imageAware) {\n\t\treturn engine.getLoadingUriForView(imageAware);\n\t}\n\n\t/**\n\t * Returns URI of image which is loading at this moment into passed\n\t * {@link android.widget.ImageView ImageView}\n\t */\n\tpublic String getLoadingUriForView(ImageView imageView) {\n\t\treturn engine.getLoadingUriForView(new ImageViewAware(imageView));\n\t}\n\n\t/**\n\t * Cancel the task of loading and displaying image for passed\n\t * {@link com.nostra13.universalimageloader.core.imageaware.ImageAware ImageAware}.\n\t *\n\t * @param imageAware {@link com.nostra13.universalimageloader.core.imageaware.ImageAware ImageAware} for\n\t *                   which display task will be cancelled\n\t */\n\tpublic void cancelDisplayTask(ImageAware imageAware) {\n\t\tengine.cancelDisplayTaskFor(imageAware);\n\t}\n\n\t/**\n\t * Cancel the task of loading and displaying image for passed\n\t * {@link android.widget.ImageView ImageView}.\n\t *\n\t * @param imageView {@link android.widget.ImageView ImageView} for which display task will be cancelled\n\t */\n\tpublic void cancelDisplayTask(ImageView imageView) {\n\t\tengine.cancelDisplayTaskFor(new ImageViewAware(imageView));\n\t}\n\n\t/**\n\t * Denies or allows ImageLoader to download images from the network.<br />\n\t * <br />\n\t * If downloads are denied and if image isn't cached then\n\t * {@link ImageLoadingListener#onLoadingFailed(String, View, FailReason)} callback will be fired with\n\t * {@link FailReason.FailType#NETWORK_DENIED}\n\t *\n\t * @param denyNetworkDownloads pass <b>true</b> - to deny engine to download images from the network; <b>false</b> -\n\t *                             to allow engine to download images from network.\n\t */\n\tpublic void denyNetworkDownloads(boolean denyNetworkDownloads) {\n\t\tengine.denyNetworkDownloads(denyNetworkDownloads);\n\t}\n\n\t/**\n\t * Sets option whether ImageLoader will use {@link FlushedInputStream} for network downloads to handle <a\n\t * href=\"http://code.google.com/p/android/issues/detail?id=6066\">this known problem</a> or not.\n\t *\n\t * @param handleSlowNetwork pass <b>true</b> - to use {@link FlushedInputStream} for network downloads; <b>false</b>\n\t *                          - otherwise.\n\t */\n\tpublic void handleSlowNetwork(boolean handleSlowNetwork) {\n\t\tengine.handleSlowNetwork(handleSlowNetwork);\n\t}\n\n\t/**\n\t * Pause ImageLoader. All new \"load&display\" tasks won't be executed until ImageLoader is {@link #resume() resumed}.\n\t * <br />\n\t * Already running tasks are not paused.\n\t */\n\tpublic void pause() {\n\t\tif (isInited()) {\n\t\t\tengine.pause();\n\t\t} else {\n\t\t\tL.w(\"Trying to pause not-initialized ImageLoader\");\n\t\t}\n\t}\n\n\t/** Resumes waiting \"load&display\" tasks */\n\tpublic void resume() {\n\t\tif (isInited()) {\n\t\t\tengine.resume();\n\t\t} else {\n\t\t\tL.w(\"Trying to resume not-initialized ImageLoader\");\n\t\t}\n\t}\n\n\t/**\n\t * Cancels all running and scheduled display image tasks.<br />\n\t * <b>NOTE:</b> This method doesn't shutdown\n\t * {@linkplain com.nostra13.universalimageloader.core.ImageLoaderConfiguration.Builder#taskExecutor(java.util.concurrent.Executor)\n\t * custom task executors} if you set them.<br />\n\t * ImageLoader still can be used after calling this method.\n\t */\n\tpublic void stop() {\n\t\tif (isInited()) {\n\t\t\tengine.stop();\n\t\t} else {\n\t\t\tL.w(\"Trying to stop not-initialized ImageLoader\");\n\t\t}\n\t}\n\n\t/**\n\t * {@linkplain #stop() Stops ImageLoader} and clears current configuration. <br />\n\t * You can {@linkplain #init(ImageLoaderConfiguration) init} ImageLoader with new configuration after calling this\n\t * method.\n\t */\n\tpublic void destroy() {\n\t\tif (isInited()) {\n\t\t\tL.d(LOG_DESTROY);\n\t\t\tstop();\n\t\t\tconfiguration.diskCache.close();\n\t\t\tengine = null;\n\t\t\tconfiguration = null;\n\t\t} else {\n\t\t\tL.w(\"Trying to destroy not-initialized ImageLoader\");\n\t\t}\n\t}\n\n\tprivate static Handler defineHandler(DisplayImageOptions options) {\n\t\tHandler handler = options.getHandler();\n\t\tif (options.isSyncLoading()) {\n\t\t\thandler = null;\n\t\t} else if (handler == null && Looper.myLooper() == Looper.getMainLooper()) {\n\t\t\thandler = new Handler();\n\t\t}\n\t\treturn handler;\n\t}\n\n\t/**\n\t * Listener which is designed for synchronous image loading.\n\t *\n\t * @author Sergey Tarasevich (nostra13[at]gmail[dot]com)\n\t * @since 1.9.0\n\t */\n\tprivate static class SyncImageLoadingListener extends SimpleImageLoadingListener {\n\n\t\tprivate Bitmap loadedImage;\n\n\t\t@Override\n\t\tpublic void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) {\n\t\t\tthis.loadedImage = loadedImage;\n\t\t}\n\n\t\tpublic Bitmap getLoadedBitmap() {\n\t\t\treturn loadedImage;\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "library/src/main/java/com/nostra13/universalimageloader/core/ImageLoaderConfiguration.java",
    "content": "/*******************************************************************************\n * Copyright 2011-2014 Sergey Tarasevich\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *******************************************************************************/\npackage com.nostra13.universalimageloader.core;\n\nimport android.content.Context;\nimport android.content.res.Resources;\nimport android.util.DisplayMetrics;\nimport com.nostra13.universalimageloader.cache.disc.DiskCache;\nimport com.nostra13.universalimageloader.cache.disc.naming.FileNameGenerator;\nimport com.nostra13.universalimageloader.cache.memory.MemoryCache;\nimport com.nostra13.universalimageloader.cache.memory.impl.FuzzyKeyMemoryCache;\nimport com.nostra13.universalimageloader.core.assist.FlushedInputStream;\nimport com.nostra13.universalimageloader.core.assist.ImageSize;\nimport com.nostra13.universalimageloader.core.assist.QueueProcessingType;\nimport com.nostra13.universalimageloader.core.decode.ImageDecoder;\nimport com.nostra13.universalimageloader.core.download.ImageDownloader;\nimport com.nostra13.universalimageloader.core.process.BitmapProcessor;\nimport com.nostra13.universalimageloader.utils.L;\nimport com.nostra13.universalimageloader.utils.MemoryCacheUtils;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.util.concurrent.Executor;\n\n/**\n * Presents configuration for {@link ImageLoader}\n *\n * @author Sergey Tarasevich (nostra13[at]gmail[dot]com)\n * @see ImageLoader\n * @see MemoryCache\n * @see DiskCache\n * @see DisplayImageOptions\n * @see ImageDownloader\n * @see FileNameGenerator\n * @since 1.0.0\n */\npublic final class ImageLoaderConfiguration {\n\n\tfinal Resources resources;\n\n\tfinal int maxImageWidthForMemoryCache;\n\tfinal int maxImageHeightForMemoryCache;\n\tfinal int maxImageWidthForDiskCache;\n\tfinal int maxImageHeightForDiskCache;\n\tfinal BitmapProcessor processorForDiskCache;\n\n\tfinal Executor taskExecutor;\n\tfinal Executor taskExecutorForCachedImages;\n\tfinal boolean customExecutor;\n\tfinal boolean customExecutorForCachedImages;\n\n\tfinal int threadPoolSize;\n\tfinal int threadPriority;\n\tfinal QueueProcessingType tasksProcessingType;\n\n\tfinal MemoryCache memoryCache;\n\tfinal DiskCache diskCache;\n\tfinal ImageDownloader downloader;\n\tfinal ImageDecoder decoder;\n\tfinal DisplayImageOptions defaultDisplayImageOptions;\n\n\tfinal ImageDownloader networkDeniedDownloader;\n\tfinal ImageDownloader slowNetworkDownloader;\n\n\tprivate ImageLoaderConfiguration(final Builder builder) {\n\t\tresources = builder.context.getResources();\n\t\tmaxImageWidthForMemoryCache = builder.maxImageWidthForMemoryCache;\n\t\tmaxImageHeightForMemoryCache = builder.maxImageHeightForMemoryCache;\n\t\tmaxImageWidthForDiskCache = builder.maxImageWidthForDiskCache;\n\t\tmaxImageHeightForDiskCache = builder.maxImageHeightForDiskCache;\n\t\tprocessorForDiskCache = builder.processorForDiskCache;\n\t\ttaskExecutor = builder.taskExecutor;\n\t\ttaskExecutorForCachedImages = builder.taskExecutorForCachedImages;\n\t\tthreadPoolSize = builder.threadPoolSize;\n\t\tthreadPriority = builder.threadPriority;\n\t\ttasksProcessingType = builder.tasksProcessingType;\n\t\tdiskCache = builder.diskCache;\n\t\tmemoryCache = builder.memoryCache;\n\t\tdefaultDisplayImageOptions = builder.defaultDisplayImageOptions;\n\t\tdownloader = builder.downloader;\n\t\tdecoder = builder.decoder;\n\n\t\tcustomExecutor = builder.customExecutor;\n\t\tcustomExecutorForCachedImages = builder.customExecutorForCachedImages;\n\n\t\tnetworkDeniedDownloader = new NetworkDeniedImageDownloader(downloader);\n\t\tslowNetworkDownloader = new SlowNetworkImageDownloader(downloader);\n\n\t\tL.writeDebugLogs(builder.writeLogs);\n\t}\n\n\t/**\n\t * Creates default configuration for {@link ImageLoader} <br />\n\t * <b>Default values:</b>\n\t * <ul>\n\t * <li>maxImageWidthForMemoryCache = device's screen width</li>\n\t * <li>maxImageHeightForMemoryCache = device's screen height</li>\n\t * <li>maxImageWidthForDikcCache = unlimited</li>\n\t * <li>maxImageHeightForDiskCache = unlimited</li>\n\t * <li>threadPoolSize = {@link Builder#DEFAULT_THREAD_POOL_SIZE this}</li>\n\t * <li>threadPriority = {@link Builder#DEFAULT_THREAD_PRIORITY this}</li>\n\t * <li>allow to cache different sizes of image in memory</li>\n\t * <li>memoryCache = {@link DefaultConfigurationFactory#createMemoryCache(android.content.Context, int)}</li>\n\t * <li>diskCache = {@link com.nostra13.universalimageloader.cache.disc.impl.UnlimitedDiskCache}</li>\n\t * <li>imageDownloader = {@link DefaultConfigurationFactory#createImageDownloader(Context)}</li>\n\t * <li>imageDecoder = {@link DefaultConfigurationFactory#createImageDecoder(boolean)}</li>\n\t * <li>diskCacheFileNameGenerator = {@link DefaultConfigurationFactory#createFileNameGenerator()}</li>\n\t * <li>defaultDisplayImageOptions = {@link DisplayImageOptions#createSimple() Simple options}</li>\n\t * <li>tasksProcessingOrder = {@link QueueProcessingType#FIFO}</li>\n\t * <li>detailed logging disabled</li>\n\t * </ul>\n\t */\n\tpublic static ImageLoaderConfiguration createDefault(Context context) {\n\t\treturn new Builder(context).build();\n\t}\n\n\tImageSize getMaxImageSize() {\n\t\tDisplayMetrics displayMetrics = resources.getDisplayMetrics();\n\n\t\tint width = maxImageWidthForMemoryCache;\n\t\tif (width <= 0) {\n\t\t\twidth = displayMetrics.widthPixels;\n\t\t}\n\t\tint height = maxImageHeightForMemoryCache;\n\t\tif (height <= 0) {\n\t\t\theight = displayMetrics.heightPixels;\n\t\t}\n\t\treturn new ImageSize(width, height);\n\t}\n\n\t/**\n\t * Builder for {@link ImageLoaderConfiguration}\n\t *\n\t * @author Sergey Tarasevich (nostra13[at]gmail[dot]com)\n\t */\n\tpublic static class Builder {\n\n\t\tprivate static final String WARNING_OVERLAP_DISK_CACHE_PARAMS = \"diskCache(), diskCacheSize() and diskCacheFileCount calls overlap each other\";\n\t\tprivate static final String WARNING_OVERLAP_DISK_CACHE_NAME_GENERATOR = \"diskCache() and diskCacheFileNameGenerator() calls overlap each other\";\n\t\tprivate static final String WARNING_OVERLAP_MEMORY_CACHE = \"memoryCache() and memoryCacheSize() calls overlap each other\";\n\t\tprivate static final String WARNING_OVERLAP_EXECUTOR = \"threadPoolSize(), threadPriority() and tasksProcessingOrder() calls \"\n\t\t\t\t+ \"can overlap taskExecutor() and taskExecutorForCachedImages() calls.\";\n\n\t\t/** {@value} */\n\t\tpublic static final int DEFAULT_THREAD_POOL_SIZE = 3;\n\t\t/** {@value} */\n\t\tpublic static final int DEFAULT_THREAD_PRIORITY = Thread.NORM_PRIORITY - 2;\n\t\t/** {@value} */\n\t\tpublic static final QueueProcessingType DEFAULT_TASK_PROCESSING_TYPE = QueueProcessingType.FIFO;\n\n\t\tprivate Context context;\n\n\t\tprivate int maxImageWidthForMemoryCache = 0;\n\t\tprivate int maxImageHeightForMemoryCache = 0;\n\t\tprivate int maxImageWidthForDiskCache = 0;\n\t\tprivate int maxImageHeightForDiskCache = 0;\n\t\tprivate BitmapProcessor processorForDiskCache = null;\n\n\t\tprivate Executor taskExecutor = null;\n\t\tprivate Executor taskExecutorForCachedImages = null;\n\t\tprivate boolean customExecutor = false;\n\t\tprivate boolean customExecutorForCachedImages = false;\n\n\t\tprivate int threadPoolSize = DEFAULT_THREAD_POOL_SIZE;\n\t\tprivate int threadPriority = DEFAULT_THREAD_PRIORITY;\n\t\tprivate boolean denyCacheImageMultipleSizesInMemory = false;\n\t\tprivate QueueProcessingType tasksProcessingType = DEFAULT_TASK_PROCESSING_TYPE;\n\n\t\tprivate int memoryCacheSize = 0;\n\t\tprivate long diskCacheSize = 0;\n\t\tprivate int diskCacheFileCount = 0;\n\n\t\tprivate MemoryCache memoryCache = null;\n\t\tprivate DiskCache diskCache = null;\n\t\tprivate FileNameGenerator diskCacheFileNameGenerator = null;\n\t\tprivate ImageDownloader downloader = null;\n\t\tprivate ImageDecoder decoder;\n\t\tprivate DisplayImageOptions defaultDisplayImageOptions = null;\n\n\t\tprivate boolean writeLogs = false;\n\n\t\tpublic Builder(Context context) {\n\t\t\tthis.context = context.getApplicationContext();\n\t\t}\n\n\t\t/**\n\t\t * Sets options for memory cache\n\t\t *\n\t\t * @param maxImageWidthForMemoryCache  Maximum image width which will be used for memory saving during decoding\n\t\t *                                     an image to {@link android.graphics.Bitmap Bitmap}. <b>Default value - device's screen width</b>\n\t\t * @param maxImageHeightForMemoryCache Maximum image height which will be used for memory saving during decoding\n\t\t *                                     an image to {@link android.graphics.Bitmap Bitmap}. <b>Default value</b> - device's screen height\n\t\t */\n\t\tpublic Builder memoryCacheExtraOptions(int maxImageWidthForMemoryCache, int maxImageHeightForMemoryCache) {\n\t\t\tthis.maxImageWidthForMemoryCache = maxImageWidthForMemoryCache;\n\t\t\tthis.maxImageHeightForMemoryCache = maxImageHeightForMemoryCache;\n\t\t\treturn this;\n\t\t}\n\n\t\t/**\n\t\t * @deprecated Use\n\t\t * {@link #diskCacheExtraOptions(int, int, com.nostra13.universalimageloader.core.process.BitmapProcessor)}\n\t\t * instead\n\t\t */\n\t\t@Deprecated\n\t\tpublic Builder discCacheExtraOptions(int maxImageWidthForDiskCache, int maxImageHeightForDiskCache,\n\t\t\t\tBitmapProcessor processorForDiskCache) {\n\t\t\treturn diskCacheExtraOptions(maxImageWidthForDiskCache, maxImageHeightForDiskCache, processorForDiskCache);\n\t\t}\n\n\t\t/**\n\t\t * Sets options for resizing/compressing of downloaded images before saving to disk cache.<br />\n\t\t * <b>NOTE: Use this option only when you have appropriate needs. It can make ImageLoader slower.</b>\n\t\t *\n\t\t * @param maxImageWidthForDiskCache  Maximum width of downloaded images for saving at disk cache\n\t\t * @param maxImageHeightForDiskCache Maximum height of downloaded images for saving at disk cache\n\t\t * @param processorForDiskCache      null-ok; {@linkplain BitmapProcessor Bitmap processor} which process images before saving them in disc cache\n\t\t */\n\t\tpublic Builder diskCacheExtraOptions(int maxImageWidthForDiskCache, int maxImageHeightForDiskCache,\n\t\t\t\tBitmapProcessor processorForDiskCache) {\n\t\t\tthis.maxImageWidthForDiskCache = maxImageWidthForDiskCache;\n\t\t\tthis.maxImageHeightForDiskCache = maxImageHeightForDiskCache;\n\t\t\tthis.processorForDiskCache = processorForDiskCache;\n\t\t\treturn this;\n\t\t}\n\n\t\t/**\n\t\t * Sets custom {@linkplain Executor executor} for tasks of loading and displaying images.<br />\n\t\t * <br />\n\t\t * <b>NOTE:</b> If you set custom executor then following configuration options will not be considered for this\n\t\t * executor:\n\t\t * <ul>\n\t\t * <li>{@link #threadPoolSize(int)}</li>\n\t\t * <li>{@link #threadPriority(int)}</li>\n\t\t * <li>{@link #tasksProcessingOrder(QueueProcessingType)}</li>\n\t\t * </ul>\n\t\t *\n\t\t * @see #taskExecutorForCachedImages(Executor)\n\t\t */\n\t\tpublic Builder taskExecutor(Executor executor) {\n\t\t\tif (threadPoolSize != DEFAULT_THREAD_POOL_SIZE || threadPriority != DEFAULT_THREAD_PRIORITY || tasksProcessingType != DEFAULT_TASK_PROCESSING_TYPE) {\n\t\t\t\tL.w(WARNING_OVERLAP_EXECUTOR);\n\t\t\t}\n\n\t\t\tthis.taskExecutor = executor;\n\t\t\treturn this;\n\t\t}\n\n\t\t/**\n\t\t * Sets custom {@linkplain Executor executor} for tasks of displaying <b>cached on disk</b> images (these tasks\n\t\t * are executed quickly so UIL prefer to use separate executor for them).<br />\n\t\t * <br />\n\t\t * If you set the same executor for {@linkplain #taskExecutor(Executor) general tasks} and\n\t\t * tasks about cached images (this method) then these tasks will be in the\n\t\t * same thread pool. So short-lived tasks can wait a long time for their turn.<br />\n\t\t * <br />\n\t\t * <b>NOTE:</b> If you set custom executor then following configuration options will not be considered for this\n\t\t * executor:\n\t\t * <ul>\n\t\t * <li>{@link #threadPoolSize(int)}</li>\n\t\t * <li>{@link #threadPriority(int)}</li>\n\t\t * <li>{@link #tasksProcessingOrder(QueueProcessingType)}</li>\n\t\t * </ul>\n\t\t *\n\t\t * @see #taskExecutor(Executor)\n\t\t */\n\t\tpublic Builder taskExecutorForCachedImages(Executor executorForCachedImages) {\n\t\t\tif (threadPoolSize != DEFAULT_THREAD_POOL_SIZE || threadPriority != DEFAULT_THREAD_PRIORITY || tasksProcessingType != DEFAULT_TASK_PROCESSING_TYPE) {\n\t\t\t\tL.w(WARNING_OVERLAP_EXECUTOR);\n\t\t\t}\n\n\t\t\tthis.taskExecutorForCachedImages = executorForCachedImages;\n\t\t\treturn this;\n\t\t}\n\n\t\t/**\n\t\t * Sets thread pool size for image display tasks.<br />\n\t\t * Default value - {@link #DEFAULT_THREAD_POOL_SIZE this}\n\t\t */\n\t\tpublic Builder threadPoolSize(int threadPoolSize) {\n\t\t\tif (taskExecutor != null || taskExecutorForCachedImages != null) {\n\t\t\t\tL.w(WARNING_OVERLAP_EXECUTOR);\n\t\t\t}\n\n\t\t\tthis.threadPoolSize = threadPoolSize;\n\t\t\treturn this;\n\t\t}\n\n\t\t/**\n\t\t * Sets the priority for image loading threads. Should be <b>NOT</b> greater than {@link Thread#MAX_PRIORITY} or\n\t\t * less than {@link Thread#MIN_PRIORITY}<br />\n\t\t * Default value - {@link #DEFAULT_THREAD_PRIORITY this}\n\t\t */\n\t\tpublic Builder threadPriority(int threadPriority) {\n\t\t\tif (taskExecutor != null || taskExecutorForCachedImages != null) {\n\t\t\t\tL.w(WARNING_OVERLAP_EXECUTOR);\n\t\t\t}\n\n\t\t\tif (threadPriority < Thread.MIN_PRIORITY) {\n\t\t\t\tthis.threadPriority = Thread.MIN_PRIORITY;\n\t\t\t} else {\n\t\t\t\tif (threadPriority > Thread.MAX_PRIORITY) {\n\t\t\t\t\tthis.threadPriority = Thread.MAX_PRIORITY;\n\t\t\t\t} else {\n\t\t\t\t\tthis.threadPriority = threadPriority;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn this;\n\t\t}\n\n\t\t/**\n\t\t * When you display an image in a small {@link android.widget.ImageView ImageView} and later you try to display\n\t\t * this image (from identical URI) in a larger {@link android.widget.ImageView ImageView} so decoded image of\n\t\t * bigger size will be cached in memory as a previous decoded image of smaller size.<br />\n\t\t * So <b>the default behavior is to allow to cache multiple sizes of one image in memory</b>. You can\n\t\t * <b>deny</b> it by calling <b>this</b> method: so when some image will be cached in memory then previous\n\t\t * cached size of this image (if it exists) will be removed from memory cache before.\n\t\t */\n\t\tpublic Builder denyCacheImageMultipleSizesInMemory() {\n\t\t\tthis.denyCacheImageMultipleSizesInMemory = true;\n\t\t\treturn this;\n\t\t}\n\n\t\t/**\n\t\t * Sets type of queue processing for tasks for loading and displaying images.<br />\n\t\t * Default value - {@link QueueProcessingType#FIFO}\n\t\t */\n\t\tpublic Builder tasksProcessingOrder(QueueProcessingType tasksProcessingType) {\n\t\t\tif (taskExecutor != null || taskExecutorForCachedImages != null) {\n\t\t\t\tL.w(WARNING_OVERLAP_EXECUTOR);\n\t\t\t}\n\n\t\t\tthis.tasksProcessingType = tasksProcessingType;\n\t\t\treturn this;\n\t\t}\n\n\t\t/**\n\t\t * Sets maximum memory cache size for {@link android.graphics.Bitmap bitmaps} (in bytes).<br />\n\t\t * Default value - 1/8 of available app memory.<br />\n\t\t * <b>NOTE:</b> If you use this method then\n\t\t * {@link com.nostra13.universalimageloader.cache.memory.impl.LruMemoryCache LruMemoryCache} will be used as\n\t\t * memory cache. You can use {@link #memoryCache(MemoryCache)} method to set your own implementation of\n\t\t * {@link MemoryCache}.\n\t\t */\n\t\tpublic Builder memoryCacheSize(int memoryCacheSize) {\n\t\t\tif (memoryCacheSize <= 0) throw new IllegalArgumentException(\"memoryCacheSize must be a positive number\");\n\n\t\t\tif (memoryCache != null) {\n\t\t\t\tL.w(WARNING_OVERLAP_MEMORY_CACHE);\n\t\t\t}\n\n\t\t\tthis.memoryCacheSize = memoryCacheSize;\n\t\t\treturn this;\n\t\t}\n\n\t\t/**\n\t\t * Sets maximum memory cache size (in percent of available app memory) for {@link android.graphics.Bitmap\n\t\t * bitmaps}.<br />\n\t\t * Default value - 1/8 of available app memory.<br />\n\t\t * <b>NOTE:</b> If you use this method then\n\t\t * {@link com.nostra13.universalimageloader.cache.memory.impl.LruMemoryCache LruMemoryCache} will be used as\n\t\t * memory cache. You can use {@link #memoryCache(MemoryCache)} method to set your own implementation of\n\t\t * {@link MemoryCache}.\n\t\t */\n\t\tpublic Builder memoryCacheSizePercentage(int availableMemoryPercent) {\n\t\t\tif (availableMemoryPercent <= 0 || availableMemoryPercent >= 100) {\n\t\t\t\tthrow new IllegalArgumentException(\"availableMemoryPercent must be in range (0 < % < 100)\");\n\t\t\t}\n\n\t\t\tif (memoryCache != null) {\n\t\t\t\tL.w(WARNING_OVERLAP_MEMORY_CACHE);\n\t\t\t}\n\n\t\t\tlong availableMemory = Runtime.getRuntime().maxMemory();\n\t\t\tmemoryCacheSize = (int) (availableMemory * (availableMemoryPercent / 100f));\n\t\t\treturn this;\n\t\t}\n\n\t\t/**\n\t\t * Sets memory cache for {@link android.graphics.Bitmap bitmaps}.<br />\n\t\t * Default value - {@link com.nostra13.universalimageloader.cache.memory.impl.LruMemoryCache LruMemoryCache}\n\t\t * with limited memory cache size (size = 1/8 of available app memory)<br />\n\t\t * <br />\n\t\t * <b>NOTE:</b> If you set custom memory cache then following configuration option will not be considered:\n\t\t * <ul>\n\t\t * <li>{@link #memoryCacheSize(int)}</li>\n\t\t * </ul>\n\t\t */\n\t\tpublic Builder memoryCache(MemoryCache memoryCache) {\n\t\t\tif (memoryCacheSize != 0) {\n\t\t\t\tL.w(WARNING_OVERLAP_MEMORY_CACHE);\n\t\t\t}\n\n\t\t\tthis.memoryCache = memoryCache;\n\t\t\treturn this;\n\t\t}\n\n\t\t/** @deprecated Use {@link #diskCacheSize(int)} instead */\n\t\t@Deprecated\n\t\tpublic Builder discCacheSize(int maxCacheSize) {\n\t\t\treturn diskCacheSize(maxCacheSize);\n\t\t}\n\n\t\t/**\n\t\t * Sets maximum disk cache size for images (in bytes).<br />\n\t\t * By default: disk cache is unlimited.<br />\n\t\t * <b>NOTE:</b> If you use this method then\n\t\t * {@link com.nostra13.universalimageloader.cache.disc.impl.ext.LruDiskCache LruDiskCache}\n\t\t * will be used as disk cache. You can use {@link #diskCache(DiskCache)} method for introduction your own\n\t\t * implementation of {@link DiskCache}\n\t\t */\n\t\tpublic Builder diskCacheSize(int maxCacheSize) {\n\t\t\tif (maxCacheSize <= 0) throw new IllegalArgumentException(\"maxCacheSize must be a positive number\");\n\n\t\t\tif (diskCache != null) {\n\t\t\t\tL.w(WARNING_OVERLAP_DISK_CACHE_PARAMS);\n\t\t\t}\n\n\t\t\tthis.diskCacheSize = maxCacheSize;\n\t\t\treturn this;\n\t\t}\n\n\t\t/** @deprecated Use {@link #diskCacheFileCount(int)} instead */\n\t\t@Deprecated\n\t\tpublic Builder discCacheFileCount(int maxFileCount) {\n\t\t\treturn diskCacheFileCount(maxFileCount);\n\t\t}\n\n\t\t/**\n\t\t * Sets maximum file count in disk cache directory.<br />\n\t\t * By default: disk cache is unlimited.<br />\n\t\t * <b>NOTE:</b> If you use this method then\n\t\t * {@link com.nostra13.universalimageloader.cache.disc.impl.ext.LruDiskCache LruDiskCache}\n\t\t * will be used as disk cache. You can use {@link #diskCache(DiskCache)} method for introduction your own\n\t\t * implementation of {@link DiskCache}\n\t\t */\n\t\tpublic Builder diskCacheFileCount(int maxFileCount) {\n\t\t\tif (maxFileCount <= 0) throw new IllegalArgumentException(\"maxFileCount must be a positive number\");\n\n\t\t\tif (diskCache != null) {\n\t\t\t\tL.w(WARNING_OVERLAP_DISK_CACHE_PARAMS);\n\t\t\t}\n\n\t\t\tthis.diskCacheFileCount = maxFileCount;\n\t\t\treturn this;\n\t\t}\n\n\t\t/** @deprecated Use {@link #diskCacheFileNameGenerator(com.nostra13.universalimageloader.cache.disc.naming.FileNameGenerator)} */\n\t\t@Deprecated\n\t\tpublic Builder discCacheFileNameGenerator(FileNameGenerator fileNameGenerator) {\n\t\t\treturn diskCacheFileNameGenerator(fileNameGenerator);\n\t\t}\n\n\t\t/**\n\t\t * Sets name generator for files cached in disk cache.<br />\n\t\t * Default value -\n\t\t * {@link com.nostra13.universalimageloader.core.DefaultConfigurationFactory#createFileNameGenerator()\n\t\t * DefaultConfigurationFactory.createFileNameGenerator()}\n\t\t */\n\t\tpublic Builder diskCacheFileNameGenerator(FileNameGenerator fileNameGenerator) {\n\t\t\tif (diskCache != null) {\n\t\t\t\tL.w(WARNING_OVERLAP_DISK_CACHE_NAME_GENERATOR);\n\t\t\t}\n\n\t\t\tthis.diskCacheFileNameGenerator = fileNameGenerator;\n\t\t\treturn this;\n\t\t}\n\n\t\t/** @deprecated Use {@link #diskCache(com.nostra13.universalimageloader.cache.disc.DiskCache)} */\n\t\t@Deprecated\n\t\tpublic Builder discCache(DiskCache diskCache) {\n\t\t\treturn diskCache(diskCache);\n\t\t}\n\n\t\t/**\n\t\t * Sets disk cache for images.<br />\n\t\t * Default value - {@link com.nostra13.universalimageloader.cache.disc.impl.UnlimitedDiskCache\n\t\t * UnlimitedDiskCache}. Cache directory is defined by\n\t\t * {@link com.nostra13.universalimageloader.utils.StorageUtils#getCacheDirectory(Context)\n\t\t * StorageUtils.getCacheDirectory(Context)}.<br />\n\t\t * <br />\n\t\t * <b>NOTE:</b> If you set custom disk cache then following configuration option will not be considered:\n\t\t * <ul>\n\t\t * <li>{@link #diskCacheSize(int)}</li>\n\t\t * <li>{@link #diskCacheFileCount(int)}</li>\n\t\t * <li>{@link #diskCacheFileNameGenerator(FileNameGenerator)}</li>\n\t\t * </ul>\n\t\t */\n\t\tpublic Builder diskCache(DiskCache diskCache) {\n\t\t\tif (diskCacheSize > 0 || diskCacheFileCount > 0) {\n\t\t\t\tL.w(WARNING_OVERLAP_DISK_CACHE_PARAMS);\n\t\t\t}\n\t\t\tif (diskCacheFileNameGenerator != null) {\n\t\t\t\tL.w(WARNING_OVERLAP_DISK_CACHE_NAME_GENERATOR);\n\t\t\t}\n\n\t\t\tthis.diskCache = diskCache;\n\t\t\treturn this;\n\t\t}\n\n\t\t/**\n\t\t * Sets utility which will be responsible for downloading of image.<br />\n\t\t * Default value -\n\t\t * {@link com.nostra13.universalimageloader.core.DefaultConfigurationFactory#createImageDownloader(Context)\n\t\t * DefaultConfigurationFactory.createImageDownloader()}\n\t\t */\n\t\tpublic Builder imageDownloader(ImageDownloader imageDownloader) {\n\t\t\tthis.downloader = imageDownloader;\n\t\t\treturn this;\n\t\t}\n\n\t\t/**\n\t\t * Sets utility which will be responsible for decoding of image stream.<br />\n\t\t * Default value -\n\t\t * {@link com.nostra13.universalimageloader.core.DefaultConfigurationFactory#createImageDecoder(boolean)\n\t\t * DefaultConfigurationFactory.createImageDecoder()}\n\t\t */\n\t\tpublic Builder imageDecoder(ImageDecoder imageDecoder) {\n\t\t\tthis.decoder = imageDecoder;\n\t\t\treturn this;\n\t\t}\n\n\t\t/**\n\t\t * Sets default {@linkplain DisplayImageOptions display image options} for image displaying. These options will\n\t\t * be used for every {@linkplain ImageLoader#displayImage(String, android.widget.ImageView) image display call}\n\t\t * without passing custom {@linkplain DisplayImageOptions options}<br />\n\t\t * Default value - {@link DisplayImageOptions#createSimple() Simple options}\n\t\t */\n\t\tpublic Builder defaultDisplayImageOptions(DisplayImageOptions defaultDisplayImageOptions) {\n\t\t\tthis.defaultDisplayImageOptions = defaultDisplayImageOptions;\n\t\t\treturn this;\n\t\t}\n\n\t\t/**\n\t\t * Enables detail logging of {@link ImageLoader} work. To prevent detail logs don't call this method.\n\t\t * Consider {@link com.nostra13.universalimageloader.utils.L#disableLogging()} to disable\n\t\t * ImageLoader logging completely (even error logs)\n\t\t */\n\t\tpublic Builder writeDebugLogs() {\n\t\t\tthis.writeLogs = true;\n\t\t\treturn this;\n\t\t}\n\n\t\t/** Builds configured {@link ImageLoaderConfiguration} object */\n\t\tpublic ImageLoaderConfiguration build() {\n\t\t\tinitEmptyFieldsWithDefaultValues();\n\t\t\treturn new ImageLoaderConfiguration(this);\n\t\t}\n\n\t\tprivate void initEmptyFieldsWithDefaultValues() {\n\t\t\tif (taskExecutor == null) {\n\t\t\t\ttaskExecutor = DefaultConfigurationFactory\n\t\t\t\t\t\t.createExecutor(threadPoolSize, threadPriority, tasksProcessingType);\n\t\t\t} else {\n\t\t\t\tcustomExecutor = true;\n\t\t\t}\n\t\t\tif (taskExecutorForCachedImages == null) {\n\t\t\t\ttaskExecutorForCachedImages = DefaultConfigurationFactory\n\t\t\t\t\t\t.createExecutor(threadPoolSize, threadPriority, tasksProcessingType);\n\t\t\t} else {\n\t\t\t\tcustomExecutorForCachedImages = true;\n\t\t\t}\n\t\t\tif (diskCache == null) {\n\t\t\t\tif (diskCacheFileNameGenerator == null) {\n\t\t\t\t\tdiskCacheFileNameGenerator = DefaultConfigurationFactory.createFileNameGenerator();\n\t\t\t\t}\n\t\t\t\tdiskCache = DefaultConfigurationFactory\n\t\t\t\t\t\t.createDiskCache(context, diskCacheFileNameGenerator, diskCacheSize, diskCacheFileCount);\n\t\t\t}\n\t\t\tif (memoryCache == null) {\n\t\t\t\tmemoryCache = DefaultConfigurationFactory.createMemoryCache(context, memoryCacheSize);\n\t\t\t}\n\t\t\tif (denyCacheImageMultipleSizesInMemory) {\n\t\t\t\tmemoryCache = new FuzzyKeyMemoryCache(memoryCache, MemoryCacheUtils.createFuzzyKeyComparator());\n\t\t\t}\n\t\t\tif (downloader == null) {\n\t\t\t\tdownloader = DefaultConfigurationFactory.createImageDownloader(context);\n\t\t\t}\n\t\t\tif (decoder == null) {\n\t\t\t\tdecoder = DefaultConfigurationFactory.createImageDecoder(writeLogs);\n\t\t\t}\n\t\t\tif (defaultDisplayImageOptions == null) {\n\t\t\t\tdefaultDisplayImageOptions = DisplayImageOptions.createSimple();\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Decorator. Prevents downloads from network (throws {@link IllegalStateException exception}).<br />\n\t * In most cases this downloader shouldn't be used directly.\n\t *\n\t * @author Sergey Tarasevich (nostra13[at]gmail[dot]com)\n\t * @since 1.8.0\n\t */\n\tprivate static class NetworkDeniedImageDownloader implements ImageDownloader {\n\n\t\tprivate final ImageDownloader wrappedDownloader;\n\n\t\tpublic NetworkDeniedImageDownloader(ImageDownloader wrappedDownloader) {\n\t\t\tthis.wrappedDownloader = wrappedDownloader;\n\t\t}\n\n\t\t@Override\n\t\tpublic InputStream getStream(String imageUri, Object extra) throws IOException {\n\t\t\tswitch (Scheme.ofUri(imageUri)) {\n\t\t\t\tcase HTTP:\n\t\t\t\tcase HTTPS:\n\t\t\t\t\tthrow new IllegalStateException();\n\t\t\t\tdefault:\n\t\t\t\t\treturn wrappedDownloader.getStream(imageUri, extra);\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Decorator. Handles <a href=\"http://code.google.com/p/android/issues/detail?id=6066\">this problem</a> on slow networks\n\t * using {@link com.nostra13.universalimageloader.core.assist.FlushedInputStream}.\n\t *\n\t * @author Sergey Tarasevich (nostra13[at]gmail[dot]com)\n\t * @since 1.8.1\n\t */\n\tprivate static class SlowNetworkImageDownloader implements ImageDownloader {\n\n\t\tprivate final ImageDownloader wrappedDownloader;\n\n\t\tpublic SlowNetworkImageDownloader(ImageDownloader wrappedDownloader) {\n\t\t\tthis.wrappedDownloader = wrappedDownloader;\n\t\t}\n\n\t\t@Override\n\t\tpublic InputStream getStream(String imageUri, Object extra) throws IOException {\n\t\t\tInputStream imageStream = wrappedDownloader.getStream(imageUri, extra);\n\t\t\tswitch (Scheme.ofUri(imageUri)) {\n\t\t\t\tcase HTTP:\n\t\t\t\tcase HTTPS:\n\t\t\t\t\treturn new FlushedInputStream(imageStream);\n\t\t\t\tdefault:\n\t\t\t\t\treturn imageStream;\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "library/src/main/java/com/nostra13/universalimageloader/core/ImageLoaderEngine.java",
    "content": "/*******************************************************************************\n * Copyright 2011-2014 Sergey Tarasevich\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *******************************************************************************/\npackage com.nostra13.universalimageloader.core;\n\nimport android.view.View;\nimport com.nostra13.universalimageloader.core.assist.FailReason;\nimport com.nostra13.universalimageloader.core.assist.FlushedInputStream;\nimport com.nostra13.universalimageloader.core.imageaware.ImageAware;\nimport com.nostra13.universalimageloader.core.listener.ImageLoadingListener;\n\nimport java.io.File;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.WeakHashMap;\nimport java.util.concurrent.Executor;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.atomic.AtomicBoolean;\nimport java.util.concurrent.locks.ReentrantLock;\n\nimport static com.nostra13.universalimageloader.core.download.ImageDownloader.*;\n\n/**\n * {@link ImageLoader} engine which responsible for {@linkplain LoadAndDisplayImageTask display task} execution.\n *\n * @author Sergey Tarasevich (nostra13[at]gmail[dot]com)\n * @since 1.7.1\n */\nclass ImageLoaderEngine {\n\n\tfinal ImageLoaderConfiguration configuration;\n\n\tprivate Executor taskExecutor;\n\tprivate Executor taskExecutorForCachedImages;\n\tprivate Executor taskDistributor;\n\n\tprivate final Map<Integer, String> cacheKeysForImageAwares = Collections\n\t\t\t.synchronizedMap(new HashMap<Integer, String>());\n\tprivate final Map<String, ReentrantLock> uriLocks = new WeakHashMap<String, ReentrantLock>();\n\n\tprivate final AtomicBoolean paused = new AtomicBoolean(false);\n\tprivate final AtomicBoolean networkDenied = new AtomicBoolean(false);\n\tprivate final AtomicBoolean slowNetwork = new AtomicBoolean(false);\n\n\tprivate final Object pauseLock = new Object();\n\n\tImageLoaderEngine(ImageLoaderConfiguration configuration) {\n\t\tthis.configuration = configuration;\n\n\t\ttaskExecutor = configuration.taskExecutor;\n\t\ttaskExecutorForCachedImages = configuration.taskExecutorForCachedImages;\n\n\t\ttaskDistributor = DefaultConfigurationFactory.createTaskDistributor();\n\t}\n\n\t/** Submits task to execution pool */\n\tvoid submit(final LoadAndDisplayImageTask task) {\n\t\ttaskDistributor.execute(new Runnable() {\n\t\t\t@Override\n\t\t\tpublic void run() {\n\t\t\t\tFile image = configuration.diskCache.get(task.getLoadingUri());\n\t\t\t\tboolean isImageCachedOnDisk = image != null && image.exists()\n\t\t\t\t\t\t|| isLocalUri(task.getLoadingUri());\n\t\t\t\tinitExecutorsIfNeed();\n\t\t\t\tif (isImageCachedOnDisk) {\n\t\t\t\t\ttaskExecutorForCachedImages.execute(task);\n\t\t\t\t} else {\n\t\t\t\t\ttaskExecutor.execute(task);\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t}\n\n\t/** Submits task to execution pool */\n\tvoid submit(ProcessAndDisplayImageTask task) {\n\t\tinitExecutorsIfNeed();\n\t\ttaskExecutorForCachedImages.execute(task);\n\t}\n\n\tprivate boolean isLocalUri(String uri) {\n\t\tScheme scheme = Scheme.ofUri(uri);\n\t\treturn scheme == Scheme.ASSETS || scheme == Scheme.FILE || scheme == Scheme.DRAWABLE;\n\t}\n\n\tprivate void initExecutorsIfNeed() {\n\t\tif (!configuration.customExecutor && ((ExecutorService) taskExecutor).isShutdown()) {\n\t\t\ttaskExecutor = createTaskExecutor();\n\t\t}\n\t\tif (!configuration.customExecutorForCachedImages && ((ExecutorService) taskExecutorForCachedImages)\n\t\t\t\t.isShutdown()) {\n\t\t\ttaskExecutorForCachedImages = createTaskExecutor();\n\t\t}\n\t}\n\n\tprivate Executor createTaskExecutor() {\n\t\treturn DefaultConfigurationFactory\n\t\t\t\t.createExecutor(configuration.threadPoolSize, configuration.threadPriority,\n\t\t\t\tconfiguration.tasksProcessingType);\n\t}\n\n\t/**\n\t * Returns URI of image which is loading at this moment into passed {@link com.nostra13.universalimageloader.core.imageaware.ImageAware}\n\t */\n\tString getLoadingUriForView(ImageAware imageAware) {\n\t\treturn cacheKeysForImageAwares.get(imageAware.getId());\n\t}\n\n\t/**\n\t * Associates <b>memoryCacheKey</b> with <b>imageAware</b>. Then it helps to define image URI is loaded into View at\n\t * exact moment.\n\t */\n\tvoid prepareDisplayTaskFor(ImageAware imageAware, String memoryCacheKey) {\n\t\tcacheKeysForImageAwares.put(imageAware.getId(), memoryCacheKey);\n\t}\n\n\t/**\n\t * Cancels the task of loading and displaying image for incoming <b>imageAware</b>.\n\t *\n\t * @param imageAware {@link com.nostra13.universalimageloader.core.imageaware.ImageAware} for which display task\n\t *                   will be cancelled\n\t */\n\tvoid cancelDisplayTaskFor(ImageAware imageAware) {\n\t\tcacheKeysForImageAwares.remove(imageAware.getId());\n\t}\n\n\t/**\n\t * Denies or allows engine to download images from the network.<br /> <br /> If downloads are denied and if image\n\t * isn't cached then {@link ImageLoadingListener#onLoadingFailed(String, View, FailReason)} callback will be fired\n\t * with {@link FailReason.FailType#NETWORK_DENIED}\n\t *\n\t * @param denyNetworkDownloads pass <b>true</b> - to deny engine to download images from the network; <b>false</b> -\n\t *                             to allow engine to download images from network.\n\t */\n\tvoid denyNetworkDownloads(boolean denyNetworkDownloads) {\n\t\tnetworkDenied.set(denyNetworkDownloads);\n\t}\n\n\t/**\n\t * Sets option whether ImageLoader will use {@link FlushedInputStream} for network downloads to handle <a\n\t * href=\"http://code.google.com/p/android/issues/detail?id=6066\">this known problem</a> or not.\n\t *\n\t * @param handleSlowNetwork pass <b>true</b> - to use {@link FlushedInputStream} for network downloads; <b>false</b>\n\t *                          - otherwise.\n\t */\n\tvoid handleSlowNetwork(boolean handleSlowNetwork) {\n\t\tslowNetwork.set(handleSlowNetwork);\n\t}\n\n\t/**\n\t * Pauses engine. All new \"load&display\" tasks won't be executed until ImageLoader is {@link #resume() resumed}.<br\n\t * /> Already running tasks are not paused.\n\t */\n\tvoid pause() {\n\t\tpaused.set(true);\n\t}\n\n\t/** Resumes engine work. Paused \"load&display\" tasks will continue its work. */\n\tvoid resume() {\n\t\tpaused.set(false);\n\t\tsynchronized (pauseLock) {\n\t\t\tpauseLock.notifyAll();\n\t\t}\n\t}\n\n\t/**\n\t * Stops engine, cancels all running and scheduled display image tasks. Clears internal data.\n\t * <br />\n\t * <b>NOTE:</b> This method doesn't shutdown\n\t * {@linkplain com.nostra13.universalimageloader.core.ImageLoaderConfiguration.Builder#taskExecutor(java.util.concurrent.Executor)\n\t * custom task executors} if you set them.\n\t */\n\tvoid stop() {\n\t\tif (!configuration.customExecutor) {\n\t\t\t((ExecutorService) taskExecutor).shutdownNow();\n\t\t}\n\t\tif (!configuration.customExecutorForCachedImages) {\n\t\t\t((ExecutorService) taskExecutorForCachedImages).shutdownNow();\n\t\t}\n\n\t\tcacheKeysForImageAwares.clear();\n\t\turiLocks.clear();\n\t}\n\n\tvoid fireCallback(Runnable r) {\n\t\ttaskDistributor.execute(r);\n\t}\n\n\tReentrantLock getLockForUri(String uri) {\n\t\tReentrantLock lock = uriLocks.get(uri);\n\t\tif (lock == null) {\n\t\t\tlock = new ReentrantLock();\n\t\t\turiLocks.put(uri, lock);\n\t\t}\n\t\treturn lock;\n\t}\n\n\tAtomicBoolean getPause() {\n\t\treturn paused;\n\t}\n\n\tObject getPauseLock() {\n\t\treturn pauseLock;\n\t}\n\n\tboolean isNetworkDenied() {\n\t\treturn networkDenied.get();\n\t}\n\n\tboolean isSlowNetwork() {\n\t\treturn slowNetwork.get();\n\t}\n}\n"
  },
  {
    "path": "library/src/main/java/com/nostra13/universalimageloader/core/ImageLoadingInfo.java",
    "content": "/*******************************************************************************\n * Copyright 2011-2013 Sergey Tarasevich\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *******************************************************************************/\npackage com.nostra13.universalimageloader.core;\n\nimport com.nostra13.universalimageloader.core.listener.ImageLoadingListener;\nimport com.nostra13.universalimageloader.core.listener.ImageLoadingProgressListener;\nimport com.nostra13.universalimageloader.core.assist.ImageSize;\nimport com.nostra13.universalimageloader.core.imageaware.ImageAware;\n\nimport java.util.concurrent.locks.ReentrantLock;\n\n/**\n * Information for load'n'display image task\n *\n * @author Sergey Tarasevich (nostra13[at]gmail[dot]com)\n * @see com.nostra13.universalimageloader.utils.MemoryCacheUtils\n * @see DisplayImageOptions\n * @see ImageLoadingListener\n * @see com.nostra13.universalimageloader.core.listener.ImageLoadingProgressListener\n * @since 1.3.1\n */\nfinal class ImageLoadingInfo {\n\n\tfinal String uri;\n\tfinal String memoryCacheKey;\n\tfinal ImageAware imageAware;\n\tfinal ImageSize targetSize;\n\tfinal DisplayImageOptions options;\n\tfinal ImageLoadingListener listener;\n\tfinal ImageLoadingProgressListener progressListener;\n\tfinal ReentrantLock loadFromUriLock;\n\n\tpublic ImageLoadingInfo(String uri, ImageAware imageAware, ImageSize targetSize, String memoryCacheKey,\n\t\t\tDisplayImageOptions options, ImageLoadingListener listener,\n\t\t\tImageLoadingProgressListener progressListener, ReentrantLock loadFromUriLock) {\n\t\tthis.uri = uri;\n\t\tthis.imageAware = imageAware;\n\t\tthis.targetSize = targetSize;\n\t\tthis.options = options;\n\t\tthis.listener = listener;\n\t\tthis.progressListener = progressListener;\n\t\tthis.loadFromUriLock = loadFromUriLock;\n\t\tthis.memoryCacheKey = memoryCacheKey;\n\t}\n}\n"
  },
  {
    "path": "library/src/main/java/com/nostra13/universalimageloader/core/LoadAndDisplayImageTask.java",
    "content": "/*******************************************************************************\n * Copyright 2011-2014 Sergey Tarasevich\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *******************************************************************************/\npackage com.nostra13.universalimageloader.core;\n\nimport android.graphics.Bitmap;\nimport android.os.Handler;\nimport com.nostra13.universalimageloader.core.assist.FailReason;\nimport com.nostra13.universalimageloader.core.assist.FailReason.FailType;\nimport com.nostra13.universalimageloader.core.assist.ImageScaleType;\nimport com.nostra13.universalimageloader.core.assist.ImageSize;\nimport com.nostra13.universalimageloader.core.assist.LoadedFrom;\nimport com.nostra13.universalimageloader.core.assist.ViewScaleType;\nimport com.nostra13.universalimageloader.core.decode.ImageDecoder;\nimport com.nostra13.universalimageloader.core.decode.ImageDecodingInfo;\nimport com.nostra13.universalimageloader.core.download.ImageDownloader;\nimport com.nostra13.universalimageloader.core.download.ImageDownloader.Scheme;\nimport com.nostra13.universalimageloader.core.imageaware.ImageAware;\nimport com.nostra13.universalimageloader.core.listener.ImageLoadingListener;\nimport com.nostra13.universalimageloader.core.listener.ImageLoadingProgressListener;\nimport com.nostra13.universalimageloader.utils.IoUtils;\nimport com.nostra13.universalimageloader.utils.L;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.util.concurrent.atomic.AtomicBoolean;\nimport java.util.concurrent.locks.ReentrantLock;\n\n/**\n * Presents load'n'display image task. Used to load image from Internet or file system, decode it to {@link Bitmap}, and\n * display it in {@link com.nostra13.universalimageloader.core.imageaware.ImageAware} using {@link DisplayBitmapTask}.\n *\n * @author Sergey Tarasevich (nostra13[at]gmail[dot]com)\n * @see ImageLoaderConfiguration\n * @see ImageLoadingInfo\n * @since 1.3.1\n */\nfinal class LoadAndDisplayImageTask implements Runnable, IoUtils.CopyListener {\n\n\tprivate static final String LOG_WAITING_FOR_RESUME = \"ImageLoader is paused. Waiting...  [%s]\";\n\tprivate static final String LOG_RESUME_AFTER_PAUSE = \".. Resume loading [%s]\";\n\tprivate static final String LOG_DELAY_BEFORE_LOADING = \"Delay %d ms before loading...  [%s]\";\n\tprivate static final String LOG_START_DISPLAY_IMAGE_TASK = \"Start display image task [%s]\";\n\tprivate static final String LOG_WAITING_FOR_IMAGE_LOADED = \"Image already is loading. Waiting... [%s]\";\n\tprivate static final String LOG_GET_IMAGE_FROM_MEMORY_CACHE_AFTER_WAITING = \"...Get cached bitmap from memory after waiting. [%s]\";\n\tprivate static final String LOG_LOAD_IMAGE_FROM_NETWORK = \"Load image from network [%s]\";\n\tprivate static final String LOG_LOAD_IMAGE_FROM_DISK_CACHE = \"Load image from disk cache [%s]\";\n\tprivate static final String LOG_RESIZE_CACHED_IMAGE_FILE = \"Resize image in disk cache [%s]\";\n\tprivate static final String LOG_PREPROCESS_IMAGE = \"PreProcess image before caching in memory [%s]\";\n\tprivate static final String LOG_POSTPROCESS_IMAGE = \"PostProcess image before displaying [%s]\";\n\tprivate static final String LOG_CACHE_IMAGE_IN_MEMORY = \"Cache image in memory [%s]\";\n\tprivate static final String LOG_CACHE_IMAGE_ON_DISK = \"Cache image on disk [%s]\";\n\tprivate static final String LOG_PROCESS_IMAGE_BEFORE_CACHE_ON_DISK = \"Process image before cache on disk [%s]\";\n\tprivate static final String LOG_TASK_CANCELLED_IMAGEAWARE_REUSED = \"ImageAware is reused for another image. Task is cancelled. [%s]\";\n\tprivate static final String LOG_TASK_CANCELLED_IMAGEAWARE_COLLECTED = \"ImageAware was collected by GC. Task is cancelled. [%s]\";\n\tprivate static final String LOG_TASK_INTERRUPTED = \"Task was interrupted [%s]\";\n\n\tprivate static final String ERROR_NO_IMAGE_STREAM = \"No stream for image [%s]\";\n\tprivate static final String ERROR_PRE_PROCESSOR_NULL = \"Pre-processor returned null [%s]\";\n\tprivate static final String ERROR_POST_PROCESSOR_NULL = \"Post-processor returned null [%s]\";\n\tprivate static final String ERROR_PROCESSOR_FOR_DISK_CACHE_NULL = \"Bitmap processor for disk cache returned null [%s]\";\n\n\tprivate final ImageLoaderEngine engine;\n\tprivate final ImageLoadingInfo imageLoadingInfo;\n\tprivate final Handler handler;\n\n\t// Helper references\n\tprivate final ImageLoaderConfiguration configuration;\n\tprivate final ImageDownloader downloader;\n\tprivate final ImageDownloader networkDeniedDownloader;\n\tprivate final ImageDownloader slowNetworkDownloader;\n\tprivate final ImageDecoder decoder;\n\tfinal String uri;\n\tprivate final String memoryCacheKey;\n\tfinal ImageAware imageAware;\n\tprivate final ImageSize targetSize;\n\tfinal DisplayImageOptions options;\n\tfinal ImageLoadingListener listener;\n\tfinal ImageLoadingProgressListener progressListener;\n\tprivate final boolean syncLoading;\n\n\t// State vars\n\tprivate LoadedFrom loadedFrom = LoadedFrom.NETWORK;\n\n\tpublic LoadAndDisplayImageTask(ImageLoaderEngine engine, ImageLoadingInfo imageLoadingInfo, Handler handler) {\n\t\tthis.engine = engine;\n\t\tthis.imageLoadingInfo = imageLoadingInfo;\n\t\tthis.handler = handler;\n\n\t\tconfiguration = engine.configuration;\n\t\tdownloader = configuration.downloader;\n\t\tnetworkDeniedDownloader = configuration.networkDeniedDownloader;\n\t\tslowNetworkDownloader = configuration.slowNetworkDownloader;\n\t\tdecoder = configuration.decoder;\n\t\turi = imageLoadingInfo.uri;\n\t\tmemoryCacheKey = imageLoadingInfo.memoryCacheKey;\n\t\timageAware = imageLoadingInfo.imageAware;\n\t\ttargetSize = imageLoadingInfo.targetSize;\n\t\toptions = imageLoadingInfo.options;\n\t\tlistener = imageLoadingInfo.listener;\n\t\tprogressListener = imageLoadingInfo.progressListener;\n\t\tsyncLoading = options.isSyncLoading();\n\t}\n\n\t@Override\n\tpublic void run() {\n\t\tif (waitIfPaused()) return;\n\t\tif (delayIfNeed()) return;\n\n\t\tReentrantLock loadFromUriLock = imageLoadingInfo.loadFromUriLock;\n\t\tL.d(LOG_START_DISPLAY_IMAGE_TASK, memoryCacheKey);\n\t\tif (loadFromUriLock.isLocked()) {\n\t\t\tL.d(LOG_WAITING_FOR_IMAGE_LOADED, memoryCacheKey);\n\t\t}\n\n\t\tloadFromUriLock.lock();\n\t\tBitmap bmp;\n\t\ttry {\n\t\t\tcheckTaskNotActual();\n\n\t\t\tbmp = configuration.memoryCache.get(memoryCacheKey);\n\t\t\tif (bmp == null || bmp.isRecycled()) {\n\t\t\t\tbmp = tryLoadBitmap();\n\t\t\t\tif (bmp == null) return; // listener callback already was fired\n\n\t\t\t\tcheckTaskNotActual();\n\t\t\t\tcheckTaskInterrupted();\n\n\t\t\t\tif (options.shouldPreProcess()) {\n\t\t\t\t\tL.d(LOG_PREPROCESS_IMAGE, memoryCacheKey);\n\t\t\t\t\tbmp = options.getPreProcessor().process(bmp);\n\t\t\t\t\tif (bmp == null) {\n\t\t\t\t\t\tL.e(ERROR_PRE_PROCESSOR_NULL, memoryCacheKey);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (bmp != null && options.isCacheInMemory()) {\n\t\t\t\t\tL.d(LOG_CACHE_IMAGE_IN_MEMORY, memoryCacheKey);\n\t\t\t\t\tconfiguration.memoryCache.put(memoryCacheKey, bmp);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tloadedFrom = LoadedFrom.MEMORY_CACHE;\n\t\t\t\tL.d(LOG_GET_IMAGE_FROM_MEMORY_CACHE_AFTER_WAITING, memoryCacheKey);\n\t\t\t}\n\n\t\t\tif (bmp != null && options.shouldPostProcess()) {\n\t\t\t\tL.d(LOG_POSTPROCESS_IMAGE, memoryCacheKey);\n\t\t\t\tbmp = options.getPostProcessor().process(bmp);\n\t\t\t\tif (bmp == null) {\n\t\t\t\t\tL.e(ERROR_POST_PROCESSOR_NULL, memoryCacheKey);\n\t\t\t\t}\n\t\t\t}\n\t\t\tcheckTaskNotActual();\n\t\t\tcheckTaskInterrupted();\n\t\t} catch (TaskCancelledException e) {\n\t\t\tfireCancelEvent();\n\t\t\treturn;\n\t\t} finally {\n\t\t\tloadFromUriLock.unlock();\n\t\t}\n\n\t\tDisplayBitmapTask displayBitmapTask = new DisplayBitmapTask(bmp, imageLoadingInfo, engine, loadedFrom);\n\t\trunTask(displayBitmapTask, syncLoading, handler, engine);\n\t}\n\n\t/** @return <b>true</b> - if task should be interrupted; <b>false</b> - otherwise */\n\tprivate boolean waitIfPaused() {\n\t\tAtomicBoolean pause = engine.getPause();\n\t\tif (pause.get()) {\n\t\t\tsynchronized (engine.getPauseLock()) {\n\t\t\t\tif (pause.get()) {\n\t\t\t\t\tL.d(LOG_WAITING_FOR_RESUME, memoryCacheKey);\n\t\t\t\t\ttry {\n\t\t\t\t\t\tengine.getPauseLock().wait();\n\t\t\t\t\t} catch (InterruptedException e) {\n\t\t\t\t\t\tL.e(LOG_TASK_INTERRUPTED, memoryCacheKey);\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t}\n\t\t\t\t\tL.d(LOG_RESUME_AFTER_PAUSE, memoryCacheKey);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn isTaskNotActual();\n\t}\n\n\t/** @return <b>true</b> - if task should be interrupted; <b>false</b> - otherwise */\n\tprivate boolean delayIfNeed() {\n\t\tif (options.shouldDelayBeforeLoading()) {\n\t\t\tL.d(LOG_DELAY_BEFORE_LOADING, options.getDelayBeforeLoading(), memoryCacheKey);\n\t\t\ttry {\n\t\t\t\tThread.sleep(options.getDelayBeforeLoading());\n\t\t\t} catch (InterruptedException e) {\n\t\t\t\tL.e(LOG_TASK_INTERRUPTED, memoryCacheKey);\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\treturn isTaskNotActual();\n\t\t}\n\t\treturn false;\n\t}\n\n\tprivate Bitmap tryLoadBitmap() throws TaskCancelledException {\n\t\tBitmap bitmap = null;\n\t\ttry {\n\t\t\tFile imageFile = configuration.diskCache.get(uri);\n\t\t\tif (imageFile != null && imageFile.exists() && imageFile.length() > 0) {\n\t\t\t\tL.d(LOG_LOAD_IMAGE_FROM_DISK_CACHE, memoryCacheKey);\n\t\t\t\tloadedFrom = LoadedFrom.DISC_CACHE;\n\n\t\t\t\tcheckTaskNotActual();\n\t\t\t\tbitmap = decodeImage(Scheme.FILE.wrap(imageFile.getAbsolutePath()));\n\t\t\t}\n\t\t\tif (bitmap == null || bitmap.getWidth() <= 0 || bitmap.getHeight() <= 0) {\n\t\t\t\tL.d(LOG_LOAD_IMAGE_FROM_NETWORK, memoryCacheKey);\n\t\t\t\tloadedFrom = LoadedFrom.NETWORK;\n\n\t\t\t\tString imageUriForDecoding = uri;\n\t\t\t\tif (options.isCacheOnDisk() && tryCacheImageOnDisk()) {\n\t\t\t\t\timageFile = configuration.diskCache.get(uri);\n\t\t\t\t\tif (imageFile != null) {\n\t\t\t\t\t\timageUriForDecoding = Scheme.FILE.wrap(imageFile.getAbsolutePath());\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tcheckTaskNotActual();\n\t\t\t\tbitmap = decodeImage(imageUriForDecoding);\n\n\t\t\t\tif (bitmap == null || bitmap.getWidth() <= 0 || bitmap.getHeight() <= 0) {\n\t\t\t\t\tfireFailEvent(FailType.DECODING_ERROR, null);\n\t\t\t\t}\n\t\t\t}\n\t\t} catch (IllegalStateException e) {\n\t\t\tfireFailEvent(FailType.NETWORK_DENIED, null);\n\t\t} catch (TaskCancelledException e) {\n\t\t\tthrow e;\n\t\t} catch (IOException e) {\n\t\t\tL.e(e);\n\t\t\tfireFailEvent(FailType.IO_ERROR, e);\n\t\t} catch (OutOfMemoryError e) {\n\t\t\tL.e(e);\n\t\t\tfireFailEvent(FailType.OUT_OF_MEMORY, e);\n\t\t} catch (Throwable e) {\n\t\t\tL.e(e);\n\t\t\tfireFailEvent(FailType.UNKNOWN, e);\n\t\t}\n\t\treturn bitmap;\n\t}\n\n\tprivate Bitmap decodeImage(String imageUri) throws IOException {\n\t\tViewScaleType viewScaleType = imageAware.getScaleType();\n\t\tImageDecodingInfo decodingInfo = new ImageDecodingInfo(memoryCacheKey, imageUri, uri, targetSize, viewScaleType,\n\t\t\t\tgetDownloader(), options);\n\t\treturn decoder.decode(decodingInfo);\n\t}\n\n\t/** @return <b>true</b> - if image was downloaded successfully; <b>false</b> - otherwise */\n\tprivate boolean tryCacheImageOnDisk() throws TaskCancelledException {\n\t\tL.d(LOG_CACHE_IMAGE_ON_DISK, memoryCacheKey);\n\n\t\tboolean loaded;\n\t\ttry {\n\t\t\tloaded = downloadImage();\n\t\t\tif (loaded) {\n\t\t\t\tint width = configuration.maxImageWidthForDiskCache;\n\t\t\t\tint height = configuration.maxImageHeightForDiskCache;\n\t\t\t\tif (width > 0 || height > 0) {\n\t\t\t\t\tL.d(LOG_RESIZE_CACHED_IMAGE_FILE, memoryCacheKey);\n\t\t\t\t\tresizeAndSaveImage(width, height); // TODO : process boolean result\n\t\t\t\t}\n\t\t\t}\n\t\t} catch (IOException e) {\n\t\t\tL.e(e);\n\t\t\tloaded = false;\n\t\t}\n\t\treturn loaded;\n\t}\n\n\tprivate boolean downloadImage() throws IOException {\n\t\tInputStream is = getDownloader().getStream(uri, options.getExtraForDownloader());\n\t\tif (is == null) {\n\t\t\tL.e(ERROR_NO_IMAGE_STREAM, memoryCacheKey);\n\t\t\treturn false;\n\t\t} else {\n\t\t\ttry {\n\t\t\t\treturn configuration.diskCache.save(uri, is, this);\n\t\t\t} finally {\n\t\t\t\tIoUtils.closeSilently(is);\n\t\t\t}\n\t\t}\n\t}\n\n\t/** Decodes image file into Bitmap, resize it and save it back */\n\tprivate boolean resizeAndSaveImage(int maxWidth, int maxHeight) throws IOException {\n\t\t// Decode image file, compress and re-save it\n\t\tboolean saved = false;\n\t\tFile targetFile = configuration.diskCache.get(uri);\n\t\tif (targetFile != null && targetFile.exists()) {\n\t\t\tImageSize targetImageSize = new ImageSize(maxWidth, maxHeight);\n\t\t\tDisplayImageOptions specialOptions = new DisplayImageOptions.Builder().cloneFrom(options)\n\t\t\t\t\t.imageScaleType(ImageScaleType.IN_SAMPLE_INT).build();\n\t\t\tImageDecodingInfo decodingInfo = new ImageDecodingInfo(memoryCacheKey,\n\t\t\t\t\tScheme.FILE.wrap(targetFile.getAbsolutePath()), uri, targetImageSize, ViewScaleType.FIT_INSIDE,\n\t\t\t\t\tgetDownloader(), specialOptions);\n\t\t\tBitmap bmp = decoder.decode(decodingInfo);\n\t\t\tif (bmp != null && configuration.processorForDiskCache != null) {\n\t\t\t\tL.d(LOG_PROCESS_IMAGE_BEFORE_CACHE_ON_DISK, memoryCacheKey);\n\t\t\t\tbmp = configuration.processorForDiskCache.process(bmp);\n\t\t\t\tif (bmp == null) {\n\t\t\t\t\tL.e(ERROR_PROCESSOR_FOR_DISK_CACHE_NULL, memoryCacheKey);\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (bmp != null) {\n\t\t\t\tsaved = configuration.diskCache.save(uri, bmp);\n\t\t\t\tbmp.recycle();\n\t\t\t}\n\t\t}\n\t\treturn saved;\n\t}\n\n\t@Override\n\tpublic boolean onBytesCopied(int current, int total) {\n\t\treturn syncLoading || fireProgressEvent(current, total);\n\t}\n\n\t/** @return <b>true</b> - if loading should be continued; <b>false</b> - if loading should be interrupted */\n\tprivate boolean fireProgressEvent(final int current, final int total) {\n\t\tif (isTaskInterrupted() || isTaskNotActual()) return false;\n\t\tif (progressListener != null) {\n\t\t\tRunnable r = new Runnable() {\n\t\t\t\t@Override\n\t\t\t\tpublic void run() {\n\t\t\t\t\tprogressListener.onProgressUpdate(uri, imageAware.getWrappedView(), current, total);\n\t\t\t\t}\n\t\t\t};\n\t\t\trunTask(r, false, handler, engine);\n\t\t}\n\t\treturn true;\n\t}\n\n\tprivate void fireFailEvent(final FailType failType, final Throwable failCause) {\n\t\tif (syncLoading || isTaskInterrupted() || isTaskNotActual()) return;\n\t\tRunnable r = new Runnable() {\n\t\t\t@Override\n\t\t\tpublic void run() {\n\t\t\t\tif (options.shouldShowImageOnFail()) {\n\t\t\t\t\timageAware.setImageDrawable(options.getImageOnFail(configuration.resources));\n\t\t\t\t}\n\t\t\t\tlistener.onLoadingFailed(uri, imageAware.getWrappedView(), new FailReason(failType, failCause));\n\t\t\t}\n\t\t};\n\t\trunTask(r, false, handler, engine);\n\t}\n\n\tprivate void fireCancelEvent() {\n\t\tif (syncLoading || isTaskInterrupted()) return;\n\t\tRunnable r = new Runnable() {\n\t\t\t@Override\n\t\t\tpublic void run() {\n\t\t\t\tlistener.onLoadingCancelled(uri, imageAware.getWrappedView());\n\t\t\t}\n\t\t};\n\t\trunTask(r, false, handler, engine);\n\t}\n\n\tprivate ImageDownloader getDownloader() {\n\t\tImageDownloader d;\n\t\tif (engine.isNetworkDenied()) {\n\t\t\td = networkDeniedDownloader;\n\t\t} else if (engine.isSlowNetwork()) {\n\t\t\td = slowNetworkDownloader;\n\t\t} else {\n\t\t\td = downloader;\n\t\t}\n\t\treturn d;\n\t}\n\n\t/**\n\t * @throws TaskCancelledException if task is not actual (target ImageAware is collected by GC or the image URI of\n\t *                                this task doesn't match to image URI which is actual for current ImageAware at\n\t *                                this moment)\n\t */\n\tprivate void checkTaskNotActual() throws TaskCancelledException {\n\t\tcheckViewCollected();\n\t\tcheckViewReused();\n\t}\n\n\t/**\n\t * @return <b>true</b> - if task is not actual (target ImageAware is collected by GC or the image URI of this task\n\t * doesn't match to image URI which is actual for current ImageAware at this moment)); <b>false</b> - otherwise\n\t */\n\tprivate boolean isTaskNotActual() {\n\t\treturn isViewCollected() || isViewReused();\n\t}\n\n\t/** @throws TaskCancelledException if target ImageAware is collected */\n\tprivate void checkViewCollected() throws TaskCancelledException {\n\t\tif (isViewCollected()) {\n\t\t\tthrow new TaskCancelledException();\n\t\t}\n\t}\n\n\t/** @return <b>true</b> - if target ImageAware is collected by GC; <b>false</b> - otherwise */\n\tprivate boolean isViewCollected() {\n\t\tif (imageAware.isCollected()) {\n\t\t\tL.d(LOG_TASK_CANCELLED_IMAGEAWARE_COLLECTED, memoryCacheKey);\n\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n\n\t/** @throws TaskCancelledException if target ImageAware is collected by GC */\n\tprivate void checkViewReused() throws TaskCancelledException {\n\t\tif (isViewReused()) {\n\t\t\tthrow new TaskCancelledException();\n\t\t}\n\t}\n\n\t/** @return <b>true</b> - if current ImageAware is reused for displaying another image; <b>false</b> - otherwise */\n\tprivate boolean isViewReused() {\n\t\tString currentCacheKey = engine.getLoadingUriForView(imageAware);\n\t\t// Check whether memory cache key (image URI) for current ImageAware is actual.\n\t\t// If ImageAware is reused for another task then current task should be cancelled.\n\t\tboolean imageAwareWasReused = !memoryCacheKey.equals(currentCacheKey);\n\t\tif (imageAwareWasReused) {\n\t\t\tL.d(LOG_TASK_CANCELLED_IMAGEAWARE_REUSED, memoryCacheKey);\n\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n\n\t/** @throws TaskCancelledException if current task was interrupted */\n\tprivate void checkTaskInterrupted() throws TaskCancelledException {\n\t\tif (isTaskInterrupted()) {\n\t\t\tthrow new TaskCancelledException();\n\t\t}\n\t}\n\n\t/** @return <b>true</b> - if current task was interrupted; <b>false</b> - otherwise */\n\tprivate boolean isTaskInterrupted() {\n\t\tif (Thread.interrupted()) {\n\t\t\tL.d(LOG_TASK_INTERRUPTED, memoryCacheKey);\n\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n\n\tString getLoadingUri() {\n\t\treturn uri;\n\t}\n\n\tstatic void runTask(Runnable r, boolean sync, Handler handler, ImageLoaderEngine engine) {\n\t\tif (sync) {\n\t\t\tr.run();\n\t\t} else if (handler == null) {\n\t\t\tengine.fireCallback(r);\n\t\t} else {\n\t\t\thandler.post(r);\n\t\t}\n\t}\n\n\t/**\n\t * Exceptions for case when task is cancelled (thread is interrupted, image view is reused for another task, view is\n\t * collected by GC).\n\t *\n\t * @author Sergey Tarasevich (nostra13[at]gmail[dot]com)\n\t * @since 1.9.1\n\t */\n\tclass TaskCancelledException extends Exception {\n\t}\n}\n"
  },
  {
    "path": "library/src/main/java/com/nostra13/universalimageloader/core/ProcessAndDisplayImageTask.java",
    "content": "/*******************************************************************************\n * Copyright 2011-2014 Sergey Tarasevich\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *******************************************************************************/\npackage com.nostra13.universalimageloader.core;\n\nimport android.graphics.Bitmap;\nimport android.os.Handler;\nimport android.widget.ImageView;\nimport com.nostra13.universalimageloader.core.assist.LoadedFrom;\nimport com.nostra13.universalimageloader.core.process.BitmapProcessor;\nimport com.nostra13.universalimageloader.utils.L;\n\n/**\n * Presents process'n'display image task. Processes image {@linkplain Bitmap} and display it in {@link ImageView} using\n * {@link DisplayBitmapTask}.\n *\n * @author Sergey Tarasevich (nostra13[at]gmail[dot]com)\n * @since 1.8.0\n */\nfinal class ProcessAndDisplayImageTask implements Runnable {\n\n\tprivate static final String LOG_POSTPROCESS_IMAGE = \"PostProcess image before displaying [%s]\";\n\n\tprivate final ImageLoaderEngine engine;\n\tprivate final Bitmap bitmap;\n\tprivate final ImageLoadingInfo imageLoadingInfo;\n\tprivate final Handler handler;\n\n\tpublic ProcessAndDisplayImageTask(ImageLoaderEngine engine, Bitmap bitmap, ImageLoadingInfo imageLoadingInfo,\n\t\t\tHandler handler) {\n\t\tthis.engine = engine;\n\t\tthis.bitmap = bitmap;\n\t\tthis.imageLoadingInfo = imageLoadingInfo;\n\t\tthis.handler = handler;\n\t}\n\n\t@Override\n\tpublic void run() {\n\t\tL.d(LOG_POSTPROCESS_IMAGE, imageLoadingInfo.memoryCacheKey);\n\n\t\tBitmapProcessor processor = imageLoadingInfo.options.getPostProcessor();\n\t\tBitmap processedBitmap = processor.process(bitmap);\n\t\tDisplayBitmapTask displayBitmapTask = new DisplayBitmapTask(processedBitmap, imageLoadingInfo, engine,\n\t\t\t\tLoadedFrom.MEMORY_CACHE);\n\t\tLoadAndDisplayImageTask.runTask(displayBitmapTask, imageLoadingInfo.options.isSyncLoading(), handler, engine);\n\t}\n}\n"
  },
  {
    "path": "library/src/main/java/com/nostra13/universalimageloader/core/assist/ContentLengthInputStream.java",
    "content": "/*******************************************************************************\n * Copyright 2013-2014 Sergey Tarasevich\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *******************************************************************************/\npackage com.nostra13.universalimageloader.core.assist;\n\nimport java.io.IOException;\nimport java.io.InputStream;\n\n/**\n * Decorator for {@link java.io.InputStream InputStream}. Provides possibility to return defined stream length by\n * {@link #available()} method.\n *\n * @author Sergey Tarasevich (nostra13[at]gmail[dot]com), Mariotaku\n * @since 1.9.1\n */\npublic class ContentLengthInputStream extends InputStream {\n\n\tprivate final InputStream stream;\n\tprivate final int length;\n\n\tpublic ContentLengthInputStream(InputStream stream, int length) {\n\t\tthis.stream = stream;\n\t\tthis.length = length;\n\t}\n\n\t@Override\n\tpublic int available() {\n\t\treturn length;\n\t}\n\n\t@Override\n\tpublic void close() throws IOException {\n\t\tstream.close();\n\t}\n\n\t@Override\n\tpublic void mark(int readLimit) {\n\t\tstream.mark(readLimit);\n\t}\n\n\t@Override\n\tpublic int read() throws IOException {\n\t\treturn stream.read();\n\t}\n\n\t@Override\n\tpublic int read(byte[] buffer) throws IOException {\n\t\treturn stream.read(buffer);\n\t}\n\n\t@Override\n\tpublic int read(byte[] buffer, int byteOffset, int byteCount) throws IOException {\n\t\treturn stream.read(buffer, byteOffset, byteCount);\n\t}\n\n\t@Override\n\tpublic void reset() throws IOException {\n\t\tstream.reset();\n\t}\n\n\t@Override\n\tpublic long skip(long byteCount) throws IOException {\n\t\treturn stream.skip(byteCount);\n\t}\n\n\t@Override\n\tpublic boolean markSupported() {\n\t\treturn stream.markSupported();\n\t}\n}"
  },
  {
    "path": "library/src/main/java/com/nostra13/universalimageloader/core/assist/FailReason.java",
    "content": "/*******************************************************************************\n * Copyright 2011-2014 Sergey Tarasevich\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *******************************************************************************/\npackage com.nostra13.universalimageloader.core.assist;\n\n/**\n * Presents the reason why image loading and displaying was failed\n *\n * @author Sergey Tarasevich (nostra13[at]gmail[dot]com)\n * @since 1.0.0\n */\npublic class FailReason {\n\n\tprivate final FailType type;\n\n\tprivate final Throwable cause;\n\n\tpublic FailReason(FailType type, Throwable cause) {\n\t\tthis.type = type;\n\t\tthis.cause = cause;\n\t}\n\n\t/** @return {@linkplain FailType Fail type} */\n\tpublic FailType getType() {\n\t\treturn type;\n\t}\n\n\t/** @return Thrown exception/error, can be <b>null</b> */\n\tpublic Throwable getCause() {\n\t\treturn cause;\n\t}\n\n\t/** Presents type of fail while image loading */\n\tpublic static enum FailType {\n\t\t/** Input/output error. Can be caused by network communication fail or error while caching image on file system. */\n\t\tIO_ERROR,\n\t\t/**\n\t\t * Error while\n\t\t * {@linkplain android.graphics.BitmapFactory#decodeStream(java.io.InputStream, android.graphics.Rect, android.graphics.BitmapFactory.Options)\n\t\t * decode image to Bitmap}\n\t\t */\n\t\tDECODING_ERROR,\n\t\t/**\n\t\t * {@linkplain com.nostra13.universalimageloader.core.ImageLoader#denyNetworkDownloads(boolean) Network\n\t\t * downloads are denied} and requested image wasn't cached in disk cache before.\n\t\t */\n\t\tNETWORK_DENIED,\n\t\t/** Not enough memory to create needed Bitmap for image */\n\t\tOUT_OF_MEMORY,\n\t\t/** Unknown error was occurred while loading image */\n\t\tUNKNOWN\n\t}\n}"
  },
  {
    "path": "library/src/main/java/com/nostra13/universalimageloader/core/assist/FlushedInputStream.java",
    "content": "package com.nostra13.universalimageloader.core.assist;\n\nimport java.io.FilterInputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\n\n/**\n * Many streams obtained over slow connection show <a href=\"http://code.google.com/p/android/issues/detail?id=6066\">this\n * problem</a>.\n */\npublic class FlushedInputStream extends FilterInputStream {\n\n\tpublic FlushedInputStream(InputStream inputStream) {\n\t\tsuper(inputStream);\n\t}\n\n\t@Override\n\tpublic long skip(long n) throws IOException {\n\t\tlong totalBytesSkipped = 0L;\n\t\twhile (totalBytesSkipped < n) {\n\t\t\tlong bytesSkipped = in.skip(n - totalBytesSkipped);\n\t\t\tif (bytesSkipped == 0L) {\n\t\t\t\tint by_te = read();\n\t\t\t\tif (by_te < 0) {\n\t\t\t\t\tbreak; // we reached EOF\n\t\t\t\t} else {\n\t\t\t\t\tbytesSkipped = 1; // we read one byte\n\t\t\t\t}\n\t\t\t}\n\t\t\ttotalBytesSkipped += bytesSkipped;\n\t\t}\n\t\treturn totalBytesSkipped;\n\t}\n}\n"
  },
  {
    "path": "library/src/main/java/com/nostra13/universalimageloader/core/assist/ImageScaleType.java",
    "content": "/*******************************************************************************\n * Copyright 2011-2014 Sergey Tarasevich\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *******************************************************************************/\npackage com.nostra13.universalimageloader.core.assist;\n\n/**\n * Type of image scaling during decoding.\n *\n * @author Sergey Tarasevich (nostra13[at]gmail[dot]com)\n * @since 1.5.0\n */\npublic enum ImageScaleType {\n\t/** Image won't be scaled */\n\tNONE,\n\t/**\n\t * Image will be scaled down only if image size is greater than\n\t * {@linkplain javax.microedition.khronos.opengles.GL10#GL_MAX_TEXTURE_SIZE maximum acceptable texture size}.\n\t * Usually it's 2048x2048.<br />\n\t * If Bitmap is expected to display than it must not exceed this size (otherwise you'll get the exception\n\t * \"OpenGLRenderer: Bitmap too large to be uploaded into a texture\".<br />\n\t * Image will be subsampled in an integer number of times (1, 2, 3, ...) to maximum texture size of device.\n\t */\n\tNONE_SAFE,\n\t/**\n\t * Image will be reduces 2-fold until next reduce step make image smaller target size.<br />\n\t * It's <b>fast</b> type and it's preferable for usage in lists/grids/galleries (and other\n\t * {@linkplain android.widget.AdapterView adapter-views}) .<br />\n\t * Relates to {@link android.graphics.BitmapFactory.Options#inSampleSize}<br />\n\t * Note: If original image size is smaller than target size then original image <b>won't</b> be scaled.\n\t */\n\tIN_SAMPLE_POWER_OF_2,\n\t/**\n\t * Image will be subsampled in an integer number of times (1, 2, 3, ...). Use it if memory economy is quite\n\t * important.<br />\n\t * Relates to {@link android.graphics.BitmapFactory.Options#inSampleSize}<br />\n\t * Note: If original image size is smaller than target size then original image <b>won't</b> be scaled.\n\t */\n\tIN_SAMPLE_INT,\n\t/**\n\t * Image will scaled-down exactly to target size (scaled width or height or both will be equal to target size;\n\t * depends on {@linkplain android.widget.ImageView.ScaleType ImageView's scale type}). Use it if memory economy is\n\t * critically important.<br />\n\t * <b>Note:</b> If original image size is smaller than target size then original image <b>won't</b> be scaled.<br />\n\t * <br />\n\t * <b>NOTE:</b> For creating result Bitmap (of exact size) additional Bitmap will be created with\n\t * {@link android.graphics.Bitmap#createBitmap(android.graphics.Bitmap, int, int, int, int, android.graphics.Matrix, boolean)\n\t * Bitmap.createBitmap(...)}.<br />\n\t * <b>Cons:</b> Saves memory by keeping smaller Bitmap in memory cache (comparing with IN_SAMPLE... scale types)<br />\n\t * <b>Pros:</b> Requires more memory in one time for creation of result Bitmap.\n\t */\n\tEXACTLY,\n\t/**\n\t * Image will scaled exactly to target size (scaled width or height or both will be equal to target size; depends on\n\t * {@linkplain android.widget.ImageView.ScaleType ImageView's scale type}). Use it if memory economy is critically\n\t * important.<br />\n\t * <b>Note:</b> If original image size is smaller than target size then original image <b>will be stretched</b> to\n\t * target size.<br />\n\t * <br />\n\t * <b>NOTE:</b> For creating result Bitmap (of exact size) additional Bitmap will be created with\n\t * {@link android.graphics.Bitmap#createBitmap(android.graphics.Bitmap, int, int, int, int, android.graphics.Matrix, boolean)\n\t * Bitmap.createBitmap(...)}.<br />\n\t * <b>Cons:</b> Saves memory by keeping smaller Bitmap in memory cache (comparing with IN_SAMPLE... scale types)<br />\n\t * <b>Pros:</b> Requires more memory in one time for creation of result Bitmap.\n\t */\n\tEXACTLY_STRETCHED\n}\n"
  },
  {
    "path": "library/src/main/java/com/nostra13/universalimageloader/core/assist/ImageSize.java",
    "content": "/*******************************************************************************\n * Copyright 2011-2013 Sergey Tarasevich\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *******************************************************************************/\npackage com.nostra13.universalimageloader.core.assist;\n\n/**\n * Present width and height values\n *\n * @author Sergey Tarasevich (nostra13[at]gmail[dot]com)\n * @since 1.0.0\n */\npublic class ImageSize {\n\n\tprivate static final int TO_STRING_MAX_LENGHT = 9; // \"9999x9999\".length()\n\tprivate static final String SEPARATOR = \"x\";\n\n\tprivate final int width;\n\tprivate final int height;\n\n\tpublic ImageSize(int width, int height) {\n\t\tthis.width = width;\n\t\tthis.height = height;\n\t}\n\n\tpublic ImageSize(int width, int height, int rotation) {\n\t\tif (rotation % 180 == 0) {\n\t\t\tthis.width = width;\n\t\t\tthis.height = height;\n\t\t} else {\n\t\t\tthis.width = height;\n\t\t\tthis.height = width;\n\t\t}\n\t}\n\n\tpublic int getWidth() {\n\t\treturn width;\n\t}\n\n\tpublic int getHeight() {\n\t\treturn height;\n\t}\n\n\t/** Scales down dimensions in <b>sampleSize</b> times. Returns new object. */\n\tpublic ImageSize scaleDown(int sampleSize) {\n\t\treturn new ImageSize(width / sampleSize, height / sampleSize);\n\t}\n\n\t/** Scales dimensions according to incoming scale. Returns new object. */\n\tpublic ImageSize scale(float scale) {\n\t\treturn new ImageSize((int) (width * scale), (int) (height * scale));\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn new StringBuilder(TO_STRING_MAX_LENGHT).append(width).append(SEPARATOR).append(height).toString();\n\t}\n}\n"
  },
  {
    "path": "library/src/main/java/com/nostra13/universalimageloader/core/assist/LoadedFrom.java",
    "content": "package com.nostra13.universalimageloader.core.assist;\n\n/**\n * Source image loaded from.\n *\n * @author Sergey Tarasevich (nostra13[at]gmail[dot]com)\n */\npublic enum LoadedFrom {\n    NETWORK, DISC_CACHE, MEMORY_CACHE\n}"
  },
  {
    "path": "library/src/main/java/com/nostra13/universalimageloader/core/assist/QueueProcessingType.java",
    "content": "/*******************************************************************************\n * Copyright 2011-2013 Sergey Tarasevich\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *******************************************************************************/\npackage com.nostra13.universalimageloader.core.assist;\n\n/**\n * Queue processing type which will be used for display task processing\n *\n * @author Sergey Tarasevich (nostra13[at]gmail[dot]com)\n * @since 1.6.3\n */\npublic enum QueueProcessingType {\n\tFIFO, LIFO\n}\n"
  },
  {
    "path": "library/src/main/java/com/nostra13/universalimageloader/core/assist/ViewScaleType.java",
    "content": "/*******************************************************************************\n * Copyright 2011-2013 Sergey Tarasevich\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *******************************************************************************/\npackage com.nostra13.universalimageloader.core.assist;\n\nimport android.widget.ImageView;\nimport android.widget.ImageView.ScaleType;\n\n/**\n * Simplify {@linkplain ScaleType ImageView's scale type} to 2 types: {@link #FIT_INSIDE} and {@link #CROP}\n *\n * @author Sergey Tarasevich (nostra13[at]gmail[dot]com)\n * @since 1.6.1\n */\npublic enum ViewScaleType {\n\t/**\n\t * Scale the image uniformly (maintain the image's aspect ratio) so that at least one dimension (width or height) of\n\t * the image will be equal to or less the corresponding dimension of the view.\n\t */\n\tFIT_INSIDE,\n\t/**\n\t * Scale the image uniformly (maintain the image's aspect ratio) so that both dimensions (width and height) of the\n\t * image will be equal to or larger than the corresponding dimension of the view.\n\t */\n\tCROP;\n\n\t/**\n\t * Defines scale type of ImageView.\n\t *\n\t * @param imageView {@link ImageView}\n\t * @return {@link #FIT_INSIDE} for\n\t *         <ul>\n\t *         <li>{@link ScaleType#FIT_CENTER}</li>\n\t *         <li>{@link ScaleType#FIT_XY}</li>\n\t *         <li>{@link ScaleType#FIT_START}</li>\n\t *         <li>{@link ScaleType#FIT_END}</li>\n\t *         <li>{@link ScaleType#CENTER_INSIDE}</li>\n\t *         </ul>\n\t *         {@link #CROP} for\n\t *         <ul>\n\t *         <li>{@link ScaleType#CENTER}</li>\n\t *         <li>{@link ScaleType#CENTER_CROP}</li>\n\t *         <li>{@link ScaleType#MATRIX}</li>\n\t *         </ul>\n\t */\n\tpublic static ViewScaleType fromImageView(ImageView imageView) {\n\t\tswitch (imageView.getScaleType()) {\n\t\t\tcase FIT_CENTER:\n\t\t\tcase FIT_XY:\n\t\t\tcase FIT_START:\n\t\t\tcase FIT_END:\n\t\t\tcase CENTER_INSIDE:\n\t\t\t\treturn FIT_INSIDE;\n\t\t\tcase MATRIX:\n\t\t\tcase CENTER:\n\t\t\tcase CENTER_CROP:\n\t\t\tdefault:\n\t\t\t\treturn CROP;\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "library/src/main/java/com/nostra13/universalimageloader/core/assist/deque/BlockingDeque.java",
    "content": "/*\n * Written by Doug Lea with assistance from members of JCP JSR-166\n * Expert Group and released to the public domain, as explained at\n * http://creativecommons.org/licenses/publicdomain\n */\n\npackage com.nostra13.universalimageloader.core.assist.deque;\n\nimport java.util.Iterator;\nimport java.util.NoSuchElementException;\nimport java.util.concurrent.BlockingQueue;\nimport java.util.concurrent.TimeUnit;\n\n/**\n * A {@link Deque} that additionally supports blocking operations that wait\n * for the deque to become non-empty when retrieving an element, and wait for\n * space to become available in the deque when storing an element.\n * <p/>\n * <p><tt>BlockingDeque</tt> methods come in four forms, with different ways\n * of handling operations that cannot be satisfied immediately, but may be\n * satisfied at some point in the future:\n * one throws an exception, the second returns a special value (either\n * <tt>null</tt> or <tt>false</tt>, depending on the operation), the third\n * blocks the current thread indefinitely until the operation can succeed,\n * and the fourth blocks for only a given maximum time limit before giving\n * up.  These methods are summarized in the following table:\n * <p/>\n * <p/>\n * <table BORDER CELLPADDING=3 CELLSPACING=1>\n * <tr>\n * <td ALIGN=CENTER COLSPAN = 5> <b>First Element (Head)</b></td>\n * </tr>\n * <tr>\n * <td></td>\n * <td ALIGN=CENTER><em>Throws exception</em></td>\n * <td ALIGN=CENTER><em>Special value</em></td>\n * <td ALIGN=CENTER><em>Blocks</em></td>\n * <td ALIGN=CENTER><em>Times out</em></td>\n * </tr>\n * <tr>\n * <td><b>Insert</b></td>\n * <td>{@link #addFirst addFirst(e)}</td>\n * <td>{@link #offerFirst offerFirst(e)}</td>\n * <td>{@link #putFirst putFirst(e)}</td>\n * <td>{@link #offerFirst offerFirst(e, time, unit)}</td>\n * </tr>\n * <tr>\n * <td><b>Remove</b></td>\n * <td>{@link #removeFirst removeFirst()}</td>\n * <td>{@link #pollFirst pollFirst()}</td>\n * <td>{@link #takeFirst takeFirst()}</td>\n * <td>{@link #pollFirst(long, TimeUnit) pollFirst(time, unit)}</td>\n * </tr>\n * <tr>\n * <td><b>Examine</b></td>\n * <td>{@link #getFirst getFirst()}</td>\n * <td>{@link #peekFirst peekFirst()}</td>\n * <td><em>not applicable</em></td>\n * <td><em>not applicable</em></td>\n * </tr>\n * <tr>\n * <td ALIGN=CENTER COLSPAN = 5> <b>Last Element (Tail)</b></td>\n * </tr>\n * <tr>\n * <td></td>\n * <td ALIGN=CENTER><em>Throws exception</em></td>\n * <td ALIGN=CENTER><em>Special value</em></td>\n * <td ALIGN=CENTER><em>Blocks</em></td>\n * <td ALIGN=CENTER><em>Times out</em></td>\n * </tr>\n * <tr>\n * <td><b>Insert</b></td>\n * <td>{@link #addLast addLast(e)}</td>\n * <td>{@link #offerLast offerLast(e)}</td>\n * <td>{@link #putLast putLast(e)}</td>\n * <td>{@link #offerLast offerLast(e, time, unit)}</td>\n * </tr>\n * <tr>\n * <td><b>Remove</b></td>\n * <td>{@link #removeLast() removeLast()}</td>\n * <td>{@link #pollLast() pollLast()}</td>\n * <td>{@link #takeLast takeLast()}</td>\n * <td>{@link #pollLast(long, TimeUnit) pollLast(time, unit)}</td>\n * </tr>\n * <tr>\n * <td><b>Examine</b></td>\n * <td>{@link #getLast getLast()}</td>\n * <td>{@link #peekLast peekLast()}</td>\n * <td><em>not applicable</em></td>\n * <td><em>not applicable</em></td>\n * </tr>\n * </table>\n * <p/>\n * <p>Like any {@link BlockingQueue}, a <tt>BlockingDeque</tt> is thread safe,\n * does not permit null elements, and may (or may not) be\n * capacity-constrained.\n * <p/>\n * <p>A <tt>BlockingDeque</tt> implementation may be used directly as a FIFO\n * <tt>BlockingQueue</tt>. The methods inherited from the\n * <tt>BlockingQueue</tt> interface are precisely equivalent to\n * <tt>BlockingDeque</tt> methods as indicated in the following table:\n * <p/>\n * <p/>\n * <table BORDER CELLPADDING=3 CELLSPACING=1>\n * <tr>\n * <td ALIGN=CENTER> <b><tt>BlockingQueue</tt> Method</b></td>\n * <td ALIGN=CENTER> <b>Equivalent <tt>BlockingDeque</tt> Method</b></td>\n * </tr>\n * <tr>\n * <td ALIGN=CENTER COLSPAN = 2> <b>Insert</b></td>\n * </tr>\n * <tr>\n * <td>{@link #add add(e)}</td>\n * <td>{@link #addLast addLast(e)}</td>\n * </tr>\n * <tr>\n * <td>{@link #offer offer(e)}</td>\n * <td>{@link #offerLast offerLast(e)}</td>\n * </tr>\n * <tr>\n * <td>{@link #put put(e)}</td>\n * <td>{@link #putLast putLast(e)}</td>\n * </tr>\n * <tr>\n * <td>{@link #offer offer(e, time, unit)}</td>\n * <td>{@link #offerLast offerLast(e, time, unit)}</td>\n * </tr>\n * <tr>\n * <td ALIGN=CENTER COLSPAN = 2> <b>Remove</b></td>\n * </tr>\n * <tr>\n * <td>{@link #remove() remove()}</td>\n * <td>{@link #removeFirst() removeFirst()}</td>\n * </tr>\n * <tr>\n * <td>{@link #poll() poll()}</td>\n * <td>{@link #pollFirst() pollFirst()}</td>\n * </tr>\n * <tr>\n * <td>{@link #take() take()}</td>\n * <td>{@link #takeFirst() takeFirst()}</td>\n * </tr>\n * <tr>\n * <td>{@link #poll(long, TimeUnit) poll(time, unit)}</td>\n * <td>{@link #pollFirst(long, TimeUnit) pollFirst(time, unit)}</td>\n * </tr>\n * <tr>\n * <td ALIGN=CENTER COLSPAN = 2> <b>Examine</b></td>\n * </tr>\n * <tr>\n * <td>{@link #element() element()}</td>\n * <td>{@link #getFirst() getFirst()}</td>\n * </tr>\n * <tr>\n * <td>{@link #peek() peek()}</td>\n * <td>{@link #peekFirst() peekFirst()}</td>\n * </tr>\n * </table>\n * <p/>\n * <p>Memory consistency effects: As with other concurrent\n * collections, actions in a thread prior to placing an object into a\n * {@code BlockingDeque}\n * <a href=\"package-summary.html#MemoryVisibility\"><i>happen-before</i></a>\n * actions subsequent to the access or removal of that element from\n * the {@code BlockingDeque} in another thread.\n * <p/>\n * <p>This interface is a member of the\n * <a href=\"{@docRoot}/../technotes/guides/collections/index.html\">\n * Java Collections Framework</a>.\n *\n * @param <E> the type of elements held in this collection\n * @author Doug Lea\n * @since 1.6\n */\npublic interface BlockingDeque<E> extends BlockingQueue<E>, Deque<E> {\n    /*\n     * We have \"diamond\" multiple interface inheritance here, and that\n     * introduces ambiguities.  Methods might end up with different\n     * specs depending on the branch chosen by javadoc.  Thus a lot of\n     * methods specs here are copied from superinterfaces.\n     */\n\n    /**\n     * Inserts the specified element at the front of this deque if it is\n     * possible to do so immediately without violating capacity restrictions,\n     * throwing an <tt>IllegalStateException</tt> if no space is currently\n     * available.  When using a capacity-restricted deque, it is generally\n     * preferable to use {@link #offerFirst offerFirst}.\n     *\n     * @param e the element to add\n     * @throws IllegalStateException    {@inheritDoc}\n     * @throws ClassCastException       {@inheritDoc}\n     * @throws NullPointerException     if the specified element is null\n     * @throws IllegalArgumentException {@inheritDoc}\n     */\n    void addFirst(E e);\n\n    /**\n     * Inserts the specified element at the end of this deque if it is\n     * possible to do so immediately without violating capacity restrictions,\n     * throwing an <tt>IllegalStateException</tt> if no space is currently\n     * available.  When using a capacity-restricted deque, it is generally\n     * preferable to use {@link #offerLast offerLast}.\n     *\n     * @param e the element to add\n     * @throws IllegalStateException    {@inheritDoc}\n     * @throws ClassCastException       {@inheritDoc}\n     * @throws NullPointerException     if the specified element is null\n     * @throws IllegalArgumentException {@inheritDoc}\n     */\n    void addLast(E e);\n\n    /**\n     * Inserts the specified element at the front of this deque if it is\n     * possible to do so immediately without violating capacity restrictions,\n     * returning <tt>true</tt> upon success and <tt>false</tt> if no space is\n     * currently available.\n     * When using a capacity-restricted deque, this method is generally\n     * preferable to the {@link #addFirst addFirst} method, which can\n     * fail to insert an element only by throwing an exception.\n     *\n     * @param e the element to add\n     * @throws ClassCastException       {@inheritDoc}\n     * @throws NullPointerException     if the specified element is null\n     * @throws IllegalArgumentException {@inheritDoc}\n     */\n    boolean offerFirst(E e);\n\n    /**\n     * Inserts the specified element at the end of this deque if it is\n     * possible to do so immediately without violating capacity restrictions,\n     * returning <tt>true</tt> upon success and <tt>false</tt> if no space is\n     * currently available.\n     * When using a capacity-restricted deque, this method is generally\n     * preferable to the {@link #addLast addLast} method, which can\n     * fail to insert an element only by throwing an exception.\n     *\n     * @param e the element to add\n     * @throws ClassCastException       {@inheritDoc}\n     * @throws NullPointerException     if the specified element is null\n     * @throws IllegalArgumentException {@inheritDoc}\n     */\n    boolean offerLast(E e);\n\n    /**\n     * Inserts the specified element at the front of this deque,\n     * waiting if necessary for space to become available.\n     *\n     * @param e the element to add\n     * @throws InterruptedException     if interrupted while waiting\n     * @throws ClassCastException       if the class of the specified element\n     *                                  prevents it from being added to this deque\n     * @throws NullPointerException     if the specified element is null\n     * @throws IllegalArgumentException if some property of the specified\n     *                                  element prevents it from being added to this deque\n     */\n    void putFirst(E e) throws InterruptedException;\n\n    /**\n     * Inserts the specified element at the end of this deque,\n     * waiting if necessary for space to become available.\n     *\n     * @param e the element to add\n     * @throws InterruptedException     if interrupted while waiting\n     * @throws ClassCastException       if the class of the specified element\n     *                                  prevents it from being added to this deque\n     * @throws NullPointerException     if the specified element is null\n     * @throws IllegalArgumentException if some property of the specified\n     *                                  element prevents it from being added to this deque\n     */\n    void putLast(E e) throws InterruptedException;\n\n    /**\n     * Inserts the specified element at the front of this deque,\n     * waiting up to the specified wait time if necessary for space to\n     * become available.\n     *\n     * @param e       the element to add\n     * @param timeout how long to wait before giving up, in units of\n     *                <tt>unit</tt>\n     * @param unit    a <tt>TimeUnit</tt> determining how to interpret the\n     *                <tt>timeout</tt> parameter\n     * @return <tt>true</tt> if successful, or <tt>false</tt> if\n     * the specified waiting time elapses before space is available\n     * @throws InterruptedException     if interrupted while waiting\n     * @throws ClassCastException       if the class of the specified element\n     *                                  prevents it from being added to this deque\n     * @throws NullPointerException     if the specified element is null\n     * @throws IllegalArgumentException if some property of the specified\n     *                                  element prevents it from being added to this deque\n     */\n    boolean offerFirst(E e, long timeout, TimeUnit unit)\n            throws InterruptedException;\n\n    /**\n     * Inserts the specified element at the end of this deque,\n     * waiting up to the specified wait time if necessary for space to\n     * become available.\n     *\n     * @param e       the element to add\n     * @param timeout how long to wait before giving up, in units of\n     *                <tt>unit</tt>\n     * @param unit    a <tt>TimeUnit</tt> determining how to interpret the\n     *                <tt>timeout</tt> parameter\n     * @return <tt>true</tt> if successful, or <tt>false</tt> if\n     * the specified waiting time elapses before space is available\n     * @throws InterruptedException     if interrupted while waiting\n     * @throws ClassCastException       if the class of the specified element\n     *                                  prevents it from being added to this deque\n     * @throws NullPointerException     if the specified element is null\n     * @throws IllegalArgumentException if some property of the specified\n     *                                  element prevents it from being added to this deque\n     */\n    boolean offerLast(E e, long timeout, TimeUnit unit)\n            throws InterruptedException;\n\n    /**\n     * Retrieves and removes the first element of this deque, waiting\n     * if necessary until an element becomes available.\n     *\n     * @return the head of this deque\n     * @throws InterruptedException if interrupted while waiting\n     */\n    E takeFirst() throws InterruptedException;\n\n    /**\n     * Retrieves and removes the last element of this deque, waiting\n     * if necessary until an element becomes available.\n     *\n     * @return the tail of this deque\n     * @throws InterruptedException if interrupted while waiting\n     */\n    E takeLast() throws InterruptedException;\n\n    /**\n     * Retrieves and removes the first element of this deque, waiting\n     * up to the specified wait time if necessary for an element to\n     * become available.\n     *\n     * @param timeout how long to wait before giving up, in units of\n     *                <tt>unit</tt>\n     * @param unit    a <tt>TimeUnit</tt> determining how to interpret the\n     *                <tt>timeout</tt> parameter\n     * @return the head of this deque, or <tt>null</tt> if the specified\n     * waiting time elapses before an element is available\n     * @throws InterruptedException if interrupted while waiting\n     */\n    E pollFirst(long timeout, TimeUnit unit)\n            throws InterruptedException;\n\n    /**\n     * Retrieves and removes the last element of this deque, waiting\n     * up to the specified wait time if necessary for an element to\n     * become available.\n     *\n     * @param timeout how long to wait before giving up, in units of\n     *                <tt>unit</tt>\n     * @param unit    a <tt>TimeUnit</tt> determining how to interpret the\n     *                <tt>timeout</tt> parameter\n     * @return the tail of this deque, or <tt>null</tt> if the specified\n     * waiting time elapses before an element is available\n     * @throws InterruptedException if interrupted while waiting\n     */\n    E pollLast(long timeout, TimeUnit unit)\n            throws InterruptedException;\n\n    /**\n     * Removes the first occurrence of the specified element from this deque.\n     * If the deque does not contain the element, it is unchanged.\n     * More formally, removes the first element <tt>e</tt> such that\n     * <tt>o.equals(e)</tt> (if such an element exists).\n     * Returns <tt>true</tt> if this deque contained the specified element\n     * (or equivalently, if this deque changed as a result of the call).\n     *\n     * @param o element to be removed from this deque, if present\n     * @return <tt>true</tt> if an element was removed as a result of this call\n     * @throws ClassCastException   if the class of the specified element\n     *                              is incompatible with this deque (optional)\n     * @throws NullPointerException if the specified element is null (optional)\n     */\n    boolean removeFirstOccurrence(Object o);\n\n    /**\n     * Removes the last occurrence of the specified element from this deque.\n     * If the deque does not contain the element, it is unchanged.\n     * More formally, removes the last element <tt>e</tt> such that\n     * <tt>o.equals(e)</tt> (if such an element exists).\n     * Returns <tt>true</tt> if this deque contained the specified element\n     * (or equivalently, if this deque changed as a result of the call).\n     *\n     * @param o element to be removed from this deque, if present\n     * @return <tt>true</tt> if an element was removed as a result of this call\n     * @throws ClassCastException   if the class of the specified element\n     *                              is incompatible with this deque (optional)\n     * @throws NullPointerException if the specified element is null (optional)\n     */\n    boolean removeLastOccurrence(Object o);\n\n    // *** BlockingQueue methods ***\n\n    /**\n     * Inserts the specified element into the queue represented by this deque\n     * (in other words, at the tail of this deque) if it is possible to do so\n     * immediately without violating capacity restrictions, returning\n     * <tt>true</tt> upon success and throwing an\n     * <tt>IllegalStateException</tt> if no space is currently available.\n     * When using a capacity-restricted deque, it is generally preferable to\n     * use {@link #offer offer}.\n     * <p/>\n     * <p>This method is equivalent to {@link #addLast addLast}.\n     *\n     * @param e the element to add\n     * @throws IllegalStateException    {@inheritDoc}\n     * @throws ClassCastException       if the class of the specified element\n     *                                  prevents it from being added to this deque\n     * @throws NullPointerException     if the specified element is null\n     * @throws IllegalArgumentException if some property of the specified\n     *                                  element prevents it from being added to this deque\n     */\n    boolean add(E e);\n\n    /**\n     * Inserts the specified element into the queue represented by this deque\n     * (in other words, at the tail of this deque) if it is possible to do so\n     * immediately without violating capacity restrictions, returning\n     * <tt>true</tt> upon success and <tt>false</tt> if no space is currently\n     * available.  When using a capacity-restricted deque, this method is\n     * generally preferable to the {@link #add} method, which can fail to\n     * insert an element only by throwing an exception.\n     * <p/>\n     * <p>This method is equivalent to {@link #offerLast offerLast}.\n     *\n     * @param e the element to add\n     * @throws ClassCastException       if the class of the specified element\n     *                                  prevents it from being added to this deque\n     * @throws NullPointerException     if the specified element is null\n     * @throws IllegalArgumentException if some property of the specified\n     *                                  element prevents it from being added to this deque\n     */\n    boolean offer(E e);\n\n    /**\n     * Inserts the specified element into the queue represented by this deque\n     * (in other words, at the tail of this deque), waiting if necessary for\n     * space to become available.\n     * <p/>\n     * <p>This method is equivalent to {@link #putLast putLast}.\n     *\n     * @param e the element to add\n     * @throws InterruptedException     {@inheritDoc}\n     * @throws ClassCastException       if the class of the specified element\n     *                                  prevents it from being added to this deque\n     * @throws NullPointerException     if the specified element is null\n     * @throws IllegalArgumentException if some property of the specified\n     *                                  element prevents it from being added to this deque\n     */\n    void put(E e) throws InterruptedException;\n\n    /**\n     * Inserts the specified element into the queue represented by this deque\n     * (in other words, at the tail of this deque), waiting up to the\n     * specified wait time if necessary for space to become available.\n     * <p/>\n     * <p>This method is equivalent to\n     * {@link #offerLast offerLast}.\n     *\n     * @param e the element to add\n     * @return <tt>true</tt> if the element was added to this deque, else\n     * <tt>false</tt>\n     * @throws InterruptedException     {@inheritDoc}\n     * @throws ClassCastException       if the class of the specified element\n     *                                  prevents it from being added to this deque\n     * @throws NullPointerException     if the specified element is null\n     * @throws IllegalArgumentException if some property of the specified\n     *                                  element prevents it from being added to this deque\n     */\n    boolean offer(E e, long timeout, TimeUnit unit)\n            throws InterruptedException;\n\n    /**\n     * Retrieves and removes the head of the queue represented by this deque\n     * (in other words, the first element of this deque).\n     * This method differs from {@link #poll poll} only in that it\n     * throws an exception if this deque is empty.\n     * <p/>\n     * <p>This method is equivalent to {@link #removeFirst() removeFirst}.\n     *\n     * @return the head of the queue represented by this deque\n     * @throws NoSuchElementException if this deque is empty\n     */\n    E remove();\n\n    /**\n     * Retrieves and removes the head of the queue represented by this deque\n     * (in other words, the first element of this deque), or returns\n     * <tt>null</tt> if this deque is empty.\n     * <p/>\n     * <p>This method is equivalent to {@link #pollFirst()}.\n     *\n     * @return the head of this deque, or <tt>null</tt> if this deque is empty\n     */\n    E poll();\n\n    /**\n     * Retrieves and removes the head of the queue represented by this deque\n     * (in other words, the first element of this deque), waiting if\n     * necessary until an element becomes available.\n     * <p/>\n     * <p>This method is equivalent to {@link #takeFirst() takeFirst}.\n     *\n     * @return the head of this deque\n     * @throws InterruptedException if interrupted while waiting\n     */\n    E take() throws InterruptedException;\n\n    /**\n     * Retrieves and removes the head of the queue represented by this deque\n     * (in other words, the first element of this deque), waiting up to the\n     * specified wait time if necessary for an element to become available.\n     * <p/>\n     * <p>This method is equivalent to\n     * {@link #pollFirst(long, TimeUnit) pollFirst}.\n     *\n     * @return the head of this deque, or <tt>null</tt> if the\n     * specified waiting time elapses before an element is available\n     * @throws InterruptedException if interrupted while waiting\n     */\n    E poll(long timeout, TimeUnit unit)\n            throws InterruptedException;\n\n    /**\n     * Retrieves, but does not remove, the head of the queue represented by\n     * this deque (in other words, the first element of this deque).\n     * This method differs from {@link #peek peek} only in that it throws an\n     * exception if this deque is empty.\n     * <p/>\n     * <p>This method is equivalent to {@link #getFirst() getFirst}.\n     *\n     * @return the head of this deque\n     * @throws NoSuchElementException if this deque is empty\n     */\n    E element();\n\n    /**\n     * Retrieves, but does not remove, the head of the queue represented by\n     * this deque (in other words, the first element of this deque), or\n     * returns <tt>null</tt> if this deque is empty.\n     * <p/>\n     * <p>This method is equivalent to {@link #peekFirst() peekFirst}.\n     *\n     * @return the head of this deque, or <tt>null</tt> if this deque is empty\n     */\n    E peek();\n\n    /**\n     * Removes the first occurrence of the specified element from this deque.\n     * If the deque does not contain the element, it is unchanged.\n     * More formally, removes the first element <tt>e</tt> such that\n     * <tt>o.equals(e)</tt> (if such an element exists).\n     * Returns <tt>true</tt> if this deque contained the specified element\n     * (or equivalently, if this deque changed as a result of the call).\n     * <p/>\n     * <p>This method is equivalent to\n     * {@link #removeFirstOccurrence removeFirstOccurrence}.\n     *\n     * @param o element to be removed from this deque, if present\n     * @return <tt>true</tt> if this deque changed as a result of the call\n     * @throws ClassCastException   if the class of the specified element\n     *                              is incompatible with this deque (optional)\n     * @throws NullPointerException if the specified element is null (optional)\n     */\n    boolean remove(Object o);\n\n    /**\n     * Returns <tt>true</tt> if this deque contains the specified element.\n     * More formally, returns <tt>true</tt> if and only if this deque contains\n     * at least one element <tt>e</tt> such that <tt>o.equals(e)</tt>.\n     *\n     * @param o object to be checked for containment in this deque\n     * @return <tt>true</tt> if this deque contains the specified element\n     * @throws ClassCastException   if the class of the specified element\n     *                              is incompatible with this deque (optional)\n     * @throws NullPointerException if the specified element is null (optional)\n     */\n    public boolean contains(Object o);\n\n    /**\n     * Returns the number of elements in this deque.\n     *\n     * @return the number of elements in this deque\n     */\n    public int size();\n\n    /**\n     * Returns an iterator over the elements in this deque in proper sequence.\n     * The elements will be returned in order from first (head) to last (tail).\n     *\n     * @return an iterator over the elements in this deque in proper sequence\n     */\n    Iterator<E> iterator();\n\n    // *** Stack methods ***\n\n    /**\n     * Pushes an element onto the stack represented by this deque.  In other\n     * words, inserts the element at the front of this deque unless it would\n     * violate capacity restrictions.\n     * <p/>\n     * <p>This method is equivalent to {@link #addFirst addFirst}.\n     *\n     * @throws IllegalStateException    {@inheritDoc}\n     * @throws ClassCastException       {@inheritDoc}\n     * @throws NullPointerException     if the specified element is null\n     * @throws IllegalArgumentException {@inheritDoc}\n     */\n    void push(E e);\n}\n"
  },
  {
    "path": "library/src/main/java/com/nostra13/universalimageloader/core/assist/deque/Deque.java",
    "content": "/*\n * Written by Doug Lea and Josh Bloch with assistance from members of\n * JCP JSR-166 Expert Group and released to the public domain, as explained\n * at http://creativecommons.org/licenses/publicdomain\n */\n\npackage com.nostra13.universalimageloader.core.assist.deque;\n\nimport java.util.Collection;\nimport java.util.Iterator;\nimport java.util.List;\nimport java.util.NoSuchElementException;\nimport java.util.Queue;\nimport java.util.Stack;\n\n/**\n * A linear collection that supports element insertion and removal at\n * both ends.  The name <i>deque</i> is short for \"double ended queue\"\n * and is usually pronounced \"deck\".  Most <tt>Deque</tt>\n * implementations place no fixed limits on the number of elements\n * they may contain, but this interface supports capacity-restricted\n * deques as well as those with no fixed size limit.\n * <p/>\n * <p>This interface defines methods to access the elements at both\n * ends of the deque.  Methods are provided to insert, remove, and\n * examine the element.  Each of these methods exists in two forms:\n * one throws an exception if the operation fails, the other returns a\n * special value (either <tt>null</tt> or <tt>false</tt>, depending on\n * the operation).  The latter form of the insert operation is\n * designed specifically for use with capacity-restricted\n * <tt>Deque</tt> implementations; in most implementations, insert\n * operations cannot fail.\n * <p/>\n * <p>The twelve methods described above are summarized in the\n * following table:\n * <p/>\n * <p/>\n * <table BORDER CELLPADDING=3 CELLSPACING=1>\n * <tr>\n * <td></td>\n * <td ALIGN=CENTER COLSPAN = 2> <b>First Element (Head)</b></td>\n * <td ALIGN=CENTER COLSPAN = 2> <b>Last Element (Tail)</b></td>\n * </tr>\n * <tr>\n * <td></td>\n * <td ALIGN=CENTER><em>Throws exception</em></td>\n * <td ALIGN=CENTER><em>Special value</em></td>\n * <td ALIGN=CENTER><em>Throws exception</em></td>\n * <td ALIGN=CENTER><em>Special value</em></td>\n * </tr>\n * <tr>\n * <td><b>Insert</b></td>\n * <td>{@link #addFirst addFirst(e)}</td>\n * <td>{@link #offerFirst offerFirst(e)}</td>\n * <td>{@link #addLast addLast(e)}</td>\n * <td>{@link #offerLast offerLast(e)}</td>\n * </tr>\n * <tr>\n * <td><b>Remove</b></td>\n * <td>{@link #removeFirst removeFirst()}</td>\n * <td>{@link #pollFirst pollFirst()}</td>\n * <td>{@link #removeLast removeLast()}</td>\n * <td>{@link #pollLast pollLast()}</td>\n * </tr>\n * <tr>\n * <td><b>Examine</b></td>\n * <td>{@link #getFirst getFirst()}</td>\n * <td>{@link #peekFirst peekFirst()}</td>\n * <td>{@link #getLast getLast()}</td>\n * <td>{@link #peekLast peekLast()}</td>\n * </tr>\n * </table>\n * <p/>\n * <p>This interface extends the {@link Queue} interface.  When a deque is\n * used as a queue, FIFO (First-In-First-Out) behavior results.  Elements are\n * added at the end of the deque and removed from the beginning.  The methods\n * inherited from the <tt>Queue</tt> interface are precisely equivalent to\n * <tt>Deque</tt> methods as indicated in the following table:\n * <p/>\n * <p/>\n * <table BORDER CELLPADDING=3 CELLSPACING=1>\n * <tr>\n * <td ALIGN=CENTER> <b><tt>Queue</tt> Method</b></td>\n * <td ALIGN=CENTER> <b>Equivalent <tt>Deque</tt> Method</b></td>\n * </tr>\n * <tr>\n * <td>{@link java.util.Queue#add add(e)}</td>\n * <td>{@link #addLast addLast(e)}</td>\n * </tr>\n * <tr>\n * <td>{@link java.util.Queue#offer offer(e)}</td>\n * <td>{@link #offerLast offerLast(e)}</td>\n * </tr>\n * <tr>\n * <td>{@link java.util.Queue#remove remove()}</td>\n * <td>{@link #removeFirst removeFirst()}</td>\n * </tr>\n * <tr>\n * <td>{@link java.util.Queue#poll poll()}</td>\n * <td>{@link #pollFirst pollFirst()}</td>\n * </tr>\n * <tr>\n * <td>{@link java.util.Queue#element element()}</td>\n * <td>{@link #getFirst getFirst()}</td>\n * </tr>\n * <tr>\n * <td>{@link java.util.Queue#peek peek()}</td>\n * <td>{@link #peek peekFirst()}</td>\n * </tr>\n * </table>\n * <p/>\n * <p>Deques can also be used as LIFO (Last-In-First-Out) stacks.  This\n * interface should be used in preference to the legacy {@link Stack} class.\n * When a deque is used as a stack, elements are pushed and popped from the\n * beginning of the deque.  Stack methods are precisely equivalent to\n * <tt>Deque</tt> methods as indicated in the table below:\n * <p/>\n * <p/>\n * <table BORDER CELLPADDING=3 CELLSPACING=1>\n * <tr>\n * <td ALIGN=CENTER> <b>Stack Method</b></td>\n * <td ALIGN=CENTER> <b>Equivalent <tt>Deque</tt> Method</b></td>\n * </tr>\n * <tr>\n * <td>{@link #push push(e)}</td>\n * <td>{@link #addFirst addFirst(e)}</td>\n * </tr>\n * <tr>\n * <td>{@link #pop pop()}</td>\n * <td>{@link #removeFirst removeFirst()}</td>\n * </tr>\n * <tr>\n * <td>{@link #peek peek()}</td>\n * <td>{@link #peekFirst peekFirst()}</td>\n * </tr>\n * </table>\n * <p/>\n * <p>Note that the {@link #peek peek} method works equally well when\n * a deque is used as a queue or a stack; in either case, elements are\n * drawn from the beginning of the deque.\n * <p/>\n * <p>This interface provides two methods to remove interior\n * elements, {@link #removeFirstOccurrence removeFirstOccurrence} and\n * {@link #removeLastOccurrence removeLastOccurrence}.\n * <p/>\n * <p>Unlike the {@link List} interface, this interface does not\n * provide support for indexed access to elements.\n * <p/>\n * <p>While <tt>Deque</tt> implementations are not strictly required\n * to prohibit the insertion of null elements, they are strongly\n * encouraged to do so.  Users of any <tt>Deque</tt> implementations\n * that do allow null elements are strongly encouraged <i>not</i> to\n * take advantage of the ability to insert nulls.  This is so because\n * <tt>null</tt> is used as a special return value by various methods\n * to indicated that the deque is empty.\n * <p/>\n * <p><tt>Deque</tt> implementations generally do not define\n * element-based versions of the <tt>equals</tt> and <tt>hashCode</tt>\n * methods, but instead inherit the identity-based versions from class\n * <tt>Object</tt>.\n *\n * @param <E> the type of elements held in this collection\n * @author Doug Lea\n * @author Josh Bloch\n * @since 1.6\n */\n\npublic interface Deque<E> extends Queue<E> {\n    /**\n     * Inserts the specified element at the front of this deque if it is\n     * possible to do so immediately without violating capacity restrictions.\n     * When using a capacity-restricted deque, it is generally preferable to\n     * use method {@link #offerFirst}.\n     *\n     * @param e the element to add\n     * @throws IllegalStateException    if the element cannot be added at this\n     *                                  time due to capacity restrictions\n     * @throws ClassCastException       if the class of the specified element\n     *                                  prevents it from being added to this deque\n     * @throws NullPointerException     if the specified element is null and this\n     *                                  deque does not permit null elements\n     * @throws IllegalArgumentException if some property of the specified\n     *                                  element prevents it from being added to this deque\n     */\n    void addFirst(E e);\n\n    /**\n     * Inserts the specified element at the end of this deque if it is\n     * possible to do so immediately without violating capacity restrictions.\n     * When using a capacity-restricted deque, it is generally preferable to\n     * use method {@link #offerLast}.\n     * <p/>\n     * <p>This method is equivalent to {@link #add}.\n     *\n     * @param e the element to add\n     * @throws IllegalStateException    if the element cannot be added at this\n     *                                  time due to capacity restrictions\n     * @throws ClassCastException       if the class of the specified element\n     *                                  prevents it from being added to this deque\n     * @throws NullPointerException     if the specified element is null and this\n     *                                  deque does not permit null elements\n     * @throws IllegalArgumentException if some property of the specified\n     *                                  element prevents it from being added to this deque\n     */\n    void addLast(E e);\n\n    /**\n     * Inserts the specified element at the front of this deque unless it would\n     * violate capacity restrictions.  When using a capacity-restricted deque,\n     * this method is generally preferable to the {@link #addFirst} method,\n     * which can fail to insert an element only by throwing an exception.\n     *\n     * @param e the element to add\n     * @return <tt>true</tt> if the element was added to this deque, else\n     * <tt>false</tt>\n     * @throws ClassCastException       if the class of the specified element\n     *                                  prevents it from being added to this deque\n     * @throws NullPointerException     if the specified element is null and this\n     *                                  deque does not permit null elements\n     * @throws IllegalArgumentException if some property of the specified\n     *                                  element prevents it from being added to this deque\n     */\n    boolean offerFirst(E e);\n\n    /**\n     * Inserts the specified element at the end of this deque unless it would\n     * violate capacity restrictions.  When using a capacity-restricted deque,\n     * this method is generally preferable to the {@link #addLast} method,\n     * which can fail to insert an element only by throwing an exception.\n     *\n     * @param e the element to add\n     * @return <tt>true</tt> if the element was added to this deque, else\n     * <tt>false</tt>\n     * @throws ClassCastException       if the class of the specified element\n     *                                  prevents it from being added to this deque\n     * @throws NullPointerException     if the specified element is null and this\n     *                                  deque does not permit null elements\n     * @throws IllegalArgumentException if some property of the specified\n     *                                  element prevents it from being added to this deque\n     */\n    boolean offerLast(E e);\n\n    /**\n     * Retrieves and removes the first element of this deque.  This method\n     * differs from {@link #pollFirst pollFirst} only in that it throws an\n     * exception if this deque is empty.\n     *\n     * @return the head of this deque\n     * @throws NoSuchElementException if this deque is empty\n     */\n    E removeFirst();\n\n    /**\n     * Retrieves and removes the last element of this deque.  This method\n     * differs from {@link #pollLast pollLast} only in that it throws an\n     * exception if this deque is empty.\n     *\n     * @return the tail of this deque\n     * @throws NoSuchElementException if this deque is empty\n     */\n    E removeLast();\n\n    /**\n     * Retrieves and removes the first element of this deque,\n     * or returns <tt>null</tt> if this deque is empty.\n     *\n     * @return the head of this deque, or <tt>null</tt> if this deque is empty\n     */\n    E pollFirst();\n\n    /**\n     * Retrieves and removes the last element of this deque,\n     * or returns <tt>null</tt> if this deque is empty.\n     *\n     * @return the tail of this deque, or <tt>null</tt> if this deque is empty\n     */\n    E pollLast();\n\n    /**\n     * Retrieves, but does not remove, the first element of this deque.\n     * <p/>\n     * This method differs from {@link #peekFirst peekFirst} only in that it\n     * throws an exception if this deque is empty.\n     *\n     * @return the head of this deque\n     * @throws NoSuchElementException if this deque is empty\n     */\n    E getFirst();\n\n    /**\n     * Retrieves, but does not remove, the last element of this deque.\n     * This method differs from {@link #peekLast peekLast} only in that it\n     * throws an exception if this deque is empty.\n     *\n     * @return the tail of this deque\n     * @throws NoSuchElementException if this deque is empty\n     */\n    E getLast();\n\n    /**\n     * Retrieves, but does not remove, the first element of this deque,\n     * or returns <tt>null</tt> if this deque is empty.\n     *\n     * @return the head of this deque, or <tt>null</tt> if this deque is empty\n     */\n    E peekFirst();\n\n    /**\n     * Retrieves, but does not remove, the last element of this deque,\n     * or returns <tt>null</tt> if this deque is empty.\n     *\n     * @return the tail of this deque, or <tt>null</tt> if this deque is empty\n     */\n    E peekLast();\n\n    /**\n     * Removes the first occurrence of the specified element from this deque.\n     * If the deque does not contain the element, it is unchanged.\n     * More formally, removes the first element <tt>e</tt> such that\n     * <tt>(o==null&nbsp;?&nbsp;e==null&nbsp;:&nbsp;o.equals(e))</tt>\n     * (if such an element exists).\n     * Returns <tt>true</tt> if this deque contained the specified element\n     * (or equivalently, if this deque changed as a result of the call).\n     *\n     * @param o element to be removed from this deque, if present\n     * @return <tt>true</tt> if an element was removed as a result of this call\n     * @throws ClassCastException   if the class of the specified element\n     *                              is incompatible with this deque (optional)\n     * @throws NullPointerException if the specified element is null and this\n     *                              deque does not permit null elements (optional)\n     */\n    boolean removeFirstOccurrence(Object o);\n\n    /**\n     * Removes the last occurrence of the specified element from this deque.\n     * If the deque does not contain the element, it is unchanged.\n     * More formally, removes the last element <tt>e</tt> such that\n     * <tt>(o==null&nbsp;?&nbsp;e==null&nbsp;:&nbsp;o.equals(e))</tt>\n     * (if such an element exists).\n     * Returns <tt>true</tt> if this deque contained the specified element\n     * (or equivalently, if this deque changed as a result of the call).\n     *\n     * @param o element to be removed from this deque, if present\n     * @return <tt>true</tt> if an element was removed as a result of this call\n     * @throws ClassCastException   if the class of the specified element\n     *                              is incompatible with this deque (optional)\n     * @throws NullPointerException if the specified element is null and this\n     *                              deque does not permit null elements (optional)\n     */\n    boolean removeLastOccurrence(Object o);\n\n    // *** Queue methods ***\n\n    /**\n     * Inserts the specified element into the queue represented by this deque\n     * (in other words, at the tail of this deque) if it is possible to do so\n     * immediately without violating capacity restrictions, returning\n     * <tt>true</tt> upon success and throwing an\n     * <tt>IllegalStateException</tt> if no space is currently available.\n     * When using a capacity-restricted deque, it is generally preferable to\n     * use {@link #offer offer}.\n     * <p/>\n     * <p>This method is equivalent to {@link #addLast}.\n     *\n     * @param e the element to add\n     * @return <tt>true</tt> (as specified by {@link Collection#add})\n     * @throws IllegalStateException    if the element cannot be added at this\n     *                                  time due to capacity restrictions\n     * @throws ClassCastException       if the class of the specified element\n     *                                  prevents it from being added to this deque\n     * @throws NullPointerException     if the specified element is null and this\n     *                                  deque does not permit null elements\n     * @throws IllegalArgumentException if some property of the specified\n     *                                  element prevents it from being added to this deque\n     */\n    boolean add(E e);\n\n    /**\n     * Inserts the specified element into the queue represented by this deque\n     * (in other words, at the tail of this deque) if it is possible to do so\n     * immediately without violating capacity restrictions, returning\n     * <tt>true</tt> upon success and <tt>false</tt> if no space is currently\n     * available.  When using a capacity-restricted deque, this method is\n     * generally preferable to the {@link #add} method, which can fail to\n     * insert an element only by throwing an exception.\n     * <p/>\n     * <p>This method is equivalent to {@link #offerLast}.\n     *\n     * @param e the element to add\n     * @return <tt>true</tt> if the element was added to this deque, else\n     * <tt>false</tt>\n     * @throws ClassCastException       if the class of the specified element\n     *                                  prevents it from being added to this deque\n     * @throws NullPointerException     if the specified element is null and this\n     *                                  deque does not permit null elements\n     * @throws IllegalArgumentException if some property of the specified\n     *                                  element prevents it from being added to this deque\n     */\n    boolean offer(E e);\n\n    /**\n     * Retrieves and removes the head of the queue represented by this deque\n     * (in other words, the first element of this deque).\n     * This method differs from {@link #poll poll} only in that it throws an\n     * exception if this deque is empty.\n     * <p/>\n     * <p>This method is equivalent to {@link #removeFirst()}.\n     *\n     * @return the head of the queue represented by this deque\n     * @throws NoSuchElementException if this deque is empty\n     */\n    E remove();\n\n    /**\n     * Retrieves and removes the head of the queue represented by this deque\n     * (in other words, the first element of this deque), or returns\n     * <tt>null</tt> if this deque is empty.\n     * <p/>\n     * <p>This method is equivalent to {@link #pollFirst()}.\n     *\n     * @return the first element of this deque, or <tt>null</tt> if\n     * this deque is empty\n     */\n    E poll();\n\n    /**\n     * Retrieves, but does not remove, the head of the queue represented by\n     * this deque (in other words, the first element of this deque).\n     * This method differs from {@link #peek peek} only in that it throws an\n     * exception if this deque is empty.\n     * <p/>\n     * <p>This method is equivalent to {@link #getFirst()}.\n     *\n     * @return the head of the queue represented by this deque\n     * @throws NoSuchElementException if this deque is empty\n     */\n    E element();\n\n    /**\n     * Retrieves, but does not remove, the head of the queue represented by\n     * this deque (in other words, the first element of this deque), or\n     * returns <tt>null</tt> if this deque is empty.\n     * <p/>\n     * <p>This method is equivalent to {@link #peekFirst()}.\n     *\n     * @return the head of the queue represented by this deque, or\n     * <tt>null</tt> if this deque is empty\n     */\n    E peek();\n\n\n    // *** Stack methods ***\n\n    /**\n     * Pushes an element onto the stack represented by this deque (in other\n     * words, at the head of this deque) if it is possible to do so\n     * immediately without violating capacity restrictions, returning\n     * <tt>true</tt> upon success and throwing an\n     * <tt>IllegalStateException</tt> if no space is currently available.\n     * <p/>\n     * <p>This method is equivalent to {@link #addFirst}.\n     *\n     * @param e the element to push\n     * @throws IllegalStateException    if the element cannot be added at this\n     *                                  time due to capacity restrictions\n     * @throws ClassCastException       if the class of the specified element\n     *                                  prevents it from being added to this deque\n     * @throws NullPointerException     if the specified element is null and this\n     *                                  deque does not permit null elements\n     * @throws IllegalArgumentException if some property of the specified\n     *                                  element prevents it from being added to this deque\n     */\n    void push(E e);\n\n    /**\n     * Pops an element from the stack represented by this deque.  In other\n     * words, removes and returns the first element of this deque.\n     * <p/>\n     * <p>This method is equivalent to {@link #removeFirst()}.\n     *\n     * @return the element at the front of this deque (which is the top\n     * of the stack represented by this deque)\n     * @throws NoSuchElementException if this deque is empty\n     */\n    E pop();\n\n\n    // *** Collection methods ***\n\n    /**\n     * Removes the first occurrence of the specified element from this deque.\n     * If the deque does not contain the element, it is unchanged.\n     * More formally, removes the first element <tt>e</tt> such that\n     * <tt>(o==null&nbsp;?&nbsp;e==null&nbsp;:&nbsp;o.equals(e))</tt>\n     * (if such an element exists).\n     * Returns <tt>true</tt> if this deque contained the specified element\n     * (or equivalently, if this deque changed as a result of the call).\n     * <p/>\n     * <p>This method is equivalent to {@link #removeFirstOccurrence}.\n     *\n     * @param o element to be removed from this deque, if present\n     * @return <tt>true</tt> if an element was removed as a result of this call\n     * @throws ClassCastException   if the class of the specified element\n     *                              is incompatible with this deque (optional)\n     * @throws NullPointerException if the specified element is null and this\n     *                              deque does not permit null elements (optional)\n     */\n    boolean remove(Object o);\n\n    /**\n     * Returns <tt>true</tt> if this deque contains the specified element.\n     * More formally, returns <tt>true</tt> if and only if this deque contains\n     * at least one element <tt>e</tt> such that\n     * <tt>(o==null&nbsp;?&nbsp;e==null&nbsp;:&nbsp;o.equals(e))</tt>.\n     *\n     * @param o element whose presence in this deque is to be tested\n     * @return <tt>true</tt> if this deque contains the specified element\n     * @throws ClassCastException   if the type of the specified element\n     *                              is incompatible with this deque (optional)\n     * @throws NullPointerException if the specified element is null and this\n     *                              deque does not permit null elements (optional)\n     */\n    boolean contains(Object o);\n\n    /**\n     * Returns the number of elements in this deque.\n     *\n     * @return the number of elements in this deque\n     */\n    public int size();\n\n    /**\n     * Returns an iterator over the elements in this deque in proper sequence.\n     * The elements will be returned in order from first (head) to last (tail).\n     *\n     * @return an iterator over the elements in this deque in proper sequence\n     */\n    Iterator<E> iterator();\n\n    /**\n     * Returns an iterator over the elements in this deque in reverse\n     * sequential order.  The elements will be returned in order from\n     * last (tail) to first (head).\n     *\n     * @return an iterator over the elements in this deque in reverse\n     * sequence\n     */\n    Iterator<E> descendingIterator();\n\n}\n"
  },
  {
    "path": "library/src/main/java/com/nostra13/universalimageloader/core/assist/deque/LIFOLinkedBlockingDeque.java",
    "content": "package com.nostra13.universalimageloader.core.assist.deque;\n\nimport java.util.NoSuchElementException;\n\n/**\n * {@link LinkedBlockingDeque} using LIFO algorithm\n * \n * @author Sergey Tarasevich (nostra13[at]gmail[dot]com)\n * @since 1.6.3\n */\npublic class LIFOLinkedBlockingDeque<T> extends LinkedBlockingDeque<T> {\n\n\tprivate static final long serialVersionUID = -4114786347960826192L;\n\n\t/**\n\t * Inserts the specified element at the front of this deque if it is possible to do so immediately without violating\n\t * capacity restrictions, returning <tt>true</tt> upon success and <tt>false</tt> if no space is currently\n\t * available. When using a capacity-restricted deque, this method is generally preferable to the {@link #addFirst\n\t * addFirst} method, which can fail to insert an element only by throwing an exception.\n\t * \n\t * @param e\n\t *            the element to add\n\t * @throws ClassCastException\n\t *             {@inheritDoc}\n\t * @throws NullPointerException\n\t *             if the specified element is null\n\t * @throws IllegalArgumentException\n\t *             {@inheritDoc}\n\t */\n\t@Override\n\tpublic boolean offer(T e) {\n\t\treturn super.offerFirst(e);\n\t}\n\n\t/**\n\t * Retrieves and removes the first element of this deque. This method differs from {@link #pollFirst pollFirst} only\n\t * in that it throws an exception if this deque is empty.\n\t * \n\t * @return the head of this deque\n\t * @throws NoSuchElementException\n\t *             if this deque is empty\n\t */\n\t@Override\n\tpublic T remove() {\n\t\treturn super.removeFirst();\n\t}\n}"
  },
  {
    "path": "library/src/main/java/com/nostra13/universalimageloader/core/assist/deque/LinkedBlockingDeque.java",
    "content": "/*\n * Written by Doug Lea with assistance from members of JCP JSR-166\n * Expert Group and released to the public domain, as explained at\n * http://creativecommons.org/licenses/publicdomain\n */\n\npackage com.nostra13.universalimageloader.core.assist.deque;\n\nimport java.util.AbstractQueue;\nimport java.util.Collection;\nimport java.util.Iterator;\nimport java.util.NoSuchElementException;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.locks.Condition;\nimport java.util.concurrent.locks.ReentrantLock;\n\n/**\n * An optionally-bounded {@linkplain BlockingDeque blocking deque} based on\n * linked nodes.\n * <p/>\n * <p> The optional capacity bound constructor argument serves as a\n * way to prevent excessive expansion. The capacity, if unspecified,\n * is equal to {@link Integer#MAX_VALUE}.  Linked nodes are\n * dynamically created upon each insertion unless this would bring the\n * deque above capacity.\n * <p/>\n * <p>Most operations run in constant time (ignoring time spent\n * blocking).  Exceptions include {@link #remove(Object) remove},\n * {@link #removeFirstOccurrence removeFirstOccurrence}, {@link\n * #removeLastOccurrence removeLastOccurrence}, {@link #contains\n * contains}, {@link #iterator iterator.remove()}, and the bulk\n * operations, all of which run in linear time.\n * <p/>\n * <p>This class and its iterator implement all of the\n * <em>optional</em> methods of the {@link Collection} and {@link\n * Iterator} interfaces.\n * <p/>\n * <p>This class is a member of the\n * <a href=\"{@docRoot}/../technotes/guides/collections/index.html\">\n * Java Collections Framework</a>.\n *\n * @param <E> the type of elements held in this collection\n * @author Doug Lea\n * @since 1.6\n */\npublic class LinkedBlockingDeque<E>\n        extends AbstractQueue<E>\n        implements BlockingDeque<E>, java.io.Serializable {\n\n    /*\n     * Implemented as a simple doubly-linked list protected by a\n     * single lock and using conditions to manage blocking.\n     *\n     * To implement weakly consistent iterators, it appears we need to\n     * keep all Nodes GC-reachable from a predecessor dequeued Node.\n     * That would cause two problems:\n     * - allow a rogue Iterator to cause unbounded memory retention\n     * - cause cross-generational linking of old Nodes to new Nodes if\n     *   a Node was tenured while live, which generational GCs have a\n     *   hard time dealing with, causing repeated major collections.\n     * However, only non-deleted Nodes need to be reachable from\n     * dequeued Nodes, and reachability does not necessarily have to\n     * be of the kind understood by the GC.  We use the trick of\n     * linking a Node that has just been dequeued to itself.  Such a\n     * self-link implicitly means to jump to \"first\" (for next links)\n     * or \"last\" (for prev links).\n     */\n\n    /*\n     * We have \"diamond\" multiple interface/abstract class inheritance\n     * here, and that introduces ambiguities. Often we want the\n     * BlockingDeque javadoc combined with the AbstractQueue\n     * implementation, so a lot of method specs are duplicated here.\n     */\n\n    private static final long serialVersionUID = -387911632671998426L;\n\n    /**\n     * Doubly-linked list node class\n     */\n    static final class Node<E> {\n        /**\n         * The item, or null if this node has been removed.\n         */\n        E item;\n\n        /**\n         * One of:\n         * - the real predecessor Node\n         * - this Node, meaning the predecessor is tail\n         * - null, meaning there is no predecessor\n         */\n        Node<E> prev;\n\n        /**\n         * One of:\n         * - the real successor Node\n         * - this Node, meaning the successor is head\n         * - null, meaning there is no successor\n         */\n        Node<E> next;\n\n        Node(E x) {\n            item = x;\n        }\n    }\n\n    /**\n     * Pointer to first node.\n     * Invariant: (first == null && last == null) ||\n     * (first.prev == null && first.item != null)\n     */\n    transient Node<E> first;\n\n    /**\n     * Pointer to last node.\n     * Invariant: (first == null && last == null) ||\n     * (last.next == null && last.item != null)\n     */\n    transient Node<E> last;\n\n    /**\n     * Number of items in the deque\n     */\n    private transient int count;\n\n    /**\n     * Maximum number of items in the deque\n     */\n    private final int capacity;\n\n    /**\n     * Main lock guarding all access\n     */\n    final ReentrantLock lock = new ReentrantLock();\n\n    /**\n     * Condition for waiting takes\n     */\n    private final Condition notEmpty = lock.newCondition();\n\n    /**\n     * Condition for waiting puts\n     */\n    private final Condition notFull = lock.newCondition();\n\n    /**\n     * Creates a {@code LinkedBlockingDeque} with a capacity of\n     * {@link Integer#MAX_VALUE}.\n     */\n    public LinkedBlockingDeque() {\n        this(Integer.MAX_VALUE);\n    }\n\n    /**\n     * Creates a {@code LinkedBlockingDeque} with the given (fixed) capacity.\n     *\n     * @param capacity the capacity of this deque\n     * @throws IllegalArgumentException if {@code capacity} is less than 1\n     */\n    public LinkedBlockingDeque(int capacity) {\n        if (capacity <= 0) throw new IllegalArgumentException();\n        this.capacity = capacity;\n    }\n\n    /**\n     * Creates a {@code LinkedBlockingDeque} with a capacity of\n     * {@link Integer#MAX_VALUE}, initially containing the elements of\n     * the given collection, added in traversal order of the\n     * collection's iterator.\n     *\n     * @param c the collection of elements to initially contain\n     * @throws NullPointerException if the specified collection or any\n     *                              of its elements are null\n     */\n    public LinkedBlockingDeque(Collection<? extends E> c) {\n        this(Integer.MAX_VALUE);\n        final ReentrantLock lock = this.lock;\n        lock.lock(); // Never contended, but necessary for visibility\n        try {\n            for (E e : c) {\n                if (e == null)\n                    throw new NullPointerException();\n                if (!linkLast(new Node<E>(e)))\n                    throw new IllegalStateException(\"Deque full\");\n            }\n        } finally {\n            lock.unlock();\n        }\n    }\n\n\n    // Basic linking and unlinking operations, called only while holding lock\n\n    /**\n     * Links node as first element, or returns false if full.\n     */\n    private boolean linkFirst(Node<E> node) {\n        // assert lock.isHeldByCurrentThread();\n        if (count >= capacity)\n            return false;\n        Node<E> f = first;\n        node.next = f;\n        first = node;\n        if (last == null)\n            last = node;\n        else\n            f.prev = node;\n        ++count;\n        notEmpty.signal();\n        return true;\n    }\n\n    /**\n     * Links node as last element, or returns false if full.\n     */\n    private boolean linkLast(Node<E> node) {\n        // assert lock.isHeldByCurrentThread();\n        if (count >= capacity)\n            return false;\n        Node<E> l = last;\n        node.prev = l;\n        last = node;\n        if (first == null)\n            first = node;\n        else\n            l.next = node;\n        ++count;\n        notEmpty.signal();\n        return true;\n    }\n\n    /**\n     * Removes and returns first element, or null if empty.\n     */\n    private E unlinkFirst() {\n        // assert lock.isHeldByCurrentThread();\n        Node<E> f = first;\n        if (f == null)\n            return null;\n        Node<E> n = f.next;\n        E item = f.item;\n        f.item = null;\n        f.next = f; // help GC\n        first = n;\n        if (n == null)\n            last = null;\n        else\n            n.prev = null;\n        --count;\n        notFull.signal();\n        return item;\n    }\n\n    /**\n     * Removes and returns last element, or null if empty.\n     */\n    private E unlinkLast() {\n        // assert lock.isHeldByCurrentThread();\n        Node<E> l = last;\n        if (l == null)\n            return null;\n        Node<E> p = l.prev;\n        E item = l.item;\n        l.item = null;\n        l.prev = l; // help GC\n        last = p;\n        if (p == null)\n            first = null;\n        else\n            p.next = null;\n        --count;\n        notFull.signal();\n        return item;\n    }\n\n    /**\n     * Unlinks x.\n     */\n    void unlink(Node<E> x) {\n        // assert lock.isHeldByCurrentThread();\n        Node<E> p = x.prev;\n        Node<E> n = x.next;\n        if (p == null) {\n            unlinkFirst();\n        } else if (n == null) {\n            unlinkLast();\n        } else {\n            p.next = n;\n            n.prev = p;\n            x.item = null;\n            // Don't mess with x's links.  They may still be in use by\n            // an iterator.\n            --count;\n            notFull.signal();\n        }\n    }\n\n    // BlockingDeque methods\n\n    /**\n     * @throws IllegalStateException {@inheritDoc}\n     * @throws NullPointerException  {@inheritDoc}\n     */\n    public void addFirst(E e) {\n        if (!offerFirst(e))\n            throw new IllegalStateException(\"Deque full\");\n    }\n\n    /**\n     * @throws IllegalStateException {@inheritDoc}\n     * @throws NullPointerException  {@inheritDoc}\n     */\n    public void addLast(E e) {\n        if (!offerLast(e))\n            throw new IllegalStateException(\"Deque full\");\n    }\n\n    /**\n     * @throws NullPointerException {@inheritDoc}\n     */\n    public boolean offerFirst(E e) {\n        if (e == null) throw new NullPointerException();\n        Node<E> node = new Node<E>(e);\n        final ReentrantLock lock = this.lock;\n        lock.lock();\n        try {\n            return linkFirst(node);\n        } finally {\n            lock.unlock();\n        }\n    }\n\n    /**\n     * @throws NullPointerException {@inheritDoc}\n     */\n    public boolean offerLast(E e) {\n        if (e == null) throw new NullPointerException();\n        Node<E> node = new Node<E>(e);\n        final ReentrantLock lock = this.lock;\n        lock.lock();\n        try {\n            return linkLast(node);\n        } finally {\n            lock.unlock();\n        }\n    }\n\n    /**\n     * @throws NullPointerException {@inheritDoc}\n     * @throws InterruptedException {@inheritDoc}\n     */\n    public void putFirst(E e) throws InterruptedException {\n        if (e == null) throw new NullPointerException();\n        Node<E> node = new Node<E>(e);\n        final ReentrantLock lock = this.lock;\n        lock.lock();\n        try {\n            while (!linkFirst(node))\n                notFull.await();\n        } finally {\n            lock.unlock();\n        }\n    }\n\n    /**\n     * @throws NullPointerException {@inheritDoc}\n     * @throws InterruptedException {@inheritDoc}\n     */\n    public void putLast(E e) throws InterruptedException {\n        if (e == null) throw new NullPointerException();\n        Node<E> node = new Node<E>(e);\n        final ReentrantLock lock = this.lock;\n        lock.lock();\n        try {\n            while (!linkLast(node))\n                notFull.await();\n        } finally {\n            lock.unlock();\n        }\n    }\n\n    /**\n     * @throws NullPointerException {@inheritDoc}\n     * @throws InterruptedException {@inheritDoc}\n     */\n    public boolean offerFirst(E e, long timeout, TimeUnit unit)\n            throws InterruptedException {\n        if (e == null) throw new NullPointerException();\n        Node<E> node = new Node<E>(e);\n        long nanos = unit.toNanos(timeout);\n        final ReentrantLock lock = this.lock;\n        lock.lockInterruptibly();\n        try {\n            while (!linkFirst(node)) {\n                if (nanos <= 0)\n                    return false;\n                nanos = notFull.awaitNanos(nanos);\n            }\n            return true;\n        } finally {\n            lock.unlock();\n        }\n    }\n\n    /**\n     * @throws NullPointerException {@inheritDoc}\n     * @throws InterruptedException {@inheritDoc}\n     */\n    public boolean offerLast(E e, long timeout, TimeUnit unit)\n            throws InterruptedException {\n        if (e == null) throw new NullPointerException();\n        Node<E> node = new Node<E>(e);\n        long nanos = unit.toNanos(timeout);\n        final ReentrantLock lock = this.lock;\n        lock.lockInterruptibly();\n        try {\n            while (!linkLast(node)) {\n                if (nanos <= 0)\n                    return false;\n                nanos = notFull.awaitNanos(nanos);\n            }\n            return true;\n        } finally {\n            lock.unlock();\n        }\n    }\n\n    /**\n     * @throws NoSuchElementException {@inheritDoc}\n     */\n    public E removeFirst() {\n        E x = pollFirst();\n        if (x == null) throw new NoSuchElementException();\n        return x;\n    }\n\n    /**\n     * @throws NoSuchElementException {@inheritDoc}\n     */\n    public E removeLast() {\n        E x = pollLast();\n        if (x == null) throw new NoSuchElementException();\n        return x;\n    }\n\n    public E pollFirst() {\n        final ReentrantLock lock = this.lock;\n        lock.lock();\n        try {\n            return unlinkFirst();\n        } finally {\n            lock.unlock();\n        }\n    }\n\n    public E pollLast() {\n        final ReentrantLock lock = this.lock;\n        lock.lock();\n        try {\n            return unlinkLast();\n        } finally {\n            lock.unlock();\n        }\n    }\n\n    public E takeFirst() throws InterruptedException {\n        final ReentrantLock lock = this.lock;\n        lock.lock();\n        try {\n            E x;\n            while ((x = unlinkFirst()) == null)\n                notEmpty.await();\n            return x;\n        } finally {\n            lock.unlock();\n        }\n    }\n\n    public E takeLast() throws InterruptedException {\n        final ReentrantLock lock = this.lock;\n        lock.lock();\n        try {\n            E x;\n            while ((x = unlinkLast()) == null)\n                notEmpty.await();\n            return x;\n        } finally {\n            lock.unlock();\n        }\n    }\n\n    public E pollFirst(long timeout, TimeUnit unit)\n            throws InterruptedException {\n        long nanos = unit.toNanos(timeout);\n        final ReentrantLock lock = this.lock;\n        lock.lockInterruptibly();\n        try {\n            E x;\n            while ((x = unlinkFirst()) == null) {\n                if (nanos <= 0)\n                    return null;\n                nanos = notEmpty.awaitNanos(nanos);\n            }\n            return x;\n        } finally {\n            lock.unlock();\n        }\n    }\n\n    public E pollLast(long timeout, TimeUnit unit)\n            throws InterruptedException {\n        long nanos = unit.toNanos(timeout);\n        final ReentrantLock lock = this.lock;\n        lock.lockInterruptibly();\n        try {\n            E x;\n            while ((x = unlinkLast()) == null) {\n                if (nanos <= 0)\n                    return null;\n                nanos = notEmpty.awaitNanos(nanos);\n            }\n            return x;\n        } finally {\n            lock.unlock();\n        }\n    }\n\n    /**\n     * @throws NoSuchElementException {@inheritDoc}\n     */\n    public E getFirst() {\n        E x = peekFirst();\n        if (x == null) throw new NoSuchElementException();\n        return x;\n    }\n\n    /**\n     * @throws NoSuchElementException {@inheritDoc}\n     */\n    public E getLast() {\n        E x = peekLast();\n        if (x == null) throw new NoSuchElementException();\n        return x;\n    }\n\n    public E peekFirst() {\n        final ReentrantLock lock = this.lock;\n        lock.lock();\n        try {\n            return (first == null) ? null : first.item;\n        } finally {\n            lock.unlock();\n        }\n    }\n\n    public E peekLast() {\n        final ReentrantLock lock = this.lock;\n        lock.lock();\n        try {\n            return (last == null) ? null : last.item;\n        } finally {\n            lock.unlock();\n        }\n    }\n\n    public boolean removeFirstOccurrence(Object o) {\n        if (o == null) return false;\n        final ReentrantLock lock = this.lock;\n        lock.lock();\n        try {\n            for (Node<E> p = first; p != null; p = p.next) {\n                if (o.equals(p.item)) {\n                    unlink(p);\n                    return true;\n                }\n            }\n            return false;\n        } finally {\n            lock.unlock();\n        }\n    }\n\n    public boolean removeLastOccurrence(Object o) {\n        if (o == null) return false;\n        final ReentrantLock lock = this.lock;\n        lock.lock();\n        try {\n            for (Node<E> p = last; p != null; p = p.prev) {\n                if (o.equals(p.item)) {\n                    unlink(p);\n                    return true;\n                }\n            }\n            return false;\n        } finally {\n            lock.unlock();\n        }\n    }\n\n    // BlockingQueue methods\n\n    /**\n     * Inserts the specified element at the end of this deque unless it would\n     * violate capacity restrictions.  When using a capacity-restricted deque,\n     * it is generally preferable to use method {@link #offer offer}.\n     * <p/>\n     * <p>This method is equivalent to {@link #addLast}.\n     *\n     * @throws IllegalStateException if the element cannot be added at this\n     *                               time due to capacity restrictions\n     * @throws NullPointerException  if the specified element is null\n     */\n    public boolean add(E e) {\n        addLast(e);\n        return true;\n    }\n\n    /**\n     * @throws NullPointerException if the specified element is null\n     */\n    public boolean offer(E e) {\n        return offerLast(e);\n    }\n\n    /**\n     * @throws NullPointerException {@inheritDoc}\n     * @throws InterruptedException {@inheritDoc}\n     */\n    public void put(E e) throws InterruptedException {\n        putLast(e);\n    }\n\n    /**\n     * @throws NullPointerException {@inheritDoc}\n     * @throws InterruptedException {@inheritDoc}\n     */\n    public boolean offer(E e, long timeout, TimeUnit unit)\n            throws InterruptedException {\n        return offerLast(e, timeout, unit);\n    }\n\n    /**\n     * Retrieves and removes the head of the queue represented by this deque.\n     * This method differs from {@link #poll poll} only in that it throws an\n     * exception if this deque is empty.\n     * <p/>\n     * <p>This method is equivalent to {@link #removeFirst() removeFirst}.\n     *\n     * @return the head of the queue represented by this deque\n     * @throws NoSuchElementException if this deque is empty\n     */\n    public E remove() {\n        return removeFirst();\n    }\n\n    public E poll() {\n        return pollFirst();\n    }\n\n    public E take() throws InterruptedException {\n        return takeFirst();\n    }\n\n    public E poll(long timeout, TimeUnit unit) throws InterruptedException {\n        return pollFirst(timeout, unit);\n    }\n\n    /**\n     * Retrieves, but does not remove, the head of the queue represented by\n     * this deque.  This method differs from {@link #peek peek} only in that\n     * it throws an exception if this deque is empty.\n     * <p/>\n     * <p>This method is equivalent to {@link #getFirst() getFirst}.\n     *\n     * @return the head of the queue represented by this deque\n     * @throws NoSuchElementException if this deque is empty\n     */\n    public E element() {\n        return getFirst();\n    }\n\n    public E peek() {\n        return peekFirst();\n    }\n\n    /**\n     * Returns the number of additional elements that this deque can ideally\n     * (in the absence of memory or resource constraints) accept without\n     * blocking. This is always equal to the initial capacity of this deque\n     * less the current {@code size} of this deque.\n     * <p/>\n     * <p>Note that you <em>cannot</em> always tell if an attempt to insert\n     * an element will succeed by inspecting {@code remainingCapacity}\n     * because it may be the case that another thread is about to\n     * insert or remove an element.\n     */\n    public int remainingCapacity() {\n        final ReentrantLock lock = this.lock;\n        lock.lock();\n        try {\n            return capacity - count;\n        } finally {\n            lock.unlock();\n        }\n    }\n\n    /**\n     * @throws UnsupportedOperationException {@inheritDoc}\n     * @throws ClassCastException            {@inheritDoc}\n     * @throws NullPointerException          {@inheritDoc}\n     * @throws IllegalArgumentException      {@inheritDoc}\n     */\n    public int drainTo(Collection<? super E> c) {\n        return drainTo(c, Integer.MAX_VALUE);\n    }\n\n    /**\n     * @throws UnsupportedOperationException {@inheritDoc}\n     * @throws ClassCastException            {@inheritDoc}\n     * @throws NullPointerException          {@inheritDoc}\n     * @throws IllegalArgumentException      {@inheritDoc}\n     */\n    public int drainTo(Collection<? super E> c, int maxElements) {\n        if (c == null)\n            throw new NullPointerException();\n        if (c == this)\n            throw new IllegalArgumentException();\n        final ReentrantLock lock = this.lock;\n        lock.lock();\n        try {\n            int n = Math.min(maxElements, count);\n            for (int i = 0; i < n; i++) {\n                c.add(first.item);   // In this order, in case add() throws.\n                unlinkFirst();\n            }\n            return n;\n        } finally {\n            lock.unlock();\n        }\n    }\n\n    // Stack methods\n\n    /**\n     * @throws IllegalStateException {@inheritDoc}\n     * @throws NullPointerException  {@inheritDoc}\n     */\n    public void push(E e) {\n        addFirst(e);\n    }\n\n    /**\n     * @throws NoSuchElementException {@inheritDoc}\n     */\n    public E pop() {\n        return removeFirst();\n    }\n\n    // Collection methods\n\n    /**\n     * Removes the first occurrence of the specified element from this deque.\n     * If the deque does not contain the element, it is unchanged.\n     * More formally, removes the first element {@code e} such that\n     * {@code o.equals(e)} (if such an element exists).\n     * Returns {@code true} if this deque contained the specified element\n     * (or equivalently, if this deque changed as a result of the call).\n     * <p/>\n     * <p>This method is equivalent to\n     * {@link #removeFirstOccurrence(Object) removeFirstOccurrence}.\n     *\n     * @param o element to be removed from this deque, if present\n     * @return {@code true} if this deque changed as a result of the call\n     */\n    public boolean remove(Object o) {\n        return removeFirstOccurrence(o);\n    }\n\n    /**\n     * Returns the number of elements in this deque.\n     *\n     * @return the number of elements in this deque\n     */\n    public int size() {\n        final ReentrantLock lock = this.lock;\n        lock.lock();\n        try {\n            return count;\n        } finally {\n            lock.unlock();\n        }\n    }\n\n    /**\n     * Returns {@code true} if this deque contains the specified element.\n     * More formally, returns {@code true} if and only if this deque contains\n     * at least one element {@code e} such that {@code o.equals(e)}.\n     *\n     * @param o object to be checked for containment in this deque\n     * @return {@code true} if this deque contains the specified element\n     */\n    public boolean contains(Object o) {\n        if (o == null) return false;\n        final ReentrantLock lock = this.lock;\n        lock.lock();\n        try {\n            for (Node<E> p = first; p != null; p = p.next)\n                if (o.equals(p.item))\n                    return true;\n            return false;\n        } finally {\n            lock.unlock();\n        }\n    }\n\n    /*\n     * TODO: Add support for more efficient bulk operations.\n     *\n     * We don't want to acquire the lock for every iteration, but we\n     * also want other threads a chance to interact with the\n     * collection, especially when count is close to capacity.\n     */\n\n//     /**\n//      * Adds all of the elements in the specified collection to this\n//      * queue.  Attempts to addAll of a queue to itself result in\n//      * {@code IllegalArgumentException}. Further, the behavior of\n//      * this operation is undefined if the specified collection is\n//      * modified while the operation is in progress.\n//      *\n//      * @param c collection containing elements to be added to this queue\n//      * @return {@code true} if this queue changed as a result of the call\n//      * @throws ClassCastException            {@inheritDoc}\n//      * @throws NullPointerException          {@inheritDoc}\n//      * @throws IllegalArgumentException      {@inheritDoc}\n//      * @throws IllegalStateException         {@inheritDoc}\n//      * @see #add(Object)\n//      */\n//     public boolean addAll(Collection<? extends E> c) {\n//         if (c == null)\n//             throw new NullPointerException();\n//         if (c == this)\n//             throw new IllegalArgumentException();\n//         final ReentrantLock lock = this.lock;\n//         lock.lock();\n//         try {\n//             boolean modified = false;\n//             for (E e : c)\n//                 if (linkLast(e))\n//                     modified = true;\n//             return modified;\n//         } finally {\n//             lock.unlock();\n//         }\n//     }\n\n    /**\n     * Returns an array containing all of the elements in this deque, in\n     * proper sequence (from first to last element).\n     * <p/>\n     * <p>The returned array will be \"safe\" in that no references to it are\n     * maintained by this deque.  (In other words, this method must allocate\n     * a new array).  The caller is thus free to modify the returned array.\n     * <p/>\n     * <p>This method acts as bridge between array-based and collection-based\n     * APIs.\n     *\n     * @return an array containing all of the elements in this deque\n     */\n    public Object[] toArray() {\n        final ReentrantLock lock = this.lock;\n        lock.lock();\n        try {\n            Object[] a = new Object[count];\n            int k = 0;\n            for (Node<E> p = first; p != null; p = p.next)\n                a[k++] = p.item;\n            return a;\n        } finally {\n            lock.unlock();\n        }\n    }\n\n    /**\n     * Returns an array containing all of the elements in this deque, in\n     * proper sequence; the runtime type of the returned array is that of\n     * the specified array.  If the deque fits in the specified array, it\n     * is returned therein.  Otherwise, a new array is allocated with the\n     * runtime type of the specified array and the size of this deque.\n     * <p/>\n     * <p>If this deque fits in the specified array with room to spare\n     * (i.e., the array has more elements than this deque), the element in\n     * the array immediately following the end of the deque is set to\n     * {@code null}.\n     * <p/>\n     * <p>Like the {@link #toArray()} method, this method acts as bridge between\n     * array-based and collection-based APIs.  Further, this method allows\n     * precise control over the runtime type of the output array, and may,\n     * under certain circumstances, be used to save allocation costs.\n     * <p/>\n     * <p>Suppose {@code x} is a deque known to contain only strings.\n     * The following code can be used to dump the deque into a newly\n     * allocated array of {@code String}:\n     * <p/>\n     * <pre>\n     *     String[] y = x.toArray(new String[0]);</pre>\n     *\n     * Note that {@code toArray(new Object[0])} is identical in function to\n     * {@code toArray()}.\n     *\n     * @param a the array into which the elements of the deque are to\n     *          be stored, if it is big enough; otherwise, a new array of the\n     *          same runtime type is allocated for this purpose\n     * @return an array containing all of the elements in this deque\n     * @throws ArrayStoreException  if the runtime type of the specified array\n     *                              is not a supertype of the runtime type of every element in\n     *                              this deque\n     * @throws NullPointerException if the specified array is null\n     */\n    @SuppressWarnings(\"unchecked\")\n    public <T> T[] toArray(T[] a) {\n        final ReentrantLock lock = this.lock;\n        lock.lock();\n        try {\n            if (a.length < count)\n                a = (T[]) java.lang.reflect.Array.newInstance\n                        (a.getClass().getComponentType(), count);\n\n            int k = 0;\n            for (Node<E> p = first; p != null; p = p.next)\n                a[k++] = (T) p.item;\n            if (a.length > k)\n                a[k] = null;\n            return a;\n        } finally {\n            lock.unlock();\n        }\n    }\n\n    public String toString() {\n        final ReentrantLock lock = this.lock;\n        lock.lock();\n        try {\n            Node<E> p = first;\n            if (p == null)\n                return \"[]\";\n\n            StringBuilder sb = new StringBuilder();\n            sb.append('[');\n            for (; ; ) {\n                E e = p.item;\n                sb.append(e == this ? \"(this Collection)\" : e);\n                p = p.next;\n                if (p == null)\n                    return sb.append(']').toString();\n                sb.append(',').append(' ');\n            }\n        } finally {\n            lock.unlock();\n        }\n    }\n\n    /**\n     * Atomically removes all of the elements from this deque.\n     * The deque will be empty after this call returns.\n     */\n    public void clear() {\n        final ReentrantLock lock = this.lock;\n        lock.lock();\n        try {\n            for (Node<E> f = first; f != null; ) {\n                f.item = null;\n                Node<E> n = f.next;\n                f.prev = null;\n                f.next = null;\n                f = n;\n            }\n            first = last = null;\n            count = 0;\n            notFull.signalAll();\n        } finally {\n            lock.unlock();\n        }\n    }\n\n    /**\n     * Returns an iterator over the elements in this deque in proper sequence.\n     * The elements will be returned in order from first (head) to last (tail).\n     * <p/>\n     * <p>The returned iterator is a \"weakly consistent\" iterator that\n     * will never throw {@link java.util.ConcurrentModificationException\n     * ConcurrentModificationException}, and guarantees to traverse\n     * elements as they existed upon construction of the iterator, and\n     * may (but is not guaranteed to) reflect any modifications\n     * subsequent to construction.\n     *\n     * @return an iterator over the elements in this deque in proper sequence\n     */\n    public Iterator<E> iterator() {\n        return new Itr();\n    }\n\n    /**\n     * Returns an iterator over the elements in this deque in reverse\n     * sequential order.  The elements will be returned in order from\n     * last (tail) to first (head).\n     * <p/>\n     * <p>The returned iterator is a \"weakly consistent\" iterator that\n     * will never throw {@link java.util.ConcurrentModificationException\n     * ConcurrentModificationException}, and guarantees to traverse\n     * elements as they existed upon construction of the iterator, and\n     * may (but is not guaranteed to) reflect any modifications\n     * subsequent to construction.\n     *\n     * @return an iterator over the elements in this deque in reverse order\n     */\n    public Iterator<E> descendingIterator() {\n        return new DescendingItr();\n    }\n\n    /**\n     * Base class for Iterators for LinkedBlockingDeque\n     */\n    private abstract class AbstractItr implements Iterator<E> {\n        /**\n         * The next node to return in next()\n         */\n        Node<E> next;\n\n        /**\n         * nextItem holds on to item fields because once we claim that\n         * an element exists in hasNext(), we must return item read\n         * under lock (in advance()) even if it was in the process of\n         * being removed when hasNext() was called.\n         */\n        E nextItem;\n\n        /**\n         * Node returned by most recent call to next. Needed by remove.\n         * Reset to null if this element is deleted by a call to remove.\n         */\n        private Node<E> lastRet;\n\n        abstract Node<E> firstNode();\n\n        abstract Node<E> nextNode(Node<E> n);\n\n        AbstractItr() {\n            // set to initial position\n            final ReentrantLock lock = LinkedBlockingDeque.this.lock;\n            lock.lock();\n            try {\n                next = firstNode();\n                nextItem = (next == null) ? null : next.item;\n            } finally {\n                lock.unlock();\n            }\n        }\n\n        /**\n         * Returns the successor node of the given non-null, but\n         * possibly previously deleted, node.\n         */\n        private Node<E> succ(Node<E> n) {\n            // Chains of deleted nodes ending in null or self-links\n            // are possible if multiple interior nodes are removed.\n            for (; ; ) {\n                Node<E> s = nextNode(n);\n                if (s == null)\n                    return null;\n                else if (s.item != null)\n                    return s;\n                else if (s == n)\n                    return firstNode();\n                else\n                    n = s;\n            }\n        }\n\n        /**\n         * Advances next.\n         */\n        void advance() {\n            final ReentrantLock lock = LinkedBlockingDeque.this.lock;\n            lock.lock();\n            try {\n                // assert next != null;\n                next = succ(next);\n                nextItem = (next == null) ? null : next.item;\n            } finally {\n                lock.unlock();\n            }\n        }\n\n        public boolean hasNext() {\n            return next != null;\n        }\n\n        public E next() {\n            if (next == null)\n                throw new NoSuchElementException();\n            lastRet = next;\n            E x = nextItem;\n            advance();\n            return x;\n        }\n\n        public void remove() {\n            Node<E> n = lastRet;\n            if (n == null)\n                throw new IllegalStateException();\n            lastRet = null;\n            final ReentrantLock lock = LinkedBlockingDeque.this.lock;\n            lock.lock();\n            try {\n                if (n.item != null)\n                    unlink(n);\n            } finally {\n                lock.unlock();\n            }\n        }\n    }\n\n    /**\n     * Forward iterator\n     */\n    private class Itr extends AbstractItr {\n        Node<E> firstNode() {\n            return first;\n        }\n\n        Node<E> nextNode(Node<E> n) {\n            return n.next;\n        }\n    }\n\n    /**\n     * Descending iterator\n     */\n    private class DescendingItr extends AbstractItr {\n        Node<E> firstNode() {\n            return last;\n        }\n\n        Node<E> nextNode(Node<E> n) {\n            return n.prev;\n        }\n    }\n\n    /**\n     * Save the state of this deque to a stream (that is, serialize it).\n     *\n     * @param s the stream\n     * @serialData The capacity (int), followed by elements (each an\n     * {@code Object}) in the proper order, followed by a null\n     */\n    private void writeObject(java.io.ObjectOutputStream s)\n            throws java.io.IOException {\n        final ReentrantLock lock = this.lock;\n        lock.lock();\n        try {\n            // Write out capacity and any hidden stuff\n            s.defaultWriteObject();\n            // Write out all elements in the proper order.\n            for (Node<E> p = first; p != null; p = p.next)\n                s.writeObject(p.item);\n            // Use trailing null as sentinel\n            s.writeObject(null);\n        } finally {\n            lock.unlock();\n        }\n    }\n\n    /**\n     * Reconstitute this deque from a stream (that is,\n     * deserialize it).\n     *\n     * @param s the stream\n     */\n    private void readObject(java.io.ObjectInputStream s)\n            throws java.io.IOException, ClassNotFoundException {\n        s.defaultReadObject();\n        count = 0;\n        first = null;\n        last = null;\n        // Read in all elements and place in queue\n        for (; ; ) {\n            @SuppressWarnings(\"unchecked\")\n            E item = (E) s.readObject();\n            if (item == null)\n                break;\n            add(item);\n        }\n    }\n\n}\n"
  },
  {
    "path": "library/src/main/java/com/nostra13/universalimageloader/core/decode/BaseImageDecoder.java",
    "content": "/*******************************************************************************\n * Copyright 2011-2014 Sergey Tarasevich\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *******************************************************************************/\npackage com.nostra13.universalimageloader.core.decode;\n\nimport android.graphics.Bitmap;\nimport android.graphics.BitmapFactory;\nimport android.graphics.BitmapFactory.Options;\nimport android.graphics.Matrix;\nimport android.media.ExifInterface;\nimport com.nostra13.universalimageloader.core.assist.ImageScaleType;\nimport com.nostra13.universalimageloader.core.assist.ImageSize;\nimport com.nostra13.universalimageloader.core.download.ImageDownloader.Scheme;\nimport com.nostra13.universalimageloader.utils.ImageSizeUtils;\nimport com.nostra13.universalimageloader.utils.IoUtils;\nimport com.nostra13.universalimageloader.utils.L;\n\nimport java.io.IOException;\nimport java.io.InputStream;\n\n/**\n * Decodes images to {@link Bitmap}, scales them to needed size\n *\n * @author Sergey Tarasevich (nostra13[at]gmail[dot]com)\n * @see ImageDecodingInfo\n * @since 1.8.3\n */\npublic class BaseImageDecoder implements ImageDecoder {\n\n\tprotected static final String LOG_SUBSAMPLE_IMAGE = \"Subsample original image (%1$s) to %2$s (scale = %3$d) [%4$s]\";\n\tprotected static final String LOG_SCALE_IMAGE = \"Scale subsampled image (%1$s) to %2$s (scale = %3$.5f) [%4$s]\";\n\tprotected static final String LOG_ROTATE_IMAGE = \"Rotate image on %1$d\\u00B0 [%2$s]\";\n\tprotected static final String LOG_FLIP_IMAGE = \"Flip image horizontally [%s]\";\n\tprotected static final String ERROR_NO_IMAGE_STREAM = \"No stream for image [%s]\";\n\tprotected static final String ERROR_CANT_DECODE_IMAGE = \"Image can't be decoded [%s]\";\n\n\tprotected final boolean loggingEnabled;\n\n\t/**\n\t * @param loggingEnabled Whether debug logs will be written to LogCat. Usually should match {@link\n\t *                       com.nostra13.universalimageloader.core.ImageLoaderConfiguration.Builder#writeDebugLogs()\n\t *                       ImageLoaderConfiguration.writeDebugLogs()}\n\t */\n\tpublic BaseImageDecoder(boolean loggingEnabled) {\n\t\tthis.loggingEnabled = loggingEnabled;\n\t}\n\n\t/**\n\t * Decodes image from URI into {@link Bitmap}. Image is scaled close to incoming {@linkplain ImageSize target size}\n\t * during decoding (depend on incoming parameters).\n\t *\n\t * @param decodingInfo Needed data for decoding image\n\t * @return Decoded bitmap\n\t * @throws IOException                   if some I/O exception occurs during image reading\n\t * @throws UnsupportedOperationException if image URI has unsupported scheme(protocol)\n\t */\n\t@Override\n\tpublic Bitmap decode(ImageDecodingInfo decodingInfo) throws IOException {\n\t\tBitmap decodedBitmap;\n\t\tImageFileInfo imageInfo;\n\n\t\tInputStream imageStream = getImageStream(decodingInfo);\n\t\tif (imageStream == null) {\n\t\t\tL.e(ERROR_NO_IMAGE_STREAM, decodingInfo.getImageKey());\n\t\t\treturn null;\n\t\t}\n\t\ttry {\n\t\t\timageInfo = defineImageSizeAndRotation(imageStream, decodingInfo);\n\t\t\timageStream = resetStream(imageStream, decodingInfo);\n\t\t\tOptions decodingOptions = prepareDecodingOptions(imageInfo.imageSize, decodingInfo);\n\t\t\tdecodedBitmap = BitmapFactory.decodeStream(imageStream, null, decodingOptions);\n\t\t} finally {\n\t\t\tIoUtils.closeSilently(imageStream);\n\t\t}\n\n\t\tif (decodedBitmap == null) {\n\t\t\tL.e(ERROR_CANT_DECODE_IMAGE, decodingInfo.getImageKey());\n\t\t} else {\n\t\t\tdecodedBitmap = considerExactScaleAndOrientatiton(decodedBitmap, decodingInfo, imageInfo.exif.rotation,\n\t\t\t\t\timageInfo.exif.flipHorizontal);\n\t\t}\n\t\treturn decodedBitmap;\n\t}\n\n\tprotected InputStream getImageStream(ImageDecodingInfo decodingInfo) throws IOException {\n\t\treturn decodingInfo.getDownloader().getStream(decodingInfo.getImageUri(), decodingInfo.getExtraForDownloader());\n\t}\n\n\tprotected ImageFileInfo defineImageSizeAndRotation(InputStream imageStream, ImageDecodingInfo decodingInfo)\n\t\t\tthrows IOException {\n\t\tOptions options = new Options();\n\t\toptions.inJustDecodeBounds = true;\n\t\tBitmapFactory.decodeStream(imageStream, null, options);\n\n\t\tExifInfo exif;\n\t\tString imageUri = decodingInfo.getImageUri();\n\t\tif (decodingInfo.shouldConsiderExifParams() && canDefineExifParams(imageUri, options.outMimeType)) {\n\t\t\texif = defineExifOrientation(imageUri);\n\t\t} else {\n\t\t\texif = new ExifInfo();\n\t\t}\n\t\treturn new ImageFileInfo(new ImageSize(options.outWidth, options.outHeight, exif.rotation), exif);\n\t}\n\n\tprivate boolean canDefineExifParams(String imageUri, String mimeType) {\n\t\treturn \"image/jpeg\".equalsIgnoreCase(mimeType) && (Scheme.ofUri(imageUri) == Scheme.FILE);\n\t}\n\n\tprotected ExifInfo defineExifOrientation(String imageUri) {\n\t\tint rotation = 0;\n\t\tboolean flip = false;\n\t\ttry {\n\t\t\tExifInterface exif = new ExifInterface(Scheme.FILE.crop(imageUri));\n\t\t\tint exifOrientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);\n\t\t\tswitch (exifOrientation) {\n\t\t\t\tcase ExifInterface.ORIENTATION_FLIP_HORIZONTAL:\n\t\t\t\t\tflip = true;\n\t\t\t\tcase ExifInterface.ORIENTATION_NORMAL:\n\t\t\t\t\trotation = 0;\n\t\t\t\t\tbreak;\n\t\t\t\tcase ExifInterface.ORIENTATION_TRANSVERSE:\n\t\t\t\t\tflip = true;\n\t\t\t\tcase ExifInterface.ORIENTATION_ROTATE_90:\n\t\t\t\t\trotation = 90;\n\t\t\t\t\tbreak;\n\t\t\t\tcase ExifInterface.ORIENTATION_FLIP_VERTICAL:\n\t\t\t\t\tflip = true;\n\t\t\t\tcase ExifInterface.ORIENTATION_ROTATE_180:\n\t\t\t\t\trotation = 180;\n\t\t\t\t\tbreak;\n\t\t\t\tcase ExifInterface.ORIENTATION_TRANSPOSE:\n\t\t\t\t\tflip = true;\n\t\t\t\tcase ExifInterface.ORIENTATION_ROTATE_270:\n\t\t\t\t\trotation = 270;\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t} catch (IOException e) {\n\t\t\tL.w(\"Can't read EXIF tags from file [%s]\", imageUri);\n\t\t}\n\t\treturn new ExifInfo(rotation, flip);\n\t}\n\n\tprotected Options prepareDecodingOptions(ImageSize imageSize, ImageDecodingInfo decodingInfo) {\n\t\tImageScaleType scaleType = decodingInfo.getImageScaleType();\n\t\tint scale;\n\t\tif (scaleType == ImageScaleType.NONE) {\n\t\t\tscale = 1;\n\t\t} else if (scaleType == ImageScaleType.NONE_SAFE) {\n\t\t\tscale = ImageSizeUtils.computeMinImageSampleSize(imageSize);\n\t\t} else {\n\t\t\tImageSize targetSize = decodingInfo.getTargetSize();\n\t\t\tboolean powerOf2 = scaleType == ImageScaleType.IN_SAMPLE_POWER_OF_2;\n\t\t\tscale = ImageSizeUtils.computeImageSampleSize(imageSize, targetSize, decodingInfo.getViewScaleType(), powerOf2);\n\t\t}\n\t\tif (scale > 1 && loggingEnabled) {\n\t\t\tL.d(LOG_SUBSAMPLE_IMAGE, imageSize, imageSize.scaleDown(scale), scale, decodingInfo.getImageKey());\n\t\t}\n\n\t\tOptions decodingOptions = decodingInfo.getDecodingOptions();\n\t\tdecodingOptions.inSampleSize = scale;\n\t\treturn decodingOptions;\n\t}\n\n\tprotected InputStream resetStream(InputStream imageStream, ImageDecodingInfo decodingInfo) throws IOException {\n\t\tif (imageStream.markSupported()) {\n\t\t\ttry {\n\t\t\t\timageStream.reset();\n\t\t\t\treturn imageStream;\n\t\t\t} catch (IOException ignored) {\n\t\t\t}\n\t\t}\n\t\tIoUtils.closeSilently(imageStream);\n\t\treturn getImageStream(decodingInfo);\n\t}\n\n\tprotected Bitmap considerExactScaleAndOrientatiton(Bitmap subsampledBitmap, ImageDecodingInfo decodingInfo,\n\t\t\tint rotation, boolean flipHorizontal) {\n\t\tMatrix m = new Matrix();\n\t\t// Scale to exact size if need\n\t\tImageScaleType scaleType = decodingInfo.getImageScaleType();\n\t\tif (scaleType == ImageScaleType.EXACTLY || scaleType == ImageScaleType.EXACTLY_STRETCHED) {\n\t\t\tImageSize srcSize = new ImageSize(subsampledBitmap.getWidth(), subsampledBitmap.getHeight(), rotation);\n\t\t\tfloat scale = ImageSizeUtils.computeImageScale(srcSize, decodingInfo.getTargetSize(), decodingInfo\n\t\t\t\t\t.getViewScaleType(), scaleType == ImageScaleType.EXACTLY_STRETCHED);\n\t\t\tif (Float.compare(scale, 1f) != 0) {\n\t\t\t\tm.setScale(scale, scale);\n\n\t\t\t\tif (loggingEnabled) {\n\t\t\t\t\tL.d(LOG_SCALE_IMAGE, srcSize, srcSize.scale(scale), scale, decodingInfo.getImageKey());\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t// Flip bitmap if need\n\t\tif (flipHorizontal) {\n\t\t\tm.postScale(-1, 1);\n\n\t\t\tif (loggingEnabled) L.d(LOG_FLIP_IMAGE, decodingInfo.getImageKey());\n\t\t}\n\t\t// Rotate bitmap if need\n\t\tif (rotation != 0) {\n\t\t\tm.postRotate(rotation);\n\n\t\t\tif (loggingEnabled) L.d(LOG_ROTATE_IMAGE, rotation, decodingInfo.getImageKey());\n\t\t}\n\n\t\tBitmap finalBitmap = Bitmap.createBitmap(subsampledBitmap, 0, 0, subsampledBitmap.getWidth(), subsampledBitmap\n\t\t\t\t.getHeight(), m, true);\n\t\tif (finalBitmap != subsampledBitmap) {\n\t\t\tsubsampledBitmap.recycle();\n\t\t}\n\t\treturn finalBitmap;\n\t}\n\n\tprotected static class ExifInfo {\n\n\t\tpublic final int rotation;\n\t\tpublic final boolean flipHorizontal;\n\n\t\tprotected ExifInfo() {\n\t\t\tthis.rotation = 0;\n\t\t\tthis.flipHorizontal = false;\n\t\t}\n\n\t\tprotected ExifInfo(int rotation, boolean flipHorizontal) {\n\t\t\tthis.rotation = rotation;\n\t\t\tthis.flipHorizontal = flipHorizontal;\n\t\t}\n\t}\n\n\tprotected static class ImageFileInfo {\n\n\t\tpublic final ImageSize imageSize;\n\t\tpublic final ExifInfo exif;\n\n\t\tprotected ImageFileInfo(ImageSize imageSize, ExifInfo exif) {\n\t\t\tthis.imageSize = imageSize;\n\t\t\tthis.exif = exif;\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "library/src/main/java/com/nostra13/universalimageloader/core/decode/ImageDecoder.java",
    "content": "/*******************************************************************************\n * Copyright 2013 Sergey Tarasevich\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *******************************************************************************/\npackage com.nostra13.universalimageloader.core.decode;\n\nimport android.graphics.Bitmap;\n\nimport java.io.IOException;\n\n/**\n * Provide decoding image to result {@link Bitmap}.\n *\n * @author Sergey Tarasevich (nostra13[at]gmail[dot]com)\n * @see ImageDecodingInfo\n * @since 1.8.3\n */\npublic interface ImageDecoder {\n\n\t/**\n\t * Decodes image to {@link Bitmap} according target size and other parameters.\n\t *\n\t * @param imageDecodingInfo\n\t * @return\n\t * @throws IOException\n\t */\n\tBitmap decode(ImageDecodingInfo imageDecodingInfo) throws IOException;\n}\n"
  },
  {
    "path": "library/src/main/java/com/nostra13/universalimageloader/core/decode/ImageDecodingInfo.java",
    "content": "/*******************************************************************************\n * Copyright 2013-2014 Sergey Tarasevich\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *******************************************************************************/\npackage com.nostra13.universalimageloader.core.decode;\n\nimport android.annotation.TargetApi;\nimport android.graphics.BitmapFactory.Options;\nimport android.os.Build;\n\nimport com.nostra13.universalimageloader.core.DisplayImageOptions;\nimport com.nostra13.universalimageloader.core.assist.ImageScaleType;\nimport com.nostra13.universalimageloader.core.assist.ImageSize;\nimport com.nostra13.universalimageloader.core.assist.ViewScaleType;\nimport com.nostra13.universalimageloader.core.download.ImageDownloader;\n\n/**\n * Contains needed information for decoding image to Bitmap\n *\n * @author Sergey Tarasevich (nostra13[at]gmail[dot]com)\n * @since 1.8.3\n */\npublic class ImageDecodingInfo {\n\n\tprivate final String imageKey;\n\tprivate final String imageUri;\n\tprivate final String originalImageUri;\n\tprivate final ImageSize targetSize;\n\n\tprivate final ImageScaleType imageScaleType;\n\tprivate final ViewScaleType viewScaleType;\n\n\tprivate final ImageDownloader downloader;\n\tprivate final Object extraForDownloader;\n\n\tprivate final boolean considerExifParams;\n\tprivate final Options decodingOptions;\n\n\tpublic ImageDecodingInfo(String imageKey, String imageUri, String originalImageUri, ImageSize targetSize, ViewScaleType viewScaleType,\n\t\t\t\t\t\t\t ImageDownloader downloader, DisplayImageOptions displayOptions) {\n\t\tthis.imageKey = imageKey;\n\t\tthis.imageUri = imageUri;\n\t\tthis.originalImageUri = originalImageUri;\n\t\tthis.targetSize = targetSize;\n\n\t\tthis.imageScaleType = displayOptions.getImageScaleType();\n\t\tthis.viewScaleType = viewScaleType;\n\n\t\tthis.downloader = downloader;\n\t\tthis.extraForDownloader = displayOptions.getExtraForDownloader();\n\n\t\tconsiderExifParams = displayOptions.isConsiderExifParams();\n\t\tdecodingOptions = new Options();\n\t\tcopyOptions(displayOptions.getDecodingOptions(), decodingOptions);\n\t}\n\n\tprivate void copyOptions(Options srcOptions, Options destOptions) {\n\t\tdestOptions.inDensity = srcOptions.inDensity;\n\t\tdestOptions.inDither = srcOptions.inDither;\n\t\tdestOptions.inInputShareable = srcOptions.inInputShareable;\n\t\tdestOptions.inJustDecodeBounds = srcOptions.inJustDecodeBounds;\n\t\tdestOptions.inPreferredConfig = srcOptions.inPreferredConfig;\n\t\tdestOptions.inPurgeable = srcOptions.inPurgeable;\n\t\tdestOptions.inSampleSize = srcOptions.inSampleSize;\n\t\tdestOptions.inScaled = srcOptions.inScaled;\n\t\tdestOptions.inScreenDensity = srcOptions.inScreenDensity;\n\t\tdestOptions.inTargetDensity = srcOptions.inTargetDensity;\n\t\tdestOptions.inTempStorage = srcOptions.inTempStorage;\n\t\tif (Build.VERSION.SDK_INT >= 10) copyOptions10(srcOptions, destOptions);\n\t\tif (Build.VERSION.SDK_INT >= 11) copyOptions11(srcOptions, destOptions);\n\t}\n\n\t@TargetApi(10)\n\tprivate void copyOptions10(Options srcOptions, Options destOptions) {\n\t\tdestOptions.inPreferQualityOverSpeed = srcOptions.inPreferQualityOverSpeed;\n\t}\n\n\t@TargetApi(11)\n\tprivate void copyOptions11(Options srcOptions, Options destOptions) {\n\t\tdestOptions.inBitmap = srcOptions.inBitmap;\n\t\tdestOptions.inMutable = srcOptions.inMutable;\n\t}\n\n\t/** @return Original {@linkplain com.nostra13.universalimageloader.utils.MemoryCacheUtils#generateKey(String, ImageSize) image key} (used in memory cache). */\n\tpublic String getImageKey() {\n\t\treturn imageKey;\n\t}\n\n\t/** @return Image URI for decoding (usually image from disk cache) */\n\tpublic String getImageUri() {\n\t\treturn imageUri;\n\t}\n\n\t/** @return The original image URI which was passed to ImageLoader */\n\tpublic String getOriginalImageUri() {\n\t\treturn originalImageUri;\n\t}\n\n\t/**\n\t * @return Target size for image. Decoded bitmap should close to this size according to {@linkplain ImageScaleType\n\t * image scale type} and {@linkplain ViewScaleType view scale type}.\n\t */\n\tpublic ImageSize getTargetSize() {\n\t\treturn targetSize;\n\t}\n\n\t/**\n\t * @return {@linkplain ImageScaleType Scale type for image sampling and scaling}. This parameter affects result size\n\t * of decoded bitmap.\n\t */\n\tpublic ImageScaleType getImageScaleType() {\n\t\treturn imageScaleType;\n\t}\n\n\t/** @return {@linkplain ViewScaleType View scale type}. This parameter affects result size of decoded bitmap. */\n\tpublic ViewScaleType getViewScaleType() {\n\t\treturn viewScaleType;\n\t}\n\n\t/** @return Downloader for image loading */\n\tpublic ImageDownloader getDownloader() {\n\t\treturn downloader;\n\t}\n\n\t/** @return Auxiliary object for downloader */\n\tpublic Object getExtraForDownloader() {\n\t\treturn extraForDownloader;\n\t}\n\n\t/** @return <b>true</b> - if EXIF params of image should be considered; <b>false</b> - otherwise */\n\tpublic boolean shouldConsiderExifParams() {\n\t\treturn considerExifParams;\n\t}\n\n\t/** @return Decoding options */\n\tpublic Options getDecodingOptions() {\n\t\treturn decodingOptions;\n\t}\n}"
  },
  {
    "path": "library/src/main/java/com/nostra13/universalimageloader/core/display/BitmapDisplayer.java",
    "content": "/*******************************************************************************\n * Copyright 2011-2014 Sergey Tarasevich\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *******************************************************************************/\npackage com.nostra13.universalimageloader.core.display;\n\nimport android.graphics.Bitmap;\nimport com.nostra13.universalimageloader.core.assist.LoadedFrom;\nimport com.nostra13.universalimageloader.core.imageaware.ImageAware;\n\n/**\n * Displays {@link Bitmap} in {@link com.nostra13.universalimageloader.core.imageaware.ImageAware}. Implementations can\n * apply some changes to Bitmap or any animation for displaying Bitmap.<br />\n * Implementations have to be thread-safe.\n *\n * @author Sergey Tarasevich (nostra13[at]gmail[dot]com)\n * @see com.nostra13.universalimageloader.core.imageaware.ImageAware\n * @see com.nostra13.universalimageloader.core.assist.LoadedFrom\n * @since 1.5.6\n */\npublic interface BitmapDisplayer {\n\t/**\n\t * Displays bitmap in {@link com.nostra13.universalimageloader.core.imageaware.ImageAware}.\n\t * <b>NOTE:</b> This method is called on UI thread so it's strongly recommended not to do any heavy work in it.\n\t *\n\t * @param bitmap     Source bitmap\n\t * @param imageAware {@linkplain com.nostra13.universalimageloader.core.imageaware.ImageAware Image aware view} to\n\t *                   display Bitmap\n\t * @param loadedFrom Source of loaded image\n\t */\n\tvoid display(Bitmap bitmap, ImageAware imageAware, LoadedFrom loadedFrom);\n}\n"
  },
  {
    "path": "library/src/main/java/com/nostra13/universalimageloader/core/display/CircleBitmapDisplayer.java",
    "content": "/*******************************************************************************\n * Copyright 2015 Sergey Tarasevich\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *******************************************************************************/\npackage com.nostra13.universalimageloader.core.display;\n\nimport android.graphics.Bitmap;\nimport android.graphics.BitmapShader;\nimport android.graphics.Canvas;\nimport android.graphics.ColorFilter;\nimport android.graphics.Matrix;\nimport android.graphics.Paint;\nimport android.graphics.PixelFormat;\nimport android.graphics.Rect;\nimport android.graphics.RectF;\nimport android.graphics.Shader;\nimport android.graphics.drawable.Drawable;\n\nimport com.nostra13.universalimageloader.core.assist.LoadedFrom;\nimport com.nostra13.universalimageloader.core.imageaware.ImageAware;\nimport com.nostra13.universalimageloader.core.imageaware.ImageViewAware;\n\n/**\n * Can display bitmap cropped by a circle. This implementation works only with ImageViews wrapped\n * in ImageViewAware.\n * <br />\n * If this implementation doesn't meet your needs then consider\n * <a href=\"https://github.com/vinc3m1/RoundedImageView\">RoundedImageView</a> or\n * <a href=\"https://github.com/Pkmmte/CircularImageView\">CircularImageView</a> projects for usage.\n *\n * @author Qualtagh, Sergey Tarasevich (nostra13[at]gmail[dot]com)\n * @since 1.9.5\n */\npublic class CircleBitmapDisplayer implements BitmapDisplayer {\n\n\tprotected final Integer strokeColor;\n\tprotected final float strokeWidth;\n\n\tpublic CircleBitmapDisplayer() {\n\t\tthis(null);\n\t}\n\n\tpublic CircleBitmapDisplayer(Integer strokeColor) {\n\t\tthis(strokeColor, 0);\n\t}\n\n\tpublic CircleBitmapDisplayer(Integer strokeColor, float strokeWidth) {\n\t\tthis.strokeColor = strokeColor;\n\t\tthis.strokeWidth = strokeWidth;\n\t}\n\n\t@Override\n\tpublic void display(Bitmap bitmap, ImageAware imageAware, LoadedFrom loadedFrom) {\n\t\tif (!(imageAware instanceof ImageViewAware)) {\n\t\t\tthrow new IllegalArgumentException(\"ImageAware should wrap ImageView. ImageViewAware is expected.\");\n\t\t}\n\n\t\timageAware.setImageDrawable(new CircleDrawable(bitmap, strokeColor, strokeWidth));\n\t}\n\n\tpublic static class CircleDrawable extends Drawable {\n\n\t\tprotected float radius;\n\n\t\tprotected final RectF mRect = new RectF();\n\t\tprotected final RectF mBitmapRect;\n\t\tprotected final BitmapShader bitmapShader;\n\t\tprotected final Paint paint;\n\t\tprotected final Paint strokePaint;\n\t\tprotected final float strokeWidth;\n\t\tprotected float strokeRadius;\n\n\t\tpublic CircleDrawable(Bitmap bitmap, Integer strokeColor, float strokeWidth) {\n\t\t\tint diameter = Math.min(bitmap.getWidth(), bitmap.getHeight());\n\t\t\tradius = diameter / 2f;\n\n\t\t\tbitmapShader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);\n\n\t\t\tfloat left = (bitmap.getWidth() - diameter) / 2f;\n\t\t\tfloat top = (bitmap.getHeight() - diameter) / 2f;\n\t\t\tmBitmapRect = new RectF(left, top, diameter, diameter);\n\n\t\t\tpaint = new Paint();\n\t\t\tpaint.setAntiAlias(true);\n\t\t\tpaint.setShader(bitmapShader);\n\t\t\tpaint.setFilterBitmap(true);\n\t\t\tpaint.setDither(true);\n\n\t\t\tif (strokeColor == null) {\n\t\t\t\tstrokePaint = null;\n\t\t\t} else {\n\t\t\t\tstrokePaint = new Paint();\n\t\t\t\tstrokePaint.setStyle(Paint.Style.STROKE);\n\t\t\t\tstrokePaint.setColor(strokeColor);\n\t\t\t\tstrokePaint.setStrokeWidth(strokeWidth);\n\t\t\t\tstrokePaint.setAntiAlias(true);\n\t\t\t}\n\t\t\tthis.strokeWidth = strokeWidth;\n\t\t\tstrokeRadius = radius - strokeWidth / 2;\n\t\t}\n\n\t\t@Override\n\t\tprotected void onBoundsChange(Rect bounds) {\n\t\t\tsuper.onBoundsChange(bounds);\n\t\t\tmRect.set(0, 0, bounds.width(), bounds.height());\n\t\t\tradius = Math.min(bounds.width(), bounds.height()) / 2;\n\t\t\tstrokeRadius = radius - strokeWidth / 2;\n\n\t\t\t// Resize the original bitmap to fit the new bound\n\t\t\tMatrix shaderMatrix = new Matrix();\n\t\t\tshaderMatrix.setRectToRect(mBitmapRect, mRect, Matrix.ScaleToFit.FILL);\n\t\t\tbitmapShader.setLocalMatrix(shaderMatrix);\n\t\t}\n\n\t\t@Override\n\t\tpublic void draw(Canvas canvas) {\n\t\t\tcanvas.drawCircle(radius, radius, radius, paint);\n\t\t\tif (strokePaint != null) {\n\t\t\t\tcanvas.drawCircle(radius, radius, strokeRadius, strokePaint);\n\t\t\t}\n\t\t}\n\n\t\t@Override\n\t\tpublic int getOpacity() {\n\t\t\treturn PixelFormat.TRANSLUCENT;\n\t\t}\n\n\t\t@Override\n\t\tpublic void setAlpha(int alpha) {\n\t\t\tpaint.setAlpha(alpha);\n\t\t}\n\n\t\t@Override\n\t\tpublic void setColorFilter(ColorFilter cf) {\n\t\t\tpaint.setColorFilter(cf);\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "library/src/main/java/com/nostra13/universalimageloader/core/display/FadeInBitmapDisplayer.java",
    "content": "/*******************************************************************************\n * Copyright 2011-2014 Sergey Tarasevich, Daniel Martí\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *******************************************************************************/\npackage com.nostra13.universalimageloader.core.display;\n\nimport android.graphics.Bitmap;\nimport android.view.View;\nimport android.view.animation.AlphaAnimation;\nimport android.view.animation.DecelerateInterpolator;\nimport android.widget.ImageView;\nimport com.nostra13.universalimageloader.core.assist.LoadedFrom;\nimport com.nostra13.universalimageloader.core.imageaware.ImageAware;\n\n/**\n * Displays image with \"fade in\" animation\n *\n * @author Sergey Tarasevich (nostra13[at]gmail[dot]com), Daniel Martí\n * @since 1.6.4\n */\npublic class FadeInBitmapDisplayer implements BitmapDisplayer {\n\n\tprivate final int durationMillis;\n\n\tprivate final boolean animateFromNetwork;\n\tprivate final boolean animateFromDisk;\n\tprivate final boolean animateFromMemory;\n\n\t/**\n\t * @param durationMillis Duration of \"fade-in\" animation (in milliseconds)\n\t */\n\tpublic FadeInBitmapDisplayer(int durationMillis) {\n\t\tthis(durationMillis, true, true, true);\n\t}\n\n\t/**\n\t * @param durationMillis     Duration of \"fade-in\" animation (in milliseconds)\n\t * @param animateFromNetwork Whether animation should be played if image is loaded from network\n\t * @param animateFromDisk    Whether animation should be played if image is loaded from disk cache\n\t * @param animateFromMemory  Whether animation should be played if image is loaded from memory cache\n\t */\n\tpublic FadeInBitmapDisplayer(int durationMillis, boolean animateFromNetwork, boolean animateFromDisk,\n\t\t\t\t\t\t\t\t boolean animateFromMemory) {\n\t\tthis.durationMillis = durationMillis;\n\t\tthis.animateFromNetwork = animateFromNetwork;\n\t\tthis.animateFromDisk = animateFromDisk;\n\t\tthis.animateFromMemory = animateFromMemory;\n\t}\n\n\t@Override\n\tpublic void display(Bitmap bitmap, ImageAware imageAware, LoadedFrom loadedFrom) {\n\t\timageAware.setImageBitmap(bitmap);\n\n\t\tif ((animateFromNetwork && loadedFrom == LoadedFrom.NETWORK) ||\n\t\t\t\t(animateFromDisk && loadedFrom == LoadedFrom.DISC_CACHE) ||\n\t\t\t\t(animateFromMemory && loadedFrom == LoadedFrom.MEMORY_CACHE)) {\n\t\t\tanimate(imageAware.getWrappedView(), durationMillis);\n\t\t}\n\t}\n\n\t/**\n\t * Animates {@link ImageView} with \"fade-in\" effect\n\t *\n\t * @param imageView      {@link ImageView} which display image in\n\t * @param durationMillis The length of the animation in milliseconds\n\t */\n\tpublic static void animate(View imageView, int durationMillis) {\n\t\tif (imageView != null) {\n\t\t\tAlphaAnimation fadeImage = new AlphaAnimation(0, 1);\n\t\t\tfadeImage.setDuration(durationMillis);\n\t\t\tfadeImage.setInterpolator(new DecelerateInterpolator());\n\t\t\timageView.startAnimation(fadeImage);\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "library/src/main/java/com/nostra13/universalimageloader/core/display/RoundedBitmapDisplayer.java",
    "content": "/*******************************************************************************\n * Copyright 2011-2014 Sergey Tarasevich\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *******************************************************************************/\npackage com.nostra13.universalimageloader.core.display;\n\nimport android.graphics.*;\nimport android.graphics.drawable.Drawable;\n\nimport com.nostra13.universalimageloader.core.assist.LoadedFrom;\nimport com.nostra13.universalimageloader.core.imageaware.ImageAware;\nimport com.nostra13.universalimageloader.core.imageaware.ImageViewAware;\n\n/**\n * Can display bitmap with rounded corners. This implementation works only with ImageViews wrapped\n * in ImageViewAware.\n * <br />\n * This implementation is inspired by\n * <a href=\"http://www.curious-creature.org/2012/12/11/android-recipe-1-image-with-rounded-corners/\">\n * Romain Guy's article</a>. It rounds images using custom drawable drawing. Original bitmap isn't changed.\n * <br />\n * <br />\n * If this implementation doesn't meet your needs then consider\n * <a href=\"https://github.com/vinc3m1/RoundedImageView\">RoundedImageView</a> or\n * <a href=\"https://github.com/Pkmmte/CircularImageView\">CircularImageView</a> projects for usage.\n *\n * @author Sergey Tarasevich (nostra13[at]gmail[dot]com)\n * @since 1.5.6\n */\npublic class RoundedBitmapDisplayer implements BitmapDisplayer {\n\n\tprotected final int cornerRadius;\n\tprotected final int margin;\n\n\tpublic RoundedBitmapDisplayer(int cornerRadiusPixels) {\n\t\tthis(cornerRadiusPixels, 0);\n\t}\n\n\tpublic RoundedBitmapDisplayer(int cornerRadiusPixels, int marginPixels) {\n\t\tthis.cornerRadius = cornerRadiusPixels;\n\t\tthis.margin = marginPixels;\n\t}\n\n\t@Override\n\tpublic void display(Bitmap bitmap, ImageAware imageAware, LoadedFrom loadedFrom) {\n\t\tif (!(imageAware instanceof ImageViewAware)) {\n\t\t\tthrow new IllegalArgumentException(\"ImageAware should wrap ImageView. ImageViewAware is expected.\");\n\t\t}\n\n\t\timageAware.setImageDrawable(new RoundedDrawable(bitmap, cornerRadius, margin));\n\t}\n\n\tpublic static class RoundedDrawable extends Drawable {\n\n\t\tprotected final float cornerRadius;\n\t\tprotected final int margin;\n\n\t\tprotected final RectF mRect = new RectF(),\n\t\t\t\tmBitmapRect;\n\t\tprotected final BitmapShader bitmapShader;\n\t\tprotected final Paint paint;\n\n\t\tpublic RoundedDrawable(Bitmap bitmap, int cornerRadius, int margin) {\n\t\t\tthis.cornerRadius = cornerRadius;\n\t\t\tthis.margin = margin;\n\n\t\t\tbitmapShader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);\n\t\t\tmBitmapRect = new RectF (margin, margin, bitmap.getWidth() - margin, bitmap.getHeight() - margin);\n\t\t\t\n\t\t\tpaint = new Paint();\n\t\t\tpaint.setAntiAlias(true);\n\t\t\tpaint.setShader(bitmapShader);\n\t\t\tpaint.setFilterBitmap(true);\n\t\t\tpaint.setDither(true);\n\t\t}\n\n\t\t@Override\n\t\tprotected void onBoundsChange(Rect bounds) {\n\t\t\tsuper.onBoundsChange(bounds);\n\t\t\tmRect.set(margin, margin, bounds.width() - margin, bounds.height() - margin);\n\t\t\t\n\t\t\t// Resize the original bitmap to fit the new bound\n\t\t\tMatrix shaderMatrix = new Matrix();\n\t\t\tshaderMatrix.setRectToRect(mBitmapRect, mRect, Matrix.ScaleToFit.FILL);\n\t\t\tbitmapShader.setLocalMatrix(shaderMatrix);\n\t\t\t\n\t\t}\n\n\t\t@Override\n\t\tpublic void draw(Canvas canvas) {\n\t\t\tcanvas.drawRoundRect(mRect, cornerRadius, cornerRadius, paint);\n\t\t}\n\n\t\t@Override\n\t\tpublic int getOpacity() {\n\t\t\treturn PixelFormat.TRANSLUCENT;\n\t\t}\n\n\t\t@Override\n\t\tpublic void setAlpha(int alpha) {\n\t\t\tpaint.setAlpha(alpha);\n\t\t}\n\n\t\t@Override\n\t\tpublic void setColorFilter(ColorFilter cf) {\n\t\t\tpaint.setColorFilter(cf);\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "library/src/main/java/com/nostra13/universalimageloader/core/display/RoundedVignetteBitmapDisplayer.java",
    "content": "/*******************************************************************************\n * Copyright 2013 Sergey Tarasevich\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *******************************************************************************/\npackage com.nostra13.universalimageloader.core.display;\n\nimport android.graphics.*;\nimport com.nostra13.universalimageloader.core.assist.LoadedFrom;\nimport com.nostra13.universalimageloader.core.imageaware.ImageAware;\nimport com.nostra13.universalimageloader.core.imageaware.ImageViewAware;\n\n/**\n * Can display bitmap with rounded corners and vignette effect. This implementation works only with ImageViews wrapped\n * in ImageViewAware.\n * <br />\n * This implementation is inspired by\n * <a href=\"http://www.curious-creature.org/2012/12/11/android-recipe-1-image-with-rounded-corners/\">\n * Romain Guy's article</a>. It rounds images using custom drawable drawing. Original bitmap isn't changed.\n * <br />\n * <br />\n * If this implementation doesn't meet your needs then consider\n * <a href=\"https://github.com/vinc3m1/RoundedImageView\">this project</a> for usage.\n *\n * @author Sergey Tarasevich (nostra13[at]gmail[dot]com)\n * @since 1.9.1\n */\npublic class RoundedVignetteBitmapDisplayer extends RoundedBitmapDisplayer {\n\n\tpublic RoundedVignetteBitmapDisplayer(int cornerRadiusPixels, int marginPixels) {\n\t\tsuper(cornerRadiusPixels, marginPixels);\n\t}\n\n\t@Override\n\tpublic void display(Bitmap bitmap, ImageAware imageAware, LoadedFrom loadedFrom) {\n\t\tif (!(imageAware instanceof ImageViewAware)) {\n\t\t\tthrow new IllegalArgumentException(\"ImageAware should wrap ImageView. ImageViewAware is expected.\");\n\t\t}\n\n\t\timageAware.setImageDrawable(new RoundedVignetteDrawable(bitmap, cornerRadius, margin));\n\t}\n\n\tprotected static class RoundedVignetteDrawable extends RoundedDrawable {\n\n\t\tRoundedVignetteDrawable(Bitmap bitmap, int cornerRadius, int margin) {\n\t\t\tsuper(bitmap, cornerRadius, margin);\n\t\t}\n\n\t\t@Override\n\t\tprotected void onBoundsChange(Rect bounds) {\n\t\t\tsuper.onBoundsChange(bounds);\n\t\t\tRadialGradient vignette = new RadialGradient(\n\t\t\t\t\tmRect.centerX(), mRect.centerY() * 1.0f / 0.7f, mRect.centerX() * 1.3f,\n\t\t\t\t\tnew int[]{0, 0, 0x7f000000}, new float[]{0.0f, 0.7f, 1.0f},\n\t\t\t\t\tShader.TileMode.CLAMP);\n\n\t\t\tMatrix oval = new Matrix();\n\t\t\toval.setScale(1.0f, 0.7f);\n\t\t\tvignette.setLocalMatrix(oval);\n\n\t\t\tpaint.setShader(new ComposeShader(bitmapShader, vignette, PorterDuff.Mode.SRC_OVER));\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "library/src/main/java/com/nostra13/universalimageloader/core/display/SimpleBitmapDisplayer.java",
    "content": "/*******************************************************************************\n * Copyright 2011-2013 Sergey Tarasevich\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *******************************************************************************/\npackage com.nostra13.universalimageloader.core.display;\n\nimport android.graphics.Bitmap;\nimport com.nostra13.universalimageloader.core.assist.LoadedFrom;\nimport com.nostra13.universalimageloader.core.imageaware.ImageAware;\n\n/**\n * Just displays {@link Bitmap} in {@link com.nostra13.universalimageloader.core.imageaware.ImageAware}\n *\n * @author Sergey Tarasevich (nostra13[at]gmail[dot]com)\n * @since 1.5.6\n */\npublic final class SimpleBitmapDisplayer implements BitmapDisplayer {\n\t@Override\n\tpublic void display(Bitmap bitmap, ImageAware imageAware, LoadedFrom loadedFrom) {\n\t\timageAware.setImageBitmap(bitmap);\n\t}\n}"
  },
  {
    "path": "library/src/main/java/com/nostra13/universalimageloader/core/download/BaseImageDownloader.java",
    "content": "/*******************************************************************************\n * Copyright 2011-2014 Sergey Tarasevich\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *******************************************************************************/\npackage com.nostra13.universalimageloader.core.download;\n\nimport android.annotation.TargetApi;\nimport android.content.ContentResolver;\nimport android.content.Context;\nimport android.graphics.Bitmap;\nimport android.graphics.Bitmap.CompressFormat;\nimport android.media.ThumbnailUtils;\nimport android.net.Uri;\nimport android.os.Build;\nimport android.provider.ContactsContract;\nimport android.provider.MediaStore;\nimport android.webkit.MimeTypeMap;\nimport com.nostra13.universalimageloader.core.DisplayImageOptions;\nimport com.nostra13.universalimageloader.core.assist.ContentLengthInputStream;\nimport com.nostra13.universalimageloader.utils.IoUtils;\n\nimport java.io.BufferedInputStream;\nimport java.io.ByteArrayInputStream;\nimport java.io.ByteArrayOutputStream;\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.FileNotFoundException;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.net.HttpURLConnection;\nimport java.net.URL;\nimport java.net.URLConnection;\n\n/**\n * Provides retrieving of {@link InputStream} of image by URI from network or file system or app resources.<br />\n * {@link URLConnection} is used to retrieve image stream from network.\n *\n * @author Sergey Tarasevich (nostra13[at]gmail[dot]com)\n * @since 1.8.0\n */\npublic class BaseImageDownloader implements ImageDownloader {\n\t/** {@value} */\n\tpublic static final int DEFAULT_HTTP_CONNECT_TIMEOUT = 5 * 1000; // milliseconds\n\t/** {@value} */\n\tpublic static final int DEFAULT_HTTP_READ_TIMEOUT = 20 * 1000; // milliseconds\n\n\t/** {@value} */\n\tprotected static final int BUFFER_SIZE = 32 * 1024; // 32 Kb\n\t/** {@value} */\n\tprotected static final String ALLOWED_URI_CHARS = \"@#&=*+-_.,:!?()/~'%\";\n\n\tprotected static final int MAX_REDIRECT_COUNT = 5;\n\n\tprotected static final String CONTENT_CONTACTS_URI_PREFIX = \"content://com.android.contacts/\";\n\n\tprivate static final String ERROR_UNSUPPORTED_SCHEME = \"UIL doesn't support scheme(protocol) by default [%s]. \" + \"You should implement this support yourself (BaseImageDownloader.getStreamFromOtherSource(...))\";\n\n\tprotected final Context context;\n\tprotected final int connectTimeout;\n\tprotected final int readTimeout;\n\n\tpublic BaseImageDownloader(Context context) {\n\t\tthis(context, DEFAULT_HTTP_CONNECT_TIMEOUT, DEFAULT_HTTP_READ_TIMEOUT);\n\t}\n\n\tpublic BaseImageDownloader(Context context, int connectTimeout, int readTimeout) {\n\t\tthis.context = context.getApplicationContext();\n\t\tthis.connectTimeout = connectTimeout;\n\t\tthis.readTimeout = readTimeout;\n\t}\n\n\t@Override\n\tpublic InputStream getStream(String imageUri, Object extra) throws IOException {\n\t\tswitch (Scheme.ofUri(imageUri)) {\n\t\t\tcase HTTP:\n\t\t\tcase HTTPS:\n\t\t\t\treturn getStreamFromNetwork(imageUri, extra);\n\t\t\tcase FILE:\n\t\t\t\treturn getStreamFromFile(imageUri, extra);\n\t\t\tcase CONTENT:\n\t\t\t\treturn getStreamFromContent(imageUri, extra);\n\t\t\tcase ASSETS:\n\t\t\t\treturn getStreamFromAssets(imageUri, extra);\n\t\t\tcase DRAWABLE:\n\t\t\t\treturn getStreamFromDrawable(imageUri, extra);\n\t\t\tcase UNKNOWN:\n\t\t\tdefault:\n\t\t\t\treturn getStreamFromOtherSource(imageUri, extra);\n\t\t}\n\t}\n\n\t/**\n\t * Retrieves {@link InputStream} of image by URI (image is located in the network).\n\t *\n\t * @param imageUri Image URI\n\t * @param extra    Auxiliary object which was passed to {@link DisplayImageOptions.Builder#extraForDownloader(Object)\n\t *                 DisplayImageOptions.extraForDownloader(Object)}; can be null\n\t * @return {@link InputStream} of image\n\t * @throws IOException if some I/O error occurs during network request or if no InputStream could be created for\n\t *                     URL.\n\t */\n\tprotected InputStream getStreamFromNetwork(String imageUri, Object extra) throws IOException {\n\t\tHttpURLConnection conn = createConnection(imageUri, extra);\n\n\t\tint redirectCount = 0;\n\t\twhile (conn.getResponseCode() / 100 == 3 && redirectCount < MAX_REDIRECT_COUNT) {\n\t\t\tconn = createConnection(conn.getHeaderField(\"Location\"), extra);\n\t\t\tredirectCount++;\n\t\t}\n\n\t\tInputStream imageStream;\n\t\ttry {\n\t\t\timageStream = conn.getInputStream();\n\t\t} catch (IOException e) {\n\t\t\t// Read all data to allow reuse connection (http://bit.ly/1ad35PY)\n\t\t\tIoUtils.readAndCloseStream(conn.getErrorStream());\n\t\t\tthrow e;\n\t\t}\n\t\tif (!shouldBeProcessed(conn)) {\n\t\t\tIoUtils.closeSilently(imageStream);\n\t\t\tthrow new IOException(\"Image request failed with response code \" + conn.getResponseCode());\n\t\t}\n\n\t\treturn new ContentLengthInputStream(new BufferedInputStream(imageStream, BUFFER_SIZE), conn.getContentLength());\n\t}\n\n\t/**\n\t * @param conn Opened request connection (response code is available)\n\t * @return <b>true</b> - if data from connection is correct and should be read and processed;\n\t *         <b>false</b> - if response contains irrelevant data and shouldn't be processed\n\t * @throws IOException\n\t */\n\tprotected boolean shouldBeProcessed(HttpURLConnection conn) throws IOException {\n\t\treturn conn.getResponseCode() == 200;\n\t}\n\n\t/**\n\t * Create {@linkplain HttpURLConnection HTTP connection} for incoming URL\n\t *\n\t * @param url   URL to connect to\n\t * @param extra Auxiliary object which was passed to {@link DisplayImageOptions.Builder#extraForDownloader(Object)\n\t *              DisplayImageOptions.extraForDownloader(Object)}; can be null\n\t * @return {@linkplain HttpURLConnection Connection} for incoming URL. Connection isn't established so it still configurable.\n\t * @throws IOException if some I/O error occurs during network request or if no InputStream could be created for\n\t *                     URL.\n\t */\n\tprotected HttpURLConnection createConnection(String url, Object extra) throws IOException {\n\t\tString encodedUrl = Uri.encode(url, ALLOWED_URI_CHARS);\n\t\tHttpURLConnection conn = (HttpURLConnection) new URL(encodedUrl).openConnection();\n\t\tconn.setConnectTimeout(connectTimeout);\n\t\tconn.setReadTimeout(readTimeout);\n\t\treturn conn;\n\t}\n\n\t/**\n\t * Retrieves {@link InputStream} of image by URI (image is located on the local file system or SD card).\n\t *\n\t * @param imageUri Image URI\n\t * @param extra    Auxiliary object which was passed to {@link DisplayImageOptions.Builder#extraForDownloader(Object)\n\t *                 DisplayImageOptions.extraForDownloader(Object)}; can be null\n\t * @return {@link InputStream} of image\n\t * @throws IOException if some I/O error occurs reading from file system\n\t */\n\tprotected InputStream getStreamFromFile(String imageUri, Object extra) throws IOException {\n\t\tString filePath = Scheme.FILE.crop(imageUri);\n\t\tif (isVideoFileUri(imageUri)) {\n\t\t\treturn getVideoThumbnailStream(filePath);\n\t\t} else {\n\t\t\tBufferedInputStream imageStream = new BufferedInputStream(new FileInputStream(filePath), BUFFER_SIZE);\n\t\t\treturn new ContentLengthInputStream(imageStream, (int) new File(filePath).length());\n\t\t}\n\t}\n\n\t@TargetApi(Build.VERSION_CODES.FROYO)\n\tprivate InputStream getVideoThumbnailStream(String filePath) {\n\t\tif (Build.VERSION.SDK_INT >= Build.VERSION_CODES.FROYO) {\n\t\t\tBitmap bitmap = ThumbnailUtils\n\t\t\t\t\t.createVideoThumbnail(filePath, MediaStore.Images.Thumbnails.FULL_SCREEN_KIND);\n\t\t\tif (bitmap != null) {\n\t\t\t\tByteArrayOutputStream bos = new ByteArrayOutputStream();\n\t\t\t\tbitmap.compress(CompressFormat.PNG, 0, bos);\n\t\t\t\treturn new ByteArrayInputStream(bos.toByteArray());\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n\t/**\n\t * Retrieves {@link InputStream} of image by URI (image is accessed using {@link ContentResolver}).\n\t *\n\t * @param imageUri Image URI\n\t * @param extra    Auxiliary object which was passed to {@link DisplayImageOptions.Builder#extraForDownloader(Object)\n\t *                 DisplayImageOptions.extraForDownloader(Object)}; can be null\n\t * @return {@link InputStream} of image\n\t * @throws FileNotFoundException if the provided URI could not be opened\n\t */\n\tprotected InputStream getStreamFromContent(String imageUri, Object extra) throws FileNotFoundException {\n\t\tContentResolver res = context.getContentResolver();\n\n\t\tUri uri = Uri.parse(imageUri);\n\t\tif (isVideoContentUri(uri)) { // video thumbnail\n\t\t\tLong origId = Long.valueOf(uri.getLastPathSegment());\n\t\t\tBitmap bitmap = MediaStore.Video.Thumbnails\n\t\t\t\t\t.getThumbnail(res, origId, MediaStore.Images.Thumbnails.MINI_KIND, null);\n\t\t\tif (bitmap != null) {\n\t\t\t\tByteArrayOutputStream bos = new ByteArrayOutputStream();\n\t\t\t\tbitmap.compress(CompressFormat.PNG, 0, bos);\n\t\t\t\treturn new ByteArrayInputStream(bos.toByteArray());\n\t\t\t}\n\t\t} else if (imageUri.startsWith(CONTENT_CONTACTS_URI_PREFIX)) { // contacts photo\n\t\t\treturn getContactPhotoStream(uri);\n\t\t}\n\n\t\treturn res.openInputStream(uri);\n\t}\n\n\t@TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)\n\tprotected InputStream getContactPhotoStream(Uri uri) {\n\t\tContentResolver res = context.getContentResolver();\n\t\tif (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {\n\t\t\treturn ContactsContract.Contacts.openContactPhotoInputStream(res, uri, true);\n\t\t} else {\n\t\t\treturn ContactsContract.Contacts.openContactPhotoInputStream(res, uri);\n\t\t}\n\t}\n\n\t/**\n\t * Retrieves {@link InputStream} of image by URI (image is located in assets of application).\n\t *\n\t * @param imageUri Image URI\n\t * @param extra    Auxiliary object which was passed to {@link DisplayImageOptions.Builder#extraForDownloader(Object)\n\t *                 DisplayImageOptions.extraForDownloader(Object)}; can be null\n\t * @return {@link InputStream} of image\n\t * @throws IOException if some I/O error occurs file reading\n\t */\n\tprotected InputStream getStreamFromAssets(String imageUri, Object extra) throws IOException {\n\t\tString filePath = Scheme.ASSETS.crop(imageUri);\n\t\treturn context.getAssets().open(filePath);\n\t}\n\n\t/**\n\t * Retrieves {@link InputStream} of image by URI (image is located in drawable resources of application).\n\t *\n\t * @param imageUri Image URI\n\t * @param extra    Auxiliary object which was passed to {@link DisplayImageOptions.Builder#extraForDownloader(Object)\n\t *                 DisplayImageOptions.extraForDownloader(Object)}; can be null\n\t * @return {@link InputStream} of image\n\t */\n\tprotected InputStream getStreamFromDrawable(String imageUri, Object extra) {\n\t\tString drawableIdString = Scheme.DRAWABLE.crop(imageUri);\n\t\tint drawableId = Integer.parseInt(drawableIdString);\n\t\treturn context.getResources().openRawResource(drawableId);\n\t}\n\n\t/**\n\t * Retrieves {@link InputStream} of image by URI from other source with unsupported scheme. Should be overriden by\n\t * successors to implement image downloading from special sources.<br />\n\t * This method is called only if image URI has unsupported scheme. Throws {@link UnsupportedOperationException} by\n\t * default.\n\t *\n\t * @param imageUri Image URI\n\t * @param extra    Auxiliary object which was passed to {@link DisplayImageOptions.Builder#extraForDownloader(Object)\n\t *                 DisplayImageOptions.extraForDownloader(Object)}; can be null\n\t * @return {@link InputStream} of image\n\t * @throws IOException                   if some I/O error occurs\n\t * @throws UnsupportedOperationException if image URI has unsupported scheme(protocol)\n\t */\n\tprotected InputStream getStreamFromOtherSource(String imageUri, Object extra) throws IOException {\n\t\tthrow new UnsupportedOperationException(String.format(ERROR_UNSUPPORTED_SCHEME, imageUri));\n\t}\n\n\tprivate boolean isVideoContentUri(Uri uri) {\n\t\tString mimeType = context.getContentResolver().getType(uri);\n\t\treturn mimeType != null && mimeType.startsWith(\"video/\");\n\t}\n\n\tprivate boolean isVideoFileUri(String uri) {\n\t\tString extension = MimeTypeMap.getFileExtensionFromUrl(Uri.encode(uri));\n\t\tString mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);\n\t\treturn mimeType != null && mimeType.startsWith(\"video/\");\n\t}\n}\n"
  },
  {
    "path": "library/src/main/java/com/nostra13/universalimageloader/core/download/ImageDownloader.java",
    "content": "/*******************************************************************************\n * Copyright 2011-2013 Sergey Tarasevich\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *******************************************************************************/\npackage com.nostra13.universalimageloader.core.download;\n\nimport com.nostra13.universalimageloader.core.DisplayImageOptions;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.util.Locale;\n\n/**\n * Provides retrieving of {@link InputStream} of image by URI.<br />\n * Implementations have to be thread-safe.\n *\n * @author Sergey Tarasevich (nostra13[at]gmail[dot]com)\n * @since 1.4.0\n */\npublic interface ImageDownloader {\n\t/**\n\t * Retrieves {@link InputStream} of image by URI.\n\t *\n\t * @param imageUri Image URI\n\t * @param extra    Auxiliary object which was passed to {@link DisplayImageOptions.Builder#extraForDownloader(Object)\n\t *                 DisplayImageOptions.extraForDownloader(Object)}; can be null\n\t * @return {@link InputStream} of image\n\t * @throws IOException                   if some I/O error occurs during getting image stream\n\t * @throws UnsupportedOperationException if image URI has unsupported scheme(protocol)\n\t */\n\tInputStream getStream(String imageUri, Object extra) throws IOException;\n\n\t/** Represents supported schemes(protocols) of URI. Provides convenient methods for work with schemes and URIs. */\n\tpublic enum Scheme {\n\t\tHTTP(\"http\"), HTTPS(\"https\"), FILE(\"file\"), CONTENT(\"content\"), ASSETS(\"assets\"), DRAWABLE(\"drawable\"), UNKNOWN(\"\");\n\n\t\tprivate String scheme;\n\t\tprivate String uriPrefix;\n\n\t\tScheme(String scheme) {\n\t\t\tthis.scheme = scheme;\n\t\t\turiPrefix = scheme + \"://\";\n\t\t}\n\n\t\t/**\n\t\t * Defines scheme of incoming URI\n\t\t *\n\t\t * @param uri URI for scheme detection\n\t\t * @return Scheme of incoming URI\n\t\t */\n\t\tpublic static Scheme ofUri(String uri) {\n\t\t\tif (uri != null) {\n\t\t\t\tfor (Scheme s : values()) {\n\t\t\t\t\tif (s.belongsTo(uri)) {\n\t\t\t\t\t\treturn s;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn UNKNOWN;\n\t\t}\n\n\t\tprivate boolean belongsTo(String uri) {\n\t\t\treturn uri.toLowerCase(Locale.US).startsWith(uriPrefix);\n\t\t}\n\n\t\t/** Appends scheme to incoming path */\n\t\tpublic String wrap(String path) {\n\t\t\treturn uriPrefix + path;\n\t\t}\n\n\t\t/** Removed scheme part (\"scheme://\") from incoming URI */\n\t\tpublic String crop(String uri) {\n\t\t\tif (!belongsTo(uri)) {\n\t\t\t\tthrow new IllegalArgumentException(String.format(\"URI [%1$s] doesn't have expected scheme [%2$s]\", uri, scheme));\n\t\t\t}\n\t\t\treturn uri.substring(uriPrefix.length());\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "library/src/main/java/com/nostra13/universalimageloader/core/imageaware/ImageAware.java",
    "content": "/*******************************************************************************\n * Copyright 2013-2014 Sergey Tarasevich\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *******************************************************************************/\npackage com.nostra13.universalimageloader.core.imageaware;\n\nimport android.graphics.Bitmap;\nimport android.graphics.drawable.Drawable;\nimport android.view.View;\nimport com.nostra13.universalimageloader.core.assist.ViewScaleType;\n\n/**\n * Represents image aware view which provides all needed properties and behavior for image processing and displaying\n * through {@link com.nostra13.universalimageloader.core.ImageLoader ImageLoader}.\n * It can wrap any Android {@link android.view.View View} which can be accessed by {@link #getWrappedView()}. Wrapped\n * view is returned in {@link com.nostra13.universalimageloader.core.listener.ImageLoadingListener ImageLoadingListener}'s\n * callbacks.\n *\n * @author Sergey Tarasevich (nostra13[at]gmail[dot]com)\n * @see ViewAware\n * @see ImageViewAware\n * @see NonViewAware\n * @since 1.9.0\n */\npublic interface ImageAware {\n\t/**\n\t * Returns width of image aware view. This value is used to define scale size for original image.\n\t * Can return 0 if width is undefined.<br />\n\t * Is called on UI thread if ImageLoader was called on UI thread. Otherwise - on background thread.\n\t */\n\tint getWidth();\n\n\t/**\n\t * Returns height of image aware view. This value is used to define scale size for original image.\n\t * Can return 0 if height is undefined.<br />\n\t * Is called on UI thread if ImageLoader was called on UI thread. Otherwise - on background thread.\n\t */\n\tint getHeight();\n\n\t/**\n\t * Returns {@linkplain com.nostra13.universalimageloader.core.assist.ViewScaleType scale type} which is used for\n\t * scaling image for this image aware view. Must <b>NOT</b> return <b>null</b>.\n\t */\n\tViewScaleType getScaleType();\n\n\t/**\n\t * Returns wrapped Android {@link android.view.View View}. Can return <b>null</b> if no view is wrapped or view was\n\t * collected by GC.<br />\n\t * Is called on UI thread if ImageLoader was called on UI thread. Otherwise - on background thread.\n\t */\n\tView getWrappedView();\n\n\t/**\n\t * Returns a flag whether image aware view is collected by GC or whatsoever. If so then ImageLoader stop processing\n\t * of task for this image aware view and fires\n\t * {@link com.nostra13.universalimageloader.core.listener.ImageLoadingListener#onLoadingCancelled(String,\n\t * android.view.View) ImageLoadingListener#onLoadingCancelled(String, View)} callback.<br />\n\t * Mey be called on UI thread if ImageLoader was called on UI thread. Otherwise - on background thread.\n\t *\n\t * @return <b>true</b> - if view is collected by GC and ImageLoader should stop processing this image aware view;\n\t * <b>false</b> - otherwise\n\t */\n\tboolean isCollected();\n\n\t/**\n\t * Returns ID of image aware view. Point of ID is similar to Object's hashCode. This ID should be unique for every\n\t * image view instance and should be the same for same instances. This ID identifies processing task in ImageLoader\n\t * so ImageLoader won't process two image aware views with the same ID in one time. When ImageLoader get new task\n\t * it cancels old task with this ID (if any) and starts new task.\n\t * <p/>\n\t * It's reasonable to return hash code of wrapped view (if any) to prevent displaying non-actual images in view\n\t * because of view re-using.\n\t */\n\tint getId();\n\n\t/**\n\t * Sets image drawable into this image aware view.<br />\n\t * Displays drawable in this image aware view\n\t * {@linkplain com.nostra13.universalimageloader.core.DisplayImageOptions.Builder#showImageForEmptyUri(\n\t *android.graphics.drawable.Drawable) for empty Uri},\n\t * {@linkplain com.nostra13.universalimageloader.core.DisplayImageOptions.Builder#showImageOnLoading(\n\t *android.graphics.drawable.Drawable) on loading} or\n\t * {@linkplain com.nostra13.universalimageloader.core.DisplayImageOptions.Builder#showImageOnFail(\n\t *android.graphics.drawable.Drawable) on loading fail}. These drawables can be specified in\n\t * {@linkplain com.nostra13.universalimageloader.core.DisplayImageOptions display options}.<br />\n\t * Also can be called in {@link com.nostra13.universalimageloader.core.display.BitmapDisplayer BitmapDisplayer}.< br />\n\t * Is called on UI thread if ImageLoader was called on UI thread. Otherwise - on background thread.\n\t *\n\t * @return <b>true</b> if drawable was set successfully; <b>false</b> - otherwise\n\t */\n\tboolean setImageDrawable(Drawable drawable);\n\n\t/**\n\t * Sets image bitmap into this image aware view.<br />\n\t * Displays loaded and decoded image {@link android.graphics.Bitmap} in this image view aware.\n\t * Actually it's used only in\n\t * {@link com.nostra13.universalimageloader.core.display.BitmapDisplayer BitmapDisplayer}.< br />\n\t * Is called on UI thread if ImageLoader was called on UI thread. Otherwise - on background thread.\n\t *\n\t * @return <b>true</b> if bitmap was set successfully; <b>false</b> - otherwise\n\t */\n\tboolean setImageBitmap(Bitmap bitmap);\n}\n"
  },
  {
    "path": "library/src/main/java/com/nostra13/universalimageloader/core/imageaware/ImageViewAware.java",
    "content": "/*******************************************************************************\n * Copyright 2013-2014 Sergey Tarasevich\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *******************************************************************************/\npackage com.nostra13.universalimageloader.core.imageaware;\n\nimport android.graphics.Bitmap;\nimport android.graphics.drawable.AnimationDrawable;\nimport android.graphics.drawable.Drawable;\nimport android.view.View;\nimport android.widget.ImageView;\nimport com.nostra13.universalimageloader.core.assist.ViewScaleType;\nimport com.nostra13.universalimageloader.utils.L;\n\nimport java.lang.reflect.Field;\n\n/**\n * Wrapper for Android {@link android.widget.ImageView ImageView}. Keeps weak reference of ImageView to prevent memory\n * leaks.\n *\n * @author Sergey Tarasevich (nostra13[at]gmail[dot]com)\n * @since 1.9.0\n */\npublic class ImageViewAware extends ViewAware {\n\n\t/**\n\t * Constructor. <br />\n\t * References {@link #ImageViewAware(android.widget.ImageView, boolean) ImageViewAware(imageView, true)}.\n\t *\n\t * @param imageView {@link android.widget.ImageView ImageView} to work with\n\t */\n\tpublic ImageViewAware(ImageView imageView) {\n\t\tsuper(imageView);\n\t}\n\n\t/**\n\t * Constructor\n\t *\n\t * @param imageView           {@link android.widget.ImageView ImageView} to work with\n\t * @param checkActualViewSize <b>true</b> - then {@link #getWidth()} and {@link #getHeight()} will check actual\n\t *                            size of ImageView. It can cause known issues like\n\t *                            <a href=\"https://github.com/nostra13/Android-Universal-Image-Loader/issues/376\">this</a>.\n\t *                            But it helps to save memory because memory cache keeps bitmaps of actual (less in\n\t *                            general) size.\n\t *                            <p/>\n\t *                            <b>false</b> - then {@link #getWidth()} and {@link #getHeight()} will <b>NOT</b>\n\t *                            consider actual size of ImageView, just layout parameters. <br /> If you set 'false'\n\t *                            it's recommended 'android:layout_width' and 'android:layout_height' (or\n\t *                            'android:maxWidth' and 'android:maxHeight') are set with concrete values. It helps to\n\t *                            save memory.\n\t *                            <p/>\n\t */\n\tpublic ImageViewAware(ImageView imageView, boolean checkActualViewSize) {\n\t\tsuper(imageView, checkActualViewSize);\n\t}\n\n\t/**\n\t * {@inheritDoc}\n\t * <br />\n\t * 3) Get <b>maxWidth</b>.\n\t */\n\t@Override\n\tpublic int getWidth() {\n\t\tint width = super.getWidth();\n\t\tif (width <= 0) {\n\t\t\tImageView imageView = (ImageView) viewRef.get();\n\t\t\tif (imageView != null) {\n\t\t\t\twidth = imageView.getMaxWidth();\n\t\t\t}\n\t\t}\n\t\treturn width;\n\t}\n\n\t/**\n\t * {@inheritDoc}\n\t * <br />\n\t * 3) Get <b>maxHeight</b>\n\t */\n\t@Override\n\tpublic int getHeight() {\n\t\tint height = super.getHeight();\n\t\tif (height <= 0) {\n\t\t\tImageView imageView = (ImageView) viewRef.get();\n\t\t\tif (imageView != null) {\n\t\t\t\theight = imageView.getMaxHeight();\n\t\t\t}\n\t\t}\n\t\treturn height;\n\t}\n\n\t@Override\n\tpublic ViewScaleType getScaleType() {\n\t\tImageView imageView = (ImageView) viewRef.get();\n\t\tif (imageView != null) {\n\t\t\treturn ViewScaleType.fromImageView(imageView);\n\t\t}\n\t\treturn super.getScaleType();\n\t}\n\n\t@Override\n\tpublic ImageView getWrappedView() {\n\t\treturn (ImageView) super.getWrappedView();\n\t}\n\n\t@Override\n\tprotected void setImageDrawableInto(Drawable drawable, View view) {\n\t\t((ImageView) view).setImageDrawable(drawable);\n\t\tif (drawable instanceof AnimationDrawable) {\n\t\t\t((AnimationDrawable)drawable).start();\n\t\t}\n\t}\n\n\t@Override\n\tprotected void setImageBitmapInto(Bitmap bitmap, View view) {\n\t\t((ImageView) view).setImageBitmap(bitmap);\n\t}\n}\n"
  },
  {
    "path": "library/src/main/java/com/nostra13/universalimageloader/core/imageaware/NonViewAware.java",
    "content": "/*******************************************************************************\n * Copyright 2013-2014 Sergey Tarasevich\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *******************************************************************************/\npackage com.nostra13.universalimageloader.core.imageaware;\n\nimport android.graphics.Bitmap;\nimport android.graphics.drawable.Drawable;\nimport android.text.TextUtils;\nimport android.view.View;\nimport com.nostra13.universalimageloader.core.assist.ImageSize;\nimport com.nostra13.universalimageloader.core.assist.ViewScaleType;\n\n/**\n * ImageAware which provides needed info for processing of original image but do nothing for displaying image. It's\n * used when user need just load and decode image and get it in {@linkplain\n * com.nostra13.universalimageloader.core.listener.ImageLoadingListener#onLoadingComplete(String, android.view.View,\n * android.graphics.Bitmap) callback}.\n *\n * @author Sergey Tarasevich (nostra13[at]gmail[dot]com)\n * @since 1.9.0\n */\npublic class NonViewAware implements ImageAware {\n\n\tprotected final String imageUri;\n\tprotected final ImageSize imageSize;\n\tprotected final ViewScaleType scaleType;\n\n\tpublic NonViewAware(ImageSize imageSize, ViewScaleType scaleType) {\n\t\tthis(null, imageSize, scaleType);\n\t}\n\n\tpublic NonViewAware(String imageUri, ImageSize imageSize, ViewScaleType scaleType) {\n\t\tif (imageSize == null) throw new IllegalArgumentException(\"imageSize must not be null\");\n\t\tif (scaleType == null) throw new IllegalArgumentException(\"scaleType must not be null\");\n\n\t\tthis.imageUri = imageUri;\n\t\tthis.imageSize = imageSize;\n\t\tthis.scaleType = scaleType;\n\t}\n\n\t@Override\n\tpublic int getWidth() {\n\t\treturn imageSize.getWidth();\n\t}\n\n\t@Override\n\tpublic int getHeight() {\n\t\treturn imageSize.getHeight();\n\t}\n\n\t@Override\n\tpublic ViewScaleType getScaleType() {\n\t\treturn scaleType;\n\t}\n\n\t@Override\n\tpublic View getWrappedView() {\n\t\treturn null;\n\t}\n\n\t@Override\n\tpublic boolean isCollected() {\n\t\treturn false;\n\t}\n\n\t@Override\n\tpublic int getId() {\n\t\treturn TextUtils.isEmpty(imageUri) ? super.hashCode() : imageUri.hashCode();\n\t}\n\n\t@Override\n\tpublic boolean setImageDrawable(Drawable drawable) { // Do nothing\n\t\treturn true;\n\t}\n\n\t@Override\n\tpublic boolean setImageBitmap(Bitmap bitmap) { // Do nothing\n\t\treturn true;\n\t}\n}"
  },
  {
    "path": "library/src/main/java/com/nostra13/universalimageloader/core/imageaware/ViewAware.java",
    "content": "/*******************************************************************************\n * Copyright 2014 Sergey Tarasevich\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *******************************************************************************/\npackage com.nostra13.universalimageloader.core.imageaware;\n\nimport android.graphics.Bitmap;\nimport android.graphics.drawable.Drawable;\nimport android.os.Looper;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport com.nostra13.universalimageloader.core.assist.ViewScaleType;\nimport com.nostra13.universalimageloader.utils.L;\n\nimport java.lang.ref.Reference;\nimport java.lang.ref.WeakReference;\n\n/**\n * Wrapper for Android {@link android.view.View View}. Keeps weak reference of View to prevent memory leaks.\n *\n * @author Sergey Tarasevich (nostra13[at]gmail[dot]com)\n * @since 1.9.2\n */\npublic abstract class ViewAware implements ImageAware {\n\n\tpublic static final String WARN_CANT_SET_DRAWABLE = \"Can't set a drawable into view. You should call ImageLoader on UI thread for it.\";\n\tpublic static final String WARN_CANT_SET_BITMAP = \"Can't set a bitmap into view. You should call ImageLoader on UI thread for it.\";\n\n\tprotected Reference<View> viewRef;\n\tprotected boolean checkActualViewSize;\n\n\t/**\n\t * Constructor. <br />\n\t * References {@link #ViewAware(android.view.View, boolean) ImageViewAware(imageView, true)}.\n\t *\n\t * @param view {@link android.view.View View} to work with\n\t */\n\tpublic ViewAware(View view) {\n\t\tthis(view, true);\n\t}\n\n\t/**\n\t * Constructor\n\t *\n\t * @param view                {@link android.view.View View} to work with\n\t * @param checkActualViewSize <b>true</b> - then {@link #getWidth()} and {@link #getHeight()} will check actual\n\t *                            size of View. It can cause known issues like\n\t *                            <a href=\"https://github.com/nostra13/Android-Universal-Image-Loader/issues/376\">this</a>.\n\t *                            But it helps to save memory because memory cache keeps bitmaps of actual (less in\n\t *                            general) size.\n\t *                            <p/>\n\t *                            <b>false</b> - then {@link #getWidth()} and {@link #getHeight()} will <b>NOT</b>\n\t *                            consider actual size of View, just layout parameters. <br /> If you set 'false'\n\t *                            it's recommended 'android:layout_width' and 'android:layout_height' (or\n\t *                            'android:maxWidth' and 'android:maxHeight') are set with concrete values. It helps to\n\t *                            save memory.\n\t */\n\tpublic ViewAware(View view, boolean checkActualViewSize) {\n\t\tif (view == null) throw new IllegalArgumentException(\"view must not be null\");\n\n\t\tthis.viewRef = new WeakReference<View>(view);\n\t\tthis.checkActualViewSize = checkActualViewSize;\n\t}\n\n\t/**\n\t * {@inheritDoc}\n\t * <p/>\n\t * Width is defined by target {@link android.view.View view} parameters, configuration\n\t * parameters or device display dimensions.<br />\n\t * Size computing algorithm (go by steps until get non-zero value):<br />\n\t * 1) Get the actual drawn <b>getWidth()</b> of the View<br />\n\t * 2) Get <b>layout_width</b>\n\t */\n\t@Override\n\tpublic int getWidth() {\n\t\tView view = viewRef.get();\n\t\tif (view != null) {\n\t\t\tfinal ViewGroup.LayoutParams params = view.getLayoutParams();\n\t\t\tint width = 0;\n\t\t\tif (checkActualViewSize && params != null && params.width != ViewGroup.LayoutParams.WRAP_CONTENT) {\n\t\t\t\twidth = view.getWidth(); // Get actual image width\n\t\t\t}\n\t\t\tif (width <= 0 && params != null) width = params.width; // Get layout width parameter\n\t\t\treturn width;\n\t\t}\n\t\treturn 0;\n\t}\n\n\t/**\n\t * {@inheritDoc}\n\t * <p/>\n\t * Height is defined by target {@link android.view.View view} parameters, configuration\n\t * parameters or device display dimensions.<br />\n\t * Size computing algorithm (go by steps until get non-zero value):<br />\n\t * 1) Get the actual drawn <b>getHeight()</b> of the View<br />\n\t * 2) Get <b>layout_height</b>\n\t */\n\t@Override\n\tpublic int getHeight() {\n\t\tView view = viewRef.get();\n\t\tif (view != null) {\n\t\t\tfinal ViewGroup.LayoutParams params = view.getLayoutParams();\n\t\t\tint height = 0;\n\t\t\tif (checkActualViewSize && params != null && params.height != ViewGroup.LayoutParams.WRAP_CONTENT) {\n\t\t\t\theight = view.getHeight(); // Get actual image height\n\t\t\t}\n\t\t\tif (height <= 0 && params != null) height = params.height; // Get layout height parameter\n\t\t\treturn height;\n\t\t}\n\t\treturn 0;\n\t}\n\n\t@Override\n\tpublic ViewScaleType getScaleType() {\n\t\treturn ViewScaleType.CROP;\n\t}\n\n\t@Override\n\tpublic View getWrappedView() {\n\t\treturn viewRef.get();\n\t}\n\n\t@Override\n\tpublic boolean isCollected() {\n\t\treturn viewRef.get() == null;\n\t}\n\n\t@Override\n\tpublic int getId() {\n\t\tView view = viewRef.get();\n\t\treturn view == null ? super.hashCode() : view.hashCode();\n\t}\n\n\t@Override\n\tpublic boolean setImageDrawable(Drawable drawable) {\n\t\tif (Looper.myLooper() == Looper.getMainLooper()) {\n\t\t\tView view = viewRef.get();\n\t\t\tif (view != null) {\n\t\t\t\tsetImageDrawableInto(drawable, view);\n\t\t\t\treturn true;\n\t\t\t}\n\t\t} else {\n\t\t\tL.w(WARN_CANT_SET_DRAWABLE);\n\t\t}\n\t\treturn false;\n\t}\n\n\t@Override\n\tpublic boolean setImageBitmap(Bitmap bitmap) {\n\t\tif (Looper.myLooper() == Looper.getMainLooper()) {\n\t\t\tView view = viewRef.get();\n\t\t\tif (view != null) {\n\t\t\t\tsetImageBitmapInto(bitmap, view);\n\t\t\t\treturn true;\n\t\t\t}\n\t\t} else {\n\t\t\tL.w(WARN_CANT_SET_BITMAP);\n\t\t}\n\t\treturn false;\n\t}\n\n\t/**\n\t * Should set drawable into incoming view. Incoming view is guaranteed not null.<br />\n\t * This method is called on UI thread.\n\t */\n\tprotected abstract void setImageDrawableInto(Drawable drawable, View view);\n\n\t/**\n\t * Should set Bitmap into incoming view. Incoming view is guaranteed not null.< br />\n\t * This method is called on UI thread.\n\t */\n\tprotected abstract void setImageBitmapInto(Bitmap bitmap, View view);\n}\n"
  },
  {
    "path": "library/src/main/java/com/nostra13/universalimageloader/core/listener/ImageLoadingListener.java",
    "content": "/*******************************************************************************\n * Copyright 2011-2013 Sergey Tarasevich\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *******************************************************************************/\npackage com.nostra13.universalimageloader.core.listener;\n\nimport android.graphics.Bitmap;\nimport android.view.View;\nimport com.nostra13.universalimageloader.core.assist.FailReason;\n\n/**\n * Listener for image loading process.<br />\n * You can use {@link SimpleImageLoadingListener} for implementing only needed methods.\n *\n * @author Sergey Tarasevich (nostra13[at]gmail[dot]com)\n * @see SimpleImageLoadingListener\n * @see com.nostra13.universalimageloader.core.assist.FailReason\n * @since 1.0.0\n */\npublic interface ImageLoadingListener {\n\n\t/**\n\t * Is called when image loading task was started\n\t *\n\t * @param imageUri Loading image URI\n\t * @param view     View for image\n\t */\n\tvoid onLoadingStarted(String imageUri, View view);\n\n\t/**\n\t * Is called when an error was occurred during image loading\n\t *\n\t * @param imageUri   Loading image URI\n\t * @param view       View for image. Can be <b>null</b>.\n\t * @param failReason {@linkplain com.nostra13.universalimageloader.core.assist.FailReason The reason} why image\n\t *                   loading was failed\n\t */\n\tvoid onLoadingFailed(String imageUri, View view, FailReason failReason);\n\n\t/**\n\t * Is called when image is loaded successfully (and displayed in View if one was specified)\n\t *\n\t * @param imageUri    Loaded image URI\n\t * @param view        View for image. Can be <b>null</b>.\n\t * @param loadedImage Bitmap of loaded and decoded image\n\t */\n\tvoid onLoadingComplete(String imageUri, View view, Bitmap loadedImage);\n\n\t/**\n\t * Is called when image loading task was cancelled because View for image was reused in newer task\n\t *\n\t * @param imageUri Loading image URI\n\t * @param view     View for image. Can be <b>null</b>.\n\t */\n\tvoid onLoadingCancelled(String imageUri, View view);\n}\n"
  },
  {
    "path": "library/src/main/java/com/nostra13/universalimageloader/core/listener/ImageLoadingProgressListener.java",
    "content": "/*******************************************************************************\n * Copyright 2013 Sergey Tarasevich\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *******************************************************************************/\npackage com.nostra13.universalimageloader.core.listener;\n\nimport android.view.View;\n\n/**\n * Listener for image loading progress.\n *\n * @author Sergey Tarasevich (nostra13[at]gmail[dot]com)\n * @since 1.9.1\n */\npublic interface ImageLoadingProgressListener {\n\n\t/**\n\t * Is called when image loading progress changed.\n\t *\n\t * @param imageUri Image URI\n\t * @param view     View for image. Can be <b>null</b>.\n\t * @param current  Downloaded size in bytes\n\t * @param total    Total size in bytes\n\t */\n\tvoid onProgressUpdate(String imageUri, View view, int current, int total);\n}\n"
  },
  {
    "path": "library/src/main/java/com/nostra13/universalimageloader/core/listener/PauseOnScrollListener.java",
    "content": "/*******************************************************************************\n * Copyright 2011-2013 Sergey Tarasevich\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *******************************************************************************/\npackage com.nostra13.universalimageloader.core.listener;\n\nimport android.widget.AbsListView;\nimport android.widget.AbsListView.OnScrollListener;\nimport android.widget.GridView;\nimport android.widget.ListView;\nimport com.nostra13.universalimageloader.core.ImageLoader;\n\n/**\n * Listener-helper for {@linkplain AbsListView list views} ({@link ListView}, {@link GridView}) which can\n * {@linkplain ImageLoader#pause() pause ImageLoader's tasks} while list view is scrolling (touch scrolling and/or\n * fling). It prevents redundant loadings.<br />\n * Set it to your list view's {@link AbsListView#setOnScrollListener(OnScrollListener) setOnScrollListener(...)}.<br />\n * This listener can wrap your custom {@linkplain OnScrollListener listener}.\n *\n * @author Sergey Tarasevich (nostra13[at]gmail[dot]com)\n * @since 1.7.0\n */\npublic class PauseOnScrollListener implements OnScrollListener {\n\n\tprivate ImageLoader imageLoader;\n\n\tprivate final boolean pauseOnScroll;\n\tprivate final boolean pauseOnFling;\n\tprivate final OnScrollListener externalListener;\n\n\t/**\n\t * Constructor\n\t *\n\t * @param imageLoader   {@linkplain ImageLoader} instance for controlling\n\t * @param pauseOnScroll Whether {@linkplain ImageLoader#pause() pause ImageLoader} during touch scrolling\n\t * @param pauseOnFling  Whether {@linkplain ImageLoader#pause() pause ImageLoader} during fling\n\t */\n\tpublic PauseOnScrollListener(ImageLoader imageLoader, boolean pauseOnScroll, boolean pauseOnFling) {\n\t\tthis(imageLoader, pauseOnScroll, pauseOnFling, null);\n\t}\n\n\t/**\n\t * Constructor\n\t *\n\t * @param imageLoader    {@linkplain ImageLoader} instance for controlling\n\t * @param pauseOnScroll  Whether {@linkplain ImageLoader#pause() pause ImageLoader} during touch scrolling\n\t * @param pauseOnFling   Whether {@linkplain ImageLoader#pause() pause ImageLoader} during fling\n\t * @param customListener Your custom {@link OnScrollListener} for {@linkplain AbsListView list view} which also\n\t *                       will be get scroll events\n\t */\n\tpublic PauseOnScrollListener(ImageLoader imageLoader, boolean pauseOnScroll, boolean pauseOnFling,\n\t\t\tOnScrollListener customListener) {\n\t\tthis.imageLoader = imageLoader;\n\t\tthis.pauseOnScroll = pauseOnScroll;\n\t\tthis.pauseOnFling = pauseOnFling;\n\t\texternalListener = customListener;\n\t}\n\n\t@Override\n\tpublic void onScrollStateChanged(AbsListView view, int scrollState) {\n\t\tswitch (scrollState) {\n\t\t\tcase OnScrollListener.SCROLL_STATE_IDLE:\n\t\t\t\timageLoader.resume();\n\t\t\t\tbreak;\n\t\t\tcase OnScrollListener.SCROLL_STATE_TOUCH_SCROLL:\n\t\t\t\tif (pauseOnScroll) {\n\t\t\t\t\timageLoader.pause();\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase OnScrollListener.SCROLL_STATE_FLING:\n\t\t\t\tif (pauseOnFling) {\n\t\t\t\t\timageLoader.pause();\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t}\n\t\tif (externalListener != null) {\n\t\t\texternalListener.onScrollStateChanged(view, scrollState);\n\t\t}\n\t}\n\n\t@Override\n\tpublic void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {\n\t\tif (externalListener != null) {\n\t\t\texternalListener.onScroll(view, firstVisibleItem, visibleItemCount, totalItemCount);\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "library/src/main/java/com/nostra13/universalimageloader/core/listener/SimpleImageLoadingListener.java",
    "content": "/*******************************************************************************\n * Copyright 2011-2013 Sergey Tarasevich\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *******************************************************************************/\npackage com.nostra13.universalimageloader.core.listener;\n\nimport android.graphics.Bitmap;\nimport android.view.View;\nimport com.nostra13.universalimageloader.core.assist.FailReason;\n\n/**\n * A convenient class to extend when you only want to listen for a subset of all the image loading events. This\n * implements all methods in the {@link com.nostra13.universalimageloader.core.listener.ImageLoadingListener} but does\n * nothing.\n *\n * @author Sergey Tarasevich (nostra13[at]gmail[dot]com)\n * @since 1.4.0\n */\npublic class SimpleImageLoadingListener implements ImageLoadingListener {\n\t@Override\n\tpublic void onLoadingStarted(String imageUri, View view) {\n\t\t// Empty implementation\n\t}\n\n\t@Override\n\tpublic void onLoadingFailed(String imageUri, View view, FailReason failReason) {\n\t\t// Empty implementation\n\t}\n\n\t@Override\n\tpublic void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) {\n\t\t// Empty implementation\n\t}\n\n\t@Override\n\tpublic void onLoadingCancelled(String imageUri, View view) {\n\t\t// Empty implementation\n\t}\n}\n"
  },
  {
    "path": "library/src/main/java/com/nostra13/universalimageloader/core/process/BitmapProcessor.java",
    "content": "/*******************************************************************************\n * Copyright 2011-2013 Sergey Tarasevich\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *******************************************************************************/\npackage com.nostra13.universalimageloader.core.process;\n\nimport android.graphics.Bitmap;\nimport com.nostra13.universalimageloader.core.DisplayImageOptions;\n\n/**\n * Makes some processing on {@link Bitmap}. Implementations can apply any changes to original {@link Bitmap}.<br />\n * Implementations have to be thread-safe.\n *\n * @author Sergey Tarasevich (nostra13[at]gmail[dot]com)\n * @since 1.8.0\n */\npublic interface BitmapProcessor {\n\t/**\n\t * Makes some processing of incoming bitmap.<br />\n\t * This method is executing on additional thread (not on UI thread).<br />\n\t * <b>Note:</b> If this processor is used as {@linkplain DisplayImageOptions.Builder#preProcessor(BitmapProcessor)\n\t * pre-processor} then don't forget {@linkplain Bitmap#recycle() to recycle} incoming bitmap if you return a new\n\t * created one.\n\t *\n\t * @param bitmap Original {@linkplain Bitmap bitmap}\n\t * @return Processed {@linkplain Bitmap bitmap}\n\t */\n\tBitmap process(Bitmap bitmap);\n}\n"
  },
  {
    "path": "library/src/main/java/com/nostra13/universalimageloader/utils/DiskCacheUtils.java",
    "content": "/*******************************************************************************\n * Copyright 2011-2014 Sergey Tarasevich\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *******************************************************************************/\npackage com.nostra13.universalimageloader.utils;\n\nimport com.nostra13.universalimageloader.cache.disc.DiskCache;\n\nimport java.io.File;\n\n/**\n * Utility for convenient work with disk cache.<br />\n * <b>NOTE:</b> This utility works with file system so avoid using it on application main thread.\n *\n * @author Sergey Tarasevich (nostra13[at]gmail[dot]com)\n * @since 1.8.0\n */\npublic final class DiskCacheUtils {\n\n\tprivate DiskCacheUtils() {\n\t}\n\n\t/** Returns {@link File} of cached image or <b>null</b> if image was not cached in disk cache */\n\tpublic static File findInCache(String imageUri, DiskCache diskCache) {\n\t\tFile image = diskCache.get(imageUri);\n\t\treturn image != null && image.exists() ? image : null;\n\t}\n\n\t/**\n\t * Removed cached image file from disk cache (if image was cached in disk cache before)\n\t *\n\t * @return <b>true</b> - if cached image file existed and was deleted; <b>false</b> - otherwise.\n\t */\n\tpublic static boolean removeFromCache(String imageUri, DiskCache diskCache) {\n\t\tFile image = diskCache.get(imageUri);\n\t\treturn image != null && image.exists() && image.delete();\n\t}\n}\n"
  },
  {
    "path": "library/src/main/java/com/nostra13/universalimageloader/utils/ImageSizeUtils.java",
    "content": "/*******************************************************************************\n * Copyright 2013-2014 Sergey Tarasevich\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *******************************************************************************/\npackage com.nostra13.universalimageloader.utils;\n\nimport android.graphics.BitmapFactory;\nimport android.opengl.GLES10;\n\nimport com.nostra13.universalimageloader.core.assist.ImageSize;\nimport com.nostra13.universalimageloader.core.assist.ViewScaleType;\nimport com.nostra13.universalimageloader.core.imageaware.ImageAware;\n\nimport javax.microedition.khronos.opengles.GL10;\n\n/**\n * Provides calculations with image sizes, scales\n *\n * @author Sergey Tarasevich (nostra13[at]gmail[dot]com)\n * @since 1.8.3\n */\npublic final class ImageSizeUtils {\n\n    private static final int DEFAULT_MAX_BITMAP_DIMENSION = 2048;\n\n    private static ImageSize maxBitmapSize;\n\n    static {\n        int[] maxTextureSize = new int[1];\n        GLES10.glGetIntegerv(GL10.GL_MAX_TEXTURE_SIZE, maxTextureSize, 0);\n        int maxBitmapDimension = Math.max(maxTextureSize[0], DEFAULT_MAX_BITMAP_DIMENSION);\n        maxBitmapSize = new ImageSize(maxBitmapDimension, maxBitmapDimension);\n    }\n\n    private ImageSizeUtils() {\n    }\n\n    /**\n     * Defines target size for image aware view. Size is defined by target\n     * {@link com.nostra13.universalimageloader.core.imageaware.ImageAware view} parameters, configuration\n     * parameters or device display dimensions.<br />\n     */\n    public static ImageSize defineTargetSizeForView(ImageAware imageAware, ImageSize maxImageSize) {\n        int width = imageAware.getWidth();\n        if (width <= 0) {\n            width = maxImageSize.getWidth();\n        } else {\n            width = Math.min(width, maxImageSize.getWidth());\n        }\n\n        int height = imageAware.getHeight();\n        if (height <= 0) {\n            height = maxImageSize.getHeight();\n        } else {\n            height = Math.min(height, maxImageSize.getHeight());\n        }\n\n        return new ImageSize(width, height);\n    }\n\n    /**\n     * Computes sample size for downscaling image size (<b>srcSize</b>) to view size (<b>targetSize</b>). This sample\n     * size is used during\n     * {@linkplain BitmapFactory#decodeStream(java.io.InputStream, android.graphics.Rect, android.graphics.BitmapFactory.Options)\n     * decoding image} to bitmap.<br />\n     * <br />\n     * <b>Examples:</b><br />\n     * <p/>\n     * <pre>\n     * srcSize(100x100), targetSize(10x10), powerOf2Scale = true -> sampleSize = 8\n     * srcSize(100x100), targetSize(10x10), powerOf2Scale = false -> sampleSize = 10\n     *\n     * srcSize(100x100), targetSize(20x40), viewScaleType = FIT_INSIDE -> sampleSize = 5\n     * srcSize(100x100), targetSize(20x40), viewScaleType = CROP       -> sampleSize = 2\n     * </pre>\n     * <p/>\n     * <br />\n     * The sample size is the number of pixels in either dimension that correspond to a single pixel in the decoded\n     * bitmap. For example, inSampleSize == 4 returns an image that is 1/4 the width/height of the original, and 1/16\n     * the number of pixels. Any value <= 1 is treated the same as 1.\n     *\n     * @param srcSize       Original (image) size\n     * @param targetSize    Target (view) size\n     * @param viewScaleType {@linkplain ViewScaleType Scale type} for placing image in view\n     * @param powerOf2Scale <i>true</i> - if sample size be a power of 2 (1, 2, 4, 8, ...)\n     * @return Computed sample size\n     */\n    public static int computeImageSampleSize(ImageSize srcSize, ImageSize targetSize, ViewScaleType viewScaleType,\n                                             boolean powerOf2Scale) {\n        final int srcWidth = srcSize.getWidth();\n        final int srcHeight = srcSize.getHeight();\n        final int targetWidth = targetSize.getWidth();\n        final int targetHeight = targetSize.getHeight();\n\n        int scale = 1;\n\n        switch (viewScaleType) {\n            case FIT_INSIDE:\n                if (powerOf2Scale) {\n                    final int halfWidth = srcWidth / 2;\n                    final int halfHeight = srcHeight / 2;\n                    while ((halfWidth / scale) > targetWidth || (halfHeight / scale) > targetHeight) { // ||\n                        scale *= 2;\n                    }\n                } else {\n                    scale = Math.max(srcWidth / targetWidth, srcHeight / targetHeight); // max\n                }\n                break;\n            case CROP:\n                if (powerOf2Scale) {\n                    final int halfWidth = srcWidth / 2;\n                    final int halfHeight = srcHeight / 2;\n                    while ((halfWidth / scale) > targetWidth && (halfHeight / scale) > targetHeight) { // &&\n                        scale *= 2;\n                    }\n                } else {\n                    scale = Math.min(srcWidth / targetWidth, srcHeight / targetHeight); // min\n                }\n                break;\n        }\n\n        if (scale < 1) {\n            scale = 1;\n        }\n        scale = considerMaxTextureSize(srcWidth, srcHeight, scale, powerOf2Scale);\n\n        return scale;\n    }\n\n    private static int considerMaxTextureSize(int srcWidth, int srcHeight, int scale, boolean powerOf2) {\n        final int maxWidth = maxBitmapSize.getWidth();\n        final int maxHeight = maxBitmapSize.getHeight();\n        while ((srcWidth / scale) > maxWidth || (srcHeight / scale) > maxHeight) {\n            if (powerOf2) {\n                scale *= 2;\n            } else {\n                scale++;\n            }\n        }\n        return scale;\n    }\n\n    /**\n     * Computes minimal sample size for downscaling image so result image size won't exceed max acceptable OpenGL\n     * texture size.<br />\n     * We can't create Bitmap in memory with size exceed max texture size (usually this is 2048x2048) so this method\n     * calculate minimal sample size which should be applied to image to fit into these limits.\n     *\n     * @param srcSize Original image size\n     * @return Minimal sample size\n     */\n    public static int computeMinImageSampleSize(ImageSize srcSize) {\n        final int srcWidth = srcSize.getWidth();\n        final int srcHeight = srcSize.getHeight();\n        final int targetWidth = maxBitmapSize.getWidth();\n        final int targetHeight = maxBitmapSize.getHeight();\n\n        final int widthScale = (int) Math.ceil((float) srcWidth / targetWidth);\n        final int heightScale = (int) Math.ceil((float) srcHeight / targetHeight);\n\n        return Math.max(widthScale, heightScale); // max\n    }\n\n    /**\n     * Computes scale of target size (<b>targetSize</b>) to source size (<b>srcSize</b>).<br />\n     * <br />\n     * <b>Examples:</b><br />\n     * <p/>\n     * <pre>\n     * srcSize(40x40), targetSize(10x10) -> scale = 0.25\n     *\n     * srcSize(10x10), targetSize(20x20), stretch = false -> scale = 1\n     * srcSize(10x10), targetSize(20x20), stretch = true  -> scale = 2\n     *\n     * srcSize(100x100), targetSize(20x40), viewScaleType = FIT_INSIDE -> scale = 0.2\n     * srcSize(100x100), targetSize(20x40), viewScaleType = CROP       -> scale = 0.4\n     * </pre>\n     *\n     * @param srcSize       Source (image) size\n     * @param targetSize    Target (view) size\n     * @param viewScaleType {@linkplain ViewScaleType Scale type} for placing image in view\n     * @param stretch       Whether source size should be stretched if target size is larger than source size. If <b>false</b>\n     *                      then result scale value can't be greater than 1.\n     * @return Computed scale\n     */\n    public static float computeImageScale(ImageSize srcSize, ImageSize targetSize, ViewScaleType viewScaleType,\n                                          boolean stretch) {\n        final int srcWidth = srcSize.getWidth();\n        final int srcHeight = srcSize.getHeight();\n        final int targetWidth = targetSize.getWidth();\n        final int targetHeight = targetSize.getHeight();\n\n        final float widthScale = (float) srcWidth / targetWidth;\n        final float heightScale = (float) srcHeight / targetHeight;\n\n        final int destWidth;\n        final int destHeight;\n        if ((viewScaleType == ViewScaleType.FIT_INSIDE && widthScale >= heightScale) || (viewScaleType == ViewScaleType.CROP && widthScale < heightScale)) {\n            destWidth = targetWidth;\n            destHeight = (int) (srcHeight / widthScale);\n        } else {\n            destWidth = (int) (srcWidth / heightScale);\n            destHeight = targetHeight;\n        }\n\n        float scale = 1;\n        if ((!stretch && destWidth < srcWidth && destHeight < srcHeight) || (stretch && destWidth != srcWidth && destHeight != srcHeight)) {\n            scale = (float) destWidth / srcWidth;\n        }\n\n        return scale;\n    }\n}\n"
  },
  {
    "path": "library/src/main/java/com/nostra13/universalimageloader/utils/IoUtils.java",
    "content": "/*******************************************************************************\n * Copyright 2011-2014 Sergey Tarasevich\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *******************************************************************************/\npackage com.nostra13.universalimageloader.utils;\n\nimport java.io.Closeable;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\n\n/**\n * Provides I/O operations\n *\n * @author Sergey Tarasevich (nostra13[at]gmail[dot]com)\n * @since 1.0.0\n */\npublic final class IoUtils {\n\n\t/** {@value} */\n\tpublic static final int DEFAULT_BUFFER_SIZE = 32 * 1024; // 32 KB\n\t/** {@value} */\n\tpublic static final int DEFAULT_IMAGE_TOTAL_SIZE = 500 * 1024; // 500 Kb\n\t/** {@value} */\n\tpublic static final int CONTINUE_LOADING_PERCENTAGE = 75;\n\n\tprivate IoUtils() {\n\t}\n\n\t/**\n\t * Copies stream, fires progress events by listener, can be interrupted by listener. Uses buffer size =\n\t * {@value #DEFAULT_BUFFER_SIZE} bytes.\n\t *\n\t * @param is       Input stream\n\t * @param os       Output stream\n\t * @param listener null-ok; Listener of copying progress and controller of copying interrupting\n\t * @return <b>true</b> - if stream copied successfully; <b>false</b> - if copying was interrupted by listener\n\t * @throws IOException\n\t */\n\tpublic static boolean copyStream(InputStream is, OutputStream os, CopyListener listener) throws IOException {\n\t\treturn copyStream(is, os, listener, DEFAULT_BUFFER_SIZE);\n\t}\n\n\t/**\n\t * Copies stream, fires progress events by listener, can be interrupted by listener.\n\t *\n\t * @param is         Input stream\n\t * @param os         Output stream\n\t * @param listener   null-ok; Listener of copying progress and controller of copying interrupting\n\t * @param bufferSize Buffer size for copying, also represents a step for firing progress listener callback, i.e.\n\t *                   progress event will be fired after every copied <b>bufferSize</b> bytes\n\t * @return <b>true</b> - if stream copied successfully; <b>false</b> - if copying was interrupted by listener\n\t * @throws IOException\n\t */\n\tpublic static boolean copyStream(InputStream is, OutputStream os, CopyListener listener, int bufferSize)\n\t\t\tthrows IOException {\n\t\tint current = 0;\n\t\tint total = is.available();\n\t\tif (total <= 0) {\n\t\t\ttotal = DEFAULT_IMAGE_TOTAL_SIZE;\n\t\t}\n\n\t\tfinal byte[] bytes = new byte[bufferSize];\n\t\tint count;\n\t\tif (shouldStopLoading(listener, current, total)) return false;\n\t\twhile ((count = is.read(bytes, 0, bufferSize)) != -1) {\n\t\t\tos.write(bytes, 0, count);\n\t\t\tcurrent += count;\n\t\t\tif (shouldStopLoading(listener, current, total)) return false;\n\t\t}\n\t\tos.flush();\n\t\treturn true;\n\t}\n\n\tprivate static boolean shouldStopLoading(CopyListener listener, int current, int total) {\n\t\tif (listener != null) {\n\t\t\tboolean shouldContinue = listener.onBytesCopied(current, total);\n\t\t\tif (!shouldContinue) {\n\t\t\t\tif (100 * current / total < CONTINUE_LOADING_PERCENTAGE) {\n\t\t\t\t\treturn true; // if loaded more than 75% then continue loading anyway\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\n\t/**\n\t * Reads all data from stream and close it silently\n\t *\n\t * @param is Input stream\n\t */\n\tpublic static void readAndCloseStream(InputStream is) {\n\t\tfinal byte[] bytes = new byte[DEFAULT_BUFFER_SIZE];\n\t\ttry {\n\t\t\twhile (is.read(bytes, 0, DEFAULT_BUFFER_SIZE) != -1);\n\t\t} catch (IOException ignored) {\n\t\t} finally {\n\t\t\tcloseSilently(is);\n\t\t}\n\t}\n\n\tpublic static void closeSilently(Closeable closeable) {\n\t\tif (closeable != null) {\n\t\t\ttry {\n\t\t\t\tcloseable.close();\n\t\t\t} catch (Exception ignored) {\n\t\t\t}\n\t\t}\n\t}\n\n\t/** Listener and controller for copy process */\n\tpublic static interface CopyListener {\n\t\t/**\n\t\t * @param current Loaded bytes\n\t\t * @param total   Total bytes for loading\n\t\t * @return <b>true</b> - if copying should be continued; <b>false</b> - if copying should be interrupted\n\t\t */\n\t\tboolean onBytesCopied(int current, int total);\n\t}\n}\n"
  },
  {
    "path": "library/src/main/java/com/nostra13/universalimageloader/utils/L.java",
    "content": "/*******************************************************************************\n * Copyright 2011-2014 Sergey Tarasevich\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *******************************************************************************/\npackage com.nostra13.universalimageloader.utils;\n\nimport android.util.Log;\nimport com.nostra13.universalimageloader.core.ImageLoader;\n\n/**\n * \"Less-word\" analog of Android {@link android.util.Log logger}\n *\n * @author Sergey Tarasevich (nostra13[at]gmail[dot]com)\n * @since 1.6.4\n */\npublic final class L {\n\n\tprivate static final String LOG_FORMAT = \"%1$s\\n%2$s\";\n\tprivate static volatile boolean writeDebugLogs = false;\n\tprivate static volatile boolean writeLogs = true;\n\n\tprivate L() {\n\t}\n\n\t/**\n\t * Enables logger (if {@link #disableLogging()} was called before)\n\t *\n\t * @deprecated Use {@link #writeLogs(boolean) writeLogs(true)} instead\n\t */\n\t@Deprecated\n\tpublic static void enableLogging() {\n\t\twriteLogs(true);\n\t}\n\n\t/**\n\t * Disables logger, no logs will be passed to LogCat, all log methods will do nothing\n\t *\n\t * @deprecated Use {@link #writeLogs(boolean) writeLogs(false)} instead\n\t */\n\t@Deprecated\n\tpublic static void disableLogging() {\n\t\twriteLogs(false);\n\t}\n\n\t/**\n\t * Enables/disables detail logging of {@link ImageLoader} work.\n\t * Consider {@link com.nostra13.universalimageloader.utils.L#disableLogging()} to disable\n\t * ImageLoader logging completely (even error logs)<br />\n\t * Debug logs are disabled by default.\n\t */\n\tpublic static void writeDebugLogs(boolean writeDebugLogs) {\n\t\tL.writeDebugLogs = writeDebugLogs;\n\t}\n\n\t/** Enables/disables logging of {@link ImageLoader} completely (even error logs). */\n\tpublic static void writeLogs(boolean writeLogs) {\n\t\tL.writeLogs = writeLogs;\n\t}\n\n\tpublic static void d(String message, Object... args) {\n\t\tif (writeDebugLogs) {\n\t\t\tlog(Log.DEBUG, null, message, args);\n\t\t}\n\t}\n\n\tpublic static void i(String message, Object... args) {\n\t\tlog(Log.INFO, null, message, args);\n\t}\n\n\tpublic static void w(String message, Object... args) {\n\t\tlog(Log.WARN, null, message, args);\n\t}\n\n\tpublic static void e(Throwable ex) {\n\t\tlog(Log.ERROR, ex, null);\n\t}\n\n\tpublic static void e(String message, Object... args) {\n\t\tlog(Log.ERROR, null, message, args);\n\t}\n\n\tpublic static void e(Throwable ex, String message, Object... args) {\n\t\tlog(Log.ERROR, ex, message, args);\n\t}\n\n\tprivate static void log(int priority, Throwable ex, String message, Object... args) {\n\t\tif (!writeLogs) return;\n\t\tif (args.length > 0) {\n\t\t\tmessage = String.format(message, args);\n\t\t}\n\n\t\tString log;\n\t\tif (ex == null) {\n\t\t\tlog = message;\n\t\t} else {\n\t\t\tString logMessage = message == null ? ex.getMessage() : message;\n\t\t\tString logBody = Log.getStackTraceString(ex);\n\t\t\tlog = String.format(LOG_FORMAT, logMessage, logBody);\n\t\t}\n\t\tLog.println(priority, ImageLoader.TAG, log);\n\t}\n}"
  },
  {
    "path": "library/src/main/java/com/nostra13/universalimageloader/utils/MemoryCacheUtils.java",
    "content": "/*******************************************************************************\n * Copyright 2011-2014 Sergey Tarasevich\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *******************************************************************************/\npackage com.nostra13.universalimageloader.utils;\n\nimport android.graphics.Bitmap;\n\nimport com.nostra13.universalimageloader.cache.memory.MemoryCache;\nimport com.nostra13.universalimageloader.core.ImageLoaderConfiguration;\nimport com.nostra13.universalimageloader.core.assist.ImageSize;\n\nimport java.util.ArrayList;\nimport java.util.Comparator;\nimport java.util.List;\n\n/**\n * Utility for generating of keys for memory cache, key comparing and other work with memory cache\n *\n * @author Sergey Tarasevich (nostra13[at]gmail[dot]com)\n * @since 1.6.3\n */\npublic final class MemoryCacheUtils {\n\n\tprivate static final String URI_AND_SIZE_SEPARATOR = \"_\";\n\tprivate static final String WIDTH_AND_HEIGHT_SEPARATOR = \"x\";\n\n\tprivate MemoryCacheUtils() {\n\t}\n\n\t/**\n\t * Generates key for memory cache for incoming image (URI + size).<br />\n\t * Pattern for cache key - <b>[imageUri]_[width]x[height]</b>.\n\t */\n\tpublic static String generateKey(String imageUri, ImageSize targetSize) {\n\t\treturn new StringBuilder(imageUri).append(URI_AND_SIZE_SEPARATOR).append(targetSize.getWidth()).append(WIDTH_AND_HEIGHT_SEPARATOR).append(targetSize.getHeight()).toString();\n\t}\n\n\tpublic static Comparator<String> createFuzzyKeyComparator() {\n\t\treturn new Comparator<String>() {\n\t\t\t@Override\n\t\t\tpublic int compare(String key1, String key2) {\n\t\t\t\tString imageUri1 = key1.substring(0, key1.lastIndexOf(URI_AND_SIZE_SEPARATOR));\n\t\t\t\tString imageUri2 = key2.substring(0, key2.lastIndexOf(URI_AND_SIZE_SEPARATOR));\n\t\t\t\treturn imageUri1.compareTo(imageUri2);\n\t\t\t}\n\t\t};\n\t}\n\n\t/**\n\t * Searches all bitmaps in memory cache which are corresponded to incoming URI.<br />\n\t * <b>Note:</b> Memory cache can contain multiple sizes of the same image if only you didn't set\n\t * {@link ImageLoaderConfiguration.Builder#denyCacheImageMultipleSizesInMemory()\n\t * denyCacheImageMultipleSizesInMemory()} option in {@linkplain ImageLoaderConfiguration configuration}\n\t */\n\tpublic static List<Bitmap> findCachedBitmapsForImageUri(String imageUri, MemoryCache memoryCache) {\n\t\tList<Bitmap> values = new ArrayList<Bitmap>();\n\t\tfor (String key : memoryCache.keys()) {\n\t\t\tif (key.startsWith(imageUri)) {\n\t\t\t\tvalues.add(memoryCache.get(key));\n\t\t\t}\n\t\t}\n\t\treturn values;\n\t}\n\n\t/**\n\t * Searches all keys in memory cache which are corresponded to incoming URI.<br />\n\t * <b>Note:</b> Memory cache can contain multiple sizes of the same image if only you didn't set\n\t * {@link ImageLoaderConfiguration.Builder#denyCacheImageMultipleSizesInMemory()\n\t * denyCacheImageMultipleSizesInMemory()} option in {@linkplain ImageLoaderConfiguration configuration}\n\t */\n\tpublic static List<String> findCacheKeysForImageUri(String imageUri, MemoryCache memoryCache) {\n\t\tList<String> values = new ArrayList<String>();\n\t\tfor (String key : memoryCache.keys()) {\n\t\t\tif (key.startsWith(imageUri)) {\n\t\t\t\tvalues.add(key);\n\t\t\t}\n\t\t}\n\t\treturn values;\n\t}\n\n\t/**\n\t * Removes from memory cache all images for incoming URI.<br />\n\t * <b>Note:</b> Memory cache can contain multiple sizes of the same image if only you didn't set\n\t * {@link ImageLoaderConfiguration.Builder#denyCacheImageMultipleSizesInMemory()\n\t * denyCacheImageMultipleSizesInMemory()} option in {@linkplain ImageLoaderConfiguration configuration}\n\t */\n\tpublic static void removeFromCache(String imageUri, MemoryCache memoryCache) {\n\t\tList<String> keysToRemove = new ArrayList<String>();\n\t\tfor (String key : memoryCache.keys()) {\n\t\t\tif (key.startsWith(imageUri)) {\n\t\t\t\tkeysToRemove.add(key);\n\t\t\t}\n\t\t}\n\t\tfor (String keyToRemove : keysToRemove) {\n\t\t\tmemoryCache.remove(keyToRemove);\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "library/src/main/java/com/nostra13/universalimageloader/utils/StorageUtils.java",
    "content": "/*******************************************************************************\n * Copyright 2011-2014 Sergey Tarasevich\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *******************************************************************************/\npackage com.nostra13.universalimageloader.utils;\n\nimport android.content.Context;\nimport android.content.pm.PackageManager;\nimport android.os.Environment;\n\nimport java.io.File;\nimport java.io.IOException;\n\nimport static android.os.Environment.MEDIA_MOUNTED;\n\n/**\n * Provides application storage paths\n *\n * @author Sergey Tarasevich (nostra13[at]gmail[dot]com)\n * @since 1.0.0\n */\npublic final class StorageUtils {\n\n\tprivate static final String EXTERNAL_STORAGE_PERMISSION = \"android.permission.WRITE_EXTERNAL_STORAGE\";\n\tprivate static final String INDIVIDUAL_DIR_NAME = \"uil-images\";\n\n\tprivate StorageUtils() {\n\t}\n\n\t/**\n\t * Returns application cache directory. Cache directory will be created on SD card\n\t * <i>(\"/Android/data/[app_package_name]/cache\")</i> if card is mounted and app has appropriate permission. Else -\n\t * Android defines cache directory on device's file system.\n\t *\n\t * @param context Application context\n\t * @return Cache {@link File directory}.<br />\n\t * <b>NOTE:</b> Can be null in some unpredictable cases (if SD card is unmounted and\n\t * {@link android.content.Context#getCacheDir() Context.getCacheDir()} returns null).\n\t */\n\tpublic static File getCacheDirectory(Context context) {\n\t\treturn getCacheDirectory(context, true);\n\t}\n\n\t/**\n\t * Returns application cache directory. Cache directory will be created on SD card\n\t * <i>(\"/Android/data/[app_package_name]/cache\")</i> (if card is mounted and app has appropriate permission) or\n\t * on device's file system depending incoming parameters.\n\t *\n\t * @param context        Application context\n\t * @param preferExternal Whether prefer external location for cache\n\t * @return Cache {@link File directory}.<br />\n\t * <b>NOTE:</b> Can be null in some unpredictable cases (if SD card is unmounted and\n\t * {@link android.content.Context#getCacheDir() Context.getCacheDir()} returns null).\n\t */\n\tpublic static File getCacheDirectory(Context context, boolean preferExternal) {\n\t\tFile appCacheDir = null;\n\t\tString externalStorageState;\n\t\ttry {\n\t\t\texternalStorageState = Environment.getExternalStorageState();\n\t\t} catch (NullPointerException e) { // (sh)it happens (Issue #660)\n\t\t\texternalStorageState = \"\";\n\t\t} catch (IncompatibleClassChangeError e) { // (sh)it happens too (Issue #989)\n\t\t\texternalStorageState = \"\";\n\t\t}\n\t\tif (preferExternal && MEDIA_MOUNTED.equals(externalStorageState) && hasExternalStoragePermission(context)) {\n\t\t\tappCacheDir = getExternalCacheDir(context);\n\t\t}\n\t\tif (appCacheDir == null) {\n\t\t\tappCacheDir = context.getCacheDir();\n\t\t}\n\t\tif (appCacheDir == null) {\n\t\t\tString cacheDirPath = \"/data/data/\" + context.getPackageName() + \"/cache/\";\n\t\t\tL.w(\"Can't define system cache directory! '%s' will be used.\", cacheDirPath);\n\t\t\tappCacheDir = new File(cacheDirPath);\n\t\t}\n\t\treturn appCacheDir;\n\t}\n\n\t/**\n\t * Returns individual application cache directory (for only image caching from ImageLoader). Cache directory will be\n\t * created on SD card <i>(\"/Android/data/[app_package_name]/cache/uil-images\")</i> if card is mounted and app has\n\t * appropriate permission. Else - Android defines cache directory on device's file system.\n\t *\n\t * @param context Application context\n\t * @return Cache {@link File directory}\n\t */\n\tpublic static File getIndividualCacheDirectory(Context context) {\n\t\treturn getIndividualCacheDirectory(context, INDIVIDUAL_DIR_NAME);\n\t}\n\n\t/**\n\t * Returns individual application cache directory (for only image caching from ImageLoader). Cache directory will be\n\t * created on SD card <i>(\"/Android/data/[app_package_name]/cache/uil-images\")</i> if card is mounted and app has\n\t * appropriate permission. Else - Android defines cache directory on device's file system.\n\t *\n\t * @param context Application context\n\t * @param cacheDir Cache directory path (e.g.: \"AppCacheDir\", \"AppDir/cache/images\")\n\t * @return Cache {@link File directory}\n\t */\n\tpublic static File getIndividualCacheDirectory(Context context, String cacheDir) {\n\t\tFile appCacheDir = getCacheDirectory(context);\n\t\tFile individualCacheDir = new File(appCacheDir, cacheDir);\n\t\tif (!individualCacheDir.exists()) {\n\t\t\tif (!individualCacheDir.mkdir()) {\n\t\t\t\tindividualCacheDir = appCacheDir;\n\t\t\t}\n\t\t}\n\t\treturn individualCacheDir;\n\t}\n\n\t/**\n\t * Returns specified application cache directory. Cache directory will be created on SD card by defined path if card\n\t * is mounted and app has appropriate permission. Else - Android defines cache directory on device's file system.\n\t *\n\t * @param context  Application context\n\t * @param cacheDir Cache directory path (e.g.: \"AppCacheDir\", \"AppDir/cache/images\")\n\t * @return Cache {@link File directory}\n\t */\n\tpublic static File getOwnCacheDirectory(Context context, String cacheDir) {\n\t\tFile appCacheDir = null;\n\t\tif (MEDIA_MOUNTED.equals(Environment.getExternalStorageState()) && hasExternalStoragePermission(context)) {\n\t\t\tappCacheDir = new File(Environment.getExternalStorageDirectory(), cacheDir);\n\t\t}\n\t\tif (appCacheDir == null || (!appCacheDir.exists() && !appCacheDir.mkdirs())) {\n\t\t\tappCacheDir = context.getCacheDir();\n\t\t}\n\t\treturn appCacheDir;\n\t}\n\n\t/**\n\t * Returns specified application cache directory. Cache directory will be created on SD card by defined path if card\n\t * is mounted and app has appropriate permission. Else - Android defines cache directory on device's file system.\n\t *\n\t * @param context  Application context\n\t * @param cacheDir Cache directory path (e.g.: \"AppCacheDir\", \"AppDir/cache/images\")\n\t * @return Cache {@link File directory}\n\t */\n\tpublic static File getOwnCacheDirectory(Context context, String cacheDir, boolean preferExternal) {\n\t\tFile appCacheDir = null;\n\t\tif (preferExternal && MEDIA_MOUNTED.equals(Environment.getExternalStorageState()) && hasExternalStoragePermission(context)) {\n\t\t\tappCacheDir = new File(Environment.getExternalStorageDirectory(), cacheDir);\n\t\t}\n\t\tif (appCacheDir == null || (!appCacheDir.exists() && !appCacheDir.mkdirs())) {\n\t\t\tappCacheDir = context.getCacheDir();\n\t\t}\n\t\treturn appCacheDir;\n\t}\n\n\tprivate static File getExternalCacheDir(Context context) {\n\t\tFile dataDir = new File(new File(Environment.getExternalStorageDirectory(), \"Android\"), \"data\");\n\t\tFile appCacheDir = new File(new File(dataDir, context.getPackageName()), \"cache\");\n\t\tif (!appCacheDir.exists()) {\n\t\t\tif (!appCacheDir.mkdirs()) {\n\t\t\t\tL.w(\"Unable to create external cache directory\");\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tnew File(appCacheDir, \".nomedia\").createNewFile();\n\t\t\t} catch (IOException e) {\n\t\t\t\tL.i(\"Can't create \\\".nomedia\\\" file in application external cache directory\");\n\t\t\t}\n\t\t}\n\t\treturn appCacheDir;\n\t}\n\n\tprivate static boolean hasExternalStoragePermission(Context context) {\n\t\tint perm = context.checkCallingOrSelfPermission(EXTERNAL_STORAGE_PERMISSION);\n\t\treturn perm == PackageManager.PERMISSION_GRANTED;\n\t}\n}\n"
  },
  {
    "path": "library/src/test/java/com/nostra13/universalimageloader/core/assist/ImageSizeTest.java",
    "content": "package com.nostra13.universalimageloader.core.assist;\n\nimport android.app.Activity;\nimport android.content.Context;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.FrameLayout;\nimport android.widget.ImageView;\n\nimport com.nostra13.universalimageloader.core.imageaware.ImageAware;\nimport com.nostra13.universalimageloader.core.imageaware.ImageViewAware;\nimport com.nostra13.universalimageloader.utils.ImageSizeUtils;\n\nimport org.assertj.core.api.Assertions;\nimport org.junit.Before;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.robolectric.RobolectricTestRunner;\n\n@RunWith(RobolectricTestRunner.class)\npublic class ImageSizeTest {\n\tprivate Activity mActivity;\n\tprivate ImageView mView;\n\tprivate ImageAware mImageAware;\n\n\t@Before\n\tpublic void setUp() throws Exception {\n\t\tmActivity = new Activity();\n\n\t\t// Make and set view with some prelim values to test\n\t\tmView = new TestImageView(mActivity);\n\t\tmView.setLayoutParams(new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));\n\t\tmView.measure(View.MeasureSpec.makeMeasureSpec(250, View.MeasureSpec.EXACTLY), View.MeasureSpec.makeMeasureSpec(250, View.MeasureSpec.EXACTLY));\n\n\t\tmImageAware = new ImageViewAware(mView);\n\t}\n\n\t@Test\n\tpublic void testGetImageSizeScaleTo_useImageActualSize() throws Exception {\n\t\t// We layout the view to give it a width and height\n\t\tmView.measure(View.MeasureSpec.makeMeasureSpec(200, View.MeasureSpec.EXACTLY), View.MeasureSpec.makeMeasureSpec(200, View.MeasureSpec.EXACTLY));\n\t\tmView.layout(0, 0, 200, 200);\n\n\t\tImageSize expected = new ImageSize(200, 200);\n\t\tImageSize result = ImageSizeUtils.defineTargetSizeForView(mImageAware, new ImageSize(590, 590));\n\t\tAssertions.assertThat(result).isNotNull();\n\t\tAssertions.assertThat(result.getWidth()).isEqualTo(expected.getWidth());\n\t\tAssertions.assertThat(result.getHeight()).isEqualTo(expected.getHeight());\n\t}\n\n\t/**\n\t * This will make sure the view falls back to the ViewParams/Max/Or Config if wrap content so that it is never\n\t * shrunk to the first image size. In this case it falls back to the config size\n\t * \n\t * @throws Exception\n\t */\n\t@Test\n\tpublic void testGetImageSizeScaleTo_dontUseImageActualSizeWithWrapContent() throws Exception {\n\t\t//Set it to wrap content so that it will fall back to\n\t\tmView.setLayoutParams(new FrameLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));\n\t\tmView.measure(View.MeasureSpec.makeMeasureSpec(250, View.MeasureSpec.EXACTLY), View.MeasureSpec.makeMeasureSpec(250, View.MeasureSpec.EXACTLY));\n\t\t// We layout the view to give it a width and height\n\t\tmView.layout(0, 0, 200, 200);\n\n\t\tImageSize expected = new ImageSize(500, 500);\n\t\tImageSize result = ImageSizeUtils.defineTargetSizeForView(mImageAware, new ImageSize(500, 500));\n\t\tAssertions.assertThat(result).isNotNull().isEqualsToByComparingFields(expected);\n\t}\n\n\t@Test\n\tpublic void testGetImageSizeScaleTo_useImageLayoutParams() throws Exception {\n\t\t// Set a defined width\n\t\tmView.setLayoutParams(new FrameLayout.LayoutParams(300, 300));\n\n\t\tImageSize expected = new ImageSize(300, 300);\n\t\tImageSize result = ImageSizeUtils.defineTargetSizeForView(mImageAware, new ImageSize(500, 500));\n\t\tAssertions.assertThat(result).isNotNull().isEqualsToByComparingFields(expected);\n\t}\n\n\t@Test\n\tpublic void testGetImageSizeScaleTo_useImageConfigMaxSize() throws Exception {\n\t\tImageSize expected = new ImageSize(500, 500);\n\t\tImageSize result = ImageSizeUtils.defineTargetSizeForView(mImageAware, new ImageSize(500, 500));\n\t\tAssertions.assertThat(result).isNotNull().isEqualsToByComparingFields(expected);\n\t}\n\n\t@Test\n\tpublic void testComputeImageSampleSize_fitInside() throws Exception {\n\t\tfinal ViewScaleType scaleType = ViewScaleType.FIT_INSIDE;\n\t\tint result;\n\n\t\tImageSize srcSize = new ImageSize(300, 100);\n\t\tImageSize targetSize = new ImageSize(30, 10);\n\t\tresult = ImageSizeUtils.computeImageSampleSize(srcSize, targetSize, scaleType, false);\n\t\tAssertions.assertThat(result).isEqualTo(10);\n\t\tresult = ImageSizeUtils.computeImageSampleSize(srcSize, targetSize, scaleType, true);\n\t\tAssertions.assertThat(result).isEqualTo(8);\n\n\t\tsrcSize = new ImageSize(300, 100);\n\t\ttargetSize = new ImageSize(200, 200);\n\t\tresult = ImageSizeUtils.computeImageSampleSize(srcSize, targetSize, scaleType, false);\n\t\tAssertions.assertThat(result).isEqualTo(1);\n\t\tresult = ImageSizeUtils.computeImageSampleSize(srcSize, targetSize, scaleType, true);\n\t\tAssertions.assertThat(result).isEqualTo(1);\n\n\t\tsrcSize = new ImageSize(300, 100);\n\t\ttargetSize = new ImageSize(55, 40);\n\t\tresult = ImageSizeUtils.computeImageSampleSize(srcSize, targetSize, scaleType, false);\n\t\tAssertions.assertThat(result).isEqualTo(5);\n\t\tresult = ImageSizeUtils.computeImageSampleSize(srcSize, targetSize, scaleType, true);\n\t\tAssertions.assertThat(result).isEqualTo(4);\n\n\t\tsrcSize = new ImageSize(300, 100);\n\t\ttargetSize = new ImageSize(30, 40);\n\t\tresult = ImageSizeUtils.computeImageSampleSize(srcSize, targetSize, scaleType, false);\n\t\tAssertions.assertThat(result).isEqualTo(10);\n\t\tresult = ImageSizeUtils.computeImageSampleSize(srcSize, targetSize, scaleType, true);\n\t\tAssertions.assertThat(result).isEqualTo(8);\n\n\t\tsrcSize = new ImageSize(5000, 70);\n\t\ttargetSize = new ImageSize(2000, 30);\n\t\tresult = ImageSizeUtils.computeImageSampleSize(srcSize, targetSize, scaleType, false);\n\t\tAssertions.assertThat(result).isEqualTo(3);\n\t\tresult = ImageSizeUtils.computeImageSampleSize(srcSize, targetSize, scaleType, true);\n\t\tAssertions.assertThat(result).isEqualTo(4);\n\t}\n\n\t@Test\n\tpublic void testComputeImageSampleSize_centerCrop() throws Exception {\n\t\tfinal ViewScaleType scaleType = ViewScaleType.CROP;\n\t\tint result;\n\n\t\tImageSize srcSize = new ImageSize(300, 100);\n\t\tImageSize targetSize = new ImageSize(30, 10);\n\t\tresult = ImageSizeUtils.computeImageSampleSize(srcSize, targetSize, scaleType, false);\n\t\tAssertions.assertThat(result).isEqualTo(10);\n\t\tresult = ImageSizeUtils.computeImageSampleSize(srcSize, targetSize, scaleType, true);\n\t\tAssertions.assertThat(result).isEqualTo(8);\n\n\t\tsrcSize = new ImageSize(300, 100);\n\t\ttargetSize = new ImageSize(200, 200);\n\t\tresult = ImageSizeUtils.computeImageSampleSize(srcSize, targetSize, scaleType, false);\n\t\tAssertions.assertThat(result).isEqualTo(1);\n\t\tresult = ImageSizeUtils.computeImageSampleSize(srcSize, targetSize, scaleType, true);\n\t\tAssertions.assertThat(result).isEqualTo(1);\n\n\t\tsrcSize = new ImageSize(300, 100);\n\t\ttargetSize = new ImageSize(55, 40);\n\t\tresult = ImageSizeUtils.computeImageSampleSize(srcSize, targetSize, scaleType, false);\n\t\tAssertions.assertThat(result).isEqualTo(2);\n\t\tresult = ImageSizeUtils.computeImageSampleSize(srcSize, targetSize, scaleType, true);\n\t\tAssertions.assertThat(result).isEqualTo(2);\n\n\t\tsrcSize = new ImageSize(300, 100);\n\t\ttargetSize = new ImageSize(30, 30);\n\t\tresult = ImageSizeUtils.computeImageSampleSize(srcSize, targetSize, scaleType, false);\n\t\tAssertions.assertThat(result).isEqualTo(3);\n\t\tresult = ImageSizeUtils.computeImageSampleSize(srcSize, targetSize, scaleType, true);\n\t\tAssertions.assertThat(result).isEqualTo(2);\n\n\t\tsrcSize = new ImageSize(5000, 70);\n\t\ttargetSize = new ImageSize(300, 30);\n\t\tresult = ImageSizeUtils.computeImageSampleSize(srcSize, targetSize, scaleType, false);\n\t\tAssertions.assertThat(result).isEqualTo(3);\n\t\tresult = ImageSizeUtils.computeImageSampleSize(srcSize, targetSize, scaleType, true);\n\t\tAssertions.assertThat(result).isEqualTo(4);\n\t}\n\n\t/** Fixes {@link NoSuchMethodError} for <code>ImageView#onLayout(...)</code> */\n\tprivate class TestImageView extends ImageView {\n\t\tTestImageView(Context activity) {\n\t\t\tsuper(activity);\n\t\t}\n\n\t\t@Override\n\t\tpublic void onLayout(boolean changed, int left, int top, int right, int bottom) {\n\t\t\tsuper.onLayout(changed, left, top, right, bottom);\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "library/src/test/java/com/nostra13/universalimageloader/core/download/BaseImageDownloaderTest.java",
    "content": "package com.nostra13.universalimageloader.core.download;\n\nimport org.assertj.core.api.Assertions;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.robolectric.RobolectricTestRunner;\n\nimport com.nostra13.universalimageloader.core.download.ImageDownloader.Scheme;\n\n@RunWith(RobolectricTestRunner.class)\npublic class BaseImageDownloaderTest {\n\n\t@Test\n\tpublic void testSchemeHttp() throws Exception {\n\t\tString uri = \"http://image.com/1.png\";\n\t\tScheme result = Scheme.ofUri(uri);\n\t\tScheme expected = Scheme.HTTP;\n\t\tAssertions.assertThat(result).isEqualTo(expected);\n\t}\n\n\t@Test\n\tpublic void testSchemeHttps() throws Exception {\n\t\tString uri = \"https://image.com/1.png\";\n\t\tScheme result = Scheme.ofUri(uri);\n\t\tScheme expected = Scheme.HTTPS;\n\t\tAssertions.assertThat(result).isEqualTo(expected);\n\t}\n\n\t@Test\n\tpublic void testSchemeContent() throws Exception {\n\t\tString uri = \"content://path/to/content\";\n\t\tScheme result = Scheme.ofUri(uri);\n\t\tScheme expected = Scheme.CONTENT;\n\t\tAssertions.assertThat(result).isEqualTo(expected);\n\t}\n\n\t@Test\n\tpublic void testSchemeAssets() throws Exception {\n\t\tString uri = \"assets://folder/1.png\";\n\t\tScheme result = Scheme.ofUri(uri);\n\t\tScheme expected = Scheme.ASSETS;\n\t\tAssertions.assertThat(result).isEqualTo(expected);\n\t}\n\n\t@Test\n\tpublic void testSchemeDrawables() throws Exception {\n\t\tString uri = \"drawable://123456890\";\n\t\tScheme result = Scheme.ofUri(uri);\n\t\tScheme expected = Scheme.DRAWABLE;\n\t\tAssertions.assertThat(result).isEqualTo(expected);\n\t}\n\n\t@Test\n\tpublic void testSchemeFile() throws Exception {\n\t\tString uri = \"file://path/on/the/device/1.png\";\n\t\tScheme result = Scheme.ofUri(uri);\n\t\tScheme expected = Scheme.FILE;\n\t\tAssertions.assertThat(result).isEqualTo(expected);\n\t}\n\n\t@Test\n\tpublic void testSchemeUnknown() throws Exception {\n\t\tString uri = \"other://image.com/1.png\";\n\t\tScheme result = Scheme.ofUri(uri);\n\t\tScheme expected = Scheme.UNKNOWN;\n\t\tAssertions.assertThat(result).isEqualTo(expected);\n\t}\n}\n"
  },
  {
    "path": "sample/build.gradle",
    "content": "apply plugin: 'com.android.application'\n\nandroid {\n    compileSdkVersion 28\n    buildToolsVersion \"28.0.3\"\n\n    defaultConfig {\n        applicationId \"com.nostra13.universalimageloader\"\n        minSdkVersion 16\n        targetSdkVersion 28\n        versionCode 40\n        versionName \"1.9.5\"\n    }\n\n    useLibrary 'org.apache.http.legacy'\n    lintOptions {\n        abortOnError false\n    }\n}\n\ndependencies {\n    implementation project(':library')\n    implementation 'com.android.support:appcompat-v7:28.0.0'\n    implementation 'com.squareup.okhttp:okhttp:2.4.0'\n}\n\n\nFile propFile = file('signing.properties');\nif (propFile.exists()) {\n    def Properties props = new Properties()\n    props.load(new FileInputStream(propFile))\n\n    if (props.containsKey('STORE_FILE') && props.containsKey('STORE_PASSWORD') &&\n            props.containsKey('KEY_ALIAS') && props.containsKey('KEY_PASSWORD')) {\n        android.signingConfigs.release.storeFile = file(props['STORE_FILE'])\n        android.signingConfigs.release.storePassword = props['STORE_PASSWORD']\n        android.signingConfigs.release.keyAlias = props['KEY_ALIAS']\n        android.signingConfigs.release.keyPassword = props['KEY_PASSWORD']\n    } else {\n        android.buildTypes.release.signingConfig = null\n    }\n} else {\n    android.buildTypes.release.signingConfig = null\n}\n"
  },
  {
    "path": "sample/gradle.properties",
    "content": "POM_NAME=Universal Image Loader Sample\nPOM_ARTIFACT_ID=universal-image-loader-sample\nPOM_PACKAGING=apk\n"
  },
  {
    "path": "sample/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 use,\n# \"ant.properties\", and override values to adapt the script to your\n# project structure.\n\n# Project target.\ntarget=android-21\n"
  },
  {
    "path": "sample/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    package=\"com.nostra13.universalimageloader.sample\">\n\n    <uses-permission android:name=\"android.permission.INTERNET\" />\n    <uses-permission android:name=\"android.permission.WRITE_EXTERNAL_STORAGE\" />\n\n    <application\n        android:name=\".UILApplication\"\n        android:icon=\"@drawable/ic_launcher\"\n        android:label=\"@string/app_name\"\n\t\tandroid:allowBackup=\"false\">\n        <activity\n            android:name=\".activity.HomeActivity\"\n            android:label=\"@string/app_name\" >\n            <intent-filter>\n                <action android:name=\"android.intent.action.MAIN\" />\n\n                <category android:name=\"android.intent.category.LAUNCHER\" />\n            </intent-filter>\n        </activity>\n        <activity\n            android:name=\".activity.SimpleImageActivity\"\n            android:label=\"@string/ac_name_image_list\" />\n\t\t<activity\n\t\t\tandroid:name=\".activity.ComplexImageActivity\"\n\t\t\tandroid:label=\"@string/ac_name_complex\" />\n\n        <!-- Widget -->\n        <receiver android:name=\".widget.UILWidgetProvider\" >\n            <meta-data\n                android:name=\"android.appwidget.provider\"\n                android:resource=\"@xml/widget_provider\" />\n\n            <intent-filter>\n                <action android:name=\"android.appwidget.action.APPWIDGET_UPDATE\" />\n            </intent-filter>\n        </receiver>\n    </application>\n\n</manifest>\n"
  },
  {
    "path": "sample/src/main/java/com/nostra13/universalimageloader/sample/Constants.java",
    "content": "/*******************************************************************************\n * Copyright 2011-2013 Sergey Tarasevich\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *******************************************************************************/\npackage com.nostra13.universalimageloader.sample;\n\n/**\n * @author Sergey Tarasevich (nostra13[at]gmail[dot]com)\n */\npublic final class Constants {\n\n\tpublic static final String[] IMAGES = new String[] {\n\t\t\t// Heavy images\n\t\t\t\"https://lh6.googleusercontent.com/-55osAWw3x0Q/URquUtcFr5I/AAAAAAAAAbs/rWlj1RUKrYI/s1024/A%252520Photographer.jpg\",\n\t\t\t\"https://lh4.googleusercontent.com/--dq8niRp7W4/URquVgmXvgI/AAAAAAAAAbs/-gnuLQfNnBA/s1024/A%252520Song%252520of%252520Ice%252520and%252520Fire.jpg\",\n\t\t\t\"https://lh5.googleusercontent.com/-7qZeDtRKFKc/URquWZT1gOI/AAAAAAAAAbs/hqWgteyNXsg/s1024/Another%252520Rockaway%252520Sunset.jpg\",\n\t\t\t\"https://lh3.googleusercontent.com/--L0Km39l5J8/URquXHGcdNI/AAAAAAAAAbs/3ZrSJNrSomQ/s1024/Antelope%252520Butte.jpg\",\n\t\t\t\"https://lh6.googleusercontent.com/-8HO-4vIFnlw/URquZnsFgtI/AAAAAAAAAbs/WT8jViTF7vw/s1024/Antelope%252520Hallway.jpg\",\n\t\t\t\"https://lh4.googleusercontent.com/-WIuWgVcU3Qw/URqubRVcj4I/AAAAAAAAAbs/YvbwgGjwdIQ/s1024/Antelope%252520Walls.jpg\",\n\t\t\t\"https://lh6.googleusercontent.com/-UBmLbPELvoQ/URqucCdv0kI/AAAAAAAAAbs/IdNhr2VQoQs/s1024/Apre%2525CC%252580s%252520la%252520Pluie.jpg\",\n\t\t\t\"https://lh3.googleusercontent.com/-s-AFpvgSeew/URquc6dF-JI/AAAAAAAAAbs/Mt3xNGRUd68/s1024/Backlit%252520Cloud.jpg\",\n\t\t\t\"https://lh5.googleusercontent.com/-bvmif9a9YOQ/URquea3heHI/AAAAAAAAAbs/rcr6wyeQtAo/s1024/Bee%252520and%252520Flower.jpg\",\n\t\t\t\"https://lh5.googleusercontent.com/-n7mdm7I7FGs/URqueT_BT-I/AAAAAAAAAbs/9MYmXlmpSAo/s1024/Bonzai%252520Rock%252520Sunset.jpg\",\n\t\t\t\"https://lh6.googleusercontent.com/-4CN4X4t0M1k/URqufPozWzI/AAAAAAAAAbs/8wK41lg1KPs/s1024/Caterpillar.jpg\",\n\t\t\t\"https://lh3.googleusercontent.com/-rrFnVC8xQEg/URqufdrLBaI/AAAAAAAAAbs/s69WYy_fl1E/s1024/Chess.jpg\",\n\t\t\t\"https://lh5.googleusercontent.com/-WVpRptWH8Yw/URqugh-QmDI/AAAAAAAAAbs/E-MgBgtlUWU/s1024/Chihuly.jpg\",\n\t\t\t\"https://lh5.googleusercontent.com/-0BDXkYmckbo/URquhKFW84I/AAAAAAAAAbs/ogQtHCTk2JQ/s1024/Closed%252520Door.jpg\",\n\t\t\t\"https://lh3.googleusercontent.com/-PyggXXZRykM/URquh-kVvoI/AAAAAAAAAbs/hFtDwhtrHHQ/s1024/Colorado%252520River%252520Sunset.jpg\",\n\t\t\t\"https://lh3.googleusercontent.com/-ZAs4dNZtALc/URquikvOCWI/AAAAAAAAAbs/DXz4h3dll1Y/s1024/Colors%252520of%252520Autumn.jpg\",\n\t\t\t\"https://lh4.googleusercontent.com/-GztnWEIiMz8/URqukVCU7bI/AAAAAAAAAbs/jo2Hjv6MZ6M/s1024/Countryside.jpg\",\n\t\t\t\"https://lh4.googleusercontent.com/-bEg9EZ9QoiM/URquklz3FGI/AAAAAAAAAbs/UUuv8Ac2BaE/s1024/Death%252520Valley%252520-%252520Dunes.jpg\",\n\t\t\t\"https://lh6.googleusercontent.com/-ijQJ8W68tEE/URqulGkvFEI/AAAAAAAAAbs/zPXvIwi_rFw/s1024/Delicate%252520Arch.jpg\",\n\t\t\t\"https://lh5.googleusercontent.com/-Oh8mMy2ieng/URqullDwehI/AAAAAAAAAbs/TbdeEfsaIZY/s1024/Despair.jpg\",\n\t\t\t\"https://lh5.googleusercontent.com/-gl0y4UiAOlk/URqumC_KjBI/AAAAAAAAAbs/PM1eT7dn4oo/s1024/Eagle%252520Fall%252520Sunrise.jpg\",\n\t\t\t\"https://lh3.googleusercontent.com/-hYYHd2_vXPQ/URqumtJa9eI/AAAAAAAAAbs/wAalXVkbSh0/s1024/Electric%252520Storm.jpg\",\n\t\t\t\"https://lh5.googleusercontent.com/-PyY_yiyjPTo/URqunUOhHFI/AAAAAAAAAbs/azZoULNuJXc/s1024/False%252520Kiva.jpg\",\n\t\t\t\"https://lh6.googleusercontent.com/-PYvLVdvXywk/URqunwd8hfI/AAAAAAAAAbs/qiMwgkFvf6I/s1024/Fitzgerald%252520Streaks.jpg\",\n\t\t\t\"https://lh4.googleusercontent.com/-KIR_UobIIqY/URquoCZ9SlI/AAAAAAAAAbs/Y4d4q8sXu4c/s1024/Foggy%252520Sunset.jpg\",\n\t\t\t\"https://lh6.googleusercontent.com/-9lzOk_OWZH0/URquoo4xYoI/AAAAAAAAAbs/AwgzHtNVCwU/s1024/Frantic.jpg\",\n\t\t\t\"https://lh3.googleusercontent.com/-0X3JNaKaz48/URqupH78wpI/AAAAAAAAAbs/lHXxu_zbH8s/s1024/Golden%252520Gate%252520Afternoon.jpg\",\n\t\t\t\"https://lh6.googleusercontent.com/-95sb5ag7ABc/URqupl95RDI/AAAAAAAAAbs/g73R20iVTRA/s1024/Golden%252520Gate%252520Fog.jpg\",\n\t\t\t\"https://lh3.googleusercontent.com/-JB9v6rtgHhk/URqup21F-zI/AAAAAAAAAbs/64Fb8qMZWXk/s1024/Golden%252520Grass.jpg\",\n\t\t\t\"https://lh4.googleusercontent.com/-EIBGfnuLtII/URquqVHwaRI/AAAAAAAAAbs/FA4McV2u8VE/s1024/Grand%252520Teton.jpg\",\n\t\t\t\"https://lh4.googleusercontent.com/-WoMxZvmN9nY/URquq1v2AoI/AAAAAAAAAbs/grj5uMhL6NA/s1024/Grass%252520Closeup.jpg\",\n\t\t\t\"https://lh3.googleusercontent.com/-6hZiEHXx64Q/URqurxvNdqI/AAAAAAAAAbs/kWMXM3o5OVI/s1024/Green%252520Grass.jpg\",\n\t\t\t\"https://lh5.googleusercontent.com/-6LVb9OXtQ60/URquteBFuKI/AAAAAAAAAbs/4F4kRgecwFs/s1024/Hanging%252520Leaf.jpg\",\n\t\t\t\"https://lh4.googleusercontent.com/-zAvf__52ONk/URqutT_IuxI/AAAAAAAAAbs/D_bcuc0thoU/s1024/Highway%2525201.jpg\",\n\t\t\t\"https://lh6.googleusercontent.com/-H4SrUg615rA/URquuL27fXI/AAAAAAAAAbs/4aEqJfiMsOU/s1024/Horseshoe%252520Bend%252520Sunset.jpg\",\n\t\t\t\"https://lh4.googleusercontent.com/-JhFi4fb_Pqw/URquuX-QXbI/AAAAAAAAAbs/IXpYUxuweYM/s1024/Horseshoe%252520Bend.jpg\",\n\t\t\t\"https://lh5.googleusercontent.com/-UGgssvFRJ7g/URquueyJzGI/AAAAAAAAAbs/yYIBlLT0toM/s1024/Into%252520the%252520Blue.jpg\",\n\t\t\t\"https://lh3.googleusercontent.com/-CH7KoupI7uI/URquu0FF__I/AAAAAAAAAbs/R7GDmI7v_G0/s1024/Jelly%252520Fish%2525202.jpg\",\n\t\t\t\"https://lh4.googleusercontent.com/-pwuuw6yhg8U/URquvPxR3FI/AAAAAAAAAbs/VNGk6f-tsGE/s1024/Jelly%252520Fish%2525203.jpg\",\n\t\t\t\"https://lh5.googleusercontent.com/-GoUQVw1fnFw/URquv6xbC0I/AAAAAAAAAbs/zEUVTQQ43Zc/s1024/Kauai.jpg\",\n\t\t\t\"https://lh6.googleusercontent.com/-8QdYYQEpYjw/URquwvdh88I/AAAAAAAAAbs/cktDy-ysfHo/s1024/Kyoto%252520Sunset.jpg\",\n\t\t\t\"https://lh4.googleusercontent.com/-vPeekyDjOE0/URquwzJ28qI/AAAAAAAAAbs/qxcyXULsZrg/s1024/Lake%252520Tahoe%252520Colors.jpg\",\n\t\t\t\"https://lh4.googleusercontent.com/-xBPxWpD4yxU/URquxWHk8AI/AAAAAAAAAbs/ARDPeDYPiMY/s1024/Lava%252520from%252520the%252520Sky.jpg\",\n\t\t\t\"https://lh3.googleusercontent.com/-897VXrJB6RE/URquxxxd-5I/AAAAAAAAAbs/j-Cz4T4YvIw/s1024/Leica%25252050mm%252520Summilux.jpg\",\n\t\t\t\"https://lh5.googleusercontent.com/-qSJ4D4iXzGo/URquyDWiJ1I/AAAAAAAAAbs/k2pBXeWehOA/s1024/Leica%25252050mm%252520Summilux.jpg\",\n\t\t\t\"https://lh6.googleusercontent.com/-dwlPg83vzLg/URquylTVuFI/AAAAAAAAAbs/G6SyQ8b4YsI/s1024/Leica%252520M8%252520%252528Front%252529.jpg\",\n\t\t\t\"https://lh3.googleusercontent.com/-R3_EYAyJvfk/URquzQBv8eI/AAAAAAAAAbs/b9xhpUM3pEI/s1024/Light%252520to%252520Sand.jpg\",\n\t\t\t\"https://lh3.googleusercontent.com/-fHY5h67QPi0/URqu0Cp4J1I/AAAAAAAAAbs/0lG6m94Z6vM/s1024/Little%252520Bit%252520of%252520Paradise.jpg\",\n\t\t\t\"https://lh5.googleusercontent.com/-TzF_LwrCnRM/URqu0RddPOI/AAAAAAAAAbs/gaj2dLiuX0s/s1024/Lone%252520Pine%252520Sunset.jpg\",\n\t\t\t\"https://lh3.googleusercontent.com/-4HdpJ4_DXU4/URqu046dJ9I/AAAAAAAAAbs/eBOodtk2_uk/s1024/Lonely%252520Rock.jpg\",\n\t\t\t\"https://lh6.googleusercontent.com/-erbF--z-W4s/URqu1ajSLkI/AAAAAAAAAbs/xjDCDO1INzM/s1024/Longue%252520Vue.jpg\",\n\t\t\t\"https://lh6.googleusercontent.com/-0CXJRdJaqvc/URqu1opNZNI/AAAAAAAAAbs/PFB2oPUU7Lk/s1024/Look%252520Me%252520in%252520the%252520Eye.jpg\",\n\t\t\t\"https://lh3.googleusercontent.com/-D_5lNxnDN6g/URqu2Tk7HVI/AAAAAAAAAbs/p0ddca9W__Y/s1024/Lost%252520in%252520a%252520Field.jpg\",\n\t\t\t\"https://lh6.googleusercontent.com/-flsqwMrIk2Q/URqu24PcmjI/AAAAAAAAAbs/5ocIH85XofM/s1024/Marshall%252520Beach%252520Sunset.jpg\",\n\t\t\t\"https://lh4.googleusercontent.com/-Y4lgryEVTmU/URqu28kG3gI/AAAAAAAAAbs/OjXpekqtbJ4/s1024/Mono%252520Lake%252520Blue.jpg\",\n\t\t\t\"https://lh4.googleusercontent.com/-AaHAJPmcGYA/URqu3PIldHI/AAAAAAAAAbs/lcTqk1SIcRs/s1024/Monument%252520Valley%252520Overlook.jpg\",\n\t\t\t\"https://lh4.googleusercontent.com/-vKxfdQ83dQA/URqu31Yq_BI/AAAAAAAAAbs/OUoGk_2AyfM/s1024/Moving%252520Rock.jpg\",\n\t\t\t\"https://lh5.googleusercontent.com/-CG62QiPpWXg/URqu4ia4vRI/AAAAAAAAAbs/0YOdqLAlcAc/s1024/Napali%252520Coast.jpg\",\n\t\t\t\"https://lh6.googleusercontent.com/-wdGrP5PMmJQ/URqu5PZvn7I/AAAAAAAAAbs/m0abEcdPXe4/s1024/One%252520Wheel.jpg\",\n\t\t\t\"https://lh6.googleusercontent.com/-6WS5DoCGuOA/URqu5qx1UgI/AAAAAAAAAbs/giMw2ixPvrY/s1024/Open%252520Sky.jpg\",\n\t\t\t\"https://lh6.googleusercontent.com/-u8EHKj8G8GQ/URqu55sM6yI/AAAAAAAAAbs/lIXX_GlTdmI/s1024/Orange%252520Sunset.jpg\",\n\t\t\t\"https://lh6.googleusercontent.com/-74Z5qj4bTDE/URqu6LSrJrI/AAAAAAAAAbs/XzmVkw90szQ/s1024/Orchid.jpg\",\n\t\t\t\"https://lh6.googleusercontent.com/-lEQE4h6TePE/URqu6t_lSkI/AAAAAAAAAbs/zvGYKOea_qY/s1024/Over%252520there.jpg\",\n\t\t\t\"https://lh5.googleusercontent.com/-cauH-53JH2M/URqu66v_USI/AAAAAAAAAbs/EucwwqclfKQ/s1024/Plumes.jpg\",\n\t\t\t\"https://lh3.googleusercontent.com/-eDLT2jHDoy4/URqu7axzkAI/AAAAAAAAAbs/iVZE-xJ7lZs/s1024/Rainbokeh.jpg\",\n\t\t\t\"https://lh5.googleusercontent.com/-j1NLqEFIyco/URqu8L1CGcI/AAAAAAAAAbs/aqZkgX66zlI/s1024/Rainbow.jpg\",\n\t\t\t\"https://lh5.googleusercontent.com/-DRnqmK0t4VU/URqu8XYN9yI/AAAAAAAAAbs/LgvF_592WLU/s1024/Rice%252520Fields.jpg\",\n\t\t\t\"https://lh3.googleusercontent.com/-hwh1v3EOGcQ/URqu8qOaKwI/AAAAAAAAAbs/IljRJRnbJGw/s1024/Rockaway%252520Fire%252520Sky.jpg\",\n\t\t\t\"https://lh5.googleusercontent.com/-wjV6FQk7tlk/URqu9jCQ8sI/AAAAAAAAAbs/RyYUpdo-c9o/s1024/Rockaway%252520Flow.jpg\",\n\t\t\t\"https://lh6.googleusercontent.com/-6cAXNfo7D20/URqu-BdzgPI/AAAAAAAAAbs/OmsYllzJqwo/s1024/Rockaway%252520Sunset%252520Sky.jpg\",\n\t\t\t\"https://lh3.googleusercontent.com/-sl8fpGPS-RE/URqu_BOkfgI/AAAAAAAAAbs/Dg2Fv-JxOeg/s1024/Russian%252520Ridge%252520Sunset.jpg\",\n\t\t\t\"https://lh6.googleusercontent.com/-gVtY36mMBIg/URqu_q91lkI/AAAAAAAAAbs/3CiFMBcy5MA/s1024/Rust%252520Knot.jpg\",\n\t\t\t\"https://lh6.googleusercontent.com/-GHeImuHqJBE/URqu_FKfVLI/AAAAAAAAAbs/axuEJeqam7Q/s1024/Sailing%252520Stones.jpg\",\n\t\t\t\"https://lh3.googleusercontent.com/-hBbYZjTOwGc/URqu_ycpIrI/AAAAAAAAAbs/nAdJUXnGJYE/s1024/Seahorse.jpg\",\n\t\t\t\"https://lh3.googleusercontent.com/-Iwi6-i6IexY/URqvAYZHsVI/AAAAAAAAAbs/5ETWl4qXsFE/s1024/Shinjuku%252520Street.jpg\",\n\t\t\t\"https://lh6.googleusercontent.com/-amhnySTM_MY/URqvAlb5KoI/AAAAAAAAAbs/pFCFgzlKsn0/s1024/Sierra%252520Heavens.jpg\",\n\t\t\t\"https://lh5.googleusercontent.com/-dJgjepFrYSo/URqvBVJZrAI/AAAAAAAAAbs/v-F5QWpYO6s/s1024/Sierra%252520Sunset.jpg\",\n\t\t\t\"https://lh4.googleusercontent.com/-Z4zGiC5nWdc/URqvBdEwivI/AAAAAAAAAbs/ZRZR1VJ84QA/s1024/Sin%252520Lights.jpg\",\n\t\t\t\"https://lh4.googleusercontent.com/-_0cYiWW8ccY/URqvBz3iM4I/AAAAAAAAAbs/9N_Wq8MhLTY/s1024/Starry%252520Lake.jpg\",\n\t\t\t\"https://lh3.googleusercontent.com/-A9LMoRyuQUA/URqvCYx_JoI/AAAAAAAAAbs/s7sde1Bz9cI/s1024/Starry%252520Night.jpg\",\n\t\t\t\"https://lh3.googleusercontent.com/-KtLJ3k858eY/URqvC_2h_bI/AAAAAAAAAbs/zzEBImwDA_g/s1024/Stream.jpg\",\n\t\t\t\"https://lh5.googleusercontent.com/-dFB7Lad6RcA/URqvDUftwWI/AAAAAAAAAbs/BrhoUtXTN7o/s1024/Strip%252520Sunset.jpg\",\n\t\t\t\"https://lh5.googleusercontent.com/-at6apgFiN20/URqvDyffUZI/AAAAAAAAAbs/clABCx171bE/s1024/Sunset%252520Hills.jpg\",\n\t\t\t\"https://lh4.googleusercontent.com/-7-EHhtQthII/URqvEYTk4vI/AAAAAAAAAbs/QSJZoB3YjVg/s1024/Tenaya%252520Lake%2525202.jpg\",\n\t\t\t\"https://lh6.googleusercontent.com/-8MrjV_a-Pok/URqvFC5repI/AAAAAAAAAbs/9inKTg9fbCE/s1024/Tenaya%252520Lake.jpg\",\n\t\t\t\"https://lh5.googleusercontent.com/-B1HW-z4zwao/URqvFWYRwUI/AAAAAAAAAbs/8Peli53Bs8I/s1024/The%252520Cave%252520BW.jpg\",\n\t\t\t\"https://lh3.googleusercontent.com/-PO4E-xZKAnQ/URqvGRqjYkI/AAAAAAAAAbs/42nyADFsXag/s1024/The%252520Fisherman.jpg\",\n\t\t\t\"https://lh4.googleusercontent.com/-iLyZlzfdy7s/URqvG0YScdI/AAAAAAAAAbs/1J9eDKmkXtk/s1024/The%252520Night%252520is%252520Coming.jpg\",\n\t\t\t\"https://lh6.googleusercontent.com/-G-k7YkkUco0/URqvHhah6fI/AAAAAAAAAbs/_taQQG7t0vo/s1024/The%252520Road.jpg\",\n\t\t\t\"https://lh6.googleusercontent.com/-h-ALJt7kSus/URqvIThqYfI/AAAAAAAAAbs/ejiv35olWS8/s1024/Tokyo%252520Heights.jpg\",\n\t\t\t\"https://lh5.googleusercontent.com/-Hy9k-TbS7xg/URqvIjQMOxI/AAAAAAAAAbs/RSpmmOATSkg/s1024/Tokyo%252520Highway.jpg\",\n\t\t\t\"https://lh6.googleusercontent.com/-83oOvMb4OZs/URqvJL0T7lI/AAAAAAAAAbs/c5TECZ6RONM/s1024/Tokyo%252520Smog.jpg\",\n\t\t\t\"https://lh3.googleusercontent.com/-FB-jfgREEfI/URqvJI3EXAI/AAAAAAAAAbs/XfyweiRF4v8/s1024/Tufa%252520at%252520Night.jpg\",\n\t\t\t\"https://lh4.googleusercontent.com/-vngKD5Z1U8w/URqvJUCEgPI/AAAAAAAAAbs/ulxCMVcU6EU/s1024/Valley%252520Sunset.jpg\",\n\t\t\t\"https://lh6.googleusercontent.com/-DOz5I2E2oMQ/URqvKMND1kI/AAAAAAAAAbs/Iqf0IsInleo/s1024/Windmill%252520Sunrise.jpg\",\n\t\t\t\"https://lh5.googleusercontent.com/-biyiyWcJ9MU/URqvKculiAI/AAAAAAAAAbs/jyPsCplJOpE/s1024/Windmill.jpg\",\n\t\t\t\"https://lh4.googleusercontent.com/-PDT167_xRdA/URqvK36mLcI/AAAAAAAAAbs/oi2ik9QseMI/s1024/Windmills.jpg\",\n\t\t\t\"https://lh5.googleusercontent.com/-kI_QdYx7VlU/URqvLXCB6gI/AAAAAAAAAbs/N31vlZ6u89o/s1024/Yet%252520Another%252520Rockaway%252520Sunset.jpg\",\n\t\t\t\"https://lh4.googleusercontent.com/-e9NHZ5k5MSs/URqvMIBZjtI/AAAAAAAAAbs/1fV810rDNfQ/s1024/Yosemite%252520Tree.jpg\",\n\t\t\t// Light images\n\t\t\t\"http://tabletpcssource.com/wp-content/uploads/2011/05/android-logo.png\",\n\t\t\t\"http://simpozia.com/pages/images/stories/windows-icon.png\",\n\t\t\t\"http://radiotray.sourceforge.net/radio.png\",\n\t\t\t\"http://www.bandwidthblog.com/wp-content/uploads/2011/11/twitter-logo.png\",\n\t\t\t\"http://weloveicons.s3.amazonaws.com/icons/100907_itunes1.png\",\n\t\t\t\"http://weloveicons.s3.amazonaws.com/icons/100929_applications.png\",\n\t\t\t\"http://www.idyllicmusic.com/index_files/get_apple-iphone.png\",\n\t\t\t\"http://www.frenchrevolutionfood.com/wp-content/uploads/2009/04/Twitter-Bird.png\",\n\t\t\t\"http://3.bp.blogspot.com/-ka5MiRGJ_S4/TdD9OoF6bmI/AAAAAAAAE8k/7ydKtptUtSg/s1600/Google_Sky%2BMaps_Android.png\",\n\t\t\t\"http://www.desiredsoft.com/images/icon_webhosting.png\",\n\t\t\t\"http://goodereader.com/apps/wp-content/uploads/downloads/thumbnails/2012/01/hi-256-0-99dda8c730196ab93c67f0659d5b8489abdeb977.png\",\n\t\t\t\"http://1.bp.blogspot.com/-mlaJ4p_3rBU/TdD9OWxN8II/AAAAAAAAE8U/xyynWwr3_4Q/s1600/antivitus_free.png\",\n\t\t\t\"http://cdn3.iconfinder.com/data/icons/transformers/computer.png\",\n\t\t\t\"http://cdn.geekwire.com/wp-content/uploads/2011/04/firefox.png?7794fe\",\n\t\t\t\"https://ssl.gstatic.com/android/market/com.rovio.angrybirdsseasons/hi-256-9-347dae230614238a639d21508ae492302340b2ba\",\n\t\t\t\"http://androidblaze.com/wp-content/uploads/2011/12/tablet-pc-256x256.jpg\",\n\t\t\t\"http://www.theblaze.com/wp-content/uploads/2011/08/Apple.png\",\n\t\t\t\"http://1.bp.blogspot.com/-y-HQwQ4Kuu0/TdD9_iKIY7I/AAAAAAAAE88/3G4xiclDZD0/s1600/Twitter_Android.png\",\n\t\t\t\"http://3.bp.blogspot.com/-nAf4IMJGpc8/TdD9OGNUHHI/AAAAAAAAE8E/VM9yU_lIgZ4/s1600/Adobe%2BReader_Android.png\",\n\t\t\t\"http://cdn.geekwire.com/wp-content/uploads/2011/05/oovoo-android.png?7794fe\",\n\t\t\t\"http://icons.iconarchive.com/icons/kocco/ndroid/128/android-market-2-icon.png\",\n\t\t\t\"http://thecustomizewindows.com/wp-content/uploads/2011/11/Nicest-Android-Live-Wallpapers.png\",\n\t\t\t\"http://c.wrzuta.pl/wm16596/a32f1a47002ab3a949afeb4f\",\n\t\t\t\"http://macprovid.vo.llnwd.net/o43/hub/media/1090/6882/01_headline_Muse.jpg\",\n\t\t\t// Special cases\n\t\t\t\"http://cdn.urbanislandz.com/wp-content/uploads/2011/10/MMSposter-large.jpg\", // Very large image\n\t\t\t\"http://www.ioncannon.net/wp-content/uploads/2011/06/test9.webp\", // WebP image\n\t\t\t\"http://4.bp.blogspot.com/-LEvwF87bbyU/Uicaskm-g6I/AAAAAAAAZ2c/V-WZZAvFg5I/s800/Pesto+Guacamole+500w+0268.jpg\", // Image with \"Mark has been invalidated\" problem\n\t\t\t\"file:///sdcard/Universal Image Loader @#&=+-_.,!()~'%20.png\", // Image from SD card with encoded symbols\n\t\t\t\"assets://Living Things @#&=+-_.,!()~'%20.jpg\", // Image from assets\n\t\t\t\"drawable://\" + R.drawable.ic_launcher, // Image from drawables\n\t\t\t\"http://upload.wikimedia.org/wikipedia/ru/b/b6/Как_кот_с_мышами_воевал.png\", // Link with UTF-8\n\t\t\t\"https://www.eff.org/sites/default/files/chrome150_0.jpg\", // Image from HTTPS\n\t\t\t\"http://bit.ly/soBiXr\", // Redirect link\n\t\t\t\"http://img001.us.expono.com/100001/100001-1bc30-2d736f_m.jpg\", // EXIF\n\t\t\t\"\", // Empty link\n\t\t\t\"http://wrong.site.com/corruptedLink\", // Wrong link\n\t};\n\n\tprivate Constants() {\n\t}\n\n\tpublic static class Config {\n\t\tpublic static final boolean DEVELOPER_MODE = false;\n\t}\n\t\n\tpublic static class Extra {\n\t\tpublic static final String FRAGMENT_INDEX = \"com.nostra13.example.universalimageloader.FRAGMENT_INDEX\";\n\t\tpublic static final String IMAGE_POSITION = \"com.nostra13.example.universalimageloader.IMAGE_POSITION\";\n\t}\n}\n"
  },
  {
    "path": "sample/src/main/java/com/nostra13/universalimageloader/sample/UILApplication.java",
    "content": "/*******************************************************************************\n * Copyright 2011-2013 Sergey Tarasevich\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *******************************************************************************/\npackage com.nostra13.universalimageloader.sample;\n\nimport android.annotation.TargetApi;\nimport android.app.Application;\nimport android.content.Context;\nimport android.os.Build;\nimport android.os.StrictMode;\nimport com.nostra13.universalimageloader.cache.disc.naming.Md5FileNameGenerator;\nimport com.nostra13.universalimageloader.core.ImageLoader;\nimport com.nostra13.universalimageloader.core.ImageLoaderConfiguration;\nimport com.nostra13.universalimageloader.core.assist.QueueProcessingType;\n\n/**\n * @author Sergey Tarasevich (nostra13[at]gmail[dot]com)\n */\npublic class UILApplication extends Application {\n\t@TargetApi(Build.VERSION_CODES.GINGERBREAD)\n\t@SuppressWarnings(\"unused\")\n\t@Override\n\tpublic void onCreate() {\n\t\tif (Constants.Config.DEVELOPER_MODE && Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) {\n\t\t\tStrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder().detectAll().penaltyDialog().build());\n\t\t\tStrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder().detectAll().penaltyDeath().build());\n\t\t}\n\n\t\tsuper.onCreate();\n\n\t\tinitImageLoader(getApplicationContext());\n\t}\n\n\tpublic static void initImageLoader(Context context) {\n\t\t// This configuration tuning is custom. You can tune every option, you may tune some of them,\n\t\t// or you can create default configuration by\n\t\t//  ImageLoaderConfiguration.createDefault(this);\n\t\t// method.\n\t\tImageLoaderConfiguration.Builder config = new ImageLoaderConfiguration.Builder(context);\n\t\tconfig.threadPriority(Thread.NORM_PRIORITY - 2);\n\t\tconfig.denyCacheImageMultipleSizesInMemory();\n\t\tconfig.diskCacheFileNameGenerator(new Md5FileNameGenerator());\n\t\tconfig.diskCacheSize(50 * 1024 * 1024); // 50 MiB\n\t\tconfig.tasksProcessingOrder(QueueProcessingType.LIFO);\n\t\tconfig.writeDebugLogs(); // Remove for release app\n\n\t\t// Initialize ImageLoader with configuration.\n\t\tImageLoader.getInstance().init(config.build());\n\t}\n}"
  },
  {
    "path": "sample/src/main/java/com/nostra13/universalimageloader/sample/activity/ComplexImageActivity.java",
    "content": "/*******************************************************************************\n * Copyright 2014 Sergey Tarasevich\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *******************************************************************************/\npackage com.nostra13.universalimageloader.sample.activity;\n\nimport android.os.Bundle;\nimport android.support.v4.app.Fragment;\nimport android.support.v4.app.FragmentActivity;\nimport android.support.v4.app.FragmentManager;\nimport android.support.v4.app.FragmentPagerAdapter;\nimport android.support.v4.view.ViewPager;\nimport com.nostra13.universalimageloader.sample.R;\nimport com.nostra13.universalimageloader.sample.fragment.ImageGridFragment;\nimport com.nostra13.universalimageloader.sample.fragment.ImageListFragment;\n\n/**\n * @author Sergey Tarasevich (nostra13[at]gmail[dot]com)\n */\npublic class ComplexImageActivity extends FragmentActivity {\n\n\tprivate static final String STATE_POSITION = \"STATE_POSITION\";\n\n\tprivate ViewPager pager;\n\n\t@Override\n\tpublic void onCreate(Bundle savedInstanceState) {\n\t\tsuper.onCreate(savedInstanceState);\n\t\tsetContentView(R.layout.ac_complex);\n\n\t\tint pagerPosition = savedInstanceState == null ? 0 : savedInstanceState.getInt(STATE_POSITION);\n\n\t\tpager = (ViewPager) findViewById(R.id.pager);\n\t\tpager.setAdapter(new ImagePagerAdapter(getSupportFragmentManager()));\n\t\tpager.setCurrentItem(pagerPosition);\n\t}\n\n\t@Override\n\tpublic void onSaveInstanceState(Bundle outState) {\n\t\toutState.putInt(STATE_POSITION, pager.getCurrentItem());\n\t}\n\n\tprivate class ImagePagerAdapter extends FragmentPagerAdapter {\n\n\t\tFragment listFragment;\n\t\tFragment gridFragment;\n\n\t\tImagePagerAdapter(FragmentManager fm) {\n\t\t\tsuper(fm);\n\t\t\tlistFragment = new ImageListFragment();\n\t\t\tgridFragment = new ImageGridFragment();\n\t\t}\n\n\t\t@Override\n\t\tpublic int getCount() {\n\t\t\treturn 2;\n\t\t}\n\n\t\t@Override\n\t\tpublic Fragment getItem(int position) {\n\t\t\tswitch (position) {\n\t\t\t\tcase 0:\n\t\t\t\t\treturn listFragment;\n\t\t\t\tcase 1:\n\t\t\t\t\treturn gridFragment;\n\t\t\t\tdefault:\n\t\t\t\t\treturn null;\n\t\t\t}\n\t\t}\n\n\t\t@Override\n\t\tpublic CharSequence getPageTitle(int position) {\n\t\t\tswitch (position) {\n\t\t\t\tcase 0:\n\t\t\t\t\treturn getString(R.string.title_list);\n\t\t\t\tcase 1:\n\t\t\t\t\treturn getString(R.string.title_grid);\n\t\t\t\tdefault:\n\t\t\t\t\treturn null;\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "sample/src/main/java/com/nostra13/universalimageloader/sample/activity/HomeActivity.java",
    "content": "/*******************************************************************************\n * Copyright 2011-2013 Sergey Tarasevich\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *******************************************************************************/\npackage com.nostra13.universalimageloader.sample.activity;\n\nimport android.app.Activity;\nimport android.content.Intent;\nimport android.os.Bundle;\nimport android.view.Menu;\nimport android.view.MenuItem;\nimport android.view.View;\nimport com.nostra13.universalimageloader.core.ImageLoader;\nimport com.nostra13.universalimageloader.sample.Constants;\nimport com.nostra13.universalimageloader.sample.R;\nimport com.nostra13.universalimageloader.sample.fragment.ImageGalleryFragment;\nimport com.nostra13.universalimageloader.sample.fragment.ImageGridFragment;\nimport com.nostra13.universalimageloader.sample.fragment.ImageListFragment;\nimport com.nostra13.universalimageloader.sample.fragment.ImagePagerFragment;\nimport com.nostra13.universalimageloader.utils.L;\n\nimport java.io.File;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\n\n/**\n * @author Sergey Tarasevich (nostra13[at]gmail[dot]com)\n */\npublic class HomeActivity extends Activity {\n\n\tprivate static final String TEST_FILE_NAME = \"Universal Image Loader @#&=+-_.,!()~'%20.png\";\n\n\t@Override\n\tpublic void onCreate(Bundle savedInstanceState) {\n\t\tsuper.onCreate(savedInstanceState);\n\t\tsetContentView(R.layout.ac_home);\n\n\t\tFile testImageOnSdCard = new File(\"/mnt/sdcard\", TEST_FILE_NAME);\n\t\tif (!testImageOnSdCard.exists()) {\n\t\t\tcopyTestImageToSdCard(testImageOnSdCard);\n\t\t}\n\t}\n\n\tpublic void onImageListClick(View view) {\n\t\tIntent intent = new Intent(this, SimpleImageActivity.class);\n\t\tintent.putExtra(Constants.Extra.FRAGMENT_INDEX, ImageListFragment.INDEX);\n\t\tstartActivity(intent);\n\t}\n\n\tpublic void onImageGridClick(View view) {\n\t\tIntent intent = new Intent(this, SimpleImageActivity.class);\n\t\tintent.putExtra(Constants.Extra.FRAGMENT_INDEX, ImageGridFragment.INDEX);\n\t\tstartActivity(intent);\n\t}\n\n\tpublic void onImagePagerClick(View view) {\n\t\tIntent intent = new Intent(this, SimpleImageActivity.class);\n\t\tintent.putExtra(Constants.Extra.FRAGMENT_INDEX, ImagePagerFragment.INDEX);\n\t\tstartActivity(intent);\n\t}\n\n\tpublic void onImageGalleryClick(View view) {\n\t\tIntent intent = new Intent(this, SimpleImageActivity.class);\n\t\tintent.putExtra(Constants.Extra.FRAGMENT_INDEX, ImageGalleryFragment.INDEX);\n\t\tstartActivity(intent);\n\t}\n\n\tpublic void onFragmentsClick(View view) {\n\t\tIntent intent = new Intent(this, ComplexImageActivity.class);\n\t\tstartActivity(intent);\n\t}\n\n\t@Override\n\tpublic void onBackPressed() {\n\t\tImageLoader.getInstance().stop();\n\t\tsuper.onBackPressed();\n\t}\n\n\t@Override\n\tpublic boolean onCreateOptionsMenu(Menu menu) {\n\t\tgetMenuInflater().inflate(R.menu.main_menu, menu);\n\t\treturn true;\n\t}\n\n\t@Override\n\tpublic boolean onOptionsItemSelected(MenuItem item) {\n\t\tswitch (item.getItemId()) {\n\t\t\tcase R.id.item_clear_memory_cache:\n\t\t\t\tImageLoader.getInstance().clearMemoryCache();\n\t\t\t\treturn true;\n\t\t\tcase R.id.item_clear_disc_cache:\n\t\t\t\tImageLoader.getInstance().clearDiskCache();\n\t\t\t\treturn true;\n\t\t\tdefault:\n\t\t\t\treturn false;\n\t\t}\n\t}\n\n\tprivate void copyTestImageToSdCard(final File testImageOnSdCard) {\n\t\tnew Thread(new Runnable() {\n\t\t\t@Override\n\t\t\tpublic void run() {\n\t\t\t\ttry {\n\t\t\t\t\tInputStream is = getAssets().open(TEST_FILE_NAME);\n\t\t\t\t\tFileOutputStream fos = new FileOutputStream(testImageOnSdCard);\n\t\t\t\t\tbyte[] buffer = new byte[8192];\n\t\t\t\t\tint read;\n\t\t\t\t\ttry {\n\t\t\t\t\t\twhile ((read = is.read(buffer)) != -1) {\n\t\t\t\t\t\t\tfos.write(buffer, 0, read);\n\t\t\t\t\t\t}\n\t\t\t\t\t} finally {\n\t\t\t\t\t\tfos.flush();\n\t\t\t\t\t\tfos.close();\n\t\t\t\t\t\tis.close();\n\t\t\t\t\t}\n\t\t\t\t} catch (IOException e) {\n\t\t\t\t\tL.w(\"Can't copy test image onto SD card\");\n\t\t\t\t}\n\t\t\t}\n\t\t}).start();\n\t}\n}"
  },
  {
    "path": "sample/src/main/java/com/nostra13/universalimageloader/sample/activity/SimpleImageActivity.java",
    "content": "/*******************************************************************************\n * Copyright 2014 Sergey Tarasevich\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *******************************************************************************/\npackage com.nostra13.universalimageloader.sample.activity;\n\nimport android.os.Bundle;\nimport android.support.v4.app.Fragment;\nimport android.support.v4.app.FragmentActivity;\nimport com.nostra13.universalimageloader.sample.Constants;\nimport com.nostra13.universalimageloader.sample.R;\nimport com.nostra13.universalimageloader.sample.fragment.ImageGalleryFragment;\nimport com.nostra13.universalimageloader.sample.fragment.ImageGridFragment;\nimport com.nostra13.universalimageloader.sample.fragment.ImageListFragment;\nimport com.nostra13.universalimageloader.sample.fragment.ImagePagerFragment;\n\n/**\n * @author Sergey Tarasevich (nostra13[at]gmail[dot]com)\n */\npublic class SimpleImageActivity extends FragmentActivity {\n\t@Override\n\tpublic void onCreate(Bundle savedInstanceState) {\n\t\tsuper.onCreate(savedInstanceState);\n\n\t\tint frIndex = getIntent().getIntExtra(Constants.Extra.FRAGMENT_INDEX, 0);\n\t\tFragment fr;\n\t\tString tag;\n\t\tint titleRes;\n\t\tswitch (frIndex) {\n\t\t\tdefault:\n\t\t\tcase ImageListFragment.INDEX:\n\t\t\t\ttag = ImageListFragment.class.getSimpleName();\n\t\t\t\tfr = getSupportFragmentManager().findFragmentByTag(tag);\n\t\t\t\tif (fr == null) {\n\t\t\t\t\tfr = new ImageListFragment();\n\t\t\t\t}\n\t\t\t\ttitleRes = R.string.ac_name_image_list;\n\t\t\t\tbreak;\n\t\t\tcase ImageGridFragment.INDEX:\n\t\t\t\ttag = ImageGridFragment.class.getSimpleName();\n\t\t\t\tfr = getSupportFragmentManager().findFragmentByTag(tag);\n\t\t\t\tif (fr == null) {\n\t\t\t\t\tfr = new ImageGridFragment();\n\t\t\t\t}\n\t\t\t\ttitleRes = R.string.ac_name_image_grid;\n\t\t\t\tbreak;\n\t\t\tcase ImagePagerFragment.INDEX:\n\t\t\t\ttag = ImagePagerFragment.class.getSimpleName();\n\t\t\t\tfr = getSupportFragmentManager().findFragmentByTag(tag);\n\t\t\t\tif (fr == null) {\n\t\t\t\t\tfr = new ImagePagerFragment();\n\t\t\t\t\tfr.setArguments(getIntent().getExtras());\n\t\t\t\t}\n\t\t\t\ttitleRes = R.string.ac_name_image_pager;\n\t\t\t\tbreak;\n\t\t\tcase ImageGalleryFragment.INDEX:\n\t\t\t\ttag = ImageGalleryFragment.class.getSimpleName();\n\t\t\t\tfr = getSupportFragmentManager().findFragmentByTag(tag);\n\t\t\t\tif (fr == null) {\n\t\t\t\t\tfr = new ImageGalleryFragment();\n\t\t\t\t}\n\t\t\t\ttitleRes = R.string.ac_name_image_gallery;\n\t\t\t\tbreak;\n\t\t}\n\n\t\tsetTitle(titleRes);\n\t\tgetSupportFragmentManager().beginTransaction().replace(android.R.id.content, fr, tag).commit();\n\t}\n}"
  },
  {
    "path": "sample/src/main/java/com/nostra13/universalimageloader/sample/ext/Base64ImageDownloader.java",
    "content": "/*******************************************************************************\n * Copyright 2015 Sergey Tarasevich\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *******************************************************************************/\npackage com.nostra13.universalimageloader.sample.ext;\n\nimport android.annotation.TargetApi;\nimport android.content.Context;\nimport android.os.Build;\nimport android.util.Base64;\n\nimport com.nostra13.universalimageloader.core.download.BaseImageDownloader;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\n\n/**\n * Downloader supporting \"base64://...\" URIs.\n * E.g.: \"base64://data:image/jpeg;base64,/9j/4AAQSkZ...\"\n *\n * @author mrleolink, Sergey Tarasevich (nostra13[at]gmail[dot]com)\n */\n@TargetApi(Build.VERSION_CODES.FROYO)\npublic class Base64ImageDownloader extends BaseImageDownloader {\n\n\tpublic static final String BASE64_SCHEME = \"base64\";\n\tpublic static final String BASE64_URI_PREFIX = BASE64_SCHEME + \"://\";\n\n\tpublic static final String BASE64_DATA_PREFIX = \"base64,\";\n\n\tpublic Base64ImageDownloader(Context context) {\n\t\tsuper(context);\n\t}\n\n\tpublic Base64ImageDownloader(Context context, int connectTimeout, int readTimeout) {\n\t\tsuper(context, connectTimeout, readTimeout);\n\t}\n\n\t@Override\n\tpublic InputStream getStreamFromOtherSource(String imageUri, Object extra) throws IOException {\n\t\tif (imageUri.startsWith(BASE64_URI_PREFIX)) {\n\t\t\treturn getStreamFormBase64(imageUri, extra);\n\t\t}\n\t\treturn super.getStreamFromOtherSource(imageUri, extra);\n\t}\n\n\tprotected InputStream getStreamFormBase64(String imageUri, Object extra) {\n\t\tint dataStartIndex = imageUri.indexOf(BASE64_DATA_PREFIX) + BASE64_DATA_PREFIX.length();\n\t\tString base64 = imageUri.substring(dataStartIndex);\n\t\treturn new ByteArrayInputStream(Base64.decode(base64, Base64.DEFAULT));\n\t}\n}\n"
  },
  {
    "path": "sample/src/main/java/com/nostra13/universalimageloader/sample/ext/BrokenJpegImageDecoder.java",
    "content": "package com.nostra13.universalimageloader.sample.ext;\n\nimport com.nostra13.universalimageloader.core.decode.BaseImageDecoder;\nimport com.nostra13.universalimageloader.core.decode.ImageDecodingInfo;\n\nimport java.io.IOException;\nimport java.io.InputStream;\n\n/**\n * @author Sergey Tarasevich (nostra13[at]gmail[dot]com)\n */\npublic class BrokenJpegImageDecoder extends BaseImageDecoder {\n\n\tpublic BrokenJpegImageDecoder(boolean loggingEnabled) {\n\t\tsuper(loggingEnabled);\n\t}\n\n\t@Override\n\tprotected InputStream getImageStream(ImageDecodingInfo decodingInfo) throws IOException {\n\t\tInputStream stream = decodingInfo.getDownloader()\n\t\t\t\t.getStream(decodingInfo.getImageUri(), decodingInfo.getExtraForDownloader());\n\t\treturn stream == null ? null : new JpegClosedInputStream(stream);\n\t}\n\n\tprivate class JpegClosedInputStream extends InputStream {\n\n\t\tprivate static final int JPEG_EOI_1 = 0xFF;\n\t\tprivate static final int JPEG_EOI_2 = 0xD9;\n\n\t\tprivate final InputStream inputStream;\n\t\tprivate int bytesPastEnd;\n\n\t\tprivate JpegClosedInputStream(InputStream inputStream) {\n\t\t\tthis.inputStream = inputStream;\n\t\t\tbytesPastEnd = 0;\n\t\t}\n\n\t\t@Override\n\t\tpublic int read() throws IOException {\n\t\t\tint buffer = inputStream.read();\n\t\t\tif (buffer == -1) {\n\t\t\t\tif (bytesPastEnd > 0) {\n\t\t\t\t\tbuffer = JPEG_EOI_2;\n\t\t\t\t} else {\n\t\t\t\t\t++bytesPastEnd;\n\t\t\t\t\tbuffer = JPEG_EOI_1;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn buffer;\n\t\t}\n\t}\n}"
  },
  {
    "path": "sample/src/main/java/com/nostra13/universalimageloader/sample/ext/HttpClientImageDownloader.java",
    "content": "/*******************************************************************************\n * Copyright 2011-2015 Sergey Tarasevich\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *******************************************************************************/\npackage com.nostra13.universalimageloader.sample.ext;\n\nimport android.content.Context;\nimport com.nostra13.universalimageloader.core.download.BaseImageDownloader;\nimport org.apache.http.HttpEntity;\nimport org.apache.http.HttpResponse;\nimport org.apache.http.client.HttpClient;\nimport org.apache.http.client.methods.HttpGet;\nimport org.apache.http.entity.BufferedHttpEntity;\n\nimport java.io.IOException;\nimport java.io.InputStream;\n\n/**\n * Implementation of ImageDownloader which uses {@link HttpClient} for image stream retrieving.\n *\n * @author Sergey Tarasevich (nostra13[at]gmail[dot]com)\n */\npublic class HttpClientImageDownloader extends BaseImageDownloader {\n\n\tprivate HttpClient httpClient;\n\n\tpublic HttpClientImageDownloader(Context context, HttpClient httpClient) {\n\t\tsuper(context);\n\t\tthis.httpClient = httpClient;\n\t}\n\n\t@Override\n\tprotected InputStream getStreamFromNetwork(String imageUri, Object extra) throws IOException {\n\t\tHttpGet httpRequest = new HttpGet(imageUri);\n\t\tHttpResponse response = httpClient.execute(httpRequest);\n\t\tHttpEntity entity = response.getEntity();\n\t\tBufferedHttpEntity bufHttpEntity = new BufferedHttpEntity(entity);\n\t\treturn bufHttpEntity.getContent();\n\t}\n}"
  },
  {
    "path": "sample/src/main/java/com/nostra13/universalimageloader/sample/ext/OkHttpImageDownloader.java",
    "content": "/*******************************************************************************\n * Copyright 2011-2015 Sergey Tarasevich\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *******************************************************************************/\npackage com.nostra13.universalimageloader.sample.ext;\n\nimport android.content.Context;\n\nimport com.nostra13.universalimageloader.core.assist.ContentLengthInputStream;\nimport com.nostra13.universalimageloader.core.download.BaseImageDownloader;\nimport com.squareup.okhttp.OkHttpClient;\nimport com.squareup.okhttp.Request;\nimport com.squareup.okhttp.ResponseBody;\n\nimport java.io.IOException;\nimport java.io.InputStream;\n\n/**\n * Implementation of ImageDownloader which uses {@link com.squareup.okhttp.OkHttpClient} for image stream retrieving.\n *\n * @author Sergey Tarasevich (nostra13[at]gmail[dot]com)\n * @author Leo Link (mr[dot]leolink[at]gmail[dot]com)\n */\npublic class OkHttpImageDownloader extends BaseImageDownloader {\n\n\tprivate OkHttpClient client;\n\n\tpublic OkHttpImageDownloader(Context context, OkHttpClient client) {\n\t\tsuper(context);\n\t\tthis.client = client;\n\t}\n\n\t@Override\n\tprotected InputStream getStreamFromNetwork(String imageUri, Object extra) throws IOException {\n\t\tRequest request = new Request.Builder().url(imageUri).build();\n\t\tResponseBody responseBody = client.newCall(request).execute().body();\n\t\tInputStream inputStream = responseBody.byteStream();\n\t\tint contentLength = (int) responseBody.contentLength();\n\t\treturn new ContentLengthInputStream(inputStream, contentLength);\n\t}\n}\n"
  },
  {
    "path": "sample/src/main/java/com/nostra13/universalimageloader/sample/ext/OldRoundedBitmapDisplayer.java",
    "content": "/*******************************************************************************\n * Copyright 2011-2015 Sergey Tarasevich\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *******************************************************************************/\npackage com.nostra13.universalimageloader.sample.ext;\n\nimport android.graphics.Bitmap;\nimport android.graphics.Bitmap.Config;\nimport android.graphics.Canvas;\nimport android.graphics.Paint;\nimport android.graphics.PorterDuff;\nimport android.graphics.PorterDuffXfermode;\nimport android.graphics.Rect;\nimport android.graphics.RectF;\nimport android.widget.ImageView;\nimport com.nostra13.universalimageloader.core.assist.LoadedFrom;\nimport com.nostra13.universalimageloader.core.display.BitmapDisplayer;\nimport com.nostra13.universalimageloader.core.imageaware.ImageAware;\nimport com.nostra13.universalimageloader.core.imageaware.ImageViewAware;\nimport com.nostra13.universalimageloader.utils.L;\n\n/**\n * Displays bitmap with rounded corners. This implementation works only with ImageViews wrapped in ImageViewAware.<br />\n * <b>NOTE:</b> It's strongly recommended your {@link ImageView} has defined width (<i>layout_width</i>) and height\n * (<i>layout_height</i>) .<br />\n * <b>NOTE:</b> New {@link Bitmap} object is created for displaying. So this class needs more memory and can cause\n * {@link OutOfMemoryError}.\n *\n * @author Sergey Tarasevich (nostra13[at]gmail[dot]com)\n */\npublic class OldRoundedBitmapDisplayer implements BitmapDisplayer {\n\n\tprivate final int roundPixels;\n\n\tpublic OldRoundedBitmapDisplayer(int roundPixels) {\n\t\tthis.roundPixels = roundPixels;\n\t}\n\n\t@Override\n\tpublic void display(Bitmap bitmap, ImageAware imageAware, LoadedFrom loadedFrom) {\n\t\tif (!(imageAware instanceof ImageViewAware)) {\n\t\t\tthrow new IllegalArgumentException(\"ImageAware should wrap ImageView. ImageViewAware is expected.\");\n\t\t}\n\t\tBitmap roundedBitmap = roundCorners(bitmap, (ImageViewAware) imageAware, roundPixels);\n\t\timageAware.setImageBitmap(roundedBitmap);\n\t}\n\n\t/**\n\t * Process incoming {@linkplain Bitmap} to make rounded corners according to target\n\t * {@link com.nostra13.universalimageloader.core.imageaware.ImageViewAware}.<br />\n\t * This method <b>doesn't display</b> result bitmap in {@link ImageView}\n\t *\n\t * @param bitmap      Incoming Bitmap to process\n\t * @param imageAware  Target {@link com.nostra13.universalimageloader.core.imageaware.ImageAware ImageAware} to\n\t *                    display bitmap in\n\t * @param roundPixels Rounded pixels of corner\n\t * @return Result bitmap with rounded corners\n\t */\n\tpublic static Bitmap roundCorners(Bitmap bitmap, ImageViewAware imageAware, int roundPixels) {\n\t\tImageView imageView = imageAware.getWrappedView();\n\t\tif (imageView == null) {\n\t\t\tL.w(\"View is collected probably. Can't round bitmap corners without view properties.\");\n\t\t\treturn bitmap;\n\t\t}\n\n\t\tBitmap roundBitmap;\n\n\t\tint bw = bitmap.getWidth();\n\t\tint bh = bitmap.getHeight();\n\t\tint vw = imageAware.getWidth();\n\t\tint vh = imageAware.getHeight();\n\t\tif (vw <= 0) vw = bw;\n\t\tif (vh <= 0) vh = bh;\n\n\t\tfinal ImageView.ScaleType scaleType = imageView.getScaleType();\n\t\tif (scaleType == null) {\n\t\t\treturn bitmap;\n\t\t}\n\n\t\tint width, height;\n\t\tRect srcRect;\n\t\tRect destRect;\n\t\tswitch (scaleType) {\n\t\t\tcase CENTER_INSIDE:\n\t\t\t\tfloat vRation = (float) vw / vh;\n\t\t\t\tfloat bRation = (float) bw / bh;\n\t\t\t\tint destWidth;\n\t\t\t\tint destHeight;\n\t\t\t\tif (vRation > bRation) {\n\t\t\t\t\tdestHeight = Math.min(vh, bh);\n\t\t\t\t\tdestWidth = (int) (bw / ((float) bh / destHeight));\n\t\t\t\t} else {\n\t\t\t\t\tdestWidth = Math.min(vw, bw);\n\t\t\t\t\tdestHeight = (int) (bh / ((float) bw / destWidth));\n\t\t\t\t}\n\t\t\t\tint x = (vw - destWidth) / 2;\n\t\t\t\tint y = (vh - destHeight) / 2;\n\t\t\t\tsrcRect = new Rect(0, 0, bw, bh);\n\t\t\t\tdestRect = new Rect(x, y, x + destWidth, y + destHeight);\n\t\t\t\twidth = vw;\n\t\t\t\theight = vh;\n\t\t\t\tbreak;\n\t\t\tcase FIT_CENTER:\n\t\t\tcase FIT_START:\n\t\t\tcase FIT_END:\n\t\t\tdefault:\n\t\t\t\tvRation = (float) vw / vh;\n\t\t\t\tbRation = (float) bw / bh;\n\t\t\t\tif (vRation > bRation) {\n\t\t\t\t\twidth = (int) (bw / ((float) bh / vh));\n\t\t\t\t\theight = vh;\n\t\t\t\t} else {\n\t\t\t\t\twidth = vw;\n\t\t\t\t\theight = (int) (bh / ((float) bw / vw));\n\t\t\t\t}\n\t\t\t\tsrcRect = new Rect(0, 0, bw, bh);\n\t\t\t\tdestRect = new Rect(0, 0, width, height);\n\t\t\t\tbreak;\n\t\t\tcase CENTER_CROP:\n\t\t\t\tvRation = (float) vw / vh;\n\t\t\t\tbRation = (float) bw / bh;\n\t\t\t\tint srcWidth;\n\t\t\t\tint srcHeight;\n\t\t\t\tif (vRation > bRation) {\n\t\t\t\t\tsrcWidth = bw;\n\t\t\t\t\tsrcHeight = (int) (vh * ((float) bw / vw));\n\t\t\t\t\tx = 0;\n\t\t\t\t\ty = (bh - srcHeight) / 2;\n\t\t\t\t} else {\n\t\t\t\t\tsrcWidth = (int) (vw * ((float) bh / vh));\n\t\t\t\t\tsrcHeight = bh;\n\t\t\t\t\tx = (bw - srcWidth) / 2;\n\t\t\t\t\ty = 0;\n\t\t\t\t}\n\t\t\t\twidth = srcWidth;// Math.min(vw, bw);\n\t\t\t\theight = srcHeight;//Math.min(vh, bh);\n\t\t\t\tsrcRect = new Rect(x, y, x + srcWidth, y + srcHeight);\n\t\t\t\tdestRect = new Rect(0, 0, width, height);\n\t\t\t\tbreak;\n\t\t\tcase FIT_XY:\n\t\t\t\twidth = vw;\n\t\t\t\theight = vh;\n\t\t\t\tsrcRect = new Rect(0, 0, bw, bh);\n\t\t\t\tdestRect = new Rect(0, 0, width, height);\n\t\t\t\tbreak;\n\t\t\tcase CENTER:\n\t\t\tcase MATRIX:\n\t\t\t\twidth = Math.min(vw, bw);\n\t\t\t\theight = Math.min(vh, bh);\n\t\t\t\tx = (bw - width) / 2;\n\t\t\t\ty = (bh - height) / 2;\n\t\t\t\tsrcRect = new Rect(x, y, x + width, y + height);\n\t\t\t\tdestRect = new Rect(0, 0, width, height);\n\t\t\t\tbreak;\n\t\t}\n\n\t\ttry {\n\t\t\troundBitmap = getRoundedCornerBitmap(bitmap, roundPixels, srcRect, destRect, width, height);\n\t\t} catch (OutOfMemoryError e) {\n\t\t\tL.e(e, \"Can't create bitmap with rounded corners. Not enough memory.\");\n\t\t\troundBitmap = bitmap;\n\t\t}\n\n\t\treturn roundBitmap;\n\t}\n\n\tprivate static Bitmap getRoundedCornerBitmap(Bitmap bitmap, int roundPixels, Rect srcRect, Rect destRect, int width,\n\t\t\tint height) {\n\t\tBitmap output = Bitmap.createBitmap(width, height, Config.ARGB_8888);\n\t\tCanvas canvas = new Canvas(output);\n\n\t\tfinal Paint paint = new Paint();\n\t\tfinal RectF destRectF = new RectF(destRect);\n\n\t\tpaint.setAntiAlias(true);\n\t\tcanvas.drawARGB(0, 0, 0, 0);\n\t\tpaint.setColor(0xFF000000);\n\t\tcanvas.drawRoundRect(destRectF, roundPixels, roundPixels, paint);\n\n\t\tpaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));\n\t\tcanvas.drawBitmap(bitmap, srcRect, destRectF, paint);\n\n\t\treturn output;\n\t}\n}"
  },
  {
    "path": "sample/src/main/java/com/nostra13/universalimageloader/sample/fragment/AbsListViewBaseFragment.java",
    "content": "/*******************************************************************************\n * Copyright 2011-2014 Sergey Tarasevich\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *******************************************************************************/\npackage com.nostra13.universalimageloader.sample.fragment;\n\nimport android.content.Intent;\nimport android.view.Menu;\nimport android.view.MenuItem;\nimport android.widget.AbsListView;\nimport com.nostra13.universalimageloader.core.ImageLoader;\nimport com.nostra13.universalimageloader.core.listener.PauseOnScrollListener;\nimport com.nostra13.universalimageloader.sample.Constants;\nimport com.nostra13.universalimageloader.sample.R;\nimport com.nostra13.universalimageloader.sample.activity.SimpleImageActivity;\n\n/**\n * @author Sergey Tarasevich (nostra13[at]gmail[dot]com)\n */\npublic abstract class AbsListViewBaseFragment extends BaseFragment {\n\n\tprotected static final String STATE_PAUSE_ON_SCROLL = \"STATE_PAUSE_ON_SCROLL\";\n\tprotected static final String STATE_PAUSE_ON_FLING = \"STATE_PAUSE_ON_FLING\";\n\n\tprotected AbsListView listView;\n\n\tprotected boolean pauseOnScroll = false;\n\tprotected boolean pauseOnFling = true;\n\n\t@Override\n\tpublic void onResume() {\n\t\tsuper.onResume();\n\t\tapplyScrollListener();\n\t}\n\n\t@Override\n\tpublic void onPrepareOptionsMenu(Menu menu) {\n\t\tMenuItem pauseOnScrollItem = menu.findItem(R.id.item_pause_on_scroll);\n\t\tpauseOnScrollItem.setVisible(true);\n\t\tpauseOnScrollItem.setChecked(pauseOnScroll);\n\n\t\tMenuItem pauseOnFlingItem = menu.findItem(R.id.item_pause_on_fling);\n\t\tpauseOnFlingItem.setVisible(true);\n\t\tpauseOnFlingItem.setChecked(pauseOnFling);\n\t}\n\n\t@Override\n\tpublic boolean onOptionsItemSelected(MenuItem item) {\n\t\tswitch (item.getItemId()) {\n\t\t\tcase R.id.item_pause_on_scroll:\n\t\t\t\tpauseOnScroll = !pauseOnScroll;\n\t\t\t\titem.setChecked(pauseOnScroll);\n\t\t\t\tapplyScrollListener();\n\t\t\t\treturn true;\n\t\t\tcase R.id.item_pause_on_fling:\n\t\t\t\tpauseOnFling = !pauseOnFling;\n\t\t\t\titem.setChecked(pauseOnFling);\n\t\t\t\tapplyScrollListener();\n\t\t\t\treturn true;\n\t\t\tdefault:\n\t\t\t\treturn super.onOptionsItemSelected(item);\n\t\t}\n\t}\n\n\tprotected void startImagePagerActivity(int position) {\n\t\tIntent intent = new Intent(getActivity(), SimpleImageActivity.class);\n\t\tintent.putExtra(Constants.Extra.FRAGMENT_INDEX, ImagePagerFragment.INDEX);\n\t\tintent.putExtra(Constants.Extra.IMAGE_POSITION, position);\n\t\tstartActivity(intent);\n\t}\n\n\tprivate void applyScrollListener() {\n\t\tlistView.setOnScrollListener(new PauseOnScrollListener(ImageLoader.getInstance(), pauseOnScroll, pauseOnFling));\n\t}\n}\n"
  },
  {
    "path": "sample/src/main/java/com/nostra13/universalimageloader/sample/fragment/BaseFragment.java",
    "content": "/*******************************************************************************\n * Copyright 2011-2014 Sergey Tarasevich\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *******************************************************************************/\npackage com.nostra13.universalimageloader.sample.fragment;\n\nimport android.os.Bundle;\nimport android.support.v4.app.Fragment;\nimport android.view.Menu;\nimport android.view.MenuInflater;\nimport android.view.MenuItem;\nimport com.nostra13.universalimageloader.core.ImageLoader;\nimport com.nostra13.universalimageloader.sample.R;\n\n/**\n * @author Sergey Tarasevich (nostra13[at]gmail[dot]com)\n */\npublic abstract class BaseFragment extends Fragment {\n\t@Override\n\tpublic void onCreate(Bundle savedInstanceState) {\n\t\tsuper.onCreate(savedInstanceState);\n\n\t\tsetHasOptionsMenu(true);\n\t}\n\n\tpublic void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {\n\t\tinflater.inflate(R.menu.main_menu, menu);\n\t}\n\n\t@Override\n\tpublic boolean onOptionsItemSelected(MenuItem item) {\n\t\tswitch (item.getItemId()) {\n\t\t\tcase R.id.item_clear_memory_cache:\n\t\t\t\tImageLoader.getInstance().clearMemoryCache();\n\t\t\t\treturn true;\n\t\t\tcase R.id.item_clear_disc_cache:\n\t\t\t\tImageLoader.getInstance().clearDiskCache();\n\t\t\t\treturn true;\n\t\t\tdefault:\n\t\t\t\treturn false;\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "sample/src/main/java/com/nostra13/universalimageloader/sample/fragment/ImageGalleryFragment.java",
    "content": "/*******************************************************************************\n * Copyright 2011-2014 Sergey Tarasevich\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *******************************************************************************/\npackage com.nostra13.universalimageloader.sample.fragment;\n\nimport android.content.Context;\nimport android.content.Intent;\nimport android.graphics.Bitmap;\nimport android.os.Bundle;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.AdapterView;\nimport android.widget.AdapterView.OnItemClickListener;\nimport android.widget.BaseAdapter;\nimport android.widget.Gallery;\nimport android.widget.ImageView;\n\nimport com.nostra13.universalimageloader.core.DisplayImageOptions;\nimport com.nostra13.universalimageloader.core.ImageLoader;\nimport com.nostra13.universalimageloader.core.display.RoundedBitmapDisplayer;\nimport com.nostra13.universalimageloader.sample.Constants;\nimport com.nostra13.universalimageloader.sample.R;\nimport com.nostra13.universalimageloader.sample.activity.SimpleImageActivity;\n\n/**\n * @author Sergey Tarasevich (nostra13[at]gmail[dot]com)\n */\npublic class ImageGalleryFragment extends BaseFragment {\n\n\tpublic static final int INDEX = 3;\n\n\t@SuppressWarnings(\"deprecation\")\n\t@Override\n\tpublic View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {\n\t\tView rootView = inflater.inflate(R.layout.fr_image_gallery, container, false);\n\t\tGallery gallery = (Gallery) rootView.findViewById(R.id.gallery);\n\t\tgallery.setAdapter(new ImageAdapter(getActivity()));\n\t\tgallery.setOnItemClickListener(new OnItemClickListener() {\n\t\t\t@Override\n\t\t\tpublic void onItemClick(AdapterView<?> parent, View view, int position, long id) {\n\t\t\t\tstartImagePagerActivity(position);\n\t\t\t}\n\t\t});\n\t\treturn rootView;\n\t}\n\n\n\tprivate void startImagePagerActivity(int position) {\n\t\tIntent intent = new Intent(getActivity(), SimpleImageActivity.class);\n\t\tintent.putExtra(Constants.Extra.FRAGMENT_INDEX, ImagePagerFragment.INDEX);\n\t\tintent.putExtra(Constants.Extra.IMAGE_POSITION, position);\n\t\tstartActivity(intent);\n\t}\n\n\tprivate static class ImageAdapter extends BaseAdapter {\n\n\t\tprivate static final String[] IMAGE_URLS = Constants.IMAGES;\n\n\t\tprivate LayoutInflater inflater;\n\n\t\tprivate DisplayImageOptions options;\n\n\t\tImageAdapter(Context context) {\n\t\t\tinflater = LayoutInflater.from(context);\n\n\t\t\toptions = new DisplayImageOptions.Builder()\n\t\t\t\t\t.showImageOnLoading(R.drawable.ic_stub)\n\t\t\t\t\t.showImageForEmptyUri(R.drawable.ic_empty)\n\t\t\t\t\t.showImageOnFail(R.drawable.ic_error)\n\t\t\t\t\t.cacheInMemory(true)\n\t\t\t\t\t.cacheOnDisk(true)\n\t\t\t\t\t.considerExifParams(true)\n\t\t\t\t\t.bitmapConfig(Bitmap.Config.RGB_565)\n\t\t\t\t\t.displayer(new RoundedBitmapDisplayer(20))\n\t\t\t\t\t.build();\n\t\t}\n\n\t\t@Override\n\t\tpublic int getCount() {\n\t\t\treturn IMAGE_URLS.length;\n\t\t}\n\n\t\t@Override\n\t\tpublic Object getItem(int position) {\n\t\t\treturn position;\n\t\t}\n\n\t\t@Override\n\t\tpublic long getItemId(int position) {\n\t\t\treturn position;\n\t\t}\n\n\t\t@Override\n\t\tpublic View getView(int position, View convertView, ViewGroup parent) {\n\t\t\tImageView imageView = (ImageView) convertView;\n\t\t\tif (imageView == null) {\n\t\t\t\timageView = (ImageView) inflater.inflate(R.layout.item_gallery_image, parent, false);\n\t\t\t}\n\t\t\tImageLoader.getInstance().displayImage(IMAGE_URLS[position], imageView, options);\n\t\t\treturn imageView;\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "sample/src/main/java/com/nostra13/universalimageloader/sample/fragment/ImageGridFragment.java",
    "content": "/*******************************************************************************\n * Copyright 2011-2014 Sergey Tarasevich\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *******************************************************************************/\npackage com.nostra13.universalimageloader.sample.fragment;\n\nimport android.content.Context;\nimport android.graphics.Bitmap;\nimport android.os.Bundle;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.AdapterView;\nimport android.widget.AdapterView.OnItemClickListener;\nimport android.widget.BaseAdapter;\nimport android.widget.GridView;\nimport android.widget.ImageView;\nimport android.widget.ProgressBar;\nimport com.nostra13.universalimageloader.core.DisplayImageOptions;\nimport com.nostra13.universalimageloader.core.ImageLoader;\nimport com.nostra13.universalimageloader.core.assist.FailReason;\nimport com.nostra13.universalimageloader.core.listener.ImageLoadingProgressListener;\nimport com.nostra13.universalimageloader.core.listener.SimpleImageLoadingListener;\nimport com.nostra13.universalimageloader.sample.Constants;\nimport com.nostra13.universalimageloader.sample.R;\n\n/**\n * @author Sergey Tarasevich (nostra13[at]gmail[dot]com)\n */\npublic class ImageGridFragment extends AbsListViewBaseFragment {\n\n\tpublic static final int INDEX = 1;\n\n\t@Override\n\tpublic View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {\n\t\tView rootView = inflater.inflate(R.layout.fr_image_grid, container, false);\n\t\tlistView = (GridView) rootView.findViewById(R.id.grid);\n\t\t((GridView) listView).setAdapter(new ImageAdapter(getActivity()));\n\t\tlistView.setOnItemClickListener(new OnItemClickListener() {\n\t\t\t@Override\n\t\t\tpublic void onItemClick(AdapterView<?> parent, View view, int position, long id) {\n\t\t\t\tstartImagePagerActivity(position);\n\t\t\t}\n\t\t});\n\t\treturn rootView;\n\t}\n\n\tprivate static class ImageAdapter extends BaseAdapter {\n\n\t\tprivate static final String[] IMAGE_URLS = Constants.IMAGES;\n\n\t\tprivate LayoutInflater inflater;\n\n\t\tprivate DisplayImageOptions options;\n\n\t\tImageAdapter(Context context) {\n\t\t\tinflater = LayoutInflater.from(context);\n\n\t\t\toptions = new DisplayImageOptions.Builder()\n\t\t\t\t\t.showImageOnLoading(R.drawable.ic_stub)\n\t\t\t\t\t.showImageForEmptyUri(R.drawable.ic_empty)\n\t\t\t\t\t.showImageOnFail(R.drawable.ic_error)\n\t\t\t\t\t.cacheInMemory(true)\n\t\t\t\t\t.cacheOnDisk(true)\n\t\t\t\t\t.considerExifParams(true)\n\t\t\t\t\t.bitmapConfig(Bitmap.Config.RGB_565)\n\t\t\t\t\t.build();\n\t\t}\n\n\t\t@Override\n\t\tpublic int getCount() {\n\t\t\treturn IMAGE_URLS.length;\n\t\t}\n\n\t\t@Override\n\t\tpublic Object getItem(int position) {\n\t\t\treturn null;\n\t\t}\n\n\t\t@Override\n\t\tpublic long getItemId(int position) {\n\t\t\treturn position;\n\t\t}\n\n\t\t@Override\n\t\tpublic View getView(int position, View convertView, ViewGroup parent) {\n\t\t\tfinal ViewHolder holder;\n\t\t\tView view = convertView;\n\t\t\tif (view == null) {\n\t\t\t\tview = inflater.inflate(R.layout.item_grid_image, parent, false);\n\t\t\t\tholder = new ViewHolder();\n\t\t\t\tassert view != null;\n\t\t\t\tholder.imageView = (ImageView) view.findViewById(R.id.image);\n\t\t\t\tholder.progressBar = (ProgressBar) view.findViewById(R.id.progress);\n\t\t\t\tview.setTag(holder);\n\t\t\t} else {\n\t\t\t\tholder = (ViewHolder) view.getTag();\n\t\t\t}\n\n\t\t\tImageLoader.getInstance()\n\t\t\t\t\t.displayImage(IMAGE_URLS[position], holder.imageView, options, new SimpleImageLoadingListener() {\n\t\t\t\t\t\t@Override\n\t\t\t\t\t\tpublic void onLoadingStarted(String imageUri, View view) {\n\t\t\t\t\t\t\tholder.progressBar.setProgress(0);\n\t\t\t\t\t\t\tholder.progressBar.setVisibility(View.VISIBLE);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t@Override\n\t\t\t\t\t\tpublic void onLoadingFailed(String imageUri, View view, FailReason failReason) {\n\t\t\t\t\t\t\tholder.progressBar.setVisibility(View.GONE);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t@Override\n\t\t\t\t\t\tpublic void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) {\n\t\t\t\t\t\t\tholder.progressBar.setVisibility(View.GONE);\n\t\t\t\t\t\t}\n\t\t\t\t\t}, new ImageLoadingProgressListener() {\n\t\t\t\t\t\t@Override\n\t\t\t\t\t\tpublic void onProgressUpdate(String imageUri, View view, int current, int total) {\n\t\t\t\t\t\t\tholder.progressBar.setProgress(Math.round(100.0f * current / total));\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\n\t\t\treturn view;\n\t\t}\n\t}\n\n\tstatic class ViewHolder {\n\t\tImageView imageView;\n\t\tProgressBar progressBar;\n\t}\n}"
  },
  {
    "path": "sample/src/main/java/com/nostra13/universalimageloader/sample/fragment/ImageListFragment.java",
    "content": "/*******************************************************************************\n * Copyright 2011-2014 Sergey Tarasevich\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *******************************************************************************/\npackage com.nostra13.universalimageloader.sample.fragment;\n\nimport android.content.Context;\nimport android.graphics.Bitmap;\nimport android.graphics.Color;\nimport android.os.Bundle;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.AdapterView;\nimport android.widget.AdapterView.OnItemClickListener;\nimport android.widget.BaseAdapter;\nimport android.widget.ImageView;\nimport android.widget.ListView;\nimport android.widget.TextView;\n\nimport com.nostra13.universalimageloader.core.DisplayImageOptions;\nimport com.nostra13.universalimageloader.core.ImageLoader;\nimport com.nostra13.universalimageloader.core.display.CircleBitmapDisplayer;\nimport com.nostra13.universalimageloader.core.display.FadeInBitmapDisplayer;\nimport com.nostra13.universalimageloader.core.listener.ImageLoadingListener;\nimport com.nostra13.universalimageloader.core.listener.SimpleImageLoadingListener;\nimport com.nostra13.universalimageloader.sample.Constants;\nimport com.nostra13.universalimageloader.sample.R;\n\nimport java.util.Collections;\nimport java.util.LinkedList;\nimport java.util.List;\n\n/**\n * @author Sergey Tarasevich (nostra13[at]gmail[dot]com)\n */\npublic class ImageListFragment extends AbsListViewBaseFragment {\n\n\tpublic static final int INDEX = 0;\n\n\t@Override\n\tpublic View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {\n\t\tView rootView = inflater.inflate(R.layout.fr_image_list, container, false);\n\t\tlistView = (ListView) rootView.findViewById(android.R.id.list);\n\t\t((ListView) listView).setAdapter(new ImageAdapter(getActivity()));\n\t\tlistView.setOnItemClickListener(new OnItemClickListener() {\n\t\t\t@Override\n\t\t\tpublic void onItemClick(AdapterView<?> parent, View view, int position, long id) {\n\t\t\t\tstartImagePagerActivity(position);\n\t\t\t}\n\t\t});\n\t\treturn rootView;\n\t}\n\n\t@Override\n\tpublic void onDestroy() {\n\t\tsuper.onDestroy();\n\t\tAnimateFirstDisplayListener.displayedImages.clear();\n\t}\n\n\tprivate static class ImageAdapter extends BaseAdapter {\n\n\t\tprivate static final String[] IMAGE_URLS = Constants.IMAGES;\n\n\t\tprivate LayoutInflater inflater;\n\t\tprivate ImageLoadingListener animateFirstListener = new AnimateFirstDisplayListener();\n\n\t\tprivate DisplayImageOptions options;\n\n\t\tImageAdapter(Context context) {\n\t\t\tinflater = LayoutInflater.from(context);\n\n\t\t\toptions = new DisplayImageOptions.Builder()\n\t\t\t\t\t.showImageOnLoading(R.drawable.ic_stub)\n\t\t\t\t\t.showImageForEmptyUri(R.drawable.ic_empty)\n\t\t\t\t\t.showImageOnFail(R.drawable.ic_error)\n\t\t\t\t\t.cacheInMemory(true)\n\t\t\t\t\t.cacheOnDisk(true)\n\t\t\t\t\t.considerExifParams(true)\n\t\t\t\t\t.displayer(new CircleBitmapDisplayer(Color.WHITE, 5))\n\t\t\t\t\t.build();\n\t\t}\n\n\t\t@Override\n\t\tpublic int getCount() {\n\t\t\treturn IMAGE_URLS.length;\n\t\t}\n\n\t\t@Override\n\t\tpublic Object getItem(int position) {\n\t\t\treturn position;\n\t\t}\n\n\t\t@Override\n\t\tpublic long getItemId(int position) {\n\t\t\treturn position;\n\t\t}\n\n\t\t@Override\n\t\tpublic View getView(final int position, View convertView, ViewGroup parent) {\n\t\t\tView view = convertView;\n\t\t\tfinal ViewHolder holder;\n\t\t\tif (convertView == null) {\n\t\t\t\tview = inflater.inflate(R.layout.item_list_image, parent, false);\n\t\t\t\tholder = new ViewHolder();\n\t\t\t\tholder.text = (TextView) view.findViewById(R.id.text);\n\t\t\t\tholder.image = (ImageView) view.findViewById(R.id.image);\n\t\t\t\tview.setTag(holder);\n\t\t\t} else {\n\t\t\t\tholder = (ViewHolder) view.getTag();\n\t\t\t}\n\n\t\t\tholder.text.setText(\"Item \" + (position + 1));\n\n\t\t\tImageLoader.getInstance().displayImage(IMAGE_URLS[position], holder.image, options, animateFirstListener);\n\n\t\t\treturn view;\n\t\t}\n\t}\n\n\tstatic class ViewHolder {\n\t\tTextView text;\n\t\tImageView image;\n\t}\n\n\tprivate static class AnimateFirstDisplayListener extends SimpleImageLoadingListener {\n\n\t\tstatic final List<String> displayedImages = Collections.synchronizedList(new LinkedList<String>());\n\n\t\t@Override\n\t\tpublic void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) {\n\t\t\tif (loadedImage != null) {\n\t\t\t\tImageView imageView = (ImageView) view;\n\t\t\t\tboolean firstDisplay = !displayedImages.contains(imageUri);\n\t\t\t\tif (firstDisplay) {\n\t\t\t\t\tFadeInBitmapDisplayer.animate(imageView, 500);\n\t\t\t\t\tdisplayedImages.add(imageUri);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "sample/src/main/java/com/nostra13/universalimageloader/sample/fragment/ImagePagerFragment.java",
    "content": "/*******************************************************************************\n * Copyright 2011-2014 Sergey Tarasevich\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *******************************************************************************/\npackage com.nostra13.universalimageloader.sample.fragment;\n\nimport android.content.Context;\nimport android.graphics.Bitmap;\nimport android.os.Bundle;\nimport android.os.Parcelable;\nimport android.support.v4.view.PagerAdapter;\nimport android.support.v4.view.ViewPager;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.ImageView;\nimport android.widget.ProgressBar;\nimport android.widget.Toast;\nimport com.nostra13.universalimageloader.core.DisplayImageOptions;\nimport com.nostra13.universalimageloader.core.ImageLoader;\nimport com.nostra13.universalimageloader.core.assist.FailReason;\nimport com.nostra13.universalimageloader.core.assist.ImageScaleType;\nimport com.nostra13.universalimageloader.core.display.FadeInBitmapDisplayer;\nimport com.nostra13.universalimageloader.core.listener.SimpleImageLoadingListener;\nimport com.nostra13.universalimageloader.sample.Constants;\nimport com.nostra13.universalimageloader.sample.R;\n\n/**\n * @author Sergey Tarasevich (nostra13[at]gmail[dot]com)\n */\npublic class ImagePagerFragment extends BaseFragment {\n\n\tpublic static final int INDEX = 2;\n\n\t@Override\n\tpublic View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {\n\t\tView rootView = inflater.inflate(R.layout.fr_image_pager, container, false);\n\t\tViewPager pager = (ViewPager) rootView.findViewById(R.id.pager);\n\t\tpager.setAdapter(new ImageAdapter(getActivity()));\n\t\tpager.setCurrentItem(getArguments().getInt(Constants.Extra.IMAGE_POSITION, 0));\n\t\treturn rootView;\n\t}\n\n\tprivate static class ImageAdapter extends PagerAdapter {\n\n\t\tprivate static final String[] IMAGE_URLS = Constants.IMAGES;\n\n\t\tprivate LayoutInflater inflater;\n\t\tprivate DisplayImageOptions options;\n\n\t\tImageAdapter(Context context) {\n\t\t\tinflater = LayoutInflater.from(context);\n\n\t\t\toptions = new DisplayImageOptions.Builder()\n\t\t\t\t\t.showImageForEmptyUri(R.drawable.ic_empty)\n\t\t\t\t\t.showImageOnFail(R.drawable.ic_error)\n\t\t\t\t\t.resetViewBeforeLoading(true)\n\t\t\t\t\t.cacheOnDisk(true)\n\t\t\t\t\t.imageScaleType(ImageScaleType.EXACTLY)\n\t\t\t\t\t.bitmapConfig(Bitmap.Config.RGB_565)\n\t\t\t\t\t.considerExifParams(true)\n\t\t\t\t\t.displayer(new FadeInBitmapDisplayer(300))\n\t\t\t\t\t.build();\n\t\t}\n\n\t\t@Override\n\t\tpublic void destroyItem(ViewGroup container, int position, Object object) {\n\t\t\tcontainer.removeView((View) object);\n\t\t}\n\n\t\t@Override\n\t\tpublic int getCount() {\n\t\t\treturn IMAGE_URLS.length;\n\t\t}\n\n\t\t@Override\n\t\tpublic Object instantiateItem(ViewGroup view, int position) {\n\t\t\tView imageLayout = inflater.inflate(R.layout.item_pager_image, view, false);\n\t\t\tassert imageLayout != null;\n\t\t\tImageView imageView = (ImageView) imageLayout.findViewById(R.id.image);\n\t\t\tfinal ProgressBar spinner = (ProgressBar) imageLayout.findViewById(R.id.loading);\n\n\t\t\tImageLoader.getInstance().displayImage(IMAGE_URLS[position], imageView, options, new SimpleImageLoadingListener() {\n\t\t\t\t@Override\n\t\t\t\tpublic void onLoadingStarted(String imageUri, View view) {\n\t\t\t\t\tspinner.setVisibility(View.VISIBLE);\n\t\t\t\t}\n\n\t\t\t\t@Override\n\t\t\t\tpublic void onLoadingFailed(String imageUri, View view, FailReason failReason) {\n\t\t\t\t\tString message = null;\n\t\t\t\t\tswitch (failReason.getType()) {\n\t\t\t\t\t\tcase IO_ERROR:\n\t\t\t\t\t\t\tmessage = \"Input/Output error\";\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase DECODING_ERROR:\n\t\t\t\t\t\t\tmessage = \"Image can't be decoded\";\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase NETWORK_DENIED:\n\t\t\t\t\t\t\tmessage = \"Downloads are denied\";\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase OUT_OF_MEMORY:\n\t\t\t\t\t\t\tmessage = \"Out Of Memory error\";\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase UNKNOWN:\n\t\t\t\t\t\t\tmessage = \"Unknown error\";\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tToast.makeText(view.getContext(), message, Toast.LENGTH_SHORT).show();\n\n\t\t\t\t\tspinner.setVisibility(View.GONE);\n\t\t\t\t}\n\n\t\t\t\t@Override\n\t\t\t\tpublic void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) {\n\t\t\t\t\tspinner.setVisibility(View.GONE);\n\t\t\t\t}\n\t\t\t});\n\n\t\t\tview.addView(imageLayout, 0);\n\t\t\treturn imageLayout;\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean isViewFromObject(View view, Object object) {\n\t\t\treturn view.equals(object);\n\t\t}\n\n\t\t@Override\n\t\tpublic void restoreState(Parcelable state, ClassLoader loader) {\n\t\t}\n\n\t\t@Override\n\t\tpublic Parcelable saveState() {\n\t\t\treturn null;\n\t\t}\n\t}\n}"
  },
  {
    "path": "sample/src/main/java/com/nostra13/universalimageloader/sample/widget/UILWidgetProvider.java",
    "content": "/*******************************************************************************\n * Copyright 2011-2013 Sergey Tarasevich\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *******************************************************************************/\npackage com.nostra13.universalimageloader.sample.widget;\n\nimport android.appwidget.AppWidgetManager;\nimport android.appwidget.AppWidgetProvider;\nimport android.content.Context;\nimport android.graphics.Bitmap;\nimport android.view.View;\nimport android.widget.RemoteViews;\nimport com.nostra13.universalimageloader.core.DisplayImageOptions;\nimport com.nostra13.universalimageloader.core.ImageLoader;\nimport com.nostra13.universalimageloader.core.assist.ImageSize;\nimport com.nostra13.universalimageloader.core.listener.SimpleImageLoadingListener;\nimport com.nostra13.universalimageloader.sample.R;\nimport com.nostra13.universalimageloader.sample.UILApplication;\n\nimport static com.nostra13.universalimageloader.sample.Constants.IMAGES;\n\n/**\n * Example widget provider\n * \n * @author Sergey Tarasevich (nostra13[at]gmail[dot]com)\n */\npublic class UILWidgetProvider extends AppWidgetProvider {\n\n\tprivate static DisplayImageOptions displayOptions;\n\n\tstatic {\n\t\tdisplayOptions = DisplayImageOptions.createSimple();\n\t}\n\n\t@Override\n\tpublic void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {\n\t\tUILApplication.initImageLoader(context);\n\n\t\tfinal int widgetCount = appWidgetIds.length;\n\t\tfor (int i = 0; i < widgetCount; i++) {\n\t\t\tint appWidgetId = appWidgetIds[i];\n\t\t\tupdateAppWidget(context, appWidgetManager, appWidgetId);\n\t\t}\n\t}\n\n\tstatic void updateAppWidget(Context context, final AppWidgetManager appWidgetManager, final int appWidgetId) {\n\t\tfinal RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.widget);\n\n\t\tImageSize minImageSize = new ImageSize(70, 70); // 70 - approximate size of ImageView in widget\n\t\tImageLoader.getInstance()\n\t\t\t\t.loadImage(IMAGES[0], minImageSize, displayOptions, new SimpleImageLoadingListener() {\n\t\t\t@Override\n\t\t\tpublic void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) {\n\t\t\t\tviews.setImageViewBitmap(R.id.image_left, loadedImage);\n\t\t\t\tappWidgetManager.updateAppWidget(appWidgetId, views);\n\t\t\t}\n\t\t});\n\t\tImageLoader.getInstance()\n\t\t\t\t.loadImage(IMAGES[1], minImageSize, displayOptions, new SimpleImageLoadingListener() {\n\t\t\t@Override\n\t\t\tpublic void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) {\n\t\t\t\tviews.setImageViewBitmap(R.id.image_right, loadedImage);\n\t\t\t\tappWidgetManager.updateAppWidget(appWidgetId, views);\n\t\t\t}\n\t\t});\n\t}\n}\n"
  },
  {
    "path": "sample/src/main/res/layout/ac_complex.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<android.support.v4.view.ViewPager xmlns:android=\"http://schemas.android.com/apk/res/android\"\n\tandroid:id=\"@+id/pager\"\n\tandroid:layout_width=\"match_parent\"\n\tandroid:layout_height=\"match_parent\">\n\n\t<android.support.v4.view.PagerTitleStrip\n\t\tandroid:id=\"@+id/pager_title_strip\"\n\t\tandroid:layout_width=\"match_parent\"\n\t\tandroid:layout_height=\"30dp\"\n\t\tandroid:layout_gravity=\"top\"\n\t\tandroid:paddingTop=\"4dp\"\n\t\tandroid:paddingBottom=\"4dp\" />\n</android.support.v4.view.ViewPager>\n"
  },
  {
    "path": "sample/src/main/res/layout/ac_home.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<ScrollView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n\tandroid:layout_width=\"match_parent\"\n\tandroid:layout_height=\"match_parent\">\n\n\t<LinearLayout\n\t\tandroid:layout_width=\"match_parent\"\n\t\tandroid:layout_height=\"wrap_content\"\n\t\tandroid:orientation=\"vertical\"\n\t\tandroid:gravity=\"center\">\n\n\t\t<TextView\n\t\t\tandroid:layout_width=\"fill_parent\"\n\t\t\tandroid:layout_height=\"wrap_content\"\n\t\t\tandroid:gravity=\"center\"\n\t\t\tandroid:paddingBottom=\"10dip\"\n\t\t\tandroid:paddingTop=\"20dip\"\n\t\t\tandroid:text=\"@string/label_examples\"\n\t\t\tandroid:textSize=\"24sp\" />\n\n\t\t<Button\n\t\t\tandroid:layout_width=\"320dp\"\n\t\t\tandroid:layout_height=\"wrap_content\"\n\t\t\tandroid:layout_marginLeft=\"10dip\"\n\t\t\tandroid:layout_marginRight=\"10dip\"\n\t\t\tandroid:onClick=\"onImageListClick\"\n\t\t\tandroid:text=\"@string/button_image_list\" />\n\n\t\t<Button\n\t\t\tandroid:layout_width=\"320dp\"\n\t\t\tandroid:layout_height=\"wrap_content\"\n\t\t\tandroid:layout_marginLeft=\"10dip\"\n\t\t\tandroid:layout_marginRight=\"10dip\"\n\t\t\tandroid:onClick=\"onImageGridClick\"\n\t\t\tandroid:text=\"@string/button_image_grid\" />\n\n\t\t<Button\n\t\t\tandroid:layout_width=\"320dp\"\n\t\t\tandroid:layout_height=\"wrap_content\"\n\t\t\tandroid:layout_marginLeft=\"10dip\"\n\t\t\tandroid:layout_marginRight=\"10dip\"\n\t\t\tandroid:onClick=\"onImagePagerClick\"\n\t\t\tandroid:text=\"@string/button_image_pager\" />\n\n\t\t<Button\n\t\t\tandroid:layout_width=\"320dp\"\n\t\t\tandroid:layout_height=\"wrap_content\"\n\t\t\tandroid:layout_marginLeft=\"10dip\"\n\t\t\tandroid:layout_marginRight=\"10dip\"\n\t\t\tandroid:onClick=\"onImageGalleryClick\"\n\t\t\tandroid:text=\"@string/button_image_gallery\" />\n\n\t\t<Button\n\t\t\tandroid:layout_width=\"320dp\"\n\t\t\tandroid:layout_height=\"wrap_content\"\n\t\t\tandroid:layout_marginLeft=\"10dip\"\n\t\t\tandroid:layout_marginRight=\"10dip\"\n\t\t\tandroid:onClick=\"onFragmentsClick\"\n\t\t\tandroid:text=\"@string/button_list_and_grid\" />\n\t</LinearLayout>\n\n</ScrollView>"
  },
  {
    "path": "sample/src/main/res/layout/fr_image_gallery.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Gallery xmlns:android=\"http://schemas.android.com/apk/res/android\"\n\tandroid:id=\"@+id/gallery\"\n\tandroid:layout_width=\"match_parent\"\n\tandroid:layout_height=\"wrap_content\"\n\tandroid:layout_gravity=\"center_vertical\"\n\tandroid:spacing=\"1dip\" />\n"
  },
  {
    "path": "sample/src/main/res/layout/fr_image_grid.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<GridView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n\tandroid:id=\"@+id/grid\"\n\tandroid:layout_width=\"match_parent\"\n\tandroid:layout_height=\"match_parent\"\n\tandroid:gravity=\"center\"\n\tandroid:horizontalSpacing=\"4dip\"\n\tandroid:numColumns=\"3\"\n\tandroid:stretchMode=\"columnWidth\"\n\tandroid:verticalSpacing=\"4dip\"\n\tandroid:padding=\"4dip\" />\n"
  },
  {
    "path": "sample/src/main/res/layout/fr_image_list.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<ListView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n\tandroid:id=\"@android:id/list\"\n\tandroid:layout_width=\"match_parent\"\n\tandroid:layout_height=\"match_parent\" />\n"
  },
  {
    "path": "sample/src/main/res/layout/fr_image_pager.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<android.support.v4.view.ViewPager xmlns:android=\"http://schemas.android.com/apk/res/android\"\n\tandroid:id=\"@+id/pager\"\n\tandroid:layout_width=\"match_parent\"\n\tandroid:layout_height=\"match_parent\" />\n"
  },
  {
    "path": "sample/src/main/res/layout/item_gallery_image.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<ImageView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n\tandroid:id=\"@+id/image\"\n\tandroid:layout_width=\"120dip\"\n\tandroid:layout_height=\"120dip\"\n\tandroid:layout_gravity=\"center\"\n\tandroid:adjustViewBounds=\"true\"\n\tandroid:contentDescription=\"@string/descr_image\"\n\tandroid:scaleType=\"centerCrop\" />\n"
  },
  {
    "path": "sample/src/main/res/layout/item_grid_image.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<FrameLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n\tandroid:layout_width=\"match_parent\"\n\tandroid:layout_height=\"120dip\">\n\n\t<ImageView\n\t\tandroid:id=\"@+id/image\"\n\t\tandroid:layout_width=\"match_parent\"\n\t\tandroid:layout_height=\"120dip\"\n\t\tandroid:adjustViewBounds=\"true\"\n\t\tandroid:contentDescription=\"@string/descr_image\"\n\t\tandroid:scaleType=\"centerCrop\" />\n\n\t<ProgressBar\n\t\tandroid:id=\"@+id/progress\"\n\t\tandroid:layout_width=\"match_parent\"\n\t\tandroid:layout_height=\"wrap_content\"\n\t\tandroid:indeterminate=\"false\"\n\t\tandroid:max=\"100\"\n\t\tandroid:layout_gravity=\"bottom\"\n\t\tstyle=\"@style/ProgressBarStyle\" />\n</FrameLayout>"
  },
  {
    "path": "sample/src/main/res/layout/item_list_image.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n\tandroid:layout_width=\"match_parent\"\n\tandroid:layout_height=\"wrap_content\">\n\n\t<ImageView\n\t\tandroid:id=\"@+id/image\"\n\t\tandroid:layout_width=\"72dip\"\n\t\tandroid:layout_height=\"72dip\"\n\t\tandroid:layout_margin=\"3dip\"\n\t\tandroid:adjustViewBounds=\"true\"\n\t\tandroid:contentDescription=\"@string/descr_image\"\n\t\tandroid:scaleType=\"centerCrop\" />\n\n\t<TextView\n\t\tandroid:id=\"@+id/text\"\n\t\tandroid:layout_width=\"fill_parent\"\n\t\tandroid:layout_height=\"wrap_content\"\n\t\tandroid:layout_gravity=\"start|center_vertical\"\n\t\tandroid:layout_marginLeft=\"20dip\"\n\t\tandroid:textSize=\"22sp\" />\n\n</LinearLayout>"
  },
  {
    "path": "sample/src/main/res/layout/item_pager_image.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<FrameLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n\tandroid:layout_width=\"match_parent\"\n\tandroid:layout_height=\"match_parent\"\n\tandroid:padding=\"1dip\">\n\n\t<ImageView\n\t\tandroid:id=\"@+id/image\"\n\t\tandroid:layout_width=\"wrap_content\"\n\t\tandroid:layout_height=\"wrap_content\"\n\t\tandroid:layout_gravity=\"center\"\n\t\tandroid:adjustViewBounds=\"true\"\n\t\tandroid:contentDescription=\"@string/descr_image\" />\n\n\t<ProgressBar\n\t\tandroid:id=\"@+id/loading\"\n\t\tandroid:layout_width=\"wrap_content\"\n\t\tandroid:layout_height=\"wrap_content\"\n\t\tandroid:layout_gravity=\"center\"\n\t\tandroid:visibility=\"gone\" />\n\n</FrameLayout>"
  },
  {
    "path": "sample/src/main/res/layout/widget.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n\tandroid:layout_width=\"match_parent\"\n\tandroid:layout_height=\"match_parent\"\n\tandroid:layout_margin=\"8dip\"\n\tandroid:orientation=\"horizontal\">\n\n\t<ImageView\n\t\tandroid:id=\"@+id/image_left\"\n\t\tandroid:layout_width=\"0dip\"\n\t\tandroid:layout_height=\"match_parent\"\n\t\tandroid:layout_weight=\"1\"\n\t\tandroid:contentDescription=\"@string/descr_image\"\n\t\tandroid:paddingBottom=\"4dip\"\n\t\tandroid:paddingLeft=\"8dip\"\n\t\tandroid:paddingRight=\"4dip\"\n\t\tandroid:paddingTop=\"4dip\"\n\t\tandroid:src=\"@drawable/ic_stub\" />\n\n\t<ImageView\n\t\tandroid:id=\"@+id/image_right\"\n\t\tandroid:layout_width=\"0dip\"\n\t\tandroid:layout_height=\"match_parent\"\n\t\tandroid:layout_weight=\"1\"\n\t\tandroid:contentDescription=\"@string/descr_image\"\n\t\tandroid:paddingBottom=\"4dip\"\n\t\tandroid:paddingLeft=\"4dip\"\n\t\tandroid:paddingRight=\"8dip\"\n\t\tandroid:paddingTop=\"4dip\"\n\t\tandroid:src=\"@drawable/ic_stub\" />\n\n</LinearLayout>"
  },
  {
    "path": "sample/src/main/res/menu/main_menu.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<menu xmlns:android=\"http://schemas.android.com/apk/res/android\" >\n\n    <item\n        android:id=\"@+id/item_clear_memory_cache\"\n        android:title=\"@string/menu_item_clear_memory_cache\"/>\n    <item\n        android:id=\"@+id/item_clear_disc_cache\"\n        android:title=\"@string/menu_item_clear_disc_cache\"/>\n    <item\n        android:id=\"@+id/item_pause_on_scroll\"\n        android:checkable=\"true\"\n        android:title=\"@string/menu_item_pause_on_scroll\"\n        android:visible=\"false\"/>\n    <item\n        android:id=\"@+id/item_pause_on_fling\"\n        android:checkable=\"true\"\n        android:title=\"@string/menu_item_pause_on_fling\"\n        android:visible=\"false\"/>\n\n</menu>"
  },
  {
    "path": "sample/src/main/res/values/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n\n\t<!-- Activity titles -->\n\t<string name=\"app_name\">Universal Image Loader</string>\n\t<string name=\"ac_name_image_list\">Image List Example</string>\n\t<string name=\"ac_name_image_grid\">Image Grid Example</string>\n\t<string name=\"ac_name_image_pager\">Image Pager Example</string>\n\t<string name=\"ac_name_image_gallery\">Image Gallery Example</string>\n\t<string name=\"ac_name_complex\">Complex Example</string>\n\t<!-- Labels -->\n\t<string name=\"label_examples\">Examples</string>\n\t<string name=\"button_image_list\">ListView</string>\n\t<string name=\"button_image_grid\">GridView</string>\n\t<string name=\"button_image_pager\">ViewPager</string>\n\t<string name=\"button_image_gallery\">Gallery</string>\n\t<string name=\"button_list_and_grid\">ViewPager (ListView + GridView)</string>\n\n\t<string name=\"title_list\">List</string>\n\t<string name=\"title_grid\">Grid</string>\n\n\t<string name=\"menu_item_clear_memory_cache\">Clear memory cache</string>\n\t<string name=\"menu_item_clear_disc_cache\">Clear disc cache</string>\n\t<string name=\"menu_item_pause_on_scroll\">Pause on scroll</string>\n\t<string name=\"menu_item_pause_on_fling\">Pause on fling</string>\n\n\t<!-- Content descriptions -->\n\t<string name=\"descr_image\">Image</string>\n\n</resources>"
  },
  {
    "path": "sample/src/main/res/values/styles.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n\n    <style name=\"ProgressBarStyle\" parent=\"@android:style/Widget.ProgressBar.Horizontal\"/>\n\n</resources>"
  },
  {
    "path": "sample/src/main/res/values-v11/styles.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n\n    <style name=\"ProgressBarStyle\" parent=\"@android:style/Widget.Holo.ProgressBar.Horizontal\"/>\n\n</resources>"
  },
  {
    "path": "sample/src/main/res/xml/widget_provider.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<appwidget-provider xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:initialLayout=\"@layout/widget\"\n    android:minHeight=\"40dp\"\n    android:minWidth=\"110dp\"\n    android:updatePeriodMillis=\"86400000\" />\n\n"
  },
  {
    "path": "settings.gradle",
    "content": "include ':library', ':sample'\n"
  }
]