#ImageViewEx
---
Extension of Android's ImageView that supports animated GIFs and includes a better density management.
##Author
**Francesco Pontillo** and **Sebastiano Poggi**
##Description
The **ImageViewEx** is an extension of the standard Android `ImageView` that fills in one of the biggest gaps in the standard `ImageView`: displaying **animated GIFs**.
The Android Framework `Drawable` class, in fact, only supports static GIFs. This View is able to receive a raw image in `byte[]` form, bypassing the standard `Drawable`s handling and thus providing broader support.
The `ImageViewEx` also allows you to specify what has to be considered the default image density when loading images from raw data. Android defaults to considering `mdpi` as the baseline, but using `setInDensity` you can choose to change it to whatever value you like (we suggest to stick to standard abstracted density buckets like `hdpi` thou).
The following is a brief documentation of the classes, methods and views included in this library.
##Index
1. [Import and usage](#import)
2. [ImageViewEx](#imageviewex)
* [Animated GIF](#animated-gifs)
* [Conditional animation](#conditional-animation)
* [Density level](#density-level)
* [Fill direction](#fillDirection)
* [Regular behavior](#regular-behavior)
* [Example of use](#imageviewex-example)
3. [ImageViewNext](#imageviewnext)
* [Remote loading and caching of images](#remote-loading)
* [Loading and Error Drawables](#loading-error-drawables)
* [Getting images from the Internet](#getting-from-internet)
* [Handling network failures](#network-failures)
* [Maximum number of threads](#thread-number)
* [Example of use](#imageviewnext-example)
4. [Known issues and workarounds](#issues-workarounds)
5. [Some boring stuff](#boring-stuff)
6. [Version history](#history)
7. [License](#license)
<a name="import"/>
##Import and usage
This library requires Android **API level 8** (Android 2.2) as minimum, and targets the Android **API level 17**.
You need to include in your destination project:
* [JakeWharton/DiskLruCache](https://github.com/JakeWharton/DiskLruCache) library, used for caching on disk.
* [foxykeep/DataDroid](https://github.com/foxykeep/DataDroid) library, used for handling async operations.
* [square/okhttp](https://github.com/square/okhttp) library, for a better connection management.
The Eclipse project included specifies this is a library project, although it provides two basic Activities for testing the extended `ImageView`s provided.
For your application, you need to include the permissions specified in the AndroidManifest of the library, which are:
* `android.permission.INTERNET` for getting images on the internet
* `android.permission.ACCESS_NETWORK_STATE` to monitor the network state
* `android.permission.WRITE_EXTERNAL_STORAGE` for making the cache access and write the SD card
The `ImageViewExService` service is also internally used by `ImageViewNext` for handling asynchronous operation. You need to declare this service in your `AndroidManifest.xml`:
```xml
<service android:name="net.frakbot.imageviewex.service.ImageViewExService"/>
```
<a name="imageviewex"/>
##ImageViewEx
`ImageViewEx` is an extended `ImageView` that supports some additional methods for your every-day life.
<a name="animated-gifs"/>
###Animated GIF
The best thing about `ImageViewEx` is its **automatic handling of animated GIF images** starting from a simple `byte[]`.
Simply call `img.setSource(mGIF)` and see your GIF animating. Note that there may be some issues under some conditions (see [Known issues and workarounds](#known-issues-and-workarounds)).
What if you don't know if an image is a GIF or a regular one? No problem, simply call `setSource` and `ImageViewEx` will do the rest, displaying your image as a regular one or an animated GIF when necessary.
Accessory methods are:
* `void setFramesDuration(int duration)` to set the duration, in milliseconds, of each frame during the GIF animation (it is the refresh period)
* `void setFPS(float fps)` to set the number of frames per second during the GIF animation
* `boolean isPlaying()` to know if your GIF is playing
* `boolean canPlay()` to know if your source set by `setSource` was an animated GIF after all
* `int getFramesDuration()` to get the frame duration, in milliseconds
* `float getFPS()` to get the number of frames per second during the GIF animation
* `void play()` to start the GIF, if it hasn't started yet.
* `void pause()` to pause the GIF, if it has started
* `void stop()` to stop playing the GIF, if it has started
<a name="conditional-animation"/>
###Conditional animation
As mentioned earlier, you may not want to animate some GIF under some conditions.
So we've provided you with a **conditional method** that gets triggered just before each animation begins, `boolean canAnimate()`. This method should be overridden by your custom implementation. By default, it always returns `true`. This method decides whether animations can be started for this instance of `ImageViewEx`.
If you don't want to have another class extending `ImageViewEx` and your `canAnimate()` returns the same value throughout your application, you can use the following
```java
ImageViewNext.setCanAlwaysAnimate(false);
```
to specify you never want to animate GIFs. If you don't set any value to `setCanAlwaysAnimate`, it defaults to `true`. The result you get by setting the value to `false` is that it will stop all animations, no matter what `canAnimate()` returns.
You can check the current behavior by calling the `static boolean getCanAlwaysAnimate()` method.
<a name="density-level"/>
###Density Level
You can set a **specific density to simulate** for every instance of `ImageViewEx` by using the following methods:
* `static void setClassLevelDensity(int classLevelDensity)` to set a specific density for every image
* `static void removeClassLevelDensity()` to remove the class-level customization
* `static boolean isClassLevelDensitySet()`, checks if a class-level density has been set
* `static int getClassLevelDensity()`, gets the set class-level density, or null if none has been set
You can even set a density for just one of your `ImageViewEx`s:
* `void setDensity(int fixedDensity)`, to set the density for a particular instance of `ImageViewEx`
* `int getDensity()`, gets the set density for a particular instance of `ImageViewEx` (an instance-level density has higher priority over a class-level density)
* `void dontOverrideDensity()`, restores the regular density of the `ImageViewEx`
<a name="fillDirection"/>
###Fill direction
The `ImageViewEx` has one unique feature: it allows you to decide which direction to fit the image on, and then resize
the other dimension (this function implies `adjustViewBounds`) to show the scaled image. For example, you can use this
to show a banner which fills the whole horizontal available space (the `ImageViewEx` has
`android:layout_width="match_parent"` and `android:layout_height="wrap_content"`, plus
`android:adjustViewBounds="true"`).
Setting `fillDirection="horizontal"` will prioritize filling the available horizontal space while keeping the image
aspect ratio and expanding the `ImageViewEx` to fit the height.
<a name="regular-behavior"/>
###Regular behavior
`ImageViewEx` is, after all, a regular `ImageView`, so you can go ahead and use its regular methods:
* `void setImageResource(int resId)`
* `void setImageDrawable(Drawable drawable)`
* `void setImageBitmap(Bitmap bm)`
* and so on.
<a name="imageviewex-example"/>
###Example of use
```java
// Disables animation, behaving like a regular ImageView,
// except you can still set byte[] as the source
ImageViewEx.setCanAlwaysAnimate(false);
// Sets a default density for all of the images in each ImageViewEx.
ImageViewEx.setClassLevelDensity(DisplayMetrics.DENSITY_MEDIUM);
// Sets a density for the img1 only.
// Changing the density after an object has