From 42f8427810bf3ccebf1c8c38ccb0d82c0ac3ab64 Mon Sep 17 00:00:00 2001 From: Antoine Gerard Date: Mon, 16 Oct 2017 20:02:43 +0200 Subject: [PATCH 01/19] Started an implementation of gifs in BitmapDownloader --- library/build.gradle | 6 +- .../download/BasisBitmapDownloader.java | 50 +- .../download/DownloadInstructions.java | 29 + .../droid4me/download/GifDecoder.java | 928 ++++++++++++++++++ 4 files changed, 1008 insertions(+), 5 deletions(-) create mode 100644 library/src/main/java/com/smartnsoft/droid4me/download/GifDecoder.java diff --git a/library/build.gradle b/library/build.gradle index 7ce54bfa..4e7768b5 100644 --- a/library/build.gradle +++ b/library/build.gradle @@ -5,7 +5,7 @@ apply plugin: "maven-publish" ext { - appCompatVersion="25.4.0" + appCompatVersion = "25.4.0" } android @@ -19,7 +19,7 @@ android targetSdkVersion 25 versionCode 20 - versionName "2.5.3" + versionName "2.5.4-SNAPSHOT" } buildTypes @@ -147,7 +147,7 @@ bintray { name = android.defaultConfig.versionName desc = "droid4me is a framework library dedicated to the development of Android applications" - released = new Date() + released = new Date() vcsTag = "droid4me-" + android.defaultConfig.versionName } } diff --git a/library/src/main/java/com/smartnsoft/droid4me/download/BasisBitmapDownloader.java b/library/src/main/java/com/smartnsoft/droid4me/download/BasisBitmapDownloader.java index baeebbc6..6fb2c602 100644 --- a/library/src/main/java/com/smartnsoft/droid4me/download/BasisBitmapDownloader.java +++ b/library/src/main/java/com/smartnsoft/droid4me/download/BasisBitmapDownloader.java @@ -22,6 +22,8 @@ package com.smartnsoft.droid4me.download; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.util.HashSet; @@ -643,6 +645,47 @@ protected final void onBitmapReady(boolean allright, BitmapClass bitmap) } + protected final boolean checkIfInpustreamIsAGif(InputStream inputStream) + { + final ByteArrayOutputStream buffer = new ByteArrayOutputStream(); + int nRead; + boolean ok = false; + final byte[] data = new byte[16384]; + + try + { + while ((nRead = inputStream.read(data, 0, data.length)) != -1) + { + buffer.write(data, 0, nRead); + } + buffer.flush(); + + int index = 0; + while (index < 3) + { + if (data[index] == 46 || data[index] == 47 || data[index] == 49) + { + ok = true; + index++; + } + else + { + ok = false; + break; + } + } + } + catch (IOException exception) + { + if (log.isWarnEnabled() == true) + { + log.warn("Problem occured with the inputsream", exception); + } + } + + return ok; + } + // TODO: define a pool of Command objects, so as to minimize GC, if possible private final class PreCommand extends BasisCommand @@ -1084,8 +1127,11 @@ public final void onDownloaded(InputStream inputStream) final BitmapClass bitmap = fromInputStreamToBitmap(inputStream); if (bitmap == null) { - onBitmapReady(false, null); - return; + if (checkIfInpustreamIsAGif(inputStream) == false) + { + onBitmapReady(false, null); + return; + } } // We put in cache the bitmap diff --git a/library/src/main/java/com/smartnsoft/droid4me/download/DownloadInstructions.java b/library/src/main/java/com/smartnsoft/droid4me/download/DownloadInstructions.java index 7b73a05a..e309b4ef 100644 --- a/library/src/main/java/com/smartnsoft/droid4me/download/DownloadInstructions.java +++ b/library/src/main/java/com/smartnsoft/droid4me/download/DownloadInstructions.java @@ -117,6 +117,21 @@ public Bitmap getBitmap() } + public final static class BitamapleGif + implements Bitmapable + { + + public int getSizeInBytes() + { + return 0; + } + + public void recycle() + { + + } + } + /** * An implementation of the {@link Viewable} interface specific to the Android platform. */ @@ -467,6 +482,20 @@ protected Bitmap convertInputStreamToBitmap(InputStream inputStream, String bitm } + /** + * Return the downloaded InputStream + * + * @param inputStream + * @param bitmaUid + * @param imageSpecs + * @param url + * @return + */ + protected InputStream rawInputStream(InputStream inputStream, String bitmaUid, Object imageSpecs, String url) + { + return inputStream; + } + /** * We do not want that container class to be instantiated. */ diff --git a/library/src/main/java/com/smartnsoft/droid4me/download/GifDecoder.java b/library/src/main/java/com/smartnsoft/droid4me/download/GifDecoder.java new file mode 100644 index 00000000..07b7bf98 --- /dev/null +++ b/library/src/main/java/com/smartnsoft/droid4me/download/GifDecoder.java @@ -0,0 +1,928 @@ +package com.smartnsoft.droid4me.download; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.BufferUnderflowException; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.util.ArrayList; + +import android.graphics.Bitmap; +import android.util.Log; + +/** + * This class was created by : devunwired @see available on this Gist. It is + * an optimized implementation of GifDecode.java GifDecode.java + * for Android. + * + * @author Antoine Gerard + * @since 2017.10.16 + */ + +public final class GifDecoder +{ + + private static final String TAG = GifDecoder.class.getSimpleName(); + + /** + * File read status: No errors. + */ + public static final int STATUS_OK = 0; + + /** + * File read status: Error decoding file (may be partially decoded) + */ + public static final int STATUS_FORMAT_ERROR = 1; + + /** + * File read status: Unable to open source. + */ + public static final int STATUS_OPEN_ERROR = 2; + + /** + * max decoder pixel stack size + */ + protected static final int MAX_STACK_SIZE = 4096; + + /** + * GIF Disposal Method meaning take no action + */ + private static final int DISPOSAL_UNSPECIFIED = 0; + + /** + * GIF Disposal Method meaning leave canvas from previous frame + */ + private static final int DISPOSAL_NONE = 1; + + /** + * GIF Disposal Method meaning clear canvas to background color + */ + private static final int DISPOSAL_BACKGROUND = 2; + + /** + * GIF Disposal Method meaning clear canvas to frame before last + */ + private static final int DISPOSAL_PREVIOUS = 3; + + /** + * Global status code of GIF data parsing + */ + protected int status; + + // Global File Header values and parsing flags + protected int width; // full image width + + protected int height; // full image height + + protected boolean gctFlag; // global color table used + + protected int gctSize; // size of global color table + + protected int loopCount = 1; // iterations; 0 = repeat forever + + protected int[] gct; // global color table + + protected int[] act; // active color table + + protected int bgIndex; // background color index + + protected int bgColor; // background color + + protected int pixelAspect; // pixel aspect ratio + + protected boolean lctFlag; // local color table flag + + protected int lctSize; // local color table size + + // Raw GIF data from input source + protected ByteBuffer rawData; + + // Raw data read working array + protected byte[] block = new byte[256]; // current data block + + protected int blockSize = 0; // block size last graphic control extension info + + // LZW decoder working arrays + protected short[] prefix; + + protected byte[] suffix; + + protected byte[] pixelStack; + + protected byte[] mainPixels; + + protected int[] mainScratch, copyScratch; + + protected ArrayList frames; // frames read from current file + + protected GifFrame currentFrame; + + protected Bitmap previousImage, currentImage, renderImage; + + protected int framePointer; + + protected int frameCount; + + /** + * Inner model class housing metadata for each frame + */ + private static class GifFrame + { + + public int ix, iy, iw, ih; + + /* Control Flags */ + public boolean interlace; + + public boolean transparency; + + /* Disposal Method */ + public int dispose; + + /* Transparency Index */ + public int transIndex; + + /* Delay, in ms, to next frame */ + public int delay; + + /* Index in the raw buffer where we need to start reading to decode */ + public int bufferFrameStart; + + /* Local Color Table */ + public int[] lct; + } + + /** + * Move the animation frame counter forward + */ + public void advance() + { + framePointer = (framePointer + 1) % frameCount; + } + + /** + * Gets display duration for specified frame. + * + * @param n int index of frame + * @return delay in milliseconds + */ + public int getDelay(final int n) + { + int delay = -1; + if ((n >= 0) && (n < frameCount)) + { + delay = frames.get(n).delay; + } + return delay; + } + + /** + * Gets display duration for the upcoming frame + */ + public int getNextDelay() + { + if (frameCount <= 0 || framePointer < 0) + { + return -1; + } + + return getDelay(framePointer); + } + + /** + * Gets the number of frames read from file. + * + * @return frame count + */ + public int getFrameCount() + { + return frameCount; + } + + /** + * Gets the current index of the animation frame, or -1 if animation hasn't not yet started + * + * @return frame index + */ + public int getCurrentFrameIndex() + { + return framePointer; + } + + /** + * Gets the "Netscape" iteration count, if any. A count of 0 means repeat indefinitiely. + * + * @return iteration count if one was specified, else 1. + */ + public int getLoopCount() + { + return loopCount; + } + + /** + * Get the next frame in the animation sequence. + * + * @return Bitmap representation of frame + */ + public Bitmap getNextFrame() + { + if (frameCount <= 0 || framePointer < 0 || currentImage == null) + { + return null; + } + + final GifFrame frame = frames.get(framePointer); + + // Set the appropriate color table + if (frame.lct == null) + { + act = gct; + } + else + { + act = frame.lct; + if (bgIndex == frame.transIndex) + { + bgColor = 0; + } + } + + int save = 0; + if (frame.transparency) + { + save = act[frame.transIndex]; + act[frame.transIndex] = 0; // set transparent color if specified + } + if (act == null) + { + Log.w(TAG, "No Valid Color Table"); + status = STATUS_FORMAT_ERROR; // no color table defined + return null; + } + + setPixels(framePointer); // transfer pixel data to image + + // Reset the transparent pixel in the color table + if (frame.transparency) + { + act[frame.transIndex] = save; + } + + return currentImage; + } + + /** + * Reads GIF image from stream + * + * @param is containing GIF file. + * @return read status code (0 = no errors) + */ + public int read(final InputStream is, final int contentLength) + { + if (is != null) + { + try + { + final int capacity = (contentLength > 0) ? (contentLength + 4096) : 4096; + final ByteArrayOutputStream buffer = new ByteArrayOutputStream(capacity); + int nRead; + final byte[] data = new byte[16384]; + while ((nRead = is.read(data, 0, data.length)) != -1) + { + buffer.write(data, 0, nRead); + } + buffer.flush(); + + read(buffer.toByteArray()); + } + catch (final IOException e) + { + Log.w(TAG, "Error reading data from stream", e); + } + } + else + { + status = STATUS_OPEN_ERROR; + } + + try + { + is.close(); + } + catch (final Exception e) + { + Log.w(TAG, "Error closing stream", e); + } + + return status; + } + + /** + * Reads GIF image from byte array + * + * @param data containing GIF file. + * @return read status code (0 = no errors) + */ + public int read(final byte[] data) + { + init(); + if (data != null) + { + // Initiliaze the raw data buffer + rawData = ByteBuffer.wrap(data); + rawData.rewind(); + rawData.order(ByteOrder.LITTLE_ENDIAN); + + readHeader(); + if (!err()) + { + readContents(); + if (frameCount < 0) + { + status = STATUS_FORMAT_ERROR; + } + } + } + else + { + status = STATUS_OPEN_ERROR; + } + + return status; + } + + /** + * Creates new frame image from current data (and previous frames as specified by their disposition codes). + */ + protected void setPixels(final int frameIndex) + { + final GifFrame currentFrame = frames.get(frameIndex); + GifFrame previousFrame = null; + final int previousIndex = frameIndex - 1; + if (previousIndex >= 0) + { + previousFrame = frames.get(previousIndex); + } + + // final location of blended pixels + final int[] dest = mainScratch; + + // fill in starting image contents based on last image's dispose code + if (previousFrame != null && previousFrame.dispose > DISPOSAL_UNSPECIFIED) + { + if (previousFrame.dispose == DISPOSAL_NONE && currentImage != null) + { + // Start with the current image + currentImage.getPixels(dest, 0, width, 0, 0, width, height); + } + if (previousFrame.dispose == DISPOSAL_BACKGROUND) + { + // Start with a canvas filled with the background color + int c = 0; + if (!currentFrame.transparency) + { + c = bgColor; + } + for (int i = 0; i < previousFrame.ih; i++) + { + final int n1 = (previousFrame.iy + i) * width + previousFrame.ix; + final int n2 = n1 + previousFrame.iw; + for (int k = n1; k < n2; k++) + { + dest[k] = c; + } + } + } + if (previousFrame.dispose == DISPOSAL_PREVIOUS && previousImage != null) + { + // Start with the previous frame + previousImage.getPixels(dest, 0, width, 0, 0, width, height); + } + } + + // Decode pixels for this frame into the global pixels[] scratch + decodeBitmapData(currentFrame, mainPixels); // decode pixel data + + // copy each source line to the appropriate place in the destination + int pass = 1; + int inc = 8; + int iline = 0; + for (int i = 0; i < currentFrame.ih; i++) + { + int line = i; + if (currentFrame.interlace) + { + if (iline >= currentFrame.ih) + { + pass++; + switch (pass) + { + case 2: + iline = 4; + break; + case 3: + iline = 2; + inc = 4; + break; + case 4: + iline = 1; + inc = 2; + break; + default: + break; + } + } + line = iline; + iline += inc; + } + line += currentFrame.iy; + if (line < height) + { + final int k = line * width; + int dx = k + currentFrame.ix; // start of line in dest + int dlim = dx + currentFrame.iw; // end of dest line + if ((k + width) < dlim) + { + dlim = k + width; // past dest edge + } + int sx = i * currentFrame.iw; // start of line in source + while (dx < dlim) + { + // map color and insert in destination + final int index = (mainPixels[sx++]) & 0xff; + final int c = act[index]; + if (c != 0) + { + dest[dx] = c; + } + dx++; + } + } + } + + // Copy pixels into previous image + currentImage.getPixels(copyScratch, 0, width, 0, 0, width, height); + previousImage.setPixels(copyScratch, 0, width, 0, 0, width, height); + // Set pixels for current image + currentImage.setPixels(dest, 0, width, 0, 0, width, height); + } + + /** + * Decodes LZW image data into pixel array. Adapted from John Cristy's BitmapMagick. + */ + protected void decodeBitmapData(final GifFrame frame, byte[] dstPixels) + { + if (frame != null) + { + // Jump to the frame start position + rawData.position(frame.bufferFrameStart); + } + + final int nullCode = -1; + final int npix = (frame == null) ? width * height : frame.iw * frame.ih; + int available, clear, code_mask, code_size, end_of_information, in_code, old_code, bits, code, count, i, datum, data_size, first, top, bi, pi; + + if (dstPixels == null || dstPixels.length < npix) + { + dstPixels = new byte[npix]; // allocate new pixel array + } + if (prefix == null) + { + prefix = new short[MAX_STACK_SIZE]; + } + if (suffix == null) + { + suffix = new byte[MAX_STACK_SIZE]; + } + if (pixelStack == null) + { + pixelStack = new byte[MAX_STACK_SIZE + 1]; + } + + // Initialize GIF data stream decoder. + data_size = read(); + clear = 1 << data_size; + end_of_information = clear + 1; + available = clear + 2; + old_code = nullCode; + code_size = data_size + 1; + code_mask = (1 << code_size) - 1; + for (code = 0; code < clear; code++) + { + prefix[code] = 0; // XXX ArrayIndexOutOfBoundsException + suffix[code] = (byte) code; + } + + // Decode GIF pixel stream. + datum = bits = count = first = top = pi = bi = 0; + for (i = 0; i < npix; ) + { + if (top == 0) + { + if (bits < code_size) + { + // Load bytes until there are enough bits for a code. + if (count == 0) + { + // Read a new data block. + count = readBlock(); + if (count <= 0) + { + break; + } + bi = 0; + } + datum += ((block[bi]) & 0xff) << bits; + bits += 8; + bi++; + count--; + continue; + } + // Get the next code. + code = datum & code_mask; + datum >>= code_size; + bits -= code_size; + // Interpret the code + if ((code > available) || (code == end_of_information)) + { + break; + } + if (code == clear) + { + // Reset decoder. + code_size = data_size + 1; + code_mask = (1 << code_size) - 1; + available = clear + 2; + old_code = nullCode; + continue; + } + if (old_code == nullCode) + { + pixelStack[top++] = suffix[code]; + old_code = code; + first = code; + continue; + } + in_code = code; + if (code == available) + { + pixelStack[top++] = (byte) first; + code = old_code; + } + while (code > clear) + { + pixelStack[top++] = suffix[code]; + code = prefix[code]; + } + first = (suffix[code]) & 0xff; + // Add a new string to the string table, + if (available >= MAX_STACK_SIZE) + { + break; + } + pixelStack[top++] = (byte) first; + prefix[available] = (short) old_code; + suffix[available] = (byte) first; + available++; + if (((available & code_mask) == 0) && (available < MAX_STACK_SIZE)) + { + code_size++; + code_mask += available; + } + old_code = in_code; + } + // Pop a pixel off the pixel stack. + top--; + dstPixels[pi++] = pixelStack[top]; + i++; + } + + for (i = pi; i < npix; i++) + { + dstPixels[i] = 0; // clear missing pixels + } + } + + /** + * Returns true if an error was encountered during reading/decoding + */ + protected boolean err() + { + return status != STATUS_OK; + } + + /** + * Initializes or re-initializes reader + */ + protected void init() + { + status = STATUS_OK; + frameCount = 0; + framePointer = -1; + frames = new ArrayList(); + gct = null; + } + + /** + * Reads a single byte from the input stream. + */ + protected int read() + { + int curByte = 0; + try + { + curByte = (rawData.get() & 0xFF); + } + catch (final Exception e) + { + status = STATUS_FORMAT_ERROR; + } + return curByte; + } + + /** + * Reads next variable length block from input. + * + * @return number of bytes stored in "buffer" + */ + protected int readBlock() + { + blockSize = read(); + int n = 0; + if (blockSize > 0) + { + try + { + int count; + while (n < blockSize) + { + count = blockSize - n; + rawData.get(block, n, count); + + n += count; + } + } + catch (final Exception e) + { + Log.w(TAG, "Error Reading Block", e); + status = STATUS_FORMAT_ERROR; + } + } + return n; + } + + /** + * Reads color table as 256 RGB integer values + * + * @param ncolors int number of colors to read + * @return int array containing 256 colors (packed ARGB with full alpha) + */ + protected int[] readColorTable(final int ncolors) + { + final int nbytes = 3 * ncolors; + int[] tab = null; + final byte[] c = new byte[nbytes]; + + try + { + rawData.get(c); + + tab = new int[256]; // max size to avoid bounds checks + int i = 0; + int j = 0; + while (i < ncolors) + { + final int r = (c[j++]) & 0xff; + final int g = (c[j++]) & 0xff; + final int b = (c[j++]) & 0xff; + tab[i++] = 0xff000000 | (r << 16) | (g << 8) | b; + } + } + catch (final BufferUnderflowException e) + { + Log.w(TAG, "Format Error Reading Color Table", e); + status = STATUS_FORMAT_ERROR; + } + + return tab; + } + + /** + * Main file parser. Reads GIF content blocks. + */ + protected void readContents() + { + // read GIF file content blocks + boolean done = false; + while (!(done || err())) + { + int code = read(); + switch (code) + { + case 0x2C: // image separator + readBitmap(); + break; + case 0x21: // extension + code = read(); + switch (code) + { + case 0xf9: // graphics control extension + // Start a new frame + currentFrame = new GifFrame(); + readGraphicControlExt(); + break; + case 0xff: // application extension + readBlock(); + String app = ""; + for (int i = 0; i < 11; i++) + { + app += (char) block[i]; + } + if (app.equals("NETSCAPE2.0")) + { + readNetscapeExt(); + } + else + { + skip(); // don't care + } + break; + case 0xfe:// comment extension + skip(); + break; + case 0x01:// plain text extension + skip(); + break; + default: // uninteresting extension + skip(); + } + break; + case 0x3b: // terminator + done = true; + break; + case 0x00: // bad byte, but keep going and see what happens break; + default: + status = STATUS_FORMAT_ERROR; + } + } + } + + /** + * Reads GIF file header information. + */ + protected void readHeader() + { + String id = ""; + for (int i = 0; i < 6; i++) + { + id += (char) read(); + } + if (!id.startsWith("GIF")) + { + status = STATUS_FORMAT_ERROR; + return; + } + readLSD(); + if (gctFlag && !err()) + { + gct = readColorTable(gctSize); + bgColor = gct[bgIndex]; + } + } + + /** + * Reads Graphics Control Extension values + */ + protected void readGraphicControlExt() + { + read(); // block size + final int packed = read(); // packed fields + currentFrame.dispose = (packed & 0x1c) >> 2; // disposal method + if (currentFrame.dispose == 0) + { + currentFrame.dispose = 1; // elect to keep old image if discretionary + } + currentFrame.transparency = (packed & 1) != 0; + currentFrame.delay = readShort() * 10; // delay in milliseconds + currentFrame.transIndex = read(); // transparent color index + read(); // block terminator + } + + /** + * Reads next frame image + */ + protected void readBitmap() + { + currentFrame.ix = readShort(); // (sub)image position & size + currentFrame.iy = readShort(); + currentFrame.iw = readShort(); + currentFrame.ih = readShort(); + + final int packed = read(); + lctFlag = (packed & 0x80) != 0; // 1 - local color table flag interlace + lctSize = (int) Math.pow(2, (packed & 0x07) + 1); + // 3 - sort flag + // 4-5 - reserved lctSize = 2 << (packed & 7); // 6-8 - local color + // table size + currentFrame.interlace = (packed & 0x40) != 0; + if (lctFlag) + { + currentFrame.lct = readColorTable(lctSize); // read table + } + else + { + currentFrame.lct = null; // No local color table + } + + currentFrame.bufferFrameStart = rawData.position(); // Save this as the decoding position pointer + + decodeBitmapData(null, mainPixels); // false decode pixel data to advance buffer + skip(); + if (err()) + { + return; + } + + frameCount++; + frames.add(currentFrame); // add image to frame + } + + /** + * Reads Logical Screen Descriptor + */ + protected void readLSD() + { + // logical screen size + width = readShort(); + height = readShort(); + // packed fields + final int packed = read(); + gctFlag = (packed & 0x80) != 0; // 1 : global color table flag + // 2-4 : color resolution + // 5 : gct sort flag + gctSize = 2 << (packed & 7); // 6-8 : gct size + bgIndex = read(); // background color index + pixelAspect = read(); // pixel aspect ratio + + // Now that we know the size, init scratch arrays + try + { + mainPixels = new byte[width * height]; + mainScratch = new int[width * height]; + copyScratch = new int[width * height]; + + previousImage = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565); + currentImage = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565); + } + catch (final OutOfMemoryError e) + { + // Try with halving down the bitmap size + final int dimension = (width * height) / 2; + mainPixels = new byte[dimension]; + mainScratch = new int[dimension]; + copyScratch = new int[dimension]; + + previousImage = Bitmap.createBitmap(width / 2, height / 2, Bitmap.Config.RGB_565); + currentImage = Bitmap.createBitmap(width / 2, height / 2, Bitmap.Config.RGB_565); + } + } + + /** + * Reads Netscape extenstion to obtain iteration count + */ + protected void readNetscapeExt() + { + do + { + readBlock(); + if (block[0] == 1) + { + // loop count sub-block + final int b1 = (block[1]) & 0xff; + final int b2 = (block[2]) & 0xff; + loopCount = (b2 << 8) | b1; + } + } while ((blockSize > 0) && !err()); + } + + /** + * Reads next 16-bit value, LSB first + */ + protected int readShort() + { + // read 16-bit value + return rawData.getShort(); + } + + /** + * Skips variable length blocks up to and including next zero length block. + */ + protected void skip() + { + do + { + readBlock(); + } while ((blockSize > 0) && !err()); + } +} From e32805e5005f87741da19d8074e409c0d9818146 Mon Sep 17 00:00:00 2001 From: Antoine Gerard Date: Wed, 18 Oct 2017 19:35:49 +0200 Subject: [PATCH 02/19] Working on the Gif --- .gitignore | 0 LICENSE | 0 README.md | 0 gradle/wrapper/gradle-wrapper.jar | Bin gradle/wrapper/gradle-wrapper.properties | 0 gradlew | 0 gradlew.bat | 0 library/.gitignore | 0 library/build.gradle | 54 +- library/proguard-rules.pro | 0 library/src/main/AndroidManifest.xml | 0 .../smartnsoft/droid4me/AndroidLifeCycle.java | 0 .../com/smartnsoft/droid4me/LifeCycle.java | 0 .../droid4me/analytics/AnalyticsLogger.java | 0 .../droid4me/analytics/AnalyticsSender.java | 0 .../droid4me/analytics/package-info.java | 0 .../animation/SimpleAnimationListener.java | 0 .../animation/SimpleAnimatorListener.java | 0 .../droid4me/animation/package-info.java | 0 .../droid4me/app/ActivityController.java | 0 .../smartnsoft/droid4me/app/AppInternals.java | 0 .../smartnsoft/droid4me/app/AppPublics.java | 0 .../droid4me/app/ConnectivityListener.java | 0 .../smartnsoft/droid4me/app/Droid4mizer.java | 0 .../droid4me/app/ExceptionHandlers.java | 0 .../app/ForBusinessObjectActivity.java | 0 .../droid4me/app/ProgressHandler.java | 0 .../droid4me/app/SmartActivity.java | 0 .../droid4me/app/SmartApplication.java | 0 .../droid4me/app/SmartCommands.java | 0 .../droid4me/app/SmartDialogFragment.java | 0 .../droid4me/app/SmartFragment.java | 0 .../droid4me/app/SmartIntentService.java | 0 .../droid4me/app/SmartPreferenceActivity.java | 0 .../app/SmartSplashScreenActivity.java | 0 .../smartnsoft/droid4me/app/Smartable.java | 0 .../droid4me/app/SmartableActivity.java | 0 .../com/smartnsoft/droid4me/app/Smarted.java | 0 .../smartnsoft/droid4me/app/package-info.java | 0 .../com/smartnsoft/droid4me/bo/Business.java | 0 .../smartnsoft/droid4me/bo/package-info.java | 0 .../com/smartnsoft/droid4me/cache/Cacher.java | 0 .../droid4me/cache/DbPersistence.java | 0 .../droid4me/cache/FilePersistence.java | 0 .../droid4me/cache/MemoryCacher.java | 0 .../droid4me/cache/NullPersistence.java | 0 .../droid4me/cache/Persistence.java | 0 .../com/smartnsoft/droid4me/cache/Values.java | 0 .../droid4me/cache/package-info.java | 0 .../config/AssetsConfigurationLoader.java | 0 .../droid4me/config/ConfigurationLoader.java | 0 .../InternalStorageConfigurationLoader.java | 0 .../config/ResourcesConfigurationLoader.java | 0 .../droid4me/config/package-info.java | 0 .../content/SmartBroadcastReceiver.java | 0 .../droid4me/content/TokenKeeper.java | 0 .../droid4me/content/package-info.java | 0 .../debug/Droid4meDebugInterceptor.java | 0 .../droid4me/debug/package-info.java | 0 .../download/BasisBitmapDownloader.java | 56 +- .../download/BasisDownloadInstructions.java | 0 .../droid4me/download/BitmapDownloader.java | 0 .../download/CoreBitmapDownloader.java | 0 .../droid4me/download/DownloadContracts.java | 0 .../download/DownloadInstructions.java | 200 ++- .../droid4me/download/DownloadSpecs.java | 0 .../droid4me/download/GifDecoder.java | 928 -------------- .../smartnsoft/droid4me/download/gif/Gif.java | 90 ++ .../droid4me/download/gif/GifDecoder.java | 1109 +++++++++++++++++ .../droid4me/download/gif/GifEngine.java | 318 +++++ .../droid4me/download/gif/GifFrame.java | 50 + .../droid4me/download/gif/GifHeader.java | 77 ++ .../download/gif/GifHeaderParser.java | 484 +++++++ .../download/gif/SimpleBitmapProvider.java | 54 + .../droid4me/download/package-info.java | 0 .../framework/BusinessObjectLifeCycle.java | 0 .../droid4me/framework/DetailsProvider.java | 0 .../smartnsoft/droid4me/framework/Events.java | 0 .../ForBusinessObjectImplementation.java | 0 .../droid4me/framework/SmartAdapters.java | 0 .../droid4me/framework/package-info.java | 0 .../drawable/BasicBitmapDrawable.java | 0 .../graphics/drawable/package-info.java | 0 .../droid4me/log/AndroidLogger.java | 0 .../com/smartnsoft/droid4me/log/Logger.java | 0 .../droid4me/log/LoggerFactory.java | 0 .../droid4me/log/LoggerWrapper.java | 0 .../smartnsoft/droid4me/log/Loggerable.java | 0 .../smartnsoft/droid4me/log/NativeLogger.java | 0 .../smartnsoft/droid4me/log/package-info.java | 0 .../com/smartnsoft/droid4me/package-info.java | 0 .../support/v4/app/SmartDialogFragment.java | 0 .../support/v4/app/SmartFragment.java | 0 .../support/v4/app/SmartFragmentActivity.java | 0 .../v4/content/LocalBroadcastManager.java | 0 .../droid4me/support/v4/package-info.java | 0 .../v7/app/SmartAppCompatActivity.java | 0 .../v7/app/SmartPreferenceFragmentCompat.java | 0 .../droid4me/support/v7/package-info.java | 0 .../v7/widget/SmartAppCompatImageView.java | 2 + .../droid4me/ui/SimpleWrappedListView.java | 0 .../droid4me/ui/WrappedListView.java | 0 .../smartnsoft/droid4me/ui/package-info.java | 0 .../droid4me/util/BitmapToolbox.java | 0 .../droid4me/util/SendLogsTask.java | 0 .../droid4me/util/StatefulDefaultHandler.java | 0 .../droid4me/util/package-info.java | 0 .../widget/OnSizeChangedListener.java | 0 .../droid4me/widget/SmartFrameLayout.java | 0 .../droid4me/widget/SmartLinearLayout.java | 0 .../droid4me/widget/SmartPageIndicator.java | 0 .../droid4me/widget/SmartRelativeLayout.java | 0 .../droid4me/widget/SmartViewExtension.java | 0 .../droid4me/widget/SmartViewPager.java | 0 .../droid4me/widget/package-info.java | 0 .../ws/URLConnectionWebServiceCaller.java | 0 .../droid4me/ws/WSUriStreamParser.java | 0 .../droid4me/ws/WebServiceCaller.java | 0 .../droid4me/ws/WebServiceClient.java | 0 .../ws/WithCacheWSUriStreamParser.java | 0 .../smartnsoft/droid4me/ws/package-info.java | 0 .../wscache/BackedWSUriStreamParser.java | 0 .../droid4me/wscache/package-info.java | 0 library/src/main/javadoc/overview.html | 0 .../droid4me/cache/test/PersistenceTest.java | 0 .../download/test/BitmapDownloaderTest.java | 0 .../smartnsoft/droid4me/test/BasisTests.java | 0 sample/.gitignore | 0 sample/proguard-rules.pro | 0 sample/src/main/AndroidManifest.xml | 0 sample/src/main/assets/about.css | 0 sample/src/main/assets/application_logo.png | Bin sample/src/main/assets/background.png | Bin .../src/main/assets/droid4me_inside_large.png | Bin sample/src/main/assets/smartnsoft_logo.png | Bin .../droid4sample/AboutActivity.java | 0 .../smartnsoft/droid4sample/Constants.java | 0 .../droid4sample/Droid4SampleApplication.java | 0 .../Droid4SampleSplashScreenActivity.java | 0 .../droid4sample/SettingsActivity.java | 0 .../com/smartnsoft/droid4sample/TitleBar.java | 0 .../droid4sample/ws/Droid4SampleServices.java | 0 .../res/drawable-hdpi/droid4me_inside.png | Bin .../droid4sample_splash_logo.png | Bin sample/src/main/res/drawable-hdpi/icon.png | Bin .../drawable-hdpi/poweredby_smartnsoft.png | Bin .../drawable-hdpi/smartnsoft_illustration.png | Bin .../main/res/drawable-hdpi/title_bar_home.png | Bin .../res/drawable-hdpi/title_bar_refresh.png | Bin .../title_bar_button_background_disabled.png | Bin .../title_bar_button_background_pressed.png | Bin .../title_bar_button_background_selected.png | Bin .../drawable/title_bar_button_background.xml | 0 sample/src/main/res/layout/about.xml | 0 .../res/layout/droid4sample_splash_screen.xml | 0 sample/src/main/res/layout/main_sample.xml | 0 sample/src/main/res/layout/title_bar.xml | 0 sample/src/main/res/raw/about.html | 0 sample/src/main/res/values-fr/strings.xml | 0 sample/src/main/res/values/array.xml | 0 sample/src/main/res/values/attrs.xml | 0 sample/src/main/res/values/colors.xml | 0 sample/src/main/res/values/dimen.xml | 0 sample/src/main/res/values/strings.xml | 0 sample/src/main/res/values/styles.xml | 0 sample/src/main/res/values/themes.xml | 0 sample/src/main/res/xml/settings.xml | 0 167 files changed, 2414 insertions(+), 1008 deletions(-) mode change 100644 => 100755 .gitignore mode change 100644 => 100755 LICENSE mode change 100644 => 100755 README.md mode change 100644 => 100755 gradle/wrapper/gradle-wrapper.jar mode change 100644 => 100755 gradle/wrapper/gradle-wrapper.properties mode change 100644 => 100755 gradlew mode change 100644 => 100755 gradlew.bat mode change 100644 => 100755 library/.gitignore mode change 100644 => 100755 library/build.gradle mode change 100644 => 100755 library/proguard-rules.pro mode change 100644 => 100755 library/src/main/AndroidManifest.xml mode change 100644 => 100755 library/src/main/java/com/smartnsoft/droid4me/AndroidLifeCycle.java mode change 100644 => 100755 library/src/main/java/com/smartnsoft/droid4me/LifeCycle.java mode change 100644 => 100755 library/src/main/java/com/smartnsoft/droid4me/analytics/AnalyticsLogger.java mode change 100644 => 100755 library/src/main/java/com/smartnsoft/droid4me/analytics/AnalyticsSender.java mode change 100644 => 100755 library/src/main/java/com/smartnsoft/droid4me/analytics/package-info.java mode change 100644 => 100755 library/src/main/java/com/smartnsoft/droid4me/animation/SimpleAnimationListener.java mode change 100644 => 100755 library/src/main/java/com/smartnsoft/droid4me/animation/SimpleAnimatorListener.java mode change 100644 => 100755 library/src/main/java/com/smartnsoft/droid4me/animation/package-info.java mode change 100644 => 100755 library/src/main/java/com/smartnsoft/droid4me/app/ActivityController.java mode change 100644 => 100755 library/src/main/java/com/smartnsoft/droid4me/app/AppInternals.java mode change 100644 => 100755 library/src/main/java/com/smartnsoft/droid4me/app/AppPublics.java mode change 100644 => 100755 library/src/main/java/com/smartnsoft/droid4me/app/ConnectivityListener.java mode change 100644 => 100755 library/src/main/java/com/smartnsoft/droid4me/app/Droid4mizer.java mode change 100644 => 100755 library/src/main/java/com/smartnsoft/droid4me/app/ExceptionHandlers.java mode change 100644 => 100755 library/src/main/java/com/smartnsoft/droid4me/app/ForBusinessObjectActivity.java mode change 100644 => 100755 library/src/main/java/com/smartnsoft/droid4me/app/ProgressHandler.java mode change 100644 => 100755 library/src/main/java/com/smartnsoft/droid4me/app/SmartActivity.java mode change 100644 => 100755 library/src/main/java/com/smartnsoft/droid4me/app/SmartApplication.java mode change 100644 => 100755 library/src/main/java/com/smartnsoft/droid4me/app/SmartCommands.java mode change 100644 => 100755 library/src/main/java/com/smartnsoft/droid4me/app/SmartDialogFragment.java mode change 100644 => 100755 library/src/main/java/com/smartnsoft/droid4me/app/SmartFragment.java mode change 100644 => 100755 library/src/main/java/com/smartnsoft/droid4me/app/SmartIntentService.java mode change 100644 => 100755 library/src/main/java/com/smartnsoft/droid4me/app/SmartPreferenceActivity.java mode change 100644 => 100755 library/src/main/java/com/smartnsoft/droid4me/app/SmartSplashScreenActivity.java mode change 100644 => 100755 library/src/main/java/com/smartnsoft/droid4me/app/Smartable.java mode change 100644 => 100755 library/src/main/java/com/smartnsoft/droid4me/app/SmartableActivity.java mode change 100644 => 100755 library/src/main/java/com/smartnsoft/droid4me/app/Smarted.java mode change 100644 => 100755 library/src/main/java/com/smartnsoft/droid4me/app/package-info.java mode change 100644 => 100755 library/src/main/java/com/smartnsoft/droid4me/bo/Business.java mode change 100644 => 100755 library/src/main/java/com/smartnsoft/droid4me/bo/package-info.java mode change 100644 => 100755 library/src/main/java/com/smartnsoft/droid4me/cache/Cacher.java mode change 100644 => 100755 library/src/main/java/com/smartnsoft/droid4me/cache/DbPersistence.java mode change 100644 => 100755 library/src/main/java/com/smartnsoft/droid4me/cache/FilePersistence.java mode change 100644 => 100755 library/src/main/java/com/smartnsoft/droid4me/cache/MemoryCacher.java mode change 100644 => 100755 library/src/main/java/com/smartnsoft/droid4me/cache/NullPersistence.java mode change 100644 => 100755 library/src/main/java/com/smartnsoft/droid4me/cache/Persistence.java mode change 100644 => 100755 library/src/main/java/com/smartnsoft/droid4me/cache/Values.java mode change 100644 => 100755 library/src/main/java/com/smartnsoft/droid4me/cache/package-info.java mode change 100644 => 100755 library/src/main/java/com/smartnsoft/droid4me/config/AssetsConfigurationLoader.java mode change 100644 => 100755 library/src/main/java/com/smartnsoft/droid4me/config/ConfigurationLoader.java mode change 100644 => 100755 library/src/main/java/com/smartnsoft/droid4me/config/InternalStorageConfigurationLoader.java mode change 100644 => 100755 library/src/main/java/com/smartnsoft/droid4me/config/ResourcesConfigurationLoader.java mode change 100644 => 100755 library/src/main/java/com/smartnsoft/droid4me/config/package-info.java mode change 100644 => 100755 library/src/main/java/com/smartnsoft/droid4me/content/SmartBroadcastReceiver.java mode change 100644 => 100755 library/src/main/java/com/smartnsoft/droid4me/content/TokenKeeper.java mode change 100644 => 100755 library/src/main/java/com/smartnsoft/droid4me/content/package-info.java mode change 100644 => 100755 library/src/main/java/com/smartnsoft/droid4me/debug/Droid4meDebugInterceptor.java mode change 100644 => 100755 library/src/main/java/com/smartnsoft/droid4me/debug/package-info.java mode change 100644 => 100755 library/src/main/java/com/smartnsoft/droid4me/download/BasisBitmapDownloader.java mode change 100644 => 100755 library/src/main/java/com/smartnsoft/droid4me/download/BasisDownloadInstructions.java mode change 100644 => 100755 library/src/main/java/com/smartnsoft/droid4me/download/BitmapDownloader.java mode change 100644 => 100755 library/src/main/java/com/smartnsoft/droid4me/download/CoreBitmapDownloader.java mode change 100644 => 100755 library/src/main/java/com/smartnsoft/droid4me/download/DownloadContracts.java mode change 100644 => 100755 library/src/main/java/com/smartnsoft/droid4me/download/DownloadInstructions.java mode change 100644 => 100755 library/src/main/java/com/smartnsoft/droid4me/download/DownloadSpecs.java delete mode 100644 library/src/main/java/com/smartnsoft/droid4me/download/GifDecoder.java create mode 100755 library/src/main/java/com/smartnsoft/droid4me/download/gif/Gif.java create mode 100755 library/src/main/java/com/smartnsoft/droid4me/download/gif/GifDecoder.java create mode 100755 library/src/main/java/com/smartnsoft/droid4me/download/gif/GifEngine.java create mode 100755 library/src/main/java/com/smartnsoft/droid4me/download/gif/GifFrame.java create mode 100755 library/src/main/java/com/smartnsoft/droid4me/download/gif/GifHeader.java create mode 100755 library/src/main/java/com/smartnsoft/droid4me/download/gif/GifHeaderParser.java create mode 100755 library/src/main/java/com/smartnsoft/droid4me/download/gif/SimpleBitmapProvider.java mode change 100644 => 100755 library/src/main/java/com/smartnsoft/droid4me/download/package-info.java mode change 100644 => 100755 library/src/main/java/com/smartnsoft/droid4me/framework/BusinessObjectLifeCycle.java mode change 100644 => 100755 library/src/main/java/com/smartnsoft/droid4me/framework/DetailsProvider.java mode change 100644 => 100755 library/src/main/java/com/smartnsoft/droid4me/framework/Events.java mode change 100644 => 100755 library/src/main/java/com/smartnsoft/droid4me/framework/ForBusinessObjectImplementation.java mode change 100644 => 100755 library/src/main/java/com/smartnsoft/droid4me/framework/SmartAdapters.java mode change 100644 => 100755 library/src/main/java/com/smartnsoft/droid4me/framework/package-info.java mode change 100644 => 100755 library/src/main/java/com/smartnsoft/droid4me/graphics/drawable/BasicBitmapDrawable.java mode change 100644 => 100755 library/src/main/java/com/smartnsoft/droid4me/graphics/drawable/package-info.java mode change 100644 => 100755 library/src/main/java/com/smartnsoft/droid4me/log/AndroidLogger.java mode change 100644 => 100755 library/src/main/java/com/smartnsoft/droid4me/log/Logger.java mode change 100644 => 100755 library/src/main/java/com/smartnsoft/droid4me/log/LoggerFactory.java mode change 100644 => 100755 library/src/main/java/com/smartnsoft/droid4me/log/LoggerWrapper.java mode change 100644 => 100755 library/src/main/java/com/smartnsoft/droid4me/log/Loggerable.java mode change 100644 => 100755 library/src/main/java/com/smartnsoft/droid4me/log/NativeLogger.java mode change 100644 => 100755 library/src/main/java/com/smartnsoft/droid4me/log/package-info.java mode change 100644 => 100755 library/src/main/java/com/smartnsoft/droid4me/package-info.java mode change 100644 => 100755 library/src/main/java/com/smartnsoft/droid4me/support/v4/app/SmartDialogFragment.java mode change 100644 => 100755 library/src/main/java/com/smartnsoft/droid4me/support/v4/app/SmartFragment.java mode change 100644 => 100755 library/src/main/java/com/smartnsoft/droid4me/support/v4/app/SmartFragmentActivity.java mode change 100644 => 100755 library/src/main/java/com/smartnsoft/droid4me/support/v4/content/LocalBroadcastManager.java mode change 100644 => 100755 library/src/main/java/com/smartnsoft/droid4me/support/v4/package-info.java mode change 100644 => 100755 library/src/main/java/com/smartnsoft/droid4me/support/v7/app/SmartAppCompatActivity.java mode change 100644 => 100755 library/src/main/java/com/smartnsoft/droid4me/support/v7/app/SmartPreferenceFragmentCompat.java mode change 100644 => 100755 library/src/main/java/com/smartnsoft/droid4me/support/v7/package-info.java mode change 100644 => 100755 library/src/main/java/com/smartnsoft/droid4me/support/v7/widget/SmartAppCompatImageView.java mode change 100644 => 100755 library/src/main/java/com/smartnsoft/droid4me/ui/SimpleWrappedListView.java mode change 100644 => 100755 library/src/main/java/com/smartnsoft/droid4me/ui/WrappedListView.java mode change 100644 => 100755 library/src/main/java/com/smartnsoft/droid4me/ui/package-info.java mode change 100644 => 100755 library/src/main/java/com/smartnsoft/droid4me/util/BitmapToolbox.java mode change 100644 => 100755 library/src/main/java/com/smartnsoft/droid4me/util/SendLogsTask.java mode change 100644 => 100755 library/src/main/java/com/smartnsoft/droid4me/util/StatefulDefaultHandler.java mode change 100644 => 100755 library/src/main/java/com/smartnsoft/droid4me/util/package-info.java mode change 100644 => 100755 library/src/main/java/com/smartnsoft/droid4me/widget/OnSizeChangedListener.java mode change 100644 => 100755 library/src/main/java/com/smartnsoft/droid4me/widget/SmartFrameLayout.java mode change 100644 => 100755 library/src/main/java/com/smartnsoft/droid4me/widget/SmartLinearLayout.java mode change 100644 => 100755 library/src/main/java/com/smartnsoft/droid4me/widget/SmartPageIndicator.java mode change 100644 => 100755 library/src/main/java/com/smartnsoft/droid4me/widget/SmartRelativeLayout.java mode change 100644 => 100755 library/src/main/java/com/smartnsoft/droid4me/widget/SmartViewExtension.java mode change 100644 => 100755 library/src/main/java/com/smartnsoft/droid4me/widget/SmartViewPager.java mode change 100644 => 100755 library/src/main/java/com/smartnsoft/droid4me/widget/package-info.java mode change 100644 => 100755 library/src/main/java/com/smartnsoft/droid4me/ws/URLConnectionWebServiceCaller.java mode change 100644 => 100755 library/src/main/java/com/smartnsoft/droid4me/ws/WSUriStreamParser.java mode change 100644 => 100755 library/src/main/java/com/smartnsoft/droid4me/ws/WebServiceCaller.java mode change 100644 => 100755 library/src/main/java/com/smartnsoft/droid4me/ws/WebServiceClient.java mode change 100644 => 100755 library/src/main/java/com/smartnsoft/droid4me/ws/WithCacheWSUriStreamParser.java mode change 100644 => 100755 library/src/main/java/com/smartnsoft/droid4me/ws/package-info.java mode change 100644 => 100755 library/src/main/java/com/smartnsoft/droid4me/wscache/BackedWSUriStreamParser.java mode change 100644 => 100755 library/src/main/java/com/smartnsoft/droid4me/wscache/package-info.java mode change 100644 => 100755 library/src/main/javadoc/overview.html mode change 100644 => 100755 library/src/test/java/com/smartnsoft/droid4me/cache/test/PersistenceTest.java mode change 100644 => 100755 library/src/test/java/com/smartnsoft/droid4me/download/test/BitmapDownloaderTest.java mode change 100644 => 100755 library/src/test/java/com/smartnsoft/droid4me/test/BasisTests.java mode change 100644 => 100755 sample/.gitignore mode change 100644 => 100755 sample/proguard-rules.pro mode change 100644 => 100755 sample/src/main/AndroidManifest.xml mode change 100644 => 100755 sample/src/main/assets/about.css mode change 100644 => 100755 sample/src/main/assets/application_logo.png mode change 100644 => 100755 sample/src/main/assets/background.png mode change 100644 => 100755 sample/src/main/assets/droid4me_inside_large.png mode change 100644 => 100755 sample/src/main/assets/smartnsoft_logo.png mode change 100644 => 100755 sample/src/main/java/com/smartnsoft/droid4sample/AboutActivity.java mode change 100644 => 100755 sample/src/main/java/com/smartnsoft/droid4sample/Constants.java mode change 100644 => 100755 sample/src/main/java/com/smartnsoft/droid4sample/Droid4SampleApplication.java mode change 100644 => 100755 sample/src/main/java/com/smartnsoft/droid4sample/Droid4SampleSplashScreenActivity.java mode change 100644 => 100755 sample/src/main/java/com/smartnsoft/droid4sample/SettingsActivity.java mode change 100644 => 100755 sample/src/main/java/com/smartnsoft/droid4sample/TitleBar.java mode change 100644 => 100755 sample/src/main/java/com/smartnsoft/droid4sample/ws/Droid4SampleServices.java mode change 100644 => 100755 sample/src/main/res/drawable-hdpi/droid4me_inside.png mode change 100644 => 100755 sample/src/main/res/drawable-hdpi/droid4sample_splash_logo.png mode change 100644 => 100755 sample/src/main/res/drawable-hdpi/icon.png mode change 100644 => 100755 sample/src/main/res/drawable-hdpi/poweredby_smartnsoft.png mode change 100644 => 100755 sample/src/main/res/drawable-hdpi/smartnsoft_illustration.png mode change 100644 => 100755 sample/src/main/res/drawable-hdpi/title_bar_home.png mode change 100644 => 100755 sample/src/main/res/drawable-hdpi/title_bar_refresh.png mode change 100644 => 100755 sample/src/main/res/drawable-nodpi/title_bar_button_background_disabled.png mode change 100644 => 100755 sample/src/main/res/drawable-nodpi/title_bar_button_background_pressed.png mode change 100644 => 100755 sample/src/main/res/drawable-nodpi/title_bar_button_background_selected.png mode change 100644 => 100755 sample/src/main/res/drawable/title_bar_button_background.xml mode change 100644 => 100755 sample/src/main/res/layout/about.xml mode change 100644 => 100755 sample/src/main/res/layout/droid4sample_splash_screen.xml mode change 100644 => 100755 sample/src/main/res/layout/main_sample.xml mode change 100644 => 100755 sample/src/main/res/layout/title_bar.xml mode change 100644 => 100755 sample/src/main/res/raw/about.html mode change 100644 => 100755 sample/src/main/res/values-fr/strings.xml mode change 100644 => 100755 sample/src/main/res/values/array.xml mode change 100644 => 100755 sample/src/main/res/values/attrs.xml mode change 100644 => 100755 sample/src/main/res/values/colors.xml mode change 100644 => 100755 sample/src/main/res/values/dimen.xml mode change 100644 => 100755 sample/src/main/res/values/strings.xml mode change 100644 => 100755 sample/src/main/res/values/styles.xml mode change 100644 => 100755 sample/src/main/res/values/themes.xml mode change 100644 => 100755 sample/src/main/res/xml/settings.xml diff --git a/.gitignore b/.gitignore old mode 100644 new mode 100755 diff --git a/LICENSE b/LICENSE old mode 100644 new mode 100755 diff --git a/README.md b/README.md old mode 100644 new mode 100755 diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar old mode 100644 new mode 100755 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties old mode 100644 new mode 100755 diff --git a/gradlew b/gradlew old mode 100644 new mode 100755 diff --git a/gradlew.bat b/gradlew.bat old mode 100644 new mode 100755 diff --git a/library/.gitignore b/library/.gitignore old mode 100644 new mode 100755 diff --git a/library/build.gradle b/library/build.gradle old mode 100644 new mode 100755 index 4e7768b5..152e5fb5 --- a/library/build.gradle +++ b/library/build.gradle @@ -1,5 +1,5 @@ apply plugin: "com.android.library" -apply plugin: "com.jfrog.bintray" +//apply plugin: "com.jfrog.bintray" apply plugin: "maven" apply plugin: "maven-publish" @@ -11,7 +11,7 @@ ext android { compileSdkVersion 25 - buildToolsVersion "25.0.3" + buildToolsVersion '26.0.2' defaultConfig { @@ -127,31 +127,31 @@ publishing.publications.all } } -bintray -{ - user = bintrayUsername - key = bintrayKey - - publications = ["ReleasePublication"] - - pkg - { - repo = "maven" - name = "droid4me" - userOrg = "smartnsoft" - licenses = ["LGPL-2.1"] - vcsUrl = "https://github.com/smartnsoft/droid4me.git" - publish = true - - version - { - name = android.defaultConfig.versionName - desc = "droid4me is a framework library dedicated to the development of Android applications" - released = new Date() - vcsTag = "droid4me-" + android.defaultConfig.versionName - } - } -} +//bintray +//{ +// user = bintrayUsername +// key = bintrayKey +// +// publications = ["ReleasePublication"] +// +// pkg +// { +// repo = "maven" +// name = "droid4me" +// userOrg = "smartnsoft" +// licenses = ["LGPL-2.1"] +// vcsUrl = "https://github.com/smartnsoft/droid4me.git" +// publish = true +// +// version +// { +// name = android.defaultConfig.versionName +// desc = "droid4me is a framework library dedicated to the development of Android applications" +// released = new Date() +// vcsTag = "droid4me-" + android.defaultConfig.versionName +// } +// } +//} uploadArchives { diff --git a/library/proguard-rules.pro b/library/proguard-rules.pro old mode 100644 new mode 100755 diff --git a/library/src/main/AndroidManifest.xml b/library/src/main/AndroidManifest.xml old mode 100644 new mode 100755 diff --git a/library/src/main/java/com/smartnsoft/droid4me/AndroidLifeCycle.java b/library/src/main/java/com/smartnsoft/droid4me/AndroidLifeCycle.java old mode 100644 new mode 100755 diff --git a/library/src/main/java/com/smartnsoft/droid4me/LifeCycle.java b/library/src/main/java/com/smartnsoft/droid4me/LifeCycle.java old mode 100644 new mode 100755 diff --git a/library/src/main/java/com/smartnsoft/droid4me/analytics/AnalyticsLogger.java b/library/src/main/java/com/smartnsoft/droid4me/analytics/AnalyticsLogger.java old mode 100644 new mode 100755 diff --git a/library/src/main/java/com/smartnsoft/droid4me/analytics/AnalyticsSender.java b/library/src/main/java/com/smartnsoft/droid4me/analytics/AnalyticsSender.java old mode 100644 new mode 100755 diff --git a/library/src/main/java/com/smartnsoft/droid4me/analytics/package-info.java b/library/src/main/java/com/smartnsoft/droid4me/analytics/package-info.java old mode 100644 new mode 100755 diff --git a/library/src/main/java/com/smartnsoft/droid4me/animation/SimpleAnimationListener.java b/library/src/main/java/com/smartnsoft/droid4me/animation/SimpleAnimationListener.java old mode 100644 new mode 100755 diff --git a/library/src/main/java/com/smartnsoft/droid4me/animation/SimpleAnimatorListener.java b/library/src/main/java/com/smartnsoft/droid4me/animation/SimpleAnimatorListener.java old mode 100644 new mode 100755 diff --git a/library/src/main/java/com/smartnsoft/droid4me/animation/package-info.java b/library/src/main/java/com/smartnsoft/droid4me/animation/package-info.java old mode 100644 new mode 100755 diff --git a/library/src/main/java/com/smartnsoft/droid4me/app/ActivityController.java b/library/src/main/java/com/smartnsoft/droid4me/app/ActivityController.java old mode 100644 new mode 100755 diff --git a/library/src/main/java/com/smartnsoft/droid4me/app/AppInternals.java b/library/src/main/java/com/smartnsoft/droid4me/app/AppInternals.java old mode 100644 new mode 100755 diff --git a/library/src/main/java/com/smartnsoft/droid4me/app/AppPublics.java b/library/src/main/java/com/smartnsoft/droid4me/app/AppPublics.java old mode 100644 new mode 100755 diff --git a/library/src/main/java/com/smartnsoft/droid4me/app/ConnectivityListener.java b/library/src/main/java/com/smartnsoft/droid4me/app/ConnectivityListener.java old mode 100644 new mode 100755 diff --git a/library/src/main/java/com/smartnsoft/droid4me/app/Droid4mizer.java b/library/src/main/java/com/smartnsoft/droid4me/app/Droid4mizer.java old mode 100644 new mode 100755 diff --git a/library/src/main/java/com/smartnsoft/droid4me/app/ExceptionHandlers.java b/library/src/main/java/com/smartnsoft/droid4me/app/ExceptionHandlers.java old mode 100644 new mode 100755 diff --git a/library/src/main/java/com/smartnsoft/droid4me/app/ForBusinessObjectActivity.java b/library/src/main/java/com/smartnsoft/droid4me/app/ForBusinessObjectActivity.java old mode 100644 new mode 100755 diff --git a/library/src/main/java/com/smartnsoft/droid4me/app/ProgressHandler.java b/library/src/main/java/com/smartnsoft/droid4me/app/ProgressHandler.java old mode 100644 new mode 100755 diff --git a/library/src/main/java/com/smartnsoft/droid4me/app/SmartActivity.java b/library/src/main/java/com/smartnsoft/droid4me/app/SmartActivity.java old mode 100644 new mode 100755 diff --git a/library/src/main/java/com/smartnsoft/droid4me/app/SmartApplication.java b/library/src/main/java/com/smartnsoft/droid4me/app/SmartApplication.java old mode 100644 new mode 100755 diff --git a/library/src/main/java/com/smartnsoft/droid4me/app/SmartCommands.java b/library/src/main/java/com/smartnsoft/droid4me/app/SmartCommands.java old mode 100644 new mode 100755 diff --git a/library/src/main/java/com/smartnsoft/droid4me/app/SmartDialogFragment.java b/library/src/main/java/com/smartnsoft/droid4me/app/SmartDialogFragment.java old mode 100644 new mode 100755 diff --git a/library/src/main/java/com/smartnsoft/droid4me/app/SmartFragment.java b/library/src/main/java/com/smartnsoft/droid4me/app/SmartFragment.java old mode 100644 new mode 100755 diff --git a/library/src/main/java/com/smartnsoft/droid4me/app/SmartIntentService.java b/library/src/main/java/com/smartnsoft/droid4me/app/SmartIntentService.java old mode 100644 new mode 100755 diff --git a/library/src/main/java/com/smartnsoft/droid4me/app/SmartPreferenceActivity.java b/library/src/main/java/com/smartnsoft/droid4me/app/SmartPreferenceActivity.java old mode 100644 new mode 100755 diff --git a/library/src/main/java/com/smartnsoft/droid4me/app/SmartSplashScreenActivity.java b/library/src/main/java/com/smartnsoft/droid4me/app/SmartSplashScreenActivity.java old mode 100644 new mode 100755 diff --git a/library/src/main/java/com/smartnsoft/droid4me/app/Smartable.java b/library/src/main/java/com/smartnsoft/droid4me/app/Smartable.java old mode 100644 new mode 100755 diff --git a/library/src/main/java/com/smartnsoft/droid4me/app/SmartableActivity.java b/library/src/main/java/com/smartnsoft/droid4me/app/SmartableActivity.java old mode 100644 new mode 100755 diff --git a/library/src/main/java/com/smartnsoft/droid4me/app/Smarted.java b/library/src/main/java/com/smartnsoft/droid4me/app/Smarted.java old mode 100644 new mode 100755 diff --git a/library/src/main/java/com/smartnsoft/droid4me/app/package-info.java b/library/src/main/java/com/smartnsoft/droid4me/app/package-info.java old mode 100644 new mode 100755 diff --git a/library/src/main/java/com/smartnsoft/droid4me/bo/Business.java b/library/src/main/java/com/smartnsoft/droid4me/bo/Business.java old mode 100644 new mode 100755 diff --git a/library/src/main/java/com/smartnsoft/droid4me/bo/package-info.java b/library/src/main/java/com/smartnsoft/droid4me/bo/package-info.java old mode 100644 new mode 100755 diff --git a/library/src/main/java/com/smartnsoft/droid4me/cache/Cacher.java b/library/src/main/java/com/smartnsoft/droid4me/cache/Cacher.java old mode 100644 new mode 100755 diff --git a/library/src/main/java/com/smartnsoft/droid4me/cache/DbPersistence.java b/library/src/main/java/com/smartnsoft/droid4me/cache/DbPersistence.java old mode 100644 new mode 100755 diff --git a/library/src/main/java/com/smartnsoft/droid4me/cache/FilePersistence.java b/library/src/main/java/com/smartnsoft/droid4me/cache/FilePersistence.java old mode 100644 new mode 100755 diff --git a/library/src/main/java/com/smartnsoft/droid4me/cache/MemoryCacher.java b/library/src/main/java/com/smartnsoft/droid4me/cache/MemoryCacher.java old mode 100644 new mode 100755 diff --git a/library/src/main/java/com/smartnsoft/droid4me/cache/NullPersistence.java b/library/src/main/java/com/smartnsoft/droid4me/cache/NullPersistence.java old mode 100644 new mode 100755 diff --git a/library/src/main/java/com/smartnsoft/droid4me/cache/Persistence.java b/library/src/main/java/com/smartnsoft/droid4me/cache/Persistence.java old mode 100644 new mode 100755 diff --git a/library/src/main/java/com/smartnsoft/droid4me/cache/Values.java b/library/src/main/java/com/smartnsoft/droid4me/cache/Values.java old mode 100644 new mode 100755 diff --git a/library/src/main/java/com/smartnsoft/droid4me/cache/package-info.java b/library/src/main/java/com/smartnsoft/droid4me/cache/package-info.java old mode 100644 new mode 100755 diff --git a/library/src/main/java/com/smartnsoft/droid4me/config/AssetsConfigurationLoader.java b/library/src/main/java/com/smartnsoft/droid4me/config/AssetsConfigurationLoader.java old mode 100644 new mode 100755 diff --git a/library/src/main/java/com/smartnsoft/droid4me/config/ConfigurationLoader.java b/library/src/main/java/com/smartnsoft/droid4me/config/ConfigurationLoader.java old mode 100644 new mode 100755 diff --git a/library/src/main/java/com/smartnsoft/droid4me/config/InternalStorageConfigurationLoader.java b/library/src/main/java/com/smartnsoft/droid4me/config/InternalStorageConfigurationLoader.java old mode 100644 new mode 100755 diff --git a/library/src/main/java/com/smartnsoft/droid4me/config/ResourcesConfigurationLoader.java b/library/src/main/java/com/smartnsoft/droid4me/config/ResourcesConfigurationLoader.java old mode 100644 new mode 100755 diff --git a/library/src/main/java/com/smartnsoft/droid4me/config/package-info.java b/library/src/main/java/com/smartnsoft/droid4me/config/package-info.java old mode 100644 new mode 100755 diff --git a/library/src/main/java/com/smartnsoft/droid4me/content/SmartBroadcastReceiver.java b/library/src/main/java/com/smartnsoft/droid4me/content/SmartBroadcastReceiver.java old mode 100644 new mode 100755 diff --git a/library/src/main/java/com/smartnsoft/droid4me/content/TokenKeeper.java b/library/src/main/java/com/smartnsoft/droid4me/content/TokenKeeper.java old mode 100644 new mode 100755 diff --git a/library/src/main/java/com/smartnsoft/droid4me/content/package-info.java b/library/src/main/java/com/smartnsoft/droid4me/content/package-info.java old mode 100644 new mode 100755 diff --git a/library/src/main/java/com/smartnsoft/droid4me/debug/Droid4meDebugInterceptor.java b/library/src/main/java/com/smartnsoft/droid4me/debug/Droid4meDebugInterceptor.java old mode 100644 new mode 100755 diff --git a/library/src/main/java/com/smartnsoft/droid4me/debug/package-info.java b/library/src/main/java/com/smartnsoft/droid4me/debug/package-info.java old mode 100644 new mode 100755 diff --git a/library/src/main/java/com/smartnsoft/droid4me/download/BasisBitmapDownloader.java b/library/src/main/java/com/smartnsoft/droid4me/download/BasisBitmapDownloader.java old mode 100644 new mode 100755 index 6fb2c602..ce975f61 --- a/library/src/main/java/com/smartnsoft/droid4me/download/BasisBitmapDownloader.java +++ b/library/src/main/java/com/smartnsoft/droid4me/download/BasisBitmapDownloader.java @@ -22,8 +22,6 @@ package com.smartnsoft.droid4me.download; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.util.HashSet; @@ -645,47 +643,6 @@ protected final void onBitmapReady(boolean allright, BitmapClass bitmap) } - protected final boolean checkIfInpustreamIsAGif(InputStream inputStream) - { - final ByteArrayOutputStream buffer = new ByteArrayOutputStream(); - int nRead; - boolean ok = false; - final byte[] data = new byte[16384]; - - try - { - while ((nRead = inputStream.read(data, 0, data.length)) != -1) - { - buffer.write(data, 0, nRead); - } - buffer.flush(); - - int index = 0; - while (index < 3) - { - if (data[index] == 46 || data[index] == 47 || data[index] == 49) - { - ok = true; - index++; - } - else - { - ok = false; - break; - } - } - } - catch (IOException exception) - { - if (log.isWarnEnabled() == true) - { - log.warn("Problem occured with the inputsream", exception); - } - } - - return ok; - } - // TODO: define a pool of Command objects, so as to minimize GC, if possible private final class PreCommand extends BasisCommand @@ -1124,14 +1081,11 @@ public final void onDownloaded(InputStream inputStream) } // We attempt to convert the input stream into a bitmap - final BitmapClass bitmap = fromInputStreamToBitmap(inputStream); + final BitmapClass bitmap = fromInputStreamToBitmapable(inputStream); if (bitmap == null) { - if (checkIfInpustreamIsAGif(inputStream) == false) - { - onBitmapReady(false, null); - return; - } + onBitmapReady(false, null); + return; } // We put in cache the bitmap @@ -1368,7 +1322,7 @@ protected InputStream onInputStreamDownloaded(InputStream inputStream) * @param inputStream an input stream corresponding to a bitmap * @return {@code null} if the input stream could not be properly converted ; a valid bitmap otherwise */ - protected BitmapClass fromInputStreamToBitmap(InputStream inputStream) + protected BitmapClass fromInputStreamToBitmapable(InputStream inputStream) { try { @@ -1430,7 +1384,7 @@ private final BitmapClass retrieveBitmap() } try { - final BitmapClass bitmap = fromInputStreamToBitmap(inputStream); + final BitmapClass bitmap = fromInputStreamToBitmapable(inputStream); if (downloadStartTimestamp >= 0) { final long stop = System.currentTimeMillis(); diff --git a/library/src/main/java/com/smartnsoft/droid4me/download/BasisDownloadInstructions.java b/library/src/main/java/com/smartnsoft/droid4me/download/BasisDownloadInstructions.java old mode 100644 new mode 100755 diff --git a/library/src/main/java/com/smartnsoft/droid4me/download/BitmapDownloader.java b/library/src/main/java/com/smartnsoft/droid4me/download/BitmapDownloader.java old mode 100644 new mode 100755 diff --git a/library/src/main/java/com/smartnsoft/droid4me/download/CoreBitmapDownloader.java b/library/src/main/java/com/smartnsoft/droid4me/download/CoreBitmapDownloader.java old mode 100644 new mode 100755 diff --git a/library/src/main/java/com/smartnsoft/droid4me/download/DownloadContracts.java b/library/src/main/java/com/smartnsoft/droid4me/download/DownloadContracts.java old mode 100644 new mode 100755 diff --git a/library/src/main/java/com/smartnsoft/droid4me/download/DownloadInstructions.java b/library/src/main/java/com/smartnsoft/droid4me/download/DownloadInstructions.java old mode 100644 new mode 100755 index e309b4ef..ee6dc35c --- a/library/src/main/java/com/smartnsoft/droid4me/download/DownloadInstructions.java +++ b/library/src/main/java/com/smartnsoft/droid4me/download/DownloadInstructions.java @@ -40,9 +40,12 @@ import android.view.View; import android.widget.ImageView; +import com.smartnsoft.droid4me.download.BasisDownloadInstructions.Instructions; import com.smartnsoft.droid4me.download.DownloadContracts.Bitmapable; import com.smartnsoft.droid4me.download.DownloadContracts.Handlerable; import com.smartnsoft.droid4me.download.DownloadContracts.Viewable; +import com.smartnsoft.droid4me.download.gif.Gif; +import com.smartnsoft.droid4me.download.gif.GifEngine; /** * Gathers in one place the download instructions contracts used by {@link BitmapDownloader}. @@ -117,13 +120,24 @@ public Bitmap getBitmap() } - public final static class BitamapleGif + public final static class BitmapableGif implements Bitmapable { + private final Gif gif; + + public BitmapableGif(Gif gif) + { + this.gif = gif; + } + public int getSizeInBytes() { - return 0; + if (gif == null) + { + return 0; + } + return gif.getHeight() * gif.getWidth() * gif.getFramesCount(); } public void recycle() @@ -344,6 +358,108 @@ public InputStream onInputStreamDownloaded(String bitmapUid, Object imageSpecs, } + public static abstract class GifInstructions + implements BasisDownloadInstructions.Instructions + { + + @Override + public BitmapableGif hasLocalBitmap(ViewableView view, String bitmapUid, Object imageSpecs) + { + return null; + } + + @Override + public void onBindLocalBitmap(ViewableView view, BitmapableGif bitmap, String bitmapUid, Object imageSpecs) + { + } + + @Override + public String computeUrl(String bitmapUid, Object imageSpecs) + { + return bitmapUid; + } + + @Override + public BitmapableGif hasTemporaryBitmap(ViewableView view, String bitmapUid, Object imageSpecs) + { + return null; + } + + @Override + public void onBindTemporaryBitmap(ViewableView view, BitmapableGif bitmap, String bitmapUid, Object imageSpecs) + { + } + + @Override + public InputStream downloadInputStream(String bitmapUid, Object imageSpecs, String url) + throws IOException + { + return new URL(url).openStream(); + } + + @Override + public BitmapableGif convert(InputStream inputStream, String bitmapUid, Object imageSpecs, String url) + { + + return null; + } + + @Override + public void onBitmapReady(boolean allright, ViewableView view, BitmapableGif bitmap, String bitmapUid, + Object imageSpecs) + { + + } + + @Override + public boolean onBindBitmap(boolean downloaded, ViewableView view, BitmapableGif bitmap, String bitmapUid, + Object imageSpecs) + { + return true; + } + + @Override + public void onBitmapBound(boolean result, ViewableView view, String bitmapUid, Object imageSpecs) + { + } + + @Override + public void onOver(boolean aborted, ViewableView view, String bitmapUid, Object imageSpecs) + { + } + + @Override + public InputStream getInputStream(String imageUid, Object imageSpecs, String url, + BasisDownloadInstructions.InputStreamDownloadInstructor downloadInstructor) + throws IOException + { + return null; + } + + @Override + public InputStream onInputStreamDownloaded(String imageUid, Object imageSpecs, String url, InputStream inputStream) + { + return null; + } + + protected abstract Bitmap hasLocalBitmap(View view, String bitmapUid, Object imageSpecs); + + protected abstract void onBindLocalGif(View view, Gif gif, String bitmapUid, Object imageSpecs); + + protected abstract Bitmap hasTemporaryBitmap(View view, String bitmapUid, Object imageSpecs); + + protected abstract void onBindTemporaryBitmap(View view, Bitmap bitmap, String bitmapUid, Object imageSpecs); + + protected abstract void onGifReady(boolean allright, View view, Gif bitmap, String bitmapUid, + Object imageSpecs); + + protected abstract boolean onBindGif(boolean downloaded, View view, Gif bitmap, String bitmapUid, + Object imageSpecs); + + protected abstract void onBitmapBound(boolean result, View view, String bitmapUid, Object imageSpecs); + + } + /** * An implementation of the {@link Instructions}, which returns the bitmapUid as an URL, and which does not present any temporary nor * local bitmap. @@ -482,6 +598,86 @@ protected Bitmap convertInputStreamToBitmap(InputStream inputStream, String bitm } + + public static class GifAbstractInstructions + extends GifInstructions + { + + @Override + public InputStream downloadInputStream(String bitmapUid, Object imageSpecs, String url) + throws IOException + { + final URL aURL = new URL(url); + final URLConnection connection = aURL.openConnection(); + connection.connect(); + final InputStream inputStream = connection.getInputStream(); + return inputStream; + } + + @Override + public BitmapableGif convert(InputStream inputStream, String bitmapUid, Object imageSpecs, String url) + { + final long start = System.currentTimeMillis(); + final Gif theGif = convertInputStreamToGif(inputStream, url); + if (theGif != null) + { + if (CoreBitmapDownloader.IS_DEBUG_TRACE && CoreBitmapDownloader.log.isDebugEnabled()) + { + final long stop = System.currentTimeMillis(); + CoreBitmapDownloader.log.debug("The thread '" + Thread.currentThread().getName() + "' decoded in " + (stop - start) + " relative to the URL '" + url + "'"); + } + } + return theGif == null ? null : new BitmapableGif(theGif); + } + + @Override + protected Bitmap hasLocalBitmap(View view, String bitmapUid, Object imageSpecs) + { + return null; + } + + @Override + protected void onBindLocalGif(View view, Gif gif, String bitmapUid, Object imageSpecs) + { + } + + @Override + protected Bitmap hasTemporaryBitmap(View view, String bitmapUid, Object imageSpecs) + { + return null; + } + + @Override + protected void onBindTemporaryBitmap(View view, Bitmap bitmap, String bitmapUid, Object imageSpecs) + { + + } + + @Override + protected void onGifReady(boolean allright, View view, Gif bitmap, String bitmapUid, Object imageSpecs) + { + + } + + @Override + protected boolean onBindGif(boolean downloaded, View view, Gif gif, String bitmapUid, Object imageSpecs) + { + final GifEngine engine = new GifEngine(((ImageView) (view)), gif); + return true; + } + + @Override + protected void onBitmapBound(boolean result, View view, String bitmapUid, Object imageSpecs) + { + + } + + protected Gif convertInputStreamToGif(InputStream inputStream, String url) + { + return new Gif(inputStream, url); + } + } + /** * Return the downloaded InputStream * diff --git a/library/src/main/java/com/smartnsoft/droid4me/download/DownloadSpecs.java b/library/src/main/java/com/smartnsoft/droid4me/download/DownloadSpecs.java old mode 100644 new mode 100755 diff --git a/library/src/main/java/com/smartnsoft/droid4me/download/GifDecoder.java b/library/src/main/java/com/smartnsoft/droid4me/download/GifDecoder.java deleted file mode 100644 index 07b7bf98..00000000 --- a/library/src/main/java/com/smartnsoft/droid4me/download/GifDecoder.java +++ /dev/null @@ -1,928 +0,0 @@ -package com.smartnsoft.droid4me.download; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.nio.BufferUnderflowException; -import java.nio.ByteBuffer; -import java.nio.ByteOrder; -import java.util.ArrayList; - -import android.graphics.Bitmap; -import android.util.Log; - -/** - * This class was created by : devunwired @see available on this Gist. It is - * an optimized implementation of GifDecode.java GifDecode.java - * for Android. - * - * @author Antoine Gerard - * @since 2017.10.16 - */ - -public final class GifDecoder -{ - - private static final String TAG = GifDecoder.class.getSimpleName(); - - /** - * File read status: No errors. - */ - public static final int STATUS_OK = 0; - - /** - * File read status: Error decoding file (may be partially decoded) - */ - public static final int STATUS_FORMAT_ERROR = 1; - - /** - * File read status: Unable to open source. - */ - public static final int STATUS_OPEN_ERROR = 2; - - /** - * max decoder pixel stack size - */ - protected static final int MAX_STACK_SIZE = 4096; - - /** - * GIF Disposal Method meaning take no action - */ - private static final int DISPOSAL_UNSPECIFIED = 0; - - /** - * GIF Disposal Method meaning leave canvas from previous frame - */ - private static final int DISPOSAL_NONE = 1; - - /** - * GIF Disposal Method meaning clear canvas to background color - */ - private static final int DISPOSAL_BACKGROUND = 2; - - /** - * GIF Disposal Method meaning clear canvas to frame before last - */ - private static final int DISPOSAL_PREVIOUS = 3; - - /** - * Global status code of GIF data parsing - */ - protected int status; - - // Global File Header values and parsing flags - protected int width; // full image width - - protected int height; // full image height - - protected boolean gctFlag; // global color table used - - protected int gctSize; // size of global color table - - protected int loopCount = 1; // iterations; 0 = repeat forever - - protected int[] gct; // global color table - - protected int[] act; // active color table - - protected int bgIndex; // background color index - - protected int bgColor; // background color - - protected int pixelAspect; // pixel aspect ratio - - protected boolean lctFlag; // local color table flag - - protected int lctSize; // local color table size - - // Raw GIF data from input source - protected ByteBuffer rawData; - - // Raw data read working array - protected byte[] block = new byte[256]; // current data block - - protected int blockSize = 0; // block size last graphic control extension info - - // LZW decoder working arrays - protected short[] prefix; - - protected byte[] suffix; - - protected byte[] pixelStack; - - protected byte[] mainPixels; - - protected int[] mainScratch, copyScratch; - - protected ArrayList frames; // frames read from current file - - protected GifFrame currentFrame; - - protected Bitmap previousImage, currentImage, renderImage; - - protected int framePointer; - - protected int frameCount; - - /** - * Inner model class housing metadata for each frame - */ - private static class GifFrame - { - - public int ix, iy, iw, ih; - - /* Control Flags */ - public boolean interlace; - - public boolean transparency; - - /* Disposal Method */ - public int dispose; - - /* Transparency Index */ - public int transIndex; - - /* Delay, in ms, to next frame */ - public int delay; - - /* Index in the raw buffer where we need to start reading to decode */ - public int bufferFrameStart; - - /* Local Color Table */ - public int[] lct; - } - - /** - * Move the animation frame counter forward - */ - public void advance() - { - framePointer = (framePointer + 1) % frameCount; - } - - /** - * Gets display duration for specified frame. - * - * @param n int index of frame - * @return delay in milliseconds - */ - public int getDelay(final int n) - { - int delay = -1; - if ((n >= 0) && (n < frameCount)) - { - delay = frames.get(n).delay; - } - return delay; - } - - /** - * Gets display duration for the upcoming frame - */ - public int getNextDelay() - { - if (frameCount <= 0 || framePointer < 0) - { - return -1; - } - - return getDelay(framePointer); - } - - /** - * Gets the number of frames read from file. - * - * @return frame count - */ - public int getFrameCount() - { - return frameCount; - } - - /** - * Gets the current index of the animation frame, or -1 if animation hasn't not yet started - * - * @return frame index - */ - public int getCurrentFrameIndex() - { - return framePointer; - } - - /** - * Gets the "Netscape" iteration count, if any. A count of 0 means repeat indefinitiely. - * - * @return iteration count if one was specified, else 1. - */ - public int getLoopCount() - { - return loopCount; - } - - /** - * Get the next frame in the animation sequence. - * - * @return Bitmap representation of frame - */ - public Bitmap getNextFrame() - { - if (frameCount <= 0 || framePointer < 0 || currentImage == null) - { - return null; - } - - final GifFrame frame = frames.get(framePointer); - - // Set the appropriate color table - if (frame.lct == null) - { - act = gct; - } - else - { - act = frame.lct; - if (bgIndex == frame.transIndex) - { - bgColor = 0; - } - } - - int save = 0; - if (frame.transparency) - { - save = act[frame.transIndex]; - act[frame.transIndex] = 0; // set transparent color if specified - } - if (act == null) - { - Log.w(TAG, "No Valid Color Table"); - status = STATUS_FORMAT_ERROR; // no color table defined - return null; - } - - setPixels(framePointer); // transfer pixel data to image - - // Reset the transparent pixel in the color table - if (frame.transparency) - { - act[frame.transIndex] = save; - } - - return currentImage; - } - - /** - * Reads GIF image from stream - * - * @param is containing GIF file. - * @return read status code (0 = no errors) - */ - public int read(final InputStream is, final int contentLength) - { - if (is != null) - { - try - { - final int capacity = (contentLength > 0) ? (contentLength + 4096) : 4096; - final ByteArrayOutputStream buffer = new ByteArrayOutputStream(capacity); - int nRead; - final byte[] data = new byte[16384]; - while ((nRead = is.read(data, 0, data.length)) != -1) - { - buffer.write(data, 0, nRead); - } - buffer.flush(); - - read(buffer.toByteArray()); - } - catch (final IOException e) - { - Log.w(TAG, "Error reading data from stream", e); - } - } - else - { - status = STATUS_OPEN_ERROR; - } - - try - { - is.close(); - } - catch (final Exception e) - { - Log.w(TAG, "Error closing stream", e); - } - - return status; - } - - /** - * Reads GIF image from byte array - * - * @param data containing GIF file. - * @return read status code (0 = no errors) - */ - public int read(final byte[] data) - { - init(); - if (data != null) - { - // Initiliaze the raw data buffer - rawData = ByteBuffer.wrap(data); - rawData.rewind(); - rawData.order(ByteOrder.LITTLE_ENDIAN); - - readHeader(); - if (!err()) - { - readContents(); - if (frameCount < 0) - { - status = STATUS_FORMAT_ERROR; - } - } - } - else - { - status = STATUS_OPEN_ERROR; - } - - return status; - } - - /** - * Creates new frame image from current data (and previous frames as specified by their disposition codes). - */ - protected void setPixels(final int frameIndex) - { - final GifFrame currentFrame = frames.get(frameIndex); - GifFrame previousFrame = null; - final int previousIndex = frameIndex - 1; - if (previousIndex >= 0) - { - previousFrame = frames.get(previousIndex); - } - - // final location of blended pixels - final int[] dest = mainScratch; - - // fill in starting image contents based on last image's dispose code - if (previousFrame != null && previousFrame.dispose > DISPOSAL_UNSPECIFIED) - { - if (previousFrame.dispose == DISPOSAL_NONE && currentImage != null) - { - // Start with the current image - currentImage.getPixels(dest, 0, width, 0, 0, width, height); - } - if (previousFrame.dispose == DISPOSAL_BACKGROUND) - { - // Start with a canvas filled with the background color - int c = 0; - if (!currentFrame.transparency) - { - c = bgColor; - } - for (int i = 0; i < previousFrame.ih; i++) - { - final int n1 = (previousFrame.iy + i) * width + previousFrame.ix; - final int n2 = n1 + previousFrame.iw; - for (int k = n1; k < n2; k++) - { - dest[k] = c; - } - } - } - if (previousFrame.dispose == DISPOSAL_PREVIOUS && previousImage != null) - { - // Start with the previous frame - previousImage.getPixels(dest, 0, width, 0, 0, width, height); - } - } - - // Decode pixels for this frame into the global pixels[] scratch - decodeBitmapData(currentFrame, mainPixels); // decode pixel data - - // copy each source line to the appropriate place in the destination - int pass = 1; - int inc = 8; - int iline = 0; - for (int i = 0; i < currentFrame.ih; i++) - { - int line = i; - if (currentFrame.interlace) - { - if (iline >= currentFrame.ih) - { - pass++; - switch (pass) - { - case 2: - iline = 4; - break; - case 3: - iline = 2; - inc = 4; - break; - case 4: - iline = 1; - inc = 2; - break; - default: - break; - } - } - line = iline; - iline += inc; - } - line += currentFrame.iy; - if (line < height) - { - final int k = line * width; - int dx = k + currentFrame.ix; // start of line in dest - int dlim = dx + currentFrame.iw; // end of dest line - if ((k + width) < dlim) - { - dlim = k + width; // past dest edge - } - int sx = i * currentFrame.iw; // start of line in source - while (dx < dlim) - { - // map color and insert in destination - final int index = (mainPixels[sx++]) & 0xff; - final int c = act[index]; - if (c != 0) - { - dest[dx] = c; - } - dx++; - } - } - } - - // Copy pixels into previous image - currentImage.getPixels(copyScratch, 0, width, 0, 0, width, height); - previousImage.setPixels(copyScratch, 0, width, 0, 0, width, height); - // Set pixels for current image - currentImage.setPixels(dest, 0, width, 0, 0, width, height); - } - - /** - * Decodes LZW image data into pixel array. Adapted from John Cristy's BitmapMagick. - */ - protected void decodeBitmapData(final GifFrame frame, byte[] dstPixels) - { - if (frame != null) - { - // Jump to the frame start position - rawData.position(frame.bufferFrameStart); - } - - final int nullCode = -1; - final int npix = (frame == null) ? width * height : frame.iw * frame.ih; - int available, clear, code_mask, code_size, end_of_information, in_code, old_code, bits, code, count, i, datum, data_size, first, top, bi, pi; - - if (dstPixels == null || dstPixels.length < npix) - { - dstPixels = new byte[npix]; // allocate new pixel array - } - if (prefix == null) - { - prefix = new short[MAX_STACK_SIZE]; - } - if (suffix == null) - { - suffix = new byte[MAX_STACK_SIZE]; - } - if (pixelStack == null) - { - pixelStack = new byte[MAX_STACK_SIZE + 1]; - } - - // Initialize GIF data stream decoder. - data_size = read(); - clear = 1 << data_size; - end_of_information = clear + 1; - available = clear + 2; - old_code = nullCode; - code_size = data_size + 1; - code_mask = (1 << code_size) - 1; - for (code = 0; code < clear; code++) - { - prefix[code] = 0; // XXX ArrayIndexOutOfBoundsException - suffix[code] = (byte) code; - } - - // Decode GIF pixel stream. - datum = bits = count = first = top = pi = bi = 0; - for (i = 0; i < npix; ) - { - if (top == 0) - { - if (bits < code_size) - { - // Load bytes until there are enough bits for a code. - if (count == 0) - { - // Read a new data block. - count = readBlock(); - if (count <= 0) - { - break; - } - bi = 0; - } - datum += ((block[bi]) & 0xff) << bits; - bits += 8; - bi++; - count--; - continue; - } - // Get the next code. - code = datum & code_mask; - datum >>= code_size; - bits -= code_size; - // Interpret the code - if ((code > available) || (code == end_of_information)) - { - break; - } - if (code == clear) - { - // Reset decoder. - code_size = data_size + 1; - code_mask = (1 << code_size) - 1; - available = clear + 2; - old_code = nullCode; - continue; - } - if (old_code == nullCode) - { - pixelStack[top++] = suffix[code]; - old_code = code; - first = code; - continue; - } - in_code = code; - if (code == available) - { - pixelStack[top++] = (byte) first; - code = old_code; - } - while (code > clear) - { - pixelStack[top++] = suffix[code]; - code = prefix[code]; - } - first = (suffix[code]) & 0xff; - // Add a new string to the string table, - if (available >= MAX_STACK_SIZE) - { - break; - } - pixelStack[top++] = (byte) first; - prefix[available] = (short) old_code; - suffix[available] = (byte) first; - available++; - if (((available & code_mask) == 0) && (available < MAX_STACK_SIZE)) - { - code_size++; - code_mask += available; - } - old_code = in_code; - } - // Pop a pixel off the pixel stack. - top--; - dstPixels[pi++] = pixelStack[top]; - i++; - } - - for (i = pi; i < npix; i++) - { - dstPixels[i] = 0; // clear missing pixels - } - } - - /** - * Returns true if an error was encountered during reading/decoding - */ - protected boolean err() - { - return status != STATUS_OK; - } - - /** - * Initializes or re-initializes reader - */ - protected void init() - { - status = STATUS_OK; - frameCount = 0; - framePointer = -1; - frames = new ArrayList(); - gct = null; - } - - /** - * Reads a single byte from the input stream. - */ - protected int read() - { - int curByte = 0; - try - { - curByte = (rawData.get() & 0xFF); - } - catch (final Exception e) - { - status = STATUS_FORMAT_ERROR; - } - return curByte; - } - - /** - * Reads next variable length block from input. - * - * @return number of bytes stored in "buffer" - */ - protected int readBlock() - { - blockSize = read(); - int n = 0; - if (blockSize > 0) - { - try - { - int count; - while (n < blockSize) - { - count = blockSize - n; - rawData.get(block, n, count); - - n += count; - } - } - catch (final Exception e) - { - Log.w(TAG, "Error Reading Block", e); - status = STATUS_FORMAT_ERROR; - } - } - return n; - } - - /** - * Reads color table as 256 RGB integer values - * - * @param ncolors int number of colors to read - * @return int array containing 256 colors (packed ARGB with full alpha) - */ - protected int[] readColorTable(final int ncolors) - { - final int nbytes = 3 * ncolors; - int[] tab = null; - final byte[] c = new byte[nbytes]; - - try - { - rawData.get(c); - - tab = new int[256]; // max size to avoid bounds checks - int i = 0; - int j = 0; - while (i < ncolors) - { - final int r = (c[j++]) & 0xff; - final int g = (c[j++]) & 0xff; - final int b = (c[j++]) & 0xff; - tab[i++] = 0xff000000 | (r << 16) | (g << 8) | b; - } - } - catch (final BufferUnderflowException e) - { - Log.w(TAG, "Format Error Reading Color Table", e); - status = STATUS_FORMAT_ERROR; - } - - return tab; - } - - /** - * Main file parser. Reads GIF content blocks. - */ - protected void readContents() - { - // read GIF file content blocks - boolean done = false; - while (!(done || err())) - { - int code = read(); - switch (code) - { - case 0x2C: // image separator - readBitmap(); - break; - case 0x21: // extension - code = read(); - switch (code) - { - case 0xf9: // graphics control extension - // Start a new frame - currentFrame = new GifFrame(); - readGraphicControlExt(); - break; - case 0xff: // application extension - readBlock(); - String app = ""; - for (int i = 0; i < 11; i++) - { - app += (char) block[i]; - } - if (app.equals("NETSCAPE2.0")) - { - readNetscapeExt(); - } - else - { - skip(); // don't care - } - break; - case 0xfe:// comment extension - skip(); - break; - case 0x01:// plain text extension - skip(); - break; - default: // uninteresting extension - skip(); - } - break; - case 0x3b: // terminator - done = true; - break; - case 0x00: // bad byte, but keep going and see what happens break; - default: - status = STATUS_FORMAT_ERROR; - } - } - } - - /** - * Reads GIF file header information. - */ - protected void readHeader() - { - String id = ""; - for (int i = 0; i < 6; i++) - { - id += (char) read(); - } - if (!id.startsWith("GIF")) - { - status = STATUS_FORMAT_ERROR; - return; - } - readLSD(); - if (gctFlag && !err()) - { - gct = readColorTable(gctSize); - bgColor = gct[bgIndex]; - } - } - - /** - * Reads Graphics Control Extension values - */ - protected void readGraphicControlExt() - { - read(); // block size - final int packed = read(); // packed fields - currentFrame.dispose = (packed & 0x1c) >> 2; // disposal method - if (currentFrame.dispose == 0) - { - currentFrame.dispose = 1; // elect to keep old image if discretionary - } - currentFrame.transparency = (packed & 1) != 0; - currentFrame.delay = readShort() * 10; // delay in milliseconds - currentFrame.transIndex = read(); // transparent color index - read(); // block terminator - } - - /** - * Reads next frame image - */ - protected void readBitmap() - { - currentFrame.ix = readShort(); // (sub)image position & size - currentFrame.iy = readShort(); - currentFrame.iw = readShort(); - currentFrame.ih = readShort(); - - final int packed = read(); - lctFlag = (packed & 0x80) != 0; // 1 - local color table flag interlace - lctSize = (int) Math.pow(2, (packed & 0x07) + 1); - // 3 - sort flag - // 4-5 - reserved lctSize = 2 << (packed & 7); // 6-8 - local color - // table size - currentFrame.interlace = (packed & 0x40) != 0; - if (lctFlag) - { - currentFrame.lct = readColorTable(lctSize); // read table - } - else - { - currentFrame.lct = null; // No local color table - } - - currentFrame.bufferFrameStart = rawData.position(); // Save this as the decoding position pointer - - decodeBitmapData(null, mainPixels); // false decode pixel data to advance buffer - skip(); - if (err()) - { - return; - } - - frameCount++; - frames.add(currentFrame); // add image to frame - } - - /** - * Reads Logical Screen Descriptor - */ - protected void readLSD() - { - // logical screen size - width = readShort(); - height = readShort(); - // packed fields - final int packed = read(); - gctFlag = (packed & 0x80) != 0; // 1 : global color table flag - // 2-4 : color resolution - // 5 : gct sort flag - gctSize = 2 << (packed & 7); // 6-8 : gct size - bgIndex = read(); // background color index - pixelAspect = read(); // pixel aspect ratio - - // Now that we know the size, init scratch arrays - try - { - mainPixels = new byte[width * height]; - mainScratch = new int[width * height]; - copyScratch = new int[width * height]; - - previousImage = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565); - currentImage = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565); - } - catch (final OutOfMemoryError e) - { - // Try with halving down the bitmap size - final int dimension = (width * height) / 2; - mainPixels = new byte[dimension]; - mainScratch = new int[dimension]; - copyScratch = new int[dimension]; - - previousImage = Bitmap.createBitmap(width / 2, height / 2, Bitmap.Config.RGB_565); - currentImage = Bitmap.createBitmap(width / 2, height / 2, Bitmap.Config.RGB_565); - } - } - - /** - * Reads Netscape extenstion to obtain iteration count - */ - protected void readNetscapeExt() - { - do - { - readBlock(); - if (block[0] == 1) - { - // loop count sub-block - final int b1 = (block[1]) & 0xff; - final int b2 = (block[2]) & 0xff; - loopCount = (b2 << 8) | b1; - } - } while ((blockSize > 0) && !err()); - } - - /** - * Reads next 16-bit value, LSB first - */ - protected int readShort() - { - // read 16-bit value - return rawData.getShort(); - } - - /** - * Skips variable length blocks up to and including next zero length block. - */ - protected void skip() - { - do - { - readBlock(); - } while ((blockSize > 0) && !err()); - } -} diff --git a/library/src/main/java/com/smartnsoft/droid4me/download/gif/Gif.java b/library/src/main/java/com/smartnsoft/droid4me/download/gif/Gif.java new file mode 100755 index 00000000..ed6cf91e --- /dev/null +++ b/library/src/main/java/com/smartnsoft/droid4me/download/gif/Gif.java @@ -0,0 +1,90 @@ +package com.smartnsoft.droid4me.download.gif; + +import java.io.InputStream; +import java.util.ArrayList; +import java.util.List; + +import android.graphics.Bitmap; + +import com.smartnsoft.droid4me.log.Logger; +import com.smartnsoft.droid4me.log.LoggerFactory; + + +/** + * @author Antoine Gerard + * @since 2017.10.18 + */ + +/** + * This class represents a Gif File. + */ +public final class Gif +{ + + public static final Logger log = LoggerFactory.getInstance("Gif"); + + public final List bitmaps; + + public Gif(InputStream inputStream, String url) + { + this.bitmaps = new ArrayList(); + final GifDecoder gifDecoder; + { + final long milliseconds = System.currentTimeMillis(); + gifDecoder = new GifDecoder(); + if (gifDecoder.read(inputStream, 8192) != GifDecoder.STATUS_OK) + { + if (log.isWarnEnabled()) + { + log.warn("Cannot decode the animated GIF image"); + } + return; + } + if (log.isInfoEnabled()) + { + log.info("Parsed the animated GIF with URL '" + url + "' in " + (System.currentTimeMillis() - milliseconds) + " ms"); + } + } + final int framesCount = gifDecoder.getFrameCount(); + { + final long milliseconds = System.currentTimeMillis(); + while (bitmaps.size() < framesCount) + { + gifDecoder.advance(); + final Bitmap nextBitmap = gifDecoder.getNextFrame(); + // We need to deep copy the bitmap + final Bitmap bitmap = nextBitmap.copy(nextBitmap.getConfig(), true); + if (bitmap == null) + { + break; + } + bitmaps.add(bitmap); + } + if (log.isInfoEnabled()) + { + log.info("Prepared the individual images belonging to the animated GIF with URL '" + url + "' in " + (System.currentTimeMillis() - milliseconds) + " ms"); + } + } + } + + + public int getHeight() + { + return bitmaps.size() < 1 ? 0 : bitmaps.get(0).getHeight(); + } + + public int getWidth() + { + return bitmaps.size() < 1 ? 0 : bitmaps.get(0).getWidth(); + } + + public int getFramesCount() + { + return bitmaps.size(); + } + + public Bitmap getBitmap(int index) + { + return bitmaps.get(index); + } +} diff --git a/library/src/main/java/com/smartnsoft/droid4me/download/gif/GifDecoder.java b/library/src/main/java/com/smartnsoft/droid4me/download/gif/GifDecoder.java new file mode 100755 index 00000000..9bb9dece --- /dev/null +++ b/library/src/main/java/com/smartnsoft/droid4me/download/gif/GifDecoder.java @@ -0,0 +1,1109 @@ +package com.smartnsoft.droid4me.download.gif; + +/** + * Copyright (c) 2013 Xcellent Creations, Inc. + * Copyright 2014 Google, Inc. All rights reserved. + *

+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and + * associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, + * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + *

+ * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + *

+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT + * NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.util.Arrays; + +import android.annotation.TargetApi; +import android.graphics.Bitmap; +import android.os.Build; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.util.Log; + +/** + * Reads frame data from a GIF image source and decodes it into individual frames + * for animation purposes. Image data can be read from either and InputStream source + * or a byte[]. + *

+ * This class is optimized for running animations with the frames, there + * are no methods to get individual frame images, only to decode the next frame in the + * animation sequence. Instead, it lowers its memory footprint by only housing the minimum + * data necessary to decode the next frame in the animation sequence. + *

+ * The animation must be manually moved forward using {@link #advance()} before requesting the next + * frame. This method must also be called before you request the first frame or an error will + * occur. + *

+ * Implementation adapted from sample code published in Lyons. (2004). Java for Programmers, + * republished under the MIT Open Source License + */ +public final class GifDecoder +{ + + private static final String TAG = GifDecoder.class.getSimpleName(); + + /** + * File read status: No errors. + */ + static final int STATUS_OK = 0; + + /** + * File read status: Error decoding file (may be partially decoded). + */ + static final int STATUS_FORMAT_ERROR = 1; + + /** + * File read status: Unable to open source. + */ + static final int STATUS_OPEN_ERROR = 2; + + /** + * Unable to fully decode the current frame. + */ + static final int STATUS_PARTIAL_DECODE = 3; + + /** + * max decoder pixel stack size. + */ + private static final int MAX_STACK_SIZE = 4096; + + /** + * GIF Disposal Method meaning take no action. + */ + private static final int DISPOSAL_UNSPECIFIED = 0; + + /** + * GIF Disposal Method meaning leave canvas from previous frame. + */ + private static final int DISPOSAL_NONE = 1; + + /** + * GIF Disposal Method meaning clear canvas to background color. + */ + private static final int DISPOSAL_BACKGROUND = 2; + + /** + * GIF Disposal Method meaning clear canvas to frame before last. + */ + private static final int DISPOSAL_PREVIOUS = 3; + + private static final int NULL_CODE = -1; + + private static final int INITIAL_FRAME_POINTER = -1; + + static final int LOOP_FOREVER = -1; + + private static final int BYTES_PER_INTEGER = 4; + + // Global File Header values and parsing flags. + // Active color table. + private int[] act; + + // Private color table that can be modified if needed. + private final int[] pct = new int[256]; + + // Raw GIF data from input source. + private ByteBuffer rawData; + + // Raw data read working array. + private byte[] block; + + // Temporary buffer for block reading. Reads 16k chunks from the native buffer for processing, + // to greatly reduce JNI overhead. + private static final int WORK_BUFFER_SIZE = 16384; + + @Nullable + private byte[] workBuffer; + + private int workBufferSize = 0; + + private int workBufferPosition = 0; + + private GifHeaderParser parser; + + // LZW decoder working arrays. + private short[] prefix; + + private byte[] suffix; + + private byte[] pixelStack; + + private byte[] mainPixels; + + private int[] mainScratch; + + private int framePointer; + + private int loopIndex; + + private GifHeader header; + + private BitmapProvider bitmapProvider; + + private Bitmap previousImage; + + private boolean savePrevious; + + private int status; + + private int sampleSize; + + private int downsampledHeight; + + private int downsampledWidth; + + private boolean isFirstFrameTransparent; + + /** + * An interface that can be used to provide reused {@link android.graphics.Bitmap}s to avoid GCs + * from constantly allocating {@link android.graphics.Bitmap}s for every frame. + */ + interface BitmapProvider + { + + /** + * Returns an {@link Bitmap} with exactly the given dimensions and config. + * + * @param width The width in pixels of the desired {@link android.graphics.Bitmap}. + * @param height The height in pixels of the desired {@link android.graphics.Bitmap}. + * @param config The {@link android.graphics.Bitmap.Config} of the desired {@link + * android.graphics.Bitmap}. + */ + @NonNull + Bitmap obtain(int width, int height, Bitmap.Config config); + + /** + * Releases the given Bitmap back to the pool. + */ + void release(Bitmap bitmap); + + /** + * Returns a byte array used for decoding and generating the frame bitmap. + * + * @param size the size of the byte array to obtain + */ + byte[] obtainByteArray(int size); + + /** + * Releases the given byte array back to the pool. + */ + void release(byte[] bytes); + + /** + * Returns an int array used for decoding/generating the frame bitmaps. + * + * @param size + */ + int[] obtainIntArray(int size); + + /** + * Release the given array back to the pool. + * + * @param array + */ + void release(int[] array); + } + + GifDecoder(BitmapProvider provider, GifHeader gifHeader, ByteBuffer rawData) + { + this(provider, gifHeader, rawData, 1 /*sampleSize*/); + } + + GifDecoder(BitmapProvider provider, GifHeader gifHeader, ByteBuffer rawData, + int sampleSize) + { + this(provider); + setData(gifHeader, rawData, sampleSize); + } + + GifDecoder(BitmapProvider provider) + { + this.bitmapProvider = provider; + header = new GifHeader(); + } + + GifDecoder() + { + this(new SimpleBitmapProvider()); + } + + int getWidth() + { + return header.width; + } + + int getHeight() + { + return header.height; + } + + ByteBuffer getData() + { + return rawData; + } + + /** + * Returns the current status of the decoder. + *

+ *

Status will update per frame to allow the caller to tell whether or not the current frame + * was decoded successfully and/or completely. Format and open failures persist across frames. + *

+ */ + int getStatus() + { + return status; + } + + /** + * Move the animation frame counter forward. + * + * @return boolean specifying if animation should continue or if loopCount has been fulfilled. + */ + boolean advance() + { + if (header.frameCount <= 0) + { + return false; + } + + if (framePointer == getFrameCount() - 1) + { + loopIndex++; + } + + if (header.loopCount != LOOP_FOREVER && loopIndex > header.loopCount) + { + return false; + } + + framePointer = (framePointer + 1) % header.frameCount; + return true; + } + + /** + * Gets display duration for specified frame. + * + * @param n int index of frame. + * @return delay in milliseconds. + */ + int getDelay(int n) + { + int delay = -1; + if ((n >= 0) && (n < header.frameCount)) + { + delay = header.frames.get(n).delay; + } + return delay; + } + + /** + * Gets display duration for the upcoming frame in ms. + */ + int getNextDelay() + { + if (header.frameCount <= 0 || framePointer < 0) + { + return 0; + } + + return getDelay(framePointer); + } + + /** + * Gets the number of frames read from file. + * + * @return frame count. + */ + int getFrameCount() + { + return header.frameCount; + } + + /** + * Gets the current index of the animation frame, or -1 if animation hasn't not yet started. + * + * @return frame index. + */ + int getCurrentFrameIndex() + { + return framePointer; + } + + /** + * Sets the frame pointer to a specific frame + * + * @return boolean true if the move was successful + */ + boolean setFrameIndex(int frame) + { + if (frame < INITIAL_FRAME_POINTER || frame >= getFrameCount()) + { + return false; + } + framePointer = frame; + return true; + } + + /** + * Resets the frame pointer to before the 0th frame, as if we'd never used this decoder to + * decode any frames. + */ + void resetFrameIndex() + { + framePointer = INITIAL_FRAME_POINTER; + } + + /** + * Resets the loop index to the first loop. + */ + void resetLoopIndex() + { + loopIndex = 0; + } + + /** + * Gets the "Netscape" iteration count, if any. A count of 0 means repeat indefinitely. + * + * @return iteration count if one was specified, else 1. + */ + int getLoopCount() + { + return header.loopCount; + } + + /** + * Gets the number of loops that have been shown. + * + * @return iteration count. + */ + int getLoopIndex() + { + return loopIndex; + } + + /** + * Returns an estimated byte size for this decoder based on the data provided to {@link + * #setData(GifHeader, byte[])}, as well as internal buffers. + */ + int getByteSize() + { + return rawData.limit() + mainPixels.length + (mainScratch.length * BYTES_PER_INTEGER); + } + + /** + * Get the next frame in the animation sequence. + * + * @return Bitmap representation of frame. + */ + synchronized Bitmap getNextFrame() + { + if (header.frameCount <= 0 || framePointer < 0) + { + if (Log.isLoggable(TAG, Log.DEBUG)) + { + Log.d(TAG, "unable to decode frame, frameCount=" + header.frameCount + " framePointer=" + + framePointer); + } + status = STATUS_FORMAT_ERROR; + } + if (status == STATUS_FORMAT_ERROR || status == STATUS_OPEN_ERROR) + { + if (Log.isLoggable(TAG, Log.DEBUG)) + { + Log.d(TAG, "Unable to decode frame, status=" + status); + } + return null; + } + status = STATUS_OK; + + GifFrame currentFrame = header.frames.get(framePointer); + GifFrame previousFrame = null; + int previousIndex = framePointer - 1; + if (previousIndex >= 0) + { + previousFrame = header.frames.get(previousIndex); + } + + // Set the appropriate color table. + act = currentFrame.lct != null ? currentFrame.lct : header.gct; + if (act == null) + { + if (Log.isLoggable(TAG, Log.DEBUG)) + { + Log.d(TAG, "No Valid Color Table for frame #" + framePointer); + } + // No color table defined. + status = STATUS_FORMAT_ERROR; + return null; + } + + // Reset the transparent pixel in the color table + if (currentFrame.transparency) + { + // Prepare local copy of color table ("pct = act"), see #1068 + System.arraycopy(act, 0, pct, 0, act.length); + // Forget about act reference from shared header object, use copied version + act = pct; + // Set transparent color if specified. + act[currentFrame.transIndex] = 0; + } + + // Transfer pixel data to image. + return setPixels(currentFrame, previousFrame); + } + + /** + * Reads GIF image from stream. + * + * @param is containing GIF file. + * @return read status code (0 = no errors). + */ + int read(InputStream is, int contentLength) + { + if (is != null) + { + try + { + int capacity = (contentLength > 0) ? (contentLength + 4096) : 16384; + ByteArrayOutputStream buffer = new ByteArrayOutputStream(capacity); + int nRead; + byte[] data = new byte[16384]; + while ((nRead = is.read(data, 0, data.length)) != -1) + { + buffer.write(data, 0, nRead); + } + buffer.flush(); + + read(buffer.toByteArray()); + } + catch (IOException e) + { + Log.w(TAG, "Error reading data from stream", e); + } + } + else + { + status = STATUS_OPEN_ERROR; + } + + try + { + if (is != null) + { + is.close(); + } + } + catch (IOException e) + { + Log.w(TAG, "Error closing stream", e); + } + + return status; + } + + void clear() + { + header = null; + if (mainPixels != null) + { + bitmapProvider.release(mainPixels); + } + if (mainScratch != null) + { + bitmapProvider.release(mainScratch); + } + if (previousImage != null) + { + bitmapProvider.release(previousImage); + } + previousImage = null; + rawData = null; + isFirstFrameTransparent = false; + if (block != null) + { + bitmapProvider.release(block); + } + if (workBuffer != null) + { + bitmapProvider.release(workBuffer); + } + } + + synchronized void setData(GifHeader header, byte[] data) + { + setData(header, ByteBuffer.wrap(data)); + } + + synchronized void setData(GifHeader header, ByteBuffer buffer) + { + setData(header, buffer, 1); + } + + synchronized void setData(GifHeader header, ByteBuffer buffer, int sampleSize) + { + if (sampleSize <= 0) + { + throw new IllegalArgumentException("Sample size must be >=0, not: " + sampleSize); + } + // Make sure sample size is a power of 2. + sampleSize = Integer.highestOneBit(sampleSize); + this.status = STATUS_OK; + this.header = header; + isFirstFrameTransparent = false; + framePointer = INITIAL_FRAME_POINTER; + resetLoopIndex(); + // Initialize the raw data buffer. + rawData = buffer.asReadOnlyBuffer(); + rawData.position(0); + rawData.order(ByteOrder.LITTLE_ENDIAN); + + // No point in specially saving an old frame if we're never going to use it. + savePrevious = false; + for (GifFrame frame : header.frames) + { + if (frame.dispose == DISPOSAL_PREVIOUS) + { + savePrevious = true; + break; + } + } + + this.sampleSize = sampleSize; + downsampledWidth = header.width / sampleSize; + downsampledHeight = header.height / sampleSize; + // Now that we know the size, init scratch arrays. + // TODO Find a way to avoid this entirely or at least downsample it (either should be possible). + mainPixels = bitmapProvider.obtainByteArray(header.width * header.height); + mainScratch = bitmapProvider.obtainIntArray(downsampledWidth * downsampledHeight); + } + + private GifHeaderParser getHeaderParser() + { + if (parser == null) + { + parser = new GifHeaderParser(); + } + return parser; + } + + /** + * Reads GIF image from byte array. + * + * @param data containing GIF file. + * @return read status code (0 = no errors). + */ + synchronized int read(byte[] data) + { + this.header = getHeaderParser().setData(data).parseHeader(); + if (data != null) + { + setData(header, data); + } + + return status; + } + + /** + * Creates new frame image from current data (and previous frames as specified by their + * disposition codes). + */ + private Bitmap setPixels(GifFrame currentFrame, GifFrame previousFrame) + { + // Final location of blended pixels. + final int[] dest = mainScratch; + + // clear all pixels when meet first frame + if (previousFrame == null) + { + Arrays.fill(dest, 0); + } + + // fill in starting image contents based on last image's dispose code + if (previousFrame != null && previousFrame.dispose > DISPOSAL_UNSPECIFIED) + { + // We don't need to do anything for DISPOSAL_NONE, if it has the correct pixels so will our + // mainScratch and therefore so will our dest array. + if (previousFrame.dispose == DISPOSAL_BACKGROUND) + { + // Start with a canvas filled with the background color + int c = 0; + if (!currentFrame.transparency) + { + c = header.bgColor; + if (currentFrame.lct != null && header.bgIndex == currentFrame.transIndex) + { + c = 0; + } + } + else if (framePointer == 0) + { + // TODO: We should check and see if all individual pixels are replaced. If they are, the + // first frame isn't actually transparent. For now, it's simpler and safer to assume + // drawing a transparent background means the GIF contains transparency. + isFirstFrameTransparent = true; + } + fillRect(dest, previousFrame, c); + } + else if (previousFrame.dispose == DISPOSAL_PREVIOUS) + { + if (previousImage == null) + { + fillRect(dest, previousFrame, 0); + } + else + { + // Start with the previous frame + int downsampledIH = previousFrame.ih / sampleSize; + int downsampledIY = previousFrame.iy / sampleSize; + int downsampledIW = previousFrame.iw / sampleSize; + int downsampledIX = previousFrame.ix / sampleSize; + int topLeft = downsampledIY * downsampledWidth + downsampledIX; + previousImage.getPixels(dest, topLeft, downsampledWidth, + downsampledIX, downsampledIY, downsampledIW, downsampledIH); + } + } + } + + // Decode pixels for this frame into the global pixels[] scratch. + decodeBitmapData(currentFrame); + + int downsampledIH = currentFrame.ih / sampleSize; + int downsampledIY = currentFrame.iy / sampleSize; + int downsampledIW = currentFrame.iw / sampleSize; + int downsampledIX = currentFrame.ix / sampleSize; + // Copy each source line to the appropriate place in the destination. + int pass = 1; + int inc = 8; + int iline = 0; + boolean isFirstFrame = framePointer == 0; + for (int i = 0; i < downsampledIH; i++) + { + int line = i; + if (currentFrame.interlace) + { + if (iline >= downsampledIH) + { + pass++; + switch (pass) + { + case 2: + iline = 4; + break; + case 3: + iline = 2; + inc = 4; + break; + case 4: + iline = 1; + inc = 2; + break; + default: + break; + } + } + line = iline; + iline += inc; + } + line += downsampledIY; + if (line < downsampledHeight) + { + int k = line * downsampledWidth; + // Start of line in dest. + int dx = k + downsampledIX; + // End of dest line. + int dlim = dx + downsampledIW; + if (k + downsampledWidth < dlim) + { + // Past dest edge. + dlim = k + downsampledWidth; + } + // Start of line in source. + int sx = i * sampleSize * currentFrame.iw; + int maxPositionInSource = sx + ((dlim - dx) * sampleSize); + while (dx < dlim) + { + // Map color and insert in destination. + int averageColor; + if (sampleSize == 1) + { + int currentColorIndex = ((int) mainPixels[sx]) & 0x000000ff; + averageColor = act[currentColorIndex]; + } + else + { + // TODO: This is substantially slower (up to 50ms per frame) than just grabbing the + // current color index above, even with a sample size of 1. + averageColor = averageColorsNear(sx, maxPositionInSource, currentFrame.iw); + } + if (averageColor != 0) + { + dest[dx] = averageColor; + } + else if (!isFirstFrameTransparent && isFirstFrame) + { + isFirstFrameTransparent = true; + } + sx += sampleSize; + dx++; + } + } + } + + // Copy pixels into previous image + if (savePrevious && (currentFrame.dispose == DISPOSAL_UNSPECIFIED + || currentFrame.dispose == DISPOSAL_NONE)) + { + if (previousImage == null) + { + previousImage = getNextBitmap(); + } + previousImage.setPixels(dest, 0, downsampledWidth, 0, 0, downsampledWidth, + downsampledHeight); + } + + // Set pixels for current image. + Bitmap result = getNextBitmap(); + result.setPixels(dest, 0, downsampledWidth, 0, 0, downsampledWidth, downsampledHeight); + return result; + } + + private void fillRect(int[] dest, GifFrame frame, int bgColor) + { + // The area used by the graphic must be restored to the background color. + int downsampledIH = frame.ih / sampleSize; + int downsampledIY = frame.iy / sampleSize; + int downsampledIW = frame.iw / sampleSize; + int downsampledIX = frame.ix / sampleSize; + int topLeft = downsampledIY * downsampledWidth + downsampledIX; + int bottomLeft = topLeft + downsampledIH * downsampledWidth; + for (int left = topLeft; left < bottomLeft; left += downsampledWidth) + { + int right = left + downsampledIW; + for (int pointer = left; pointer < right; pointer++) + { + dest[pointer] = bgColor; + } + } + } + + private int averageColorsNear(int positionInMainPixels, int maxPositionInMainPixels, + int currentFrameIw) + { + int alphaSum = 0; + int redSum = 0; + int greenSum = 0; + int blueSum = 0; + + int totalAdded = 0; + // Find the pixels in the current row. + for (int i = positionInMainPixels; + i < positionInMainPixels + sampleSize && i < mainPixels.length + && i < maxPositionInMainPixels; i++) + { + int currentColorIndex = ((int) mainPixels[i]) & 0xff; + int currentColor = act[currentColorIndex]; + if (currentColor != 0) + { + alphaSum += currentColor >> 24 & 0x000000ff; + redSum += currentColor >> 16 & 0x000000ff; + greenSum += currentColor >> 8 & 0x000000ff; + blueSum += currentColor & 0x000000ff; + totalAdded++; + } + } + // Find the pixels in the next row. + for (int i = positionInMainPixels + currentFrameIw; + i < positionInMainPixels + currentFrameIw + sampleSize && i < mainPixels.length + && i < maxPositionInMainPixels; i++) + { + int currentColorIndex = ((int) mainPixels[i]) & 0xff; + int currentColor = act[currentColorIndex]; + if (currentColor != 0) + { + alphaSum += currentColor >> 24 & 0x000000ff; + redSum += currentColor >> 16 & 0x000000ff; + greenSum += currentColor >> 8 & 0x000000ff; + blueSum += currentColor & 0x000000ff; + totalAdded++; + } + } + if (totalAdded == 0) + { + return 0; + } + else + { + return ((alphaSum / totalAdded) << 24) + | ((redSum / totalAdded) << 16) + | ((greenSum / totalAdded) << 8) + | (blueSum / totalAdded); + } + } + + /** + * Decodes LZW image data into pixel array. Adapted from John Cristy's BitmapMagick. + */ + private void decodeBitmapData(GifFrame frame) + { + workBufferSize = 0; + workBufferPosition = 0; + if (frame != null) + { + // Jump to the frame start position. + rawData.position(frame.bufferFrameStart); + } + + int npix = (frame == null) ? header.width * header.height : frame.iw * frame.ih; + int available, clear, codeMask, codeSize, endOfInformation, inCode, oldCode, bits, code, count, + i, datum, + dataSize, first, top, bi, pi; + + if (mainPixels == null || mainPixels.length < npix) + { + // Allocate new pixel array. + mainPixels = bitmapProvider.obtainByteArray(npix); + } + if (prefix == null) + { + prefix = new short[MAX_STACK_SIZE]; + } + if (suffix == null) + { + suffix = new byte[MAX_STACK_SIZE]; + } + if (pixelStack == null) + { + pixelStack = new byte[MAX_STACK_SIZE + 1]; + } + + // Initialize GIF data stream decoder. + dataSize = readByte(); + clear = 1 << dataSize; + endOfInformation = clear + 1; + available = clear + 2; + oldCode = NULL_CODE; + codeSize = dataSize + 1; + codeMask = (1 << codeSize) - 1; + for (code = 0; code < clear; code++) + { + // XXX ArrayIndexOutOfBoundsException. + prefix[code] = 0; + suffix[code] = (byte) code; + } + + // Decode GIF pixel stream. + datum = bits = count = first = top = pi = bi = 0; + for (i = 0; i < npix; ) + { + // Load bytes until there are enough bits for a code. + if (count == 0) + { + // Read a new data block. + count = readBlock(); + if (count <= 0) + { + status = STATUS_PARTIAL_DECODE; + break; + } + bi = 0; + } + + datum += (((int) block[bi]) & 0xff) << bits; + bits += 8; + bi++; + count--; + + while (bits >= codeSize) + { + // Get the next code. + code = datum & codeMask; + datum >>= codeSize; + bits -= codeSize; + + // Interpret the code. + if (code == clear) + { + // Reset decoder. + codeSize = dataSize + 1; + codeMask = (1 << codeSize) - 1; + available = clear + 2; + oldCode = NULL_CODE; + continue; + } + + if (code > available) + { + status = STATUS_PARTIAL_DECODE; + break; + } + + if (code == endOfInformation) + { + break; + } + + if (oldCode == NULL_CODE) + { + pixelStack[top++] = suffix[code]; + oldCode = code; + first = code; + continue; + } + inCode = code; + if (code >= available) + { + pixelStack[top++] = (byte) first; + code = oldCode; + } + while (code >= clear) + { + pixelStack[top++] = suffix[code]; + code = prefix[code]; + } + first = ((int) suffix[code]) & 0xff; + pixelStack[top++] = (byte) first; + + // Add a new string to the string table. + if (available < MAX_STACK_SIZE) + { + prefix[available] = (short) oldCode; + suffix[available] = (byte) first; + available++; + if (((available & codeMask) == 0) && (available < MAX_STACK_SIZE)) + { + codeSize++; + codeMask += available; + } + } + oldCode = inCode; + + while (top > 0) + { + // Pop a pixel off the pixel stack. + mainPixels[pi++] = pixelStack[--top]; + i++; + } + } + } + + // Clear missing pixels. + for (i = pi; i < npix; i++) + { + mainPixels[i] = 0; + } + } + + /** + * Reads the next chunk for the intermediate work buffer. + */ + private void readChunkIfNeeded() + { + if (workBufferSize > workBufferPosition) + { + return; + } + if (workBuffer == null) + { + workBuffer = bitmapProvider.obtainByteArray(WORK_BUFFER_SIZE); + } + workBufferPosition = 0; + workBufferSize = Math.min(rawData.remaining(), WORK_BUFFER_SIZE); + rawData.get(workBuffer, 0, workBufferSize); + } + + /** + * Reads a single byte from the input stream. + */ + private int readByte() + { + try + { + readChunkIfNeeded(); + return workBuffer[workBufferPosition++] & 0xFF; + } + catch (Exception e) + { + status = STATUS_FORMAT_ERROR; + return 0; + } + } + + /** + * Reads next variable length block from input. + * + * @return number of bytes stored in "buffer". + */ + private int readBlock() + { + int blockSize = readByte(); + if (blockSize > 0) + { + try + { + if (block == null) + { + block = bitmapProvider.obtainByteArray(255); + } + final int remaining = workBufferSize - workBufferPosition; + if (remaining >= blockSize) + { + // Block can be read from the current work buffer. + System.arraycopy(workBuffer, workBufferPosition, block, 0, blockSize); + workBufferPosition += blockSize; + } + else if (rawData.remaining() + remaining >= blockSize) + { + // Block can be read in two passes. + System.arraycopy(workBuffer, workBufferPosition, block, 0, remaining); + workBufferPosition = workBufferSize; + readChunkIfNeeded(); + final int secondHalfRemaining = blockSize - remaining; + System.arraycopy(workBuffer, 0, block, remaining, secondHalfRemaining); + workBufferPosition += secondHalfRemaining; + } + else + { + status = STATUS_FORMAT_ERROR; + } + } + catch (Exception e) + { + Log.w(TAG, "Error Reading Block", e); + status = STATUS_FORMAT_ERROR; + } + } + return blockSize; + } + + private Bitmap getNextBitmap() + { + Bitmap.Config config = isFirstFrameTransparent + ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565; + Bitmap result = bitmapProvider.obtain(downsampledWidth, downsampledHeight, config); + setAlpha(result); + return result; + } + + @TargetApi(12) + private static void setAlpha(Bitmap bitmap) + { + if (Build.VERSION.SDK_INT >= 12) + { + bitmap.setHasAlpha(true); + } + } +} \ No newline at end of file diff --git a/library/src/main/java/com/smartnsoft/droid4me/download/gif/GifEngine.java b/library/src/main/java/com/smartnsoft/droid4me/download/gif/GifEngine.java new file mode 100755 index 00000000..596ce481 --- /dev/null +++ b/library/src/main/java/com/smartnsoft/droid4me/download/gif/GifEngine.java @@ -0,0 +1,318 @@ +package com.smartnsoft.droid4me.download.gif; + +import android.graphics.Bitmap; +import android.os.Handler; +import android.os.Looper; +import android.util.Log; +import android.widget.ImageView; + +import com.smartnsoft.droid4me.download.BitmapDownloader; + +/** + * This class is used to display and + * animated a GIF inside every View that are + * based on ImageView. + * See {@link GifDecoder} for the logic. + * + * @author Antoine Gerard + * @since 2017.10.18 + */ + +public final class GifEngine + implements Runnable +{ + + private static final String TAG = "GifDecoderView"; + + private GifDecoder gifDecoder; + + private Gif gif; + + private Bitmap tmpBitmap; + + private final Handler handler = new Handler(Looper.getMainLooper()); + + private boolean animating; + + private boolean renderFrame; + + private boolean shouldClear; + + private Thread animationThread; + + private OnFrameAvailable frameCallback = null; + + private long framesDisplayDuration = -1L; + + private OnAnimationStop animationStopCallback = null; + + private OnAnimationStart animationStartCallback = null; + + private ImageView imageView; + + private final Runnable updateResults = new Runnable() + { + @Override + public void run() + { + if (tmpBitmap != null && !tmpBitmap.isRecycled() && imageView != null) + { + imageView.setImageBitmap(tmpBitmap); + } + } + }; + + private final Runnable cleanupRunnable = new Runnable() + { + @Override + public void run() + { + tmpBitmap = null; + gifDecoder = null; + animationThread = null; + shouldClear = false; + } + }; + + public GifEngine(final ImageView imageView, final Gif gif) + { + this.imageView = imageView; + this.gif = gif; + } + + public void setBytes(final byte[] bytes) + { + gifDecoder = new GifDecoder(); + try + { + gifDecoder.read(bytes); + } + catch (final Exception e) + { + gifDecoder = null; + Log.e(TAG, e.getMessage(), e); + return; + } + + if (animating) + { + startAnimationThread(); + } + else + { + gotoFrame(0); + } + } + + public long getFramesDisplayDuration() + { + return framesDisplayDuration; + } + + /** + * Sets custom display duration in milliseconds for the all frames. Should be called before {@link + * #startAnimation()} + * + * @param framesDisplayDuration Duration in milliseconds. Default value = -1, this property will + * be ignored and default delay from gif file will be used. + */ + public void setFramesDisplayDuration(long framesDisplayDuration) + { + this.framesDisplayDuration = framesDisplayDuration; + } + + public void startAnimation() + { + animating = true; + startAnimationThread(); + } + + public boolean isAnimating() + { + return animating; + } + + public void stopAnimation() + { + animating = false; + + if (animationThread != null) + { + animationThread.interrupt(); + animationThread = null; + } + } + + public void gotoFrame(int frame) + { + if (gifDecoder.getCurrentFrameIndex() == frame) + { + return; + } + if (gifDecoder.setFrameIndex(frame - 1) && !animating) + { + renderFrame = true; + startAnimationThread(); + } + } + + public void resetAnimation() + { + gifDecoder.resetLoopIndex(); + gotoFrame(0); + } + + public void clear() + { + animating = false; + renderFrame = false; + shouldClear = true; + stopAnimation(); + handler.post(cleanupRunnable); + } + + private boolean canStart() + { + return (animating || renderFrame) && gifDecoder != null && animationThread == null; + } + + public int getGifWidth() + { + return gifDecoder.getWidth(); + } + + public int getGifHeight() + { + return gifDecoder.getHeight(); + } + + @Override + public void run() + { + if (animationStartCallback != null) + { + animationStartCallback.onAnimationStart(); + } + + do + { + if (!animating && !renderFrame) + { + break; + } + boolean advance = gifDecoder.advance(); + + //milliseconds spent on frame decode + long frameDecodeTime = 0; + try + { + long before = System.nanoTime(); + tmpBitmap = gifDecoder.getNextFrame(); + if (frameCallback != null) + { + tmpBitmap = frameCallback.onFrameAvailable(tmpBitmap); + } + frameDecodeTime = (System.nanoTime() - before) / 1000000; + handler.post(updateResults); + } + catch (final ArrayIndexOutOfBoundsException | IllegalArgumentException e) + { + Log.w(TAG, e); + } + + renderFrame = false; + if (!animating || !advance) + { + animating = false; + break; + } + try + { + int delay = gifDecoder.getNextDelay(); + // Sleep for frame duration minus time already spent on frame decode + // Actually we need next frame decode duration here, + // but I use previous frame time to make code more readable + delay -= frameDecodeTime; + if (delay > 0) + { + Thread.sleep(framesDisplayDuration > 0 ? framesDisplayDuration : delay); + } + } + catch (final InterruptedException e) + { + // suppress exception + } + } while (animating); + + if (shouldClear) + { + handler.post(cleanupRunnable); + } + animationThread = null; + + if (animationStopCallback != null) + { + animationStopCallback.onAnimationStop(); + } + } + + public void animate() + { + if (gif != null && gif.bitmaps.isEmpty() == false) + { + + } + } + + public OnFrameAvailable getOnFrameAvailable() + { + return frameCallback; + } + + public void setOnFrameAvailable(OnFrameAvailable frameProcessor) + { + this.frameCallback = frameProcessor; + } + + public interface OnFrameAvailable + { + + Bitmap onFrameAvailable(Bitmap bitmap); + } + + public OnAnimationStop getOnAnimationStop() + { + return animationStopCallback; + } + + public void setOnAnimationStop(OnAnimationStop animationStop) + { + this.animationStopCallback = animationStop; + } + + public void setOnAnimationStart(OnAnimationStart animationStart) + { + this.animationStartCallback = animationStart; + } + + public interface OnAnimationStop + { + + void onAnimationStop(); + } + + public interface OnAnimationStart + { + + void onAnimationStart(); + } + + private void startAnimationThread() + { + if (canStart()) + { + animationThread = new Thread(this); + animationThread.start(); + } + } +} diff --git a/library/src/main/java/com/smartnsoft/droid4me/download/gif/GifFrame.java b/library/src/main/java/com/smartnsoft/droid4me/download/gif/GifFrame.java new file mode 100755 index 00000000..99eef774 --- /dev/null +++ b/library/src/main/java/com/smartnsoft/droid4me/download/gif/GifFrame.java @@ -0,0 +1,50 @@ +package com.smartnsoft.droid4me.download.gif; + +/** + * @author Antoine Gerard + * @since 2017.10.18 + */ + +/** + * Inner model class housing metadata for each frame. + */ +public final class GifFrame +{ + + int ix, iy, iw, ih; + + /** + * Control Flag. + */ + boolean interlace; + + /** + * Control Flag. + */ + boolean transparency; + + /** + * Disposal Method. + */ + int dispose; + + /** + * Transparency Index. + */ + int transIndex; + + /** + * Delay, in ms, to next frame. + */ + int delay; + + /** + * Index in the raw buffer where we need to start reading to decode. + */ + int bufferFrameStart; + + /** + * Local Color Table. + */ + int[] lct; +} diff --git a/library/src/main/java/com/smartnsoft/droid4me/download/gif/GifHeader.java b/library/src/main/java/com/smartnsoft/droid4me/download/gif/GifHeader.java new file mode 100755 index 00000000..483d2930 --- /dev/null +++ b/library/src/main/java/com/smartnsoft/droid4me/download/gif/GifHeader.java @@ -0,0 +1,77 @@ +package com.smartnsoft.droid4me.download.gif; + +/** + * @author Antoine Gerard + * @since 2017.10.18 + */ + +import java.util.ArrayList; +import java.util.List; + +/** + * A header object containing the number of frames in an animated GIF image as well as basic + * metadata like width and height that can be used to decode each individual frame of the GIF. Can + * be shared by one or more {@link GifDecoder}s to play the same animated GIF in multiple views. + */ +public final class GifHeader +{ + + int[] gct = null; + + int status = GifDecoder.STATUS_OK; + + int frameCount = 0; + + GifFrame currentFrame; + + List frames = new ArrayList<>(); + + // Logical screen size. + // Full image width. + int width; + + // Full image height. + int height; + + // 1 : global color table flag. + boolean gctFlag; + + // 2-4 : color resolution. + // 5 : gct sort flag. + // 6-8 : gct size. + int gctSize; + + // Background color index. + int bgIndex; + + // Pixel aspect ratio. + int pixelAspect; + + //TODO: this is set both during reading the header and while decoding frames... + int bgColor; + + int loopCount = 0; + + public int getHeight() + { + return height; + } + + public int getWidth() + { + return width; + } + + public int getNumFrames() + { + return frameCount; + } + + /** + * Global status code of GIF data parsing. + */ + public int getStatus() + { + return status; + } +} diff --git a/library/src/main/java/com/smartnsoft/droid4me/download/gif/GifHeaderParser.java b/library/src/main/java/com/smartnsoft/droid4me/download/gif/GifHeaderParser.java new file mode 100755 index 00000000..1fe66d6e --- /dev/null +++ b/library/src/main/java/com/smartnsoft/droid4me/download/gif/GifHeaderParser.java @@ -0,0 +1,484 @@ +package com.smartnsoft.droid4me.download.gif; + +import android.util.Log; + +import java.nio.BufferUnderflowException; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.util.Arrays; +/** + * @author Antoine Gerard + * @since 2017.10.18 + */ + +/** + * A class responsible for creating {@link GifHeader}s from data + * representing animated gifs. + */ +public final class GifHeaderParser +{ + + public static final String TAG = "GifHeaderParser"; + + // The minimum frame delay in hundredths of a second. + static final int MIN_FRAME_DELAY = 2; + + // The default frame delay in hundredths of a second for GIFs with frame delays less than the + // minimum. + static final int DEFAULT_FRAME_DELAY = 10; + + private static final int MAX_BLOCK_SIZE = 256; + + // Raw data read working array. + private final byte[] block = new byte[MAX_BLOCK_SIZE]; + + private ByteBuffer rawData; + + private GifHeader header; + + private int blockSize = 0; + + public GifHeaderParser setData(ByteBuffer data) + { + reset(); + rawData = data.asReadOnlyBuffer(); + rawData.position(0); + rawData.order(ByteOrder.LITTLE_ENDIAN); + return this; + } + + public GifHeaderParser setData(byte[] data) + { + if (data != null) + { + setData(ByteBuffer.wrap(data)); + } + else + { + rawData = null; + header.status = GifDecoder.STATUS_OPEN_ERROR; + } + return this; + } + + public void clear() + { + rawData = null; + header = null; + } + + private void reset() + { + rawData = null; + Arrays.fill(block, (byte) 0); + header = new GifHeader(); + blockSize = 0; + } + + public GifHeader parseHeader() + { + if (rawData == null) + { + throw new IllegalStateException("You must call setData() before parseHeader()"); + } + if (err()) + { + return header; + } + + readHeader(); + if (!err()) + { + readContents(); + if (header.frameCount < 0) + { + header.status = GifDecoder.STATUS_FORMAT_ERROR; + } + } + + return header; + } + + /** + * Determines if the GIF is animated by trying to read in the first 2 frames + * This method reparses the data even if the header has already been read. + */ + public boolean isAnimated() + { + readHeader(); + if (!err()) + { + readContents(2 /* maxFrames */); + } + return header.frameCount > 1; + } + + /** + * Main file parser. Reads GIF content blocks. + */ + private void readContents() + { + readContents(Integer.MAX_VALUE /* maxFrames */); + } + + /** + * Main file parser. Reads GIF content blocks. Stops after reading maxFrames + */ + private void readContents(int maxFrames) + { + // Read GIF file content blocks. + boolean done = false; + while (!(done || err() || header.frameCount > maxFrames)) + { + int code = read(); + switch (code) + { + // Image separator. + case 0x2C: + // The graphics control extension is optional, but will always come first if it exists. + // If one did + // exist, there will be a non-null current frame which we should use. However if one + // did not exist, + // the current frame will be null and we must create it here. See issue #134. + if (header.currentFrame == null) + { + header.currentFrame = new GifFrame(); + } + readBitmap(); + break; + // Extension. + case 0x21: + code = read(); + switch (code) + { + // Graphics control extension. + case 0xf9: + // Start a new frame. + header.currentFrame = new GifFrame(); + readGraphicControlExt(); + break; + // Application extension. + case 0xff: + readBlock(); + String app = ""; + for (int i = 0; i < 11; i++) + { + app += (char) block[i]; + } + if (app.equals("NETSCAPE2.0")) + { + readNetscapeExt(); + } + else + { + // Don't care. + skip(); + } + break; + // Comment extension. + case 0xfe: + skip(); + break; + // Plain text extension. + case 0x01: + skip(); + break; + // Uninteresting extension. + default: + skip(); + } + break; + // Terminator. + case 0x3b: + done = true; + break; + // Bad byte, but keep going and see what happens break; + case 0x00: + default: + header.status = GifDecoder.STATUS_FORMAT_ERROR; + } + } + } + + /** + * Reads Graphics Control Extension values. + */ + private void readGraphicControlExt() + { + // Block size. + read(); + // Packed fields. + int packed = read(); + // Disposal method. + header.currentFrame.dispose = (packed & 0x1c) >> 2; + if (header.currentFrame.dispose == 0) + { + // Elect to keep old image if discretionary. + header.currentFrame.dispose = 1; + } + header.currentFrame.transparency = (packed & 1) != 0; + // Delay in milliseconds. + int delayInHundredthsOfASecond = readShort(); + // TODO: consider allowing -1 to indicate show forever. + if (delayInHundredthsOfASecond < MIN_FRAME_DELAY) + { + delayInHundredthsOfASecond = DEFAULT_FRAME_DELAY; + } + header.currentFrame.delay = delayInHundredthsOfASecond * 10; + // Transparent color index + header.currentFrame.transIndex = read(); + // Block terminator + read(); + } + + /** + * Reads next frame image. + */ + private void readBitmap() + { + // (sub)image position & size. + header.currentFrame.ix = readShort(); + header.currentFrame.iy = readShort(); + header.currentFrame.iw = readShort(); + header.currentFrame.ih = readShort(); + + int packed = read(); + // 1 - local color table flag interlace + boolean lctFlag = (packed & 0x80) != 0; + int lctSize = (int) Math.pow(2, (packed & 0x07) + 1); + // 3 - sort flag + // 4-5 - reserved lctSize = 2 << (packed & 7); // 6-8 - local color + // table size + header.currentFrame.interlace = (packed & 0x40) != 0; + if (lctFlag) + { + // Read table. + header.currentFrame.lct = readColorTable(lctSize); + } + else + { + // No local color table. + header.currentFrame.lct = null; + } + + // Save this as the decoding position pointer. + header.currentFrame.bufferFrameStart = rawData.position(); + + // False decode pixel data to advance buffer. + skipImageData(); + + if (err()) + { + return; + } + + header.frameCount++; + // Add image to frame. + header.frames.add(header.currentFrame); + } + + /** + * Reads Netscape extension to obtain iteration count. + */ + private void readNetscapeExt() + { + do + { + readBlock(); + if (block[0] == 1) + { + // Loop count sub-block. + int b1 = ((int) block[1]) & 0xff; + int b2 = ((int) block[2]) & 0xff; + header.loopCount = (b2 << 8) | b1; + if (header.loopCount == 0) + { + header.loopCount = GifDecoder.LOOP_FOREVER; + } + } + } while ((blockSize > 0) && !err()); + } + + + /** + * Reads GIF file header information. + */ + private void readHeader() + { + String id = ""; + for (int i = 0; i < 6; i++) + { + id += (char) read(); + } + if (!id.startsWith("GIF")) + { + header.status = GifDecoder.STATUS_FORMAT_ERROR; + return; + } + readLSD(); + if (header.gctFlag && !err()) + { + header.gct = readColorTable(header.gctSize); + header.bgColor = header.gct[header.bgIndex]; + } + } + + /** + * Reads Logical Screen Descriptor. + */ + private void readLSD() + { + // Logical screen size. + header.width = readShort(); + header.height = readShort(); + // Packed fields + int packed = read(); + // 1 : global color table flag. + header.gctFlag = (packed & 0x80) != 0; + // 2-4 : color resolution. + // 5 : gct sort flag. + // 6-8 : gct size. + header.gctSize = 2 << (packed & 7); + // Background color index. + header.bgIndex = read(); + // Pixel aspect ratio + header.pixelAspect = read(); + } + + /** + * Reads color table as 256 RGB integer values. + * + * @param ncolors int number of colors to read. + * @return int array containing 256 colors (packed ARGB with full alpha). + */ + private int[] readColorTable(int ncolors) + { + int nbytes = 3 * ncolors; + int[] tab = null; + byte[] c = new byte[nbytes]; + + try + { + rawData.get(c); + + // TODO: what bounds checks are we avoiding if we know the number of colors? + // Max size to avoid bounds checks. + tab = new int[MAX_BLOCK_SIZE]; + int i = 0; + int j = 0; + while (i < ncolors) + { + int r = ((int) c[j++]) & 0xff; + int g = ((int) c[j++]) & 0xff; + int b = ((int) c[j++]) & 0xff; + tab[i++] = 0xff000000 | (r << 16) | (g << 8) | b; + } + } + catch (BufferUnderflowException e) + { + if (Log.isLoggable(TAG, Log.DEBUG)) + { + Log.d(TAG, "Format Error Reading Color Table", e); + } + header.status = GifDecoder.STATUS_FORMAT_ERROR; + } + + return tab; + } + + /** + * Skips LZW image data for a single frame to advance buffer. + */ + private void skipImageData() + { + // lzwMinCodeSize + read(); + // data sub-blocks + skip(); + } + + /** + * Skips variable length blocks up to and including next zero length block. + */ + private void skip() + { + try + { + int blockSize; + do + { + blockSize = read(); + rawData.position(rawData.position() + blockSize); + } while (blockSize > 0); + } + catch (IllegalArgumentException ex) + { + } + } + + /** + * Reads next variable length block from input. + * + * @return number of bytes stored in "buffer" + */ + private int readBlock() + { + blockSize = read(); + int n = 0; + if (blockSize > 0) + { + int count = 0; + try + { + while (n < blockSize) + { + count = blockSize - n; + rawData.get(block, n, count); + + n += count; + } + } + catch (Exception e) + { + if (Log.isLoggable(TAG, Log.DEBUG)) + { + Log.d(TAG, + "Error Reading Block n: " + n + " count: " + count + " blockSize: " + blockSize, e); + } + header.status = GifDecoder.STATUS_FORMAT_ERROR; + } + } + return n; + } + + /** + * Reads a single byte from the input stream. + */ + private int read() + { + int curByte = 0; + try + { + curByte = rawData.get() & 0xFF; + } + catch (Exception e) + { + header.status = GifDecoder.STATUS_FORMAT_ERROR; + } + return curByte; + } + + /** + * Reads next 16-bit value, LSB first. + */ + private int readShort() + { + // Read 16-bit value. + return rawData.getShort(); + } + + private boolean err() + { + return header.status != GifDecoder.STATUS_OK; + } +} diff --git a/library/src/main/java/com/smartnsoft/droid4me/download/gif/SimpleBitmapProvider.java b/library/src/main/java/com/smartnsoft/droid4me/download/gif/SimpleBitmapProvider.java new file mode 100755 index 00000000..ee48e6cf --- /dev/null +++ b/library/src/main/java/com/smartnsoft/droid4me/download/gif/SimpleBitmapProvider.java @@ -0,0 +1,54 @@ +package com.smartnsoft.droid4me.download.gif; + +import android.graphics.Bitmap; +import android.support.annotation.NonNull; + +/** + * @author Antoine Gerard + * @since 2017.10.18 + */ + +/** + * Util class for creating a Bitmap + */ +public final class SimpleBitmapProvider + implements GifDecoder.BitmapProvider +{ + + @NonNull + @Override + public Bitmap obtain(int width, int height, Bitmap.Config config) + { + return Bitmap.createBitmap(width, height, config); + } + + @Override + public void release(Bitmap bitmap) + { + bitmap.recycle(); + } + + @Override + public byte[] obtainByteArray(int size) + { + return new byte[size]; + } + + @Override + public void release(byte[] bytes) + { + // no-op + } + + @Override + public int[] obtainIntArray(int size) + { + return new int[size]; + } + + @Override + public void release(int[] array) + { + // no-op + } +} diff --git a/library/src/main/java/com/smartnsoft/droid4me/download/package-info.java b/library/src/main/java/com/smartnsoft/droid4me/download/package-info.java old mode 100644 new mode 100755 diff --git a/library/src/main/java/com/smartnsoft/droid4me/framework/BusinessObjectLifeCycle.java b/library/src/main/java/com/smartnsoft/droid4me/framework/BusinessObjectLifeCycle.java old mode 100644 new mode 100755 diff --git a/library/src/main/java/com/smartnsoft/droid4me/framework/DetailsProvider.java b/library/src/main/java/com/smartnsoft/droid4me/framework/DetailsProvider.java old mode 100644 new mode 100755 diff --git a/library/src/main/java/com/smartnsoft/droid4me/framework/Events.java b/library/src/main/java/com/smartnsoft/droid4me/framework/Events.java old mode 100644 new mode 100755 diff --git a/library/src/main/java/com/smartnsoft/droid4me/framework/ForBusinessObjectImplementation.java b/library/src/main/java/com/smartnsoft/droid4me/framework/ForBusinessObjectImplementation.java old mode 100644 new mode 100755 diff --git a/library/src/main/java/com/smartnsoft/droid4me/framework/SmartAdapters.java b/library/src/main/java/com/smartnsoft/droid4me/framework/SmartAdapters.java old mode 100644 new mode 100755 diff --git a/library/src/main/java/com/smartnsoft/droid4me/framework/package-info.java b/library/src/main/java/com/smartnsoft/droid4me/framework/package-info.java old mode 100644 new mode 100755 diff --git a/library/src/main/java/com/smartnsoft/droid4me/graphics/drawable/BasicBitmapDrawable.java b/library/src/main/java/com/smartnsoft/droid4me/graphics/drawable/BasicBitmapDrawable.java old mode 100644 new mode 100755 diff --git a/library/src/main/java/com/smartnsoft/droid4me/graphics/drawable/package-info.java b/library/src/main/java/com/smartnsoft/droid4me/graphics/drawable/package-info.java old mode 100644 new mode 100755 diff --git a/library/src/main/java/com/smartnsoft/droid4me/log/AndroidLogger.java b/library/src/main/java/com/smartnsoft/droid4me/log/AndroidLogger.java old mode 100644 new mode 100755 diff --git a/library/src/main/java/com/smartnsoft/droid4me/log/Logger.java b/library/src/main/java/com/smartnsoft/droid4me/log/Logger.java old mode 100644 new mode 100755 diff --git a/library/src/main/java/com/smartnsoft/droid4me/log/LoggerFactory.java b/library/src/main/java/com/smartnsoft/droid4me/log/LoggerFactory.java old mode 100644 new mode 100755 diff --git a/library/src/main/java/com/smartnsoft/droid4me/log/LoggerWrapper.java b/library/src/main/java/com/smartnsoft/droid4me/log/LoggerWrapper.java old mode 100644 new mode 100755 diff --git a/library/src/main/java/com/smartnsoft/droid4me/log/Loggerable.java b/library/src/main/java/com/smartnsoft/droid4me/log/Loggerable.java old mode 100644 new mode 100755 diff --git a/library/src/main/java/com/smartnsoft/droid4me/log/NativeLogger.java b/library/src/main/java/com/smartnsoft/droid4me/log/NativeLogger.java old mode 100644 new mode 100755 diff --git a/library/src/main/java/com/smartnsoft/droid4me/log/package-info.java b/library/src/main/java/com/smartnsoft/droid4me/log/package-info.java old mode 100644 new mode 100755 diff --git a/library/src/main/java/com/smartnsoft/droid4me/package-info.java b/library/src/main/java/com/smartnsoft/droid4me/package-info.java old mode 100644 new mode 100755 diff --git a/library/src/main/java/com/smartnsoft/droid4me/support/v4/app/SmartDialogFragment.java b/library/src/main/java/com/smartnsoft/droid4me/support/v4/app/SmartDialogFragment.java old mode 100644 new mode 100755 diff --git a/library/src/main/java/com/smartnsoft/droid4me/support/v4/app/SmartFragment.java b/library/src/main/java/com/smartnsoft/droid4me/support/v4/app/SmartFragment.java old mode 100644 new mode 100755 diff --git a/library/src/main/java/com/smartnsoft/droid4me/support/v4/app/SmartFragmentActivity.java b/library/src/main/java/com/smartnsoft/droid4me/support/v4/app/SmartFragmentActivity.java old mode 100644 new mode 100755 diff --git a/library/src/main/java/com/smartnsoft/droid4me/support/v4/content/LocalBroadcastManager.java b/library/src/main/java/com/smartnsoft/droid4me/support/v4/content/LocalBroadcastManager.java old mode 100644 new mode 100755 diff --git a/library/src/main/java/com/smartnsoft/droid4me/support/v4/package-info.java b/library/src/main/java/com/smartnsoft/droid4me/support/v4/package-info.java old mode 100644 new mode 100755 diff --git a/library/src/main/java/com/smartnsoft/droid4me/support/v7/app/SmartAppCompatActivity.java b/library/src/main/java/com/smartnsoft/droid4me/support/v7/app/SmartAppCompatActivity.java old mode 100644 new mode 100755 diff --git a/library/src/main/java/com/smartnsoft/droid4me/support/v7/app/SmartPreferenceFragmentCompat.java b/library/src/main/java/com/smartnsoft/droid4me/support/v7/app/SmartPreferenceFragmentCompat.java old mode 100644 new mode 100755 diff --git a/library/src/main/java/com/smartnsoft/droid4me/support/v7/package-info.java b/library/src/main/java/com/smartnsoft/droid4me/support/v7/package-info.java old mode 100644 new mode 100755 diff --git a/library/src/main/java/com/smartnsoft/droid4me/support/v7/widget/SmartAppCompatImageView.java b/library/src/main/java/com/smartnsoft/droid4me/support/v7/widget/SmartAppCompatImageView.java old mode 100644 new mode 100755 index c1529792..d723dfd7 --- a/library/src/main/java/com/smartnsoft/droid4me/support/v7/widget/SmartAppCompatImageView.java +++ b/library/src/main/java/com/smartnsoft/droid4me/support/v7/widget/SmartAppCompatImageView.java @@ -33,6 +33,8 @@ import com.smartnsoft.droid4me.widget.SmartRelativeLayout; import com.smartnsoft.droid4me.widget.SmartViewExtension; +import static android.support.v7.appcompat.R.styleable.AppCompatImageView; + /** * Enables to receive an event when the {@link ImageView} size has changed, set an automatic ratio between its width and its height, and discard the * layout requests. diff --git a/library/src/main/java/com/smartnsoft/droid4me/ui/SimpleWrappedListView.java b/library/src/main/java/com/smartnsoft/droid4me/ui/SimpleWrappedListView.java old mode 100644 new mode 100755 diff --git a/library/src/main/java/com/smartnsoft/droid4me/ui/WrappedListView.java b/library/src/main/java/com/smartnsoft/droid4me/ui/WrappedListView.java old mode 100644 new mode 100755 diff --git a/library/src/main/java/com/smartnsoft/droid4me/ui/package-info.java b/library/src/main/java/com/smartnsoft/droid4me/ui/package-info.java old mode 100644 new mode 100755 diff --git a/library/src/main/java/com/smartnsoft/droid4me/util/BitmapToolbox.java b/library/src/main/java/com/smartnsoft/droid4me/util/BitmapToolbox.java old mode 100644 new mode 100755 diff --git a/library/src/main/java/com/smartnsoft/droid4me/util/SendLogsTask.java b/library/src/main/java/com/smartnsoft/droid4me/util/SendLogsTask.java old mode 100644 new mode 100755 diff --git a/library/src/main/java/com/smartnsoft/droid4me/util/StatefulDefaultHandler.java b/library/src/main/java/com/smartnsoft/droid4me/util/StatefulDefaultHandler.java old mode 100644 new mode 100755 diff --git a/library/src/main/java/com/smartnsoft/droid4me/util/package-info.java b/library/src/main/java/com/smartnsoft/droid4me/util/package-info.java old mode 100644 new mode 100755 diff --git a/library/src/main/java/com/smartnsoft/droid4me/widget/OnSizeChangedListener.java b/library/src/main/java/com/smartnsoft/droid4me/widget/OnSizeChangedListener.java old mode 100644 new mode 100755 diff --git a/library/src/main/java/com/smartnsoft/droid4me/widget/SmartFrameLayout.java b/library/src/main/java/com/smartnsoft/droid4me/widget/SmartFrameLayout.java old mode 100644 new mode 100755 diff --git a/library/src/main/java/com/smartnsoft/droid4me/widget/SmartLinearLayout.java b/library/src/main/java/com/smartnsoft/droid4me/widget/SmartLinearLayout.java old mode 100644 new mode 100755 diff --git a/library/src/main/java/com/smartnsoft/droid4me/widget/SmartPageIndicator.java b/library/src/main/java/com/smartnsoft/droid4me/widget/SmartPageIndicator.java old mode 100644 new mode 100755 diff --git a/library/src/main/java/com/smartnsoft/droid4me/widget/SmartRelativeLayout.java b/library/src/main/java/com/smartnsoft/droid4me/widget/SmartRelativeLayout.java old mode 100644 new mode 100755 diff --git a/library/src/main/java/com/smartnsoft/droid4me/widget/SmartViewExtension.java b/library/src/main/java/com/smartnsoft/droid4me/widget/SmartViewExtension.java old mode 100644 new mode 100755 diff --git a/library/src/main/java/com/smartnsoft/droid4me/widget/SmartViewPager.java b/library/src/main/java/com/smartnsoft/droid4me/widget/SmartViewPager.java old mode 100644 new mode 100755 diff --git a/library/src/main/java/com/smartnsoft/droid4me/widget/package-info.java b/library/src/main/java/com/smartnsoft/droid4me/widget/package-info.java old mode 100644 new mode 100755 diff --git a/library/src/main/java/com/smartnsoft/droid4me/ws/URLConnectionWebServiceCaller.java b/library/src/main/java/com/smartnsoft/droid4me/ws/URLConnectionWebServiceCaller.java old mode 100644 new mode 100755 diff --git a/library/src/main/java/com/smartnsoft/droid4me/ws/WSUriStreamParser.java b/library/src/main/java/com/smartnsoft/droid4me/ws/WSUriStreamParser.java old mode 100644 new mode 100755 diff --git a/library/src/main/java/com/smartnsoft/droid4me/ws/WebServiceCaller.java b/library/src/main/java/com/smartnsoft/droid4me/ws/WebServiceCaller.java old mode 100644 new mode 100755 diff --git a/library/src/main/java/com/smartnsoft/droid4me/ws/WebServiceClient.java b/library/src/main/java/com/smartnsoft/droid4me/ws/WebServiceClient.java old mode 100644 new mode 100755 diff --git a/library/src/main/java/com/smartnsoft/droid4me/ws/WithCacheWSUriStreamParser.java b/library/src/main/java/com/smartnsoft/droid4me/ws/WithCacheWSUriStreamParser.java old mode 100644 new mode 100755 diff --git a/library/src/main/java/com/smartnsoft/droid4me/ws/package-info.java b/library/src/main/java/com/smartnsoft/droid4me/ws/package-info.java old mode 100644 new mode 100755 diff --git a/library/src/main/java/com/smartnsoft/droid4me/wscache/BackedWSUriStreamParser.java b/library/src/main/java/com/smartnsoft/droid4me/wscache/BackedWSUriStreamParser.java old mode 100644 new mode 100755 diff --git a/library/src/main/java/com/smartnsoft/droid4me/wscache/package-info.java b/library/src/main/java/com/smartnsoft/droid4me/wscache/package-info.java old mode 100644 new mode 100755 diff --git a/library/src/main/javadoc/overview.html b/library/src/main/javadoc/overview.html old mode 100644 new mode 100755 diff --git a/library/src/test/java/com/smartnsoft/droid4me/cache/test/PersistenceTest.java b/library/src/test/java/com/smartnsoft/droid4me/cache/test/PersistenceTest.java old mode 100644 new mode 100755 diff --git a/library/src/test/java/com/smartnsoft/droid4me/download/test/BitmapDownloaderTest.java b/library/src/test/java/com/smartnsoft/droid4me/download/test/BitmapDownloaderTest.java old mode 100644 new mode 100755 diff --git a/library/src/test/java/com/smartnsoft/droid4me/test/BasisTests.java b/library/src/test/java/com/smartnsoft/droid4me/test/BasisTests.java old mode 100644 new mode 100755 diff --git a/sample/.gitignore b/sample/.gitignore old mode 100644 new mode 100755 diff --git a/sample/proguard-rules.pro b/sample/proguard-rules.pro old mode 100644 new mode 100755 diff --git a/sample/src/main/AndroidManifest.xml b/sample/src/main/AndroidManifest.xml old mode 100644 new mode 100755 diff --git a/sample/src/main/assets/about.css b/sample/src/main/assets/about.css old mode 100644 new mode 100755 diff --git a/sample/src/main/assets/application_logo.png b/sample/src/main/assets/application_logo.png old mode 100644 new mode 100755 diff --git a/sample/src/main/assets/background.png b/sample/src/main/assets/background.png old mode 100644 new mode 100755 diff --git a/sample/src/main/assets/droid4me_inside_large.png b/sample/src/main/assets/droid4me_inside_large.png old mode 100644 new mode 100755 diff --git a/sample/src/main/assets/smartnsoft_logo.png b/sample/src/main/assets/smartnsoft_logo.png old mode 100644 new mode 100755 diff --git a/sample/src/main/java/com/smartnsoft/droid4sample/AboutActivity.java b/sample/src/main/java/com/smartnsoft/droid4sample/AboutActivity.java old mode 100644 new mode 100755 diff --git a/sample/src/main/java/com/smartnsoft/droid4sample/Constants.java b/sample/src/main/java/com/smartnsoft/droid4sample/Constants.java old mode 100644 new mode 100755 diff --git a/sample/src/main/java/com/smartnsoft/droid4sample/Droid4SampleApplication.java b/sample/src/main/java/com/smartnsoft/droid4sample/Droid4SampleApplication.java old mode 100644 new mode 100755 diff --git a/sample/src/main/java/com/smartnsoft/droid4sample/Droid4SampleSplashScreenActivity.java b/sample/src/main/java/com/smartnsoft/droid4sample/Droid4SampleSplashScreenActivity.java old mode 100644 new mode 100755 diff --git a/sample/src/main/java/com/smartnsoft/droid4sample/SettingsActivity.java b/sample/src/main/java/com/smartnsoft/droid4sample/SettingsActivity.java old mode 100644 new mode 100755 diff --git a/sample/src/main/java/com/smartnsoft/droid4sample/TitleBar.java b/sample/src/main/java/com/smartnsoft/droid4sample/TitleBar.java old mode 100644 new mode 100755 diff --git a/sample/src/main/java/com/smartnsoft/droid4sample/ws/Droid4SampleServices.java b/sample/src/main/java/com/smartnsoft/droid4sample/ws/Droid4SampleServices.java old mode 100644 new mode 100755 diff --git a/sample/src/main/res/drawable-hdpi/droid4me_inside.png b/sample/src/main/res/drawable-hdpi/droid4me_inside.png old mode 100644 new mode 100755 diff --git a/sample/src/main/res/drawable-hdpi/droid4sample_splash_logo.png b/sample/src/main/res/drawable-hdpi/droid4sample_splash_logo.png old mode 100644 new mode 100755 diff --git a/sample/src/main/res/drawable-hdpi/icon.png b/sample/src/main/res/drawable-hdpi/icon.png old mode 100644 new mode 100755 diff --git a/sample/src/main/res/drawable-hdpi/poweredby_smartnsoft.png b/sample/src/main/res/drawable-hdpi/poweredby_smartnsoft.png old mode 100644 new mode 100755 diff --git a/sample/src/main/res/drawable-hdpi/smartnsoft_illustration.png b/sample/src/main/res/drawable-hdpi/smartnsoft_illustration.png old mode 100644 new mode 100755 diff --git a/sample/src/main/res/drawable-hdpi/title_bar_home.png b/sample/src/main/res/drawable-hdpi/title_bar_home.png old mode 100644 new mode 100755 diff --git a/sample/src/main/res/drawable-hdpi/title_bar_refresh.png b/sample/src/main/res/drawable-hdpi/title_bar_refresh.png old mode 100644 new mode 100755 diff --git a/sample/src/main/res/drawable-nodpi/title_bar_button_background_disabled.png b/sample/src/main/res/drawable-nodpi/title_bar_button_background_disabled.png old mode 100644 new mode 100755 diff --git a/sample/src/main/res/drawable-nodpi/title_bar_button_background_pressed.png b/sample/src/main/res/drawable-nodpi/title_bar_button_background_pressed.png old mode 100644 new mode 100755 diff --git a/sample/src/main/res/drawable-nodpi/title_bar_button_background_selected.png b/sample/src/main/res/drawable-nodpi/title_bar_button_background_selected.png old mode 100644 new mode 100755 diff --git a/sample/src/main/res/drawable/title_bar_button_background.xml b/sample/src/main/res/drawable/title_bar_button_background.xml old mode 100644 new mode 100755 diff --git a/sample/src/main/res/layout/about.xml b/sample/src/main/res/layout/about.xml old mode 100644 new mode 100755 diff --git a/sample/src/main/res/layout/droid4sample_splash_screen.xml b/sample/src/main/res/layout/droid4sample_splash_screen.xml old mode 100644 new mode 100755 diff --git a/sample/src/main/res/layout/main_sample.xml b/sample/src/main/res/layout/main_sample.xml old mode 100644 new mode 100755 diff --git a/sample/src/main/res/layout/title_bar.xml b/sample/src/main/res/layout/title_bar.xml old mode 100644 new mode 100755 diff --git a/sample/src/main/res/raw/about.html b/sample/src/main/res/raw/about.html old mode 100644 new mode 100755 diff --git a/sample/src/main/res/values-fr/strings.xml b/sample/src/main/res/values-fr/strings.xml old mode 100644 new mode 100755 diff --git a/sample/src/main/res/values/array.xml b/sample/src/main/res/values/array.xml old mode 100644 new mode 100755 diff --git a/sample/src/main/res/values/attrs.xml b/sample/src/main/res/values/attrs.xml old mode 100644 new mode 100755 diff --git a/sample/src/main/res/values/colors.xml b/sample/src/main/res/values/colors.xml old mode 100644 new mode 100755 diff --git a/sample/src/main/res/values/dimen.xml b/sample/src/main/res/values/dimen.xml old mode 100644 new mode 100755 diff --git a/sample/src/main/res/values/strings.xml b/sample/src/main/res/values/strings.xml old mode 100644 new mode 100755 diff --git a/sample/src/main/res/values/styles.xml b/sample/src/main/res/values/styles.xml old mode 100644 new mode 100755 diff --git a/sample/src/main/res/values/themes.xml b/sample/src/main/res/values/themes.xml old mode 100644 new mode 100755 diff --git a/sample/src/main/res/xml/settings.xml b/sample/src/main/res/xml/settings.xml old mode 100644 new mode 100755 From a9d8f21af865d84bf79958a9951ae3afa2816a53 Mon Sep 17 00:00:00 2001 From: Antoine Gerard Date: Thu, 19 Oct 2017 15:45:17 +0200 Subject: [PATCH 03/19] Implemented a first shot of Gif compatibility into the BitmapDownloader. --- .../download/DownloadInstructions.java | 18 +- .../smartnsoft/droid4me/download/gif/Gif.java | 8 + .../droid4me/download/gif/GifEngine.java | 301 ++---------------- 3 files changed, 46 insertions(+), 281 deletions(-) diff --git a/library/src/main/java/com/smartnsoft/droid4me/download/DownloadInstructions.java b/library/src/main/java/com/smartnsoft/droid4me/download/DownloadInstructions.java index ee6dc35c..62bf898e 100755 --- a/library/src/main/java/com/smartnsoft/droid4me/download/DownloadInstructions.java +++ b/library/src/main/java/com/smartnsoft/droid4me/download/DownloadInstructions.java @@ -36,16 +36,19 @@ import android.graphics.Bitmap.Config; import android.graphics.BitmapFactory; import android.os.Build; +import android.os.Build.VERSION; +import android.os.Build.VERSION_CODES; import android.os.Handler; import android.view.View; import android.widget.ImageView; -import com.smartnsoft.droid4me.download.BasisDownloadInstructions.Instructions; import com.smartnsoft.droid4me.download.DownloadContracts.Bitmapable; import com.smartnsoft.droid4me.download.DownloadContracts.Handlerable; import com.smartnsoft.droid4me.download.DownloadContracts.Viewable; import com.smartnsoft.droid4me.download.gif.Gif; import com.smartnsoft.droid4me.download.gif.GifEngine; +import com.smartnsoft.droid4me.log.Logger; +import com.smartnsoft.droid4me.log.LoggerFactory; /** * Gathers in one place the download instructions contracts used by {@link BitmapDownloader}. @@ -57,6 +60,8 @@ public class DownloadInstructions extends BasisDownloadInstructions { + private static final Logger log = LoggerFactory.getInstance(DownloadInstructions.class); + @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @interface BitmapConfigAnnotation @@ -663,6 +668,17 @@ protected void onGifReady(boolean allright, View view, Gif bitmap, String bitmap protected boolean onBindGif(boolean downloaded, View view, Gif gif, String bitmapUid, Object imageSpecs) { final GifEngine engine = new GifEngine(((ImageView) (view)), gif); + if (VERSION.SDK_INT >= VERSION_CODES.HONEYCOMB) + { + engine.animate(); + } + else + { + if (log.isInfoEnabled() == true) + { + log.info("Gif animation is available from API 11"); + } + } return true; } diff --git a/library/src/main/java/com/smartnsoft/droid4me/download/gif/Gif.java b/library/src/main/java/com/smartnsoft/droid4me/download/gif/Gif.java index ed6cf91e..dabbf5d2 100755 --- a/library/src/main/java/com/smartnsoft/droid4me/download/gif/Gif.java +++ b/library/src/main/java/com/smartnsoft/droid4me/download/gif/Gif.java @@ -25,6 +25,8 @@ public final class Gif public final List bitmaps; + private int duration; + public Gif(InputStream inputStream, String url) { this.bitmaps = new ArrayList(); @@ -53,6 +55,7 @@ public Gif(InputStream inputStream, String url) gifDecoder.advance(); final Bitmap nextBitmap = gifDecoder.getNextFrame(); // We need to deep copy the bitmap + duration += gifDecoder.getDelay(gifDecoder.getCurrentFrameIndex()); final Bitmap bitmap = nextBitmap.copy(nextBitmap.getConfig(), true); if (bitmap == null) { @@ -87,4 +90,9 @@ public Bitmap getBitmap(int index) { return bitmaps.get(index); } + + public int getDuration() + { + return duration; + } } diff --git a/library/src/main/java/com/smartnsoft/droid4me/download/gif/GifEngine.java b/library/src/main/java/com/smartnsoft/droid4me/download/gif/GifEngine.java index 596ce481..4139487b 100755 --- a/library/src/main/java/com/smartnsoft/droid4me/download/gif/GifEngine.java +++ b/library/src/main/java/com/smartnsoft/droid4me/download/gif/GifEngine.java @@ -1,13 +1,12 @@ package com.smartnsoft.droid4me.download.gif; -import android.graphics.Bitmap; -import android.os.Handler; -import android.os.Looper; -import android.util.Log; +import android.animation.ValueAnimator; +import android.animation.ValueAnimator.AnimatorUpdateListener; +import android.os.Build.VERSION_CODES; +import android.support.annotation.RequiresApi; +import android.view.animation.LinearInterpolator; import android.widget.ImageView; -import com.smartnsoft.droid4me.download.BitmapDownloader; - /** * This class is used to display and * animated a GIF inside every View that are @@ -19,300 +18,42 @@ */ public final class GifEngine - implements Runnable { - private static final String TAG = "GifDecoderView"; - - private GifDecoder gifDecoder; - private Gif gif; - private Bitmap tmpBitmap; - - private final Handler handler = new Handler(Looper.getMainLooper()); - - private boolean animating; - - private boolean renderFrame; - - private boolean shouldClear; - - private Thread animationThread; - - private OnFrameAvailable frameCallback = null; - - private long framesDisplayDuration = -1L; - - private OnAnimationStop animationStopCallback = null; - - private OnAnimationStart animationStartCallback = null; - private ImageView imageView; - private final Runnable updateResults = new Runnable() - { - @Override - public void run() - { - if (tmpBitmap != null && !tmpBitmap.isRecycled() && imageView != null) - { - imageView.setImageBitmap(tmpBitmap); - } - } - }; - - private final Runnable cleanupRunnable = new Runnable() - { - @Override - public void run() - { - tmpBitmap = null; - gifDecoder = null; - animationThread = null; - shouldClear = false; - } - }; - public GifEngine(final ImageView imageView, final Gif gif) { this.imageView = imageView; this.gif = gif; } - public void setBytes(final byte[] bytes) - { - gifDecoder = new GifDecoder(); - try - { - gifDecoder.read(bytes); - } - catch (final Exception e) - { - gifDecoder = null; - Log.e(TAG, e.getMessage(), e); - return; - } - - if (animating) - { - startAnimationThread(); - } - else - { - gotoFrame(0); - } - } - - public long getFramesDisplayDuration() - { - return framesDisplayDuration; - } - - /** - * Sets custom display duration in milliseconds for the all frames. Should be called before {@link - * #startAnimation()} - * - * @param framesDisplayDuration Duration in milliseconds. Default value = -1, this property will - * be ignored and default delay from gif file will be used. - */ - public void setFramesDisplayDuration(long framesDisplayDuration) - { - this.framesDisplayDuration = framesDisplayDuration; - } - - public void startAnimation() - { - animating = true; - startAnimationThread(); - } - - public boolean isAnimating() - { - return animating; - } - - public void stopAnimation() - { - animating = false; - - if (animationThread != null) - { - animationThread.interrupt(); - animationThread = null; - } - } - - public void gotoFrame(int frame) - { - if (gifDecoder.getCurrentFrameIndex() == frame) - { - return; - } - if (gifDecoder.setFrameIndex(frame - 1) && !animating) - { - renderFrame = true; - startAnimationThread(); - } - } - - public void resetAnimation() - { - gifDecoder.resetLoopIndex(); - gotoFrame(0); - } - - public void clear() - { - animating = false; - renderFrame = false; - shouldClear = true; - stopAnimation(); - handler.post(cleanupRunnable); - } - - private boolean canStart() - { - return (animating || renderFrame) && gifDecoder != null && animationThread == null; - } - - public int getGifWidth() - { - return gifDecoder.getWidth(); - } - - public int getGifHeight() - { - return gifDecoder.getHeight(); - } - - @Override - public void run() + @RequiresApi(api = VERSION_CODES.HONEYCOMB) + public void animate() { - if (animationStartCallback != null) - { - animationStartCallback.onAnimationStart(); - } - - do + if (gif != null && gif.bitmaps.isEmpty() == false) { - if (!animating && !renderFrame) - { - break; - } - boolean advance = gifDecoder.advance(); - - //milliseconds spent on frame decode - long frameDecodeTime = 0; - try - { - long before = System.nanoTime(); - tmpBitmap = gifDecoder.getNextFrame(); - if (frameCallback != null) - { - tmpBitmap = frameCallback.onFrameAvailable(tmpBitmap); - } - frameDecodeTime = (System.nanoTime() - before) / 1000000; - handler.post(updateResults); - } - catch (final ArrayIndexOutOfBoundsException | IllegalArgumentException e) + int[] table = new int[gif.bitmaps.size()]; + for (int i = 0; i < table.length; i++) { - Log.w(TAG, e); + table[i] = i; } - renderFrame = false; - if (!animating || !advance) - { - animating = false; - break; - } - try + final ValueAnimator valueAnimator = ValueAnimator.ofInt(table); + valueAnimator.setInterpolator(new LinearInterpolator()); + valueAnimator.setDuration(gif.getDuration()); + valueAnimator.setRepeatCount(ValueAnimator.INFINITE); + valueAnimator.addUpdateListener(new AnimatorUpdateListener() { - int delay = gifDecoder.getNextDelay(); - // Sleep for frame duration minus time already spent on frame decode - // Actually we need next frame decode duration here, - // but I use previous frame time to make code more readable - delay -= frameDecodeTime; - if (delay > 0) + @Override + public void onAnimationUpdate(ValueAnimator animation) { - Thread.sleep(framesDisplayDuration > 0 ? framesDisplayDuration : delay); + imageView.setImageBitmap(gif.getBitmap((Integer) animation.getAnimatedValue())); } - } - catch (final InterruptedException e) - { - // suppress exception - } - } while (animating); - - if (shouldClear) - { - handler.post(cleanupRunnable); - } - animationThread = null; - - if (animationStopCallback != null) - { - animationStopCallback.onAnimationStop(); - } - } - - public void animate() - { - if (gif != null && gif.bitmaps.isEmpty() == false) - { - - } - } - - public OnFrameAvailable getOnFrameAvailable() - { - return frameCallback; - } - - public void setOnFrameAvailable(OnFrameAvailable frameProcessor) - { - this.frameCallback = frameProcessor; - } - - public interface OnFrameAvailable - { - - Bitmap onFrameAvailable(Bitmap bitmap); - } - - public OnAnimationStop getOnAnimationStop() - { - return animationStopCallback; - } - - public void setOnAnimationStop(OnAnimationStop animationStop) - { - this.animationStopCallback = animationStop; - } - - public void setOnAnimationStart(OnAnimationStart animationStart) - { - this.animationStartCallback = animationStart; - } - - public interface OnAnimationStop - { - - void onAnimationStop(); - } - - public interface OnAnimationStart - { - - void onAnimationStart(); - } - - private void startAnimationThread() - { - if (canStart()) - { - animationThread = new Thread(this); - animationThread.start(); + }); + valueAnimator.start(); } } } From c68402220cbde4a141b90f1931612a9618da9e6d Mon Sep 17 00:00:00 2001 From: Antoine Gerard Date: Fri, 17 Nov 2017 18:40:25 +0100 Subject: [PATCH 04/19] Working on the gif engine of the bitmapdownloader --- .../download/BasisBitmapDownloader.java | 2 + .../droid4me/download/BitmapDownloader.java | 3 +- .../download/DownloadInstructions.java | 188 +++++++++--------- 3 files changed, 98 insertions(+), 95 deletions(-) diff --git a/library/src/main/java/com/smartnsoft/droid4me/download/BasisBitmapDownloader.java b/library/src/main/java/com/smartnsoft/droid4me/download/BasisBitmapDownloader.java index ce975f61..09a7e5f7 100755 --- a/library/src/main/java/com/smartnsoft/droid4me/download/BasisBitmapDownloader.java +++ b/library/src/main/java/com/smartnsoft/droid4me/download/BasisBitmapDownloader.java @@ -404,6 +404,8 @@ public final void get(boolean isPreBlocking, boolean isDownloadBlocking, ViewCla } } + + public synchronized void clear() { if (log.isInfoEnabled()) diff --git a/library/src/main/java/com/smartnsoft/droid4me/download/BitmapDownloader.java b/library/src/main/java/com/smartnsoft/droid4me/download/BitmapDownloader.java index c332cb21..cce2a0bf 100755 --- a/library/src/main/java/com/smartnsoft/droid4me/download/BitmapDownloader.java +++ b/library/src/main/java/com/smartnsoft/droid4me/download/BitmapDownloader.java @@ -37,6 +37,7 @@ import android.view.ViewGroup.LayoutParams; import android.widget.LinearLayout; +import com.smartnsoft.droid4me.download.BasisDownloadInstructions.Instructions; import com.smartnsoft.droid4me.download.DownloadInstructions.BitmapableBitmap; import com.smartnsoft.droid4me.download.DownloadInstructions.HandlerableHander; import com.smartnsoft.droid4me.download.DownloadInstructions.ViewableView; @@ -339,7 +340,7 @@ protected BitmapDownloader(int instanceIndex, String name, long maxMemoryInBytes } public final void get(View view, String bitmapUid, Object imageSpecs, Handler handler, - DownloadInstructions.Instructions instructions) + Instructions instructions) { get(view != null ? new ViewableView(view) : null, bitmapUid, imageSpecs, handler != null ? new HandlerableHander(handler) : null, instructions); } diff --git a/library/src/main/java/com/smartnsoft/droid4me/download/DownloadInstructions.java b/library/src/main/java/com/smartnsoft/droid4me/download/DownloadInstructions.java index 62bf898e..a7cc4a1c 100755 --- a/library/src/main/java/com/smartnsoft/droid4me/download/DownloadInstructions.java +++ b/library/src/main/java/com/smartnsoft/droid4me/download/DownloadInstructions.java @@ -413,14 +413,14 @@ public BitmapableGif convert(InputStream inputStream, String bitmapUid, Object i public void onBitmapReady(boolean allright, ViewableView view, BitmapableGif bitmap, String bitmapUid, Object imageSpecs) { - + onGifReady(allright, view != null ? view.getView() : null, bitmap != null ? bitmap.gif : null, bitmapUid, imageSpecs); } @Override public boolean onBindBitmap(boolean downloaded, ViewableView view, BitmapableGif bitmap, String bitmapUid, Object imageSpecs) { - return true; + return onBindGif(downloaded, view != null ? view.getView() : null, bitmap != null ? bitmap.gif : null, bitmapUid, imageSpecs); } @Override @@ -444,7 +444,7 @@ public InputStream getInputStream(String imageUid, Object imageSpecs, String url @Override public InputStream onInputStreamDownloaded(String imageUid, Object imageSpecs, String url, InputStream inputStream) { - return null; + return inputStream; } protected abstract Bitmap hasLocalBitmap(View view, String bitmapUid, Object imageSpecs); @@ -465,6 +465,97 @@ protected abstract boolean onBindGif(boolean downloaded, View view, Gif bitmap, } + public static class GifAbstractInstructions + extends GifInstructions + { + + @Override + public InputStream downloadInputStream(String bitmapUid, Object imageSpecs, String url) + throws IOException + { + final URL aURL = new URL(url); + final URLConnection connection = aURL.openConnection(); + connection.connect(); + final InputStream inputStream = connection.getInputStream(); + return inputStream; + } + + @Override + public BitmapableGif convert(InputStream inputStream, String bitmapUid, Object imageSpecs, String url) + { + final long start = System.currentTimeMillis(); + final Gif theGif = convertInputStreamToGif(inputStream, url); + if (theGif != null) + { + if (CoreBitmapDownloader.IS_DEBUG_TRACE && CoreBitmapDownloader.log.isDebugEnabled()) + { + final long stop = System.currentTimeMillis(); + CoreBitmapDownloader.log.debug("The thread '" + Thread.currentThread().getName() + "' decoded in " + (stop - start) + " relative to the URL '" + url + "'"); + } + } + return theGif == null ? null : new BitmapableGif(theGif); + } + + @Override + protected Bitmap hasLocalBitmap(View view, String bitmapUid, Object imageSpecs) + { + return null; + } + + @Override + protected void onBindLocalGif(View view, Gif gif, String bitmapUid, Object imageSpecs) + { + } + + @Override + protected Bitmap hasTemporaryBitmap(View view, String bitmapUid, Object imageSpecs) + { + return null; + } + + @Override + protected void onBindTemporaryBitmap(View view, Bitmap bitmap, String bitmapUid, Object imageSpecs) + { + + } + + @Override + protected void onGifReady(boolean allright, View view, Gif bitmap, String bitmapUid, Object imageSpecs) + { + + } + + @Override + protected boolean onBindGif(boolean downloaded, View view, Gif gif, String bitmapUid, Object imageSpecs) + { + final GifEngine engine = new GifEngine(((ImageView) (view)), gif); + if (VERSION.SDK_INT >= VERSION_CODES.HONEYCOMB) + { + engine.animate(); + } + else + { + if (log.isInfoEnabled() == true) + { + log.info("Gif animation is available from API 11"); + } + } + return true; + } + + @Override + protected void onBitmapBound(boolean result, View view, String bitmapUid, Object imageSpecs) + { + + } + + protected Gif convertInputStreamToGif(InputStream inputStream, String url) + { + return new Gif(inputStream, url); + } + } + + /** * An implementation of the {@link Instructions}, which returns the bitmapUid as an URL, and which does not present any temporary nor * local bitmap. @@ -603,97 +694,6 @@ protected Bitmap convertInputStreamToBitmap(InputStream inputStream, String bitm } - - public static class GifAbstractInstructions - extends GifInstructions - { - - @Override - public InputStream downloadInputStream(String bitmapUid, Object imageSpecs, String url) - throws IOException - { - final URL aURL = new URL(url); - final URLConnection connection = aURL.openConnection(); - connection.connect(); - final InputStream inputStream = connection.getInputStream(); - return inputStream; - } - - @Override - public BitmapableGif convert(InputStream inputStream, String bitmapUid, Object imageSpecs, String url) - { - final long start = System.currentTimeMillis(); - final Gif theGif = convertInputStreamToGif(inputStream, url); - if (theGif != null) - { - if (CoreBitmapDownloader.IS_DEBUG_TRACE && CoreBitmapDownloader.log.isDebugEnabled()) - { - final long stop = System.currentTimeMillis(); - CoreBitmapDownloader.log.debug("The thread '" + Thread.currentThread().getName() + "' decoded in " + (stop - start) + " relative to the URL '" + url + "'"); - } - } - return theGif == null ? null : new BitmapableGif(theGif); - } - - @Override - protected Bitmap hasLocalBitmap(View view, String bitmapUid, Object imageSpecs) - { - return null; - } - - @Override - protected void onBindLocalGif(View view, Gif gif, String bitmapUid, Object imageSpecs) - { - } - - @Override - protected Bitmap hasTemporaryBitmap(View view, String bitmapUid, Object imageSpecs) - { - return null; - } - - @Override - protected void onBindTemporaryBitmap(View view, Bitmap bitmap, String bitmapUid, Object imageSpecs) - { - - } - - @Override - protected void onGifReady(boolean allright, View view, Gif bitmap, String bitmapUid, Object imageSpecs) - { - - } - - @Override - protected boolean onBindGif(boolean downloaded, View view, Gif gif, String bitmapUid, Object imageSpecs) - { - final GifEngine engine = new GifEngine(((ImageView) (view)), gif); - if (VERSION.SDK_INT >= VERSION_CODES.HONEYCOMB) - { - engine.animate(); - } - else - { - if (log.isInfoEnabled() == true) - { - log.info("Gif animation is available from API 11"); - } - } - return true; - } - - @Override - protected void onBitmapBound(boolean result, View view, String bitmapUid, Object imageSpecs) - { - - } - - protected Gif convertInputStreamToGif(InputStream inputStream, String url) - { - return new Gif(inputStream, url); - } - } - /** * Return the downloaded InputStream * From 4124eb7eec3557219a2fa1fd6a660901eefc2da1 Mon Sep 17 00:00:00 2001 From: Antoine Gerard Date: Fri, 22 Dec 2017 18:07:40 +0100 Subject: [PATCH 05/19] Working on the gif engine of the bitmapdownloader --- library/build.gradle | 2 +- .../com/smartnsoft/droid4me/download/BitmapDownloader.java | 2 +- .../smartnsoft/droid4me/download/DownloadInstructions.java | 5 +++-- .../main/java/com/smartnsoft/droid4me/download/gif/Gif.java | 4 ++-- 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/library/build.gradle b/library/build.gradle index 152e5fb5..e6bdf416 100755 --- a/library/build.gradle +++ b/library/build.gradle @@ -1,5 +1,5 @@ apply plugin: "com.android.library" -//apply plugin: "com.jfrog.bintray" +apply plugin: "com.jfrog.bintray" apply plugin: "maven" apply plugin: "maven-publish" diff --git a/library/src/main/java/com/smartnsoft/droid4me/download/BitmapDownloader.java b/library/src/main/java/com/smartnsoft/droid4me/download/BitmapDownloader.java index cce2a0bf..00dd1c99 100755 --- a/library/src/main/java/com/smartnsoft/droid4me/download/BitmapDownloader.java +++ b/library/src/main/java/com/smartnsoft/droid4me/download/BitmapDownloader.java @@ -196,7 +196,7 @@ public void unplug() /** * Indicates the default upper limit of memory that each cache is allowed to reach. */ - public static final long DEFAULT_HIGH_LEVEL_MEMORY_WATER_MARK_IN_BYTES = 3l * 1024l * 1024l; + public static final long DEFAULT_HIGH_LEVEL_MEMORY_WATER_MARK_IN_BYTES = 5l * 1024l * 1024l; /** * Indicates the default lower limit of memory that each cache is allowed to reach. diff --git a/library/src/main/java/com/smartnsoft/droid4me/download/DownloadInstructions.java b/library/src/main/java/com/smartnsoft/droid4me/download/DownloadInstructions.java index a7cc4a1c..59b13b21 100755 --- a/library/src/main/java/com/smartnsoft/droid4me/download/DownloadInstructions.java +++ b/library/src/main/java/com/smartnsoft/droid4me/download/DownloadInstructions.java @@ -393,6 +393,7 @@ public BitmapableGif hasTemporaryBitmap(ViewableView view, String bitmapUid, Obj @Override public void onBindTemporaryBitmap(ViewableView view, BitmapableGif bitmap, String bitmapUid, Object imageSpecs) { + onBindTemporaryBitmap(view != null ? view.getView() : null, bitmap.gif, bitmapUid, imageSpecs); } @Override @@ -453,7 +454,7 @@ public InputStream onInputStreamDownloaded(String imageUid, Object imageSpecs, S protected abstract Bitmap hasTemporaryBitmap(View view, String bitmapUid, Object imageSpecs); - protected abstract void onBindTemporaryBitmap(View view, Bitmap bitmap, String bitmapUid, Object imageSpecs); + protected abstract void onBindTemporaryBitmap(View view, Gif bitmap, String bitmapUid, Object imageSpecs); protected abstract void onGifReady(boolean allright, View view, Gif bitmap, String bitmapUid, Object imageSpecs); @@ -514,7 +515,7 @@ protected Bitmap hasTemporaryBitmap(View view, String bitmapUid, Object imageSpe } @Override - protected void onBindTemporaryBitmap(View view, Bitmap bitmap, String bitmapUid, Object imageSpecs) + protected void onBindTemporaryBitmap(View view, Gif bitmap, String bitmapUid, Object imageSpecs) { } diff --git a/library/src/main/java/com/smartnsoft/droid4me/download/gif/Gif.java b/library/src/main/java/com/smartnsoft/droid4me/download/gif/Gif.java index dabbf5d2..c0e1beaf 100755 --- a/library/src/main/java/com/smartnsoft/droid4me/download/gif/Gif.java +++ b/library/src/main/java/com/smartnsoft/droid4me/download/gif/Gif.java @@ -29,12 +29,12 @@ public final class Gif public Gif(InputStream inputStream, String url) { - this.bitmaps = new ArrayList(); + this.bitmaps = new ArrayList<>(); final GifDecoder gifDecoder; { final long milliseconds = System.currentTimeMillis(); gifDecoder = new GifDecoder(); - if (gifDecoder.read(inputStream, 8192) != GifDecoder.STATUS_OK) + if (gifDecoder.read(inputStream, 2 * 8192) != GifDecoder.STATUS_OK) { if (log.isWarnEnabled()) { From 4a45906da3c390f461d6a9b0166ad5d7eae9bcf0 Mon Sep 17 00:00:00 2001 From: Antoine Gerard Date: Fri, 22 Dec 2017 19:10:50 +0100 Subject: [PATCH 06/19] Working on the gif engine of the bitmapdownloader --- .../download/DownloadInstructions.java | 19 +++++++++++-- .../droid4me/download/gif/GifEngine.java | 28 +++++++++++++++++-- 2 files changed, 42 insertions(+), 5 deletions(-) diff --git a/library/src/main/java/com/smartnsoft/droid4me/download/DownloadInstructions.java b/library/src/main/java/com/smartnsoft/droid4me/download/DownloadInstructions.java index 59b13b21..fb29c6c4 100755 --- a/library/src/main/java/com/smartnsoft/droid4me/download/DownloadInstructions.java +++ b/library/src/main/java/com/smartnsoft/droid4me/download/DownloadInstructions.java @@ -470,6 +470,8 @@ public static class GifAbstractInstructions extends GifInstructions { + private GifEngine gifEngine; + @Override public InputStream downloadInputStream(String bitmapUid, Object imageSpecs, String url) throws IOException @@ -511,13 +513,18 @@ protected void onBindLocalGif(View view, Gif gif, String bitmapUid, Object image @Override protected Bitmap hasTemporaryBitmap(View view, String bitmapUid, Object imageSpecs) { + if (imageSpecs instanceof DownloadSpecs.TemporaryImageSpecs) + { + final DownloadSpecs.TemporaryImageSpecs temporaryImageSpecs = (DownloadSpecs.TemporaryImageSpecs) imageSpecs; + return temporaryImageSpecs.imageResourceId != -1 ? BitmapFactory.decodeResource(view.getContext().getResources(), temporaryImageSpecs.imageResourceId) : null; + } return null; } @Override protected void onBindTemporaryBitmap(View view, Gif bitmap, String bitmapUid, Object imageSpecs) { - + ((ImageView) view).setImageBitmap(bitmap.getBitmap(0)); } @Override @@ -526,13 +533,19 @@ protected void onGifReady(boolean allright, View view, Gif bitmap, String bitmap } + @Override + public void onOver(boolean aborted, ViewableView view, String bitmapUid, Object imageSpecs) + { + super.onOver(aborted, view, bitmapUid, imageSpecs); + } + @Override protected boolean onBindGif(boolean downloaded, View view, Gif gif, String bitmapUid, Object imageSpecs) { - final GifEngine engine = new GifEngine(((ImageView) (view)), gif); if (VERSION.SDK_INT >= VERSION_CODES.HONEYCOMB) { - engine.animate(); + gifEngine = new GifEngine(((ImageView) (view)), gif); + gifEngine.animate(); } else { diff --git a/library/src/main/java/com/smartnsoft/droid4me/download/gif/GifEngine.java b/library/src/main/java/com/smartnsoft/droid4me/download/gif/GifEngine.java index 4139487b..fc071511 100755 --- a/library/src/main/java/com/smartnsoft/droid4me/download/gif/GifEngine.java +++ b/library/src/main/java/com/smartnsoft/droid4me/download/gif/GifEngine.java @@ -1,5 +1,8 @@ package com.smartnsoft.droid4me.download.gif; +import java.util.HashMap; +import java.util.HashSet; + import android.animation.ValueAnimator; import android.animation.ValueAnimator.AnimatorUpdateListener; import android.os.Build.VERSION_CODES; @@ -17,20 +20,41 @@ * @since 2017.10.18 */ +@RequiresApi(api = VERSION_CODES.HONEYCOMB) public final class GifEngine { + private static volatile HashMap map = new HashMap<>(); + private Gif gif; private ImageView imageView; + private ValueAnimator valueAnimator; + public GifEngine(final ImageView imageView, final Gif gif) { this.imageView = imageView; this.gif = gif; + + final int key = imageView.hashCode(); + final GifEngine gifEngine = map.get(key); + + if (gifEngine != null) + { + gifEngine.recycle(); + } + map.put(key, this); + } + + public void recycle() + { + if (valueAnimator != null && valueAnimator.isRunning()) + { + valueAnimator.end(); + } } - @RequiresApi(api = VERSION_CODES.HONEYCOMB) public void animate() { if (gif != null && gif.bitmaps.isEmpty() == false) @@ -41,7 +65,7 @@ public void animate() table[i] = i; } - final ValueAnimator valueAnimator = ValueAnimator.ofInt(table); + valueAnimator = ValueAnimator.ofInt(table); valueAnimator.setInterpolator(new LinearInterpolator()); valueAnimator.setDuration(gif.getDuration()); valueAnimator.setRepeatCount(ValueAnimator.INFINITE); From 38f4e830d743c3205791612200a9591f56fd65ce Mon Sep 17 00:00:00 2001 From: Antoine Gerard Date: Fri, 29 Dec 2017 19:14:26 +0100 Subject: [PATCH 07/19] RED-450 #time 4h Working on the gif engine of the bitmapdownloader --- .../download/BasisBitmapDownloader.java | 1 - .../download/BasisDownloadInstructions.java | 3 +- .../download/DownloadInstructions.java | 51 ++++++++++++++----- .../smartnsoft/droid4me/download/gif/Gif.java | 19 +++++++ .../droid4me/download/gif/GifEngine.java | 11 +++- .../download/test/BitmapDownloaderTest.java | 5 +- 6 files changed, 70 insertions(+), 20 deletions(-) diff --git a/library/src/main/java/com/smartnsoft/droid4me/download/BasisBitmapDownloader.java b/library/src/main/java/com/smartnsoft/droid4me/download/BasisBitmapDownloader.java index 09a7e5f7..32227165 100755 --- a/library/src/main/java/com/smartnsoft/droid4me/download/BasisBitmapDownloader.java +++ b/library/src/main/java/com/smartnsoft/droid4me/download/BasisBitmapDownloader.java @@ -405,7 +405,6 @@ public final void get(boolean isPreBlocking, boolean isDownloadBlocking, ViewCla } - public synchronized void clear() { if (log.isInfoEnabled()) diff --git a/library/src/main/java/com/smartnsoft/droid4me/download/BasisDownloadInstructions.java b/library/src/main/java/com/smartnsoft/droid4me/download/BasisDownloadInstructions.java index 25b9544c..58464218 100755 --- a/library/src/main/java/com/smartnsoft/droid4me/download/BasisDownloadInstructions.java +++ b/library/src/main/java/com/smartnsoft/droid4me/download/BasisDownloadInstructions.java @@ -48,7 +48,8 @@ public class BasisDownloadInstructions public interface Instructions { - /**s + /** + * s * The method will be invoked, so as to known whether the bitmap could not be extracted locally, i.e. from the application .apk, or a static local * resource. *

diff --git a/library/src/main/java/com/smartnsoft/droid4me/download/DownloadInstructions.java b/library/src/main/java/com/smartnsoft/droid4me/download/DownloadInstructions.java index fb29c6c4..6a669ec6 100755 --- a/library/src/main/java/com/smartnsoft/droid4me/download/DownloadInstructions.java +++ b/library/src/main/java/com/smartnsoft/droid4me/download/DownloadInstructions.java @@ -35,6 +35,10 @@ import android.graphics.Bitmap; import android.graphics.Bitmap.Config; import android.graphics.BitmapFactory; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.Drawable; import android.os.Build; import android.os.Build.VERSION; import android.os.Build.VERSION_CODES; @@ -42,11 +46,12 @@ import android.view.View; import android.widget.ImageView; +import com.smartnsoft.droid4me.R; import com.smartnsoft.droid4me.download.DownloadContracts.Bitmapable; import com.smartnsoft.droid4me.download.DownloadContracts.Handlerable; import com.smartnsoft.droid4me.download.DownloadContracts.Viewable; +import com.smartnsoft.droid4me.download.DownloadSpecs.TemporaryImageSpecs; import com.smartnsoft.droid4me.download.gif.Gif; -import com.smartnsoft.droid4me.download.gif.GifEngine; import com.smartnsoft.droid4me.log.Logger; import com.smartnsoft.droid4me.log.LoggerFactory; @@ -131,9 +136,13 @@ public final static class BitmapableGif private final Gif gif; + private final Bitmap bitmap; + + public BitmapableGif(Gif gif) { this.gif = gif; + bitmap = gif.getBitmap(0); } public int getSizeInBytes() @@ -142,12 +151,18 @@ public int getSizeInBytes() { return 0; } - return gif.getHeight() * gif.getWidth() * gif.getFramesCount(); + else + { + return gif.getHeight() * gif.getWidth() * gif.getFramesCount(); + } } public void recycle() { - + if (gif != null) + { + gif.endAnimation(); + } } } @@ -370,12 +385,14 @@ public static abstract class GifInstructions @Override public BitmapableGif hasLocalBitmap(ViewableView view, String bitmapUid, Object imageSpecs) { - return null; + final Bitmap bitmap = hasLocalBitmap(view.getView(), bitmapUid, imageSpecs); + return bitmap == null ? null : new BitmapableGif(null); } @Override public void onBindLocalBitmap(ViewableView view, BitmapableGif bitmap, String bitmapUid, Object imageSpecs) { + ((ImageView) view.getView()).setImageBitmap(bitmap.bitmap); } @Override @@ -384,12 +401,6 @@ public String computeUrl(String bitmapUid, Object imageSpecs) return bitmapUid; } - @Override - public BitmapableGif hasTemporaryBitmap(ViewableView view, String bitmapUid, Object imageSpecs) - { - return null; - } - @Override public void onBindTemporaryBitmap(ViewableView view, BitmapableGif bitmap, String bitmapUid, Object imageSpecs) { @@ -470,7 +481,12 @@ public static class GifAbstractInstructions extends GifInstructions { - private GifEngine gifEngine; + @Override + public BitmapableGif hasTemporaryBitmap(ViewableView view, String bitmapUid, Object imageSpecs) + { + final Bitmap bitmap = hasLocalBitmap(view.getView(), bitmapUid, imageSpecs); + return bitmap == null ? null : new BitmapableGif(null); + } @Override public InputStream downloadInputStream(String bitmapUid, Object imageSpecs, String url) @@ -502,6 +518,11 @@ public BitmapableGif convert(InputStream inputStream, String bitmapUid, Object i @Override protected Bitmap hasLocalBitmap(View view, String bitmapUid, Object imageSpecs) { + if (imageSpecs instanceof DownloadSpecs.TemporaryImageSpecs) + { + final DownloadSpecs.TemporaryImageSpecs temporaryImageSpecs = (DownloadSpecs.TemporaryImageSpecs) imageSpecs; + return temporaryImageSpecs.imageResourceId != -1 ? BitmapFactory.decodeResource(view.getContext().getResources(), temporaryImageSpecs.imageResourceId) : null; + } return null; } @@ -518,7 +539,10 @@ protected Bitmap hasTemporaryBitmap(View view, String bitmapUid, Object imageSpe final DownloadSpecs.TemporaryImageSpecs temporaryImageSpecs = (DownloadSpecs.TemporaryImageSpecs) imageSpecs; return temporaryImageSpecs.imageResourceId != -1 ? BitmapFactory.decodeResource(view.getContext().getResources(), temporaryImageSpecs.imageResourceId) : null; } - return null; + else + { + return null; + } } @Override @@ -544,8 +568,7 @@ protected boolean onBindGif(boolean downloaded, View view, Gif gif, String bitma { if (VERSION.SDK_INT >= VERSION_CODES.HONEYCOMB) { - gifEngine = new GifEngine(((ImageView) (view)), gif); - gifEngine.animate(); + gif.startAnimation((ImageView) view); } else { diff --git a/library/src/main/java/com/smartnsoft/droid4me/download/gif/Gif.java b/library/src/main/java/com/smartnsoft/droid4me/download/gif/Gif.java index c0e1beaf..fab9dc41 100755 --- a/library/src/main/java/com/smartnsoft/droid4me/download/gif/Gif.java +++ b/library/src/main/java/com/smartnsoft/droid4me/download/gif/Gif.java @@ -4,7 +4,10 @@ import java.util.ArrayList; import java.util.List; +import android.annotation.TargetApi; import android.graphics.Bitmap; +import android.support.annotation.NonNull; +import android.widget.ImageView; import com.smartnsoft.droid4me.log.Logger; import com.smartnsoft.droid4me.log.LoggerFactory; @@ -27,6 +30,8 @@ public final class Gif private int duration; + private GifEngine gifEngine; + public Gif(InputStream inputStream, String url) { this.bitmaps = new ArrayList<>(); @@ -70,6 +75,18 @@ public Gif(InputStream inputStream, String url) } } + @TargetApi(android.os.Build.VERSION_CODES.HONEYCOMB) + public void startAnimation(@NonNull final ImageView imageView) + { + gifEngine = new GifEngine(imageView, this); + gifEngine.animate(); + } + + @TargetApi(android.os.Build.VERSION_CODES.HONEYCOMB) + public void endAnimation() + { + gifEngine.end(); + } public int getHeight() { @@ -95,4 +112,6 @@ public int getDuration() { return duration; } + + } diff --git a/library/src/main/java/com/smartnsoft/droid4me/download/gif/GifEngine.java b/library/src/main/java/com/smartnsoft/droid4me/download/gif/GifEngine.java index fc071511..19eada3b 100755 --- a/library/src/main/java/com/smartnsoft/droid4me/download/gif/GifEngine.java +++ b/library/src/main/java/com/smartnsoft/droid4me/download/gif/GifEngine.java @@ -23,11 +23,10 @@ @RequiresApi(api = VERSION_CODES.HONEYCOMB) public final class GifEngine { + private Gif gif; private static volatile HashMap map = new HashMap<>(); - private Gif gif; - private ImageView imageView; private ValueAnimator valueAnimator; @@ -55,6 +54,14 @@ public void recycle() } } + public void end() + { + if (valueAnimator != null && valueAnimator.isRunning()) + { + valueAnimator.end(); + } + } + public void animate() { if (gif != null && gif.bitmaps.isEmpty() == false) diff --git a/library/src/test/java/com/smartnsoft/droid4me/download/test/BitmapDownloaderTest.java b/library/src/test/java/com/smartnsoft/droid4me/download/test/BitmapDownloaderTest.java index a787a816..5ec6b5ff 100755 --- a/library/src/test/java/com/smartnsoft/droid4me/download/test/BitmapDownloaderTest.java +++ b/library/src/test/java/com/smartnsoft/droid4me/download/test/BitmapDownloaderTest.java @@ -39,6 +39,7 @@ import com.smartnsoft.droid4me.download.DownloadContracts.Bitmapable; import com.smartnsoft.droid4me.download.DownloadContracts.Handlerable; import com.smartnsoft.droid4me.download.DownloadContracts.Viewable; +import com.smartnsoft.droid4me.download.DownloadInstructions.BitmapableBitmap; import com.smartnsoft.droid4me.test.BasisTests; import junit.framework.Assert; @@ -239,7 +240,7 @@ public DummyBitmapable hasLocalBitmap(DummyViewable view, String bitmapUid, Obje } @Override - public DummyBitmapable hasTemporaryBitmap(DummyViewable view, String bitmapUid, Object imageSpecs) + public BitmapableBitmap hasTemporaryBitmap(DummyViewable view, String bitmapUid, Object imageSpecs) { expectations.hasTemporaryBitmap++; return hasTemporaryBitmap == true ? new DummyBitmapable(200 * 1024) : null; @@ -1227,7 +1228,7 @@ private void hasTemporaryBitmapExceptionInternal(boolean fromCache, final Runtim { @Override - public DummyBitmapable hasTemporaryBitmap(DummyViewable view, String bitmapUid, Object imageSpecs) + public BitmapableBitmap hasTemporaryBitmap(DummyViewable view, String bitmapUid, Object imageSpecs) { super.hasTemporaryBitmap(view, bitmapUid, imageSpecs); if (exception != null) From 993cc8cf243795bee4fb4fec6f73f1e43eb12664 Mon Sep 17 00:00:00 2001 From: Antoine Gerard Date: Tue, 2 Jan 2018 17:59:38 +0100 Subject: [PATCH 08/19] RED-450 #time 5h Optimized the display of gifs in a recycler view --- .../download/BasisBitmapDownloader.java | 1 + .../download/CoreBitmapDownloader.java | 5 + .../smartnsoft/droid4me/download/gif/Gif.java | 167 +++++++++++++----- .../droid4me/download/gif/GifDecoder.java | 1 + .../droid4me/download/gif/GifEngine.java | 90 ---------- 5 files changed, 131 insertions(+), 133 deletions(-) delete mode 100755 library/src/main/java/com/smartnsoft/droid4me/download/gif/GifEngine.java diff --git a/library/src/main/java/com/smartnsoft/droid4me/download/BasisBitmapDownloader.java b/library/src/main/java/com/smartnsoft/droid4me/download/BasisBitmapDownloader.java index 32227165..03d434c0 100755 --- a/library/src/main/java/com/smartnsoft/droid4me/download/BasisBitmapDownloader.java +++ b/library/src/main/java/com/smartnsoft/droid4me/download/BasisBitmapDownloader.java @@ -40,6 +40,7 @@ import com.smartnsoft.droid4me.download.DownloadContracts.Bitmapable; import com.smartnsoft.droid4me.download.DownloadContracts.Handlerable; import com.smartnsoft.droid4me.download.DownloadContracts.Viewable; +import com.smartnsoft.droid4me.download.DownloadInstructions.BitmapableGif; /** * An implementation of the {@link CoreBitmapDownloader} class, which is independent from the Android platform. diff --git a/library/src/main/java/com/smartnsoft/droid4me/download/CoreBitmapDownloader.java b/library/src/main/java/com/smartnsoft/droid4me/download/CoreBitmapDownloader.java index f75f4edd..2034bde1 100755 --- a/library/src/main/java/com/smartnsoft/droid4me/download/CoreBitmapDownloader.java +++ b/library/src/main/java/com/smartnsoft/droid4me/download/CoreBitmapDownloader.java @@ -38,6 +38,7 @@ import com.smartnsoft.droid4me.download.DownloadContracts.Bitmapable; import com.smartnsoft.droid4me.download.DownloadContracts.Handlerable; import com.smartnsoft.droid4me.download.DownloadContracts.Viewable; +import com.smartnsoft.droid4me.download.DownloadInstructions.BitmapableGif; import com.smartnsoft.droid4me.log.Logger; import com.smartnsoft.droid4me.log.LoggerFactory; @@ -612,6 +613,10 @@ public void rememberBinding(ViewClass view) @SuppressWarnings("unchecked") final UsedBitmap otherUsedBitmap = (UsedBitmap) view.getTag(); if (otherUsedBitmap != null) { + if (otherUsedBitmap.getBitmap() instanceof BitmapableGif) + { + otherUsedBitmap.getBitmap().recycle(); + } otherUsedBitmap.bindingCount--; if (IS_DEBUG_TRACE && log.isDebugEnabled()) { diff --git a/library/src/main/java/com/smartnsoft/droid4me/download/gif/Gif.java b/library/src/main/java/com/smartnsoft/droid4me/download/gif/Gif.java index fab9dc41..92d5b7a9 100755 --- a/library/src/main/java/com/smartnsoft/droid4me/download/gif/Gif.java +++ b/library/src/main/java/com/smartnsoft/droid4me/download/gif/Gif.java @@ -4,9 +4,15 @@ import java.util.ArrayList; import java.util.List; -import android.annotation.TargetApi; +import android.animation.ValueAnimator; +import android.animation.ValueAnimator.AnimatorUpdateListener; import android.graphics.Bitmap; +import android.os.Build.VERSION_CODES; import android.support.annotation.NonNull; +import android.support.annotation.RequiresApi; +import android.view.View; +import android.view.View.OnAttachStateChangeListener; +import android.view.animation.LinearInterpolator; import android.widget.ImageView; import com.smartnsoft.droid4me.log.Logger; @@ -19,9 +25,11 @@ */ /** - * This class represents a Gif File. + * This class represents a Gif File and its display in an ImageView */ +@RequiresApi(api = VERSION_CODES.HONEYCOMB_MR1) public final class Gif + implements OnAttachStateChangeListener { public static final Logger log = LoggerFactory.getInstance("Gif"); @@ -30,11 +38,123 @@ public final class Gif private int duration; - private GifEngine gifEngine; + private ImageView imageView; + + /** + * We are using a value animator for animating + * the gif in the ImageView + */ + private ValueAnimator valueAnimator; + public Gif(InputStream inputStream, String url) { this.bitmaps = new ArrayList<>(); + decodeGif(inputStream, url); + } + + @Override + public void onViewAttachedToWindow(View view) + { + + } + + /** + * We end the gif animation once the ImageView that plays the + * gif is detached from the current window. + * This will prevent multiple display of the same gif in a recycler view + * It will also free the memory preventing memory leak and OOM + * + * @param view + */ + @Override + public void onViewDetachedFromWindow(View view) + { + end(); + } + + @RequiresApi(api = VERSION_CODES.HONEYCOMB_MR1) + public void startAnimation(@NonNull final ImageView imageView) + { + this.imageView = imageView; + this.imageView.addOnAttachStateChangeListener(this); + animate(); + } + + @RequiresApi(android.os.Build.VERSION_CODES.HONEYCOMB_MR1) + public void endAnimation() + { + end(); + } + + + public int getHeight() + { + return bitmaps.size() < 1 ? 0 : bitmaps.get(0).getHeight(); + } + + public int getWidth() + { + return bitmaps.size() < 1 ? 0 : bitmaps.get(0).getWidth(); + } + + public int getFramesCount() + { + return bitmaps.size(); + } + + public Bitmap getBitmap(int index) + { + return bitmaps.get(index); + } + + public int getDuration() + { + return duration; + } + + private void end() + { + if (valueAnimator != null && valueAnimator.isRunning()) + { + valueAnimator.cancel(); + valueAnimator.end(); + bitmaps.clear(); + } + } + + private void animate() + { + if (bitmaps.isEmpty() == false) + { + int[] table = new int[bitmaps.size()]; + for (int i = 0; i < table.length; i++) + { + table[i] = i; + } + + valueAnimator = ValueAnimator.ofInt(table); + valueAnimator.setInterpolator(new LinearInterpolator()); + valueAnimator.setDuration(getDuration()); + valueAnimator.setRepeatCount(ValueAnimator.INFINITE); + valueAnimator.addUpdateListener(new AnimatorUpdateListener() + { + @Override + public void onAnimationUpdate(ValueAnimator animation) + { + if (valueAnimator.isRunning() && valueAnimator.isRunning()) + { + imageView.setImageBitmap(bitmaps.get((Integer) animation.getAnimatedValue())); + } + } + }); + valueAnimator.start(); + } + } + + + private void decodeGif(final InputStream inputStream, final String url) + { final GifDecoder gifDecoder; { final long milliseconds = System.currentTimeMillis(); @@ -72,46 +192,7 @@ public Gif(InputStream inputStream, String url) { log.info("Prepared the individual images belonging to the animated GIF with URL '" + url + "' in " + (System.currentTimeMillis() - milliseconds) + " ms"); } + gifDecoder.clear(); } } - - @TargetApi(android.os.Build.VERSION_CODES.HONEYCOMB) - public void startAnimation(@NonNull final ImageView imageView) - { - gifEngine = new GifEngine(imageView, this); - gifEngine.animate(); - } - - @TargetApi(android.os.Build.VERSION_CODES.HONEYCOMB) - public void endAnimation() - { - gifEngine.end(); - } - - public int getHeight() - { - return bitmaps.size() < 1 ? 0 : bitmaps.get(0).getHeight(); - } - - public int getWidth() - { - return bitmaps.size() < 1 ? 0 : bitmaps.get(0).getWidth(); - } - - public int getFramesCount() - { - return bitmaps.size(); - } - - public Bitmap getBitmap(int index) - { - return bitmaps.get(index); - } - - public int getDuration() - { - return duration; - } - - } diff --git a/library/src/main/java/com/smartnsoft/droid4me/download/gif/GifDecoder.java b/library/src/main/java/com/smartnsoft/droid4me/download/gif/GifDecoder.java index 9bb9dece..db097ea3 100755 --- a/library/src/main/java/com/smartnsoft/droid4me/download/gif/GifDecoder.java +++ b/library/src/main/java/com/smartnsoft/droid4me/download/gif/GifDecoder.java @@ -489,6 +489,7 @@ int read(InputStream is, int contentLength) buffer.flush(); read(buffer.toByteArray()); + buffer.close(); } catch (IOException e) { diff --git a/library/src/main/java/com/smartnsoft/droid4me/download/gif/GifEngine.java b/library/src/main/java/com/smartnsoft/droid4me/download/gif/GifEngine.java deleted file mode 100755 index 19eada3b..00000000 --- a/library/src/main/java/com/smartnsoft/droid4me/download/gif/GifEngine.java +++ /dev/null @@ -1,90 +0,0 @@ -package com.smartnsoft.droid4me.download.gif; - -import java.util.HashMap; -import java.util.HashSet; - -import android.animation.ValueAnimator; -import android.animation.ValueAnimator.AnimatorUpdateListener; -import android.os.Build.VERSION_CODES; -import android.support.annotation.RequiresApi; -import android.view.animation.LinearInterpolator; -import android.widget.ImageView; - -/** - * This class is used to display and - * animated a GIF inside every View that are - * based on ImageView. - * See {@link GifDecoder} for the logic. - * - * @author Antoine Gerard - * @since 2017.10.18 - */ - -@RequiresApi(api = VERSION_CODES.HONEYCOMB) -public final class GifEngine -{ - private Gif gif; - - private static volatile HashMap map = new HashMap<>(); - - private ImageView imageView; - - private ValueAnimator valueAnimator; - - public GifEngine(final ImageView imageView, final Gif gif) - { - this.imageView = imageView; - this.gif = gif; - - final int key = imageView.hashCode(); - final GifEngine gifEngine = map.get(key); - - if (gifEngine != null) - { - gifEngine.recycle(); - } - map.put(key, this); - } - - public void recycle() - { - if (valueAnimator != null && valueAnimator.isRunning()) - { - valueAnimator.end(); - } - } - - public void end() - { - if (valueAnimator != null && valueAnimator.isRunning()) - { - valueAnimator.end(); - } - } - - public void animate() - { - if (gif != null && gif.bitmaps.isEmpty() == false) - { - int[] table = new int[gif.bitmaps.size()]; - for (int i = 0; i < table.length; i++) - { - table[i] = i; - } - - valueAnimator = ValueAnimator.ofInt(table); - valueAnimator.setInterpolator(new LinearInterpolator()); - valueAnimator.setDuration(gif.getDuration()); - valueAnimator.setRepeatCount(ValueAnimator.INFINITE); - valueAnimator.addUpdateListener(new AnimatorUpdateListener() - { - @Override - public void onAnimationUpdate(ValueAnimator animation) - { - imageView.setImageBitmap(gif.getBitmap((Integer) animation.getAnimatedValue())); - } - }); - valueAnimator.start(); - } - } -} From f3d7fea2e919505957fd5631b903fe17e2138642 Mon Sep 17 00:00:00 2001 From: Antoine Gerard Date: Tue, 2 Jan 2018 18:37:21 +0100 Subject: [PATCH 09/19] Added private keyword and a final --- .../main/java/com/smartnsoft/droid4me/download/gif/Gif.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/src/main/java/com/smartnsoft/droid4me/download/gif/Gif.java b/library/src/main/java/com/smartnsoft/droid4me/download/gif/Gif.java index 92d5b7a9..fa3bc76b 100755 --- a/library/src/main/java/com/smartnsoft/droid4me/download/gif/Gif.java +++ b/library/src/main/java/com/smartnsoft/droid4me/download/gif/Gif.java @@ -34,7 +34,7 @@ public final class Gif public static final Logger log = LoggerFactory.getInstance("Gif"); - public final List bitmaps; + private final List bitmaps; private int duration; @@ -127,7 +127,7 @@ private void animate() { if (bitmaps.isEmpty() == false) { - int[] table = new int[bitmaps.size()]; + final int[] table = new int[bitmaps.size()]; for (int i = 0; i < table.length; i++) { table[i] = i; From 8114af245a5b7de2a932d64597ba74da83094753 Mon Sep 17 00:00:00 2001 From: Antoine Gerard Date: Fri, 5 Jan 2018 15:57:20 +0100 Subject: [PATCH 10/19] Prepared version for code review --- library/build.gradle | 2 +- .../download/DownloadInstructions.java | 26 ++++++++++++------- .../smartnsoft/droid4me/download/gif/Gif.java | 6 ++++- 3 files changed, 23 insertions(+), 11 deletions(-) diff --git a/library/build.gradle b/library/build.gradle index e6bdf416..4bed40c6 100755 --- a/library/build.gradle +++ b/library/build.gradle @@ -19,7 +19,7 @@ android targetSdkVersion 25 versionCode 20 - versionName "2.5.4-SNAPSHOT" + versionName "2.7-SNAPSHOT" } buildTypes diff --git a/library/src/main/java/com/smartnsoft/droid4me/download/DownloadInstructions.java b/library/src/main/java/com/smartnsoft/droid4me/download/DownloadInstructions.java index 6a669ec6..224a12d1 100755 --- a/library/src/main/java/com/smartnsoft/droid4me/download/DownloadInstructions.java +++ b/library/src/main/java/com/smartnsoft/droid4me/download/DownloadInstructions.java @@ -35,10 +35,6 @@ import android.graphics.Bitmap; import android.graphics.Bitmap.Config; import android.graphics.BitmapFactory; -import android.graphics.Canvas; -import android.graphics.Color; -import android.graphics.drawable.BitmapDrawable; -import android.graphics.drawable.Drawable; import android.os.Build; import android.os.Build.VERSION; import android.os.Build.VERSION_CODES; @@ -46,11 +42,9 @@ import android.view.View; import android.widget.ImageView; -import com.smartnsoft.droid4me.R; import com.smartnsoft.droid4me.download.DownloadContracts.Bitmapable; import com.smartnsoft.droid4me.download.DownloadContracts.Handlerable; import com.smartnsoft.droid4me.download.DownloadContracts.Viewable; -import com.smartnsoft.droid4me.download.DownloadSpecs.TemporaryImageSpecs; import com.smartnsoft.droid4me.download.gif.Gif; import com.smartnsoft.droid4me.log.Logger; import com.smartnsoft.droid4me.log.LoggerFactory; @@ -548,7 +542,10 @@ protected Bitmap hasTemporaryBitmap(View view, String bitmapUid, Object imageSpe @Override protected void onBindTemporaryBitmap(View view, Gif bitmap, String bitmapUid, Object imageSpecs) { - ((ImageView) view).setImageBitmap(bitmap.getBitmap(0)); + if (view instanceof ImageView) + { + ((ImageView) view).setImageBitmap(bitmap.getBitmap(0)); + } } @Override @@ -566,7 +563,7 @@ public void onOver(boolean aborted, ViewableView view, String bitmapUid, Object @Override protected boolean onBindGif(boolean downloaded, View view, Gif gif, String bitmapUid, Object imageSpecs) { - if (VERSION.SDK_INT >= VERSION_CODES.HONEYCOMB) + if (VERSION.SDK_INT >= VERSION_CODES.HONEYCOMB_MR1) { gif.startAnimation((ImageView) view); } @@ -588,7 +585,18 @@ protected void onBitmapBound(boolean result, View view, String bitmapUid, Object protected Gif convertInputStreamToGif(InputStream inputStream, String url) { - return new Gif(inputStream, url); + if (VERSION.SDK_INT >= VERSION_CODES.HONEYCOMB_MR1) + { + return new Gif(inputStream, url); + } + else + { + if (log.isWarnEnabled() == true) + { + log.warn("Gif support is available from API 12", new UnsupportedOperationException("Gif support is available from API 12")); + } + return null; + } } } diff --git a/library/src/main/java/com/smartnsoft/droid4me/download/gif/Gif.java b/library/src/main/java/com/smartnsoft/droid4me/download/gif/Gif.java index fa3bc76b..f3bade3a 100755 --- a/library/src/main/java/com/smartnsoft/droid4me/download/gif/Gif.java +++ b/library/src/main/java/com/smartnsoft/droid4me/download/gif/Gif.java @@ -142,7 +142,7 @@ private void animate() @Override public void onAnimationUpdate(ValueAnimator animation) { - if (valueAnimator.isRunning() && valueAnimator.isRunning()) + if (valueAnimator.isRunning()) { imageView.setImageBitmap(bitmaps.get((Integer) animation.getAnimatedValue())); } @@ -159,6 +159,7 @@ private void decodeGif(final InputStream inputStream, final String url) { final long milliseconds = System.currentTimeMillis(); gifDecoder = new GifDecoder(); + if (gifDecoder.read(inputStream, 2 * 8192) != GifDecoder.STATUS_OK) { if (log.isWarnEnabled()) @@ -167,11 +168,13 @@ private void decodeGif(final InputStream inputStream, final String url) } return; } + if (log.isInfoEnabled()) { log.info("Parsed the animated GIF with URL '" + url + "' in " + (System.currentTimeMillis() - milliseconds) + " ms"); } } + final int framesCount = gifDecoder.getFrameCount(); { final long milliseconds = System.currentTimeMillis(); @@ -192,6 +195,7 @@ private void decodeGif(final InputStream inputStream, final String url) { log.info("Prepared the individual images belonging to the animated GIF with URL '" + url + "' in " + (System.currentTimeMillis() - milliseconds) + " ms"); } + gifDecoder.clear(); } } From 922988390efd3a6e0bc22076173d1d9c2fe69c45 Mon Sep 17 00:00:00 2001 From: Antoine Gerard Date: Fri, 9 Feb 2018 17:23:17 +0100 Subject: [PATCH 11/19] RED-450 #time 1h Added review from David for PR --- .../download/BasisDownloadInstructions.java | 1 - .../droid4me/download/BitmapDownloader.java | 4 +- .../download/CoreBitmapDownloader.java | 3 +- .../download/DownloadInstructions.java | 46 ++++++++++++------- .../smartnsoft/droid4me/download/gif/Gif.java | 16 +++++-- .../v7/widget/SmartAppCompatImageView.java | 2 - 6 files changed, 47 insertions(+), 25 deletions(-) diff --git a/library/src/main/java/com/smartnsoft/droid4me/download/BasisDownloadInstructions.java b/library/src/main/java/com/smartnsoft/droid4me/download/BasisDownloadInstructions.java index 58464218..a5eb96c0 100755 --- a/library/src/main/java/com/smartnsoft/droid4me/download/BasisDownloadInstructions.java +++ b/library/src/main/java/com/smartnsoft/droid4me/download/BasisDownloadInstructions.java @@ -49,7 +49,6 @@ public interface Instructions diff --git a/library/src/main/java/com/smartnsoft/droid4me/download/BitmapDownloader.java b/library/src/main/java/com/smartnsoft/droid4me/download/BitmapDownloader.java index 00dd1c99..761b0e74 100755 --- a/library/src/main/java/com/smartnsoft/droid4me/download/BitmapDownloader.java +++ b/library/src/main/java/com/smartnsoft/droid4me/download/BitmapDownloader.java @@ -196,12 +196,12 @@ public void unplug() /** * Indicates the default upper limit of memory that each cache is allowed to reach. */ - public static final long DEFAULT_HIGH_LEVEL_MEMORY_WATER_MARK_IN_BYTES = 5l * 1024l * 1024l; + public static final long DEFAULT_HIGH_LEVEL_MEMORY_WATER_MARK_IN_BYTES = 5L * 1024L * 1024L; /** * Indicates the default lower limit of memory that each cache is allowed to reach. */ - public static final long DEFAULT_LOW_LEVEL_MEMORY_WATER_MARK_IN_BYTES = 1l * 1024l * 1024l; + public static final long DEFAULT_LOW_LEVEL_MEMORY_WATER_MARK_IN_BYTES = 1L * 1024L * 1024L; /** * The number of instances of {@link BitmapDownloader} that will be created. Defaults to {@code 1}. diff --git a/library/src/main/java/com/smartnsoft/droid4me/download/CoreBitmapDownloader.java b/library/src/main/java/com/smartnsoft/droid4me/download/CoreBitmapDownloader.java index 2034bde1..7bd1701f 100755 --- a/library/src/main/java/com/smartnsoft/droid4me/download/CoreBitmapDownloader.java +++ b/library/src/main/java/com/smartnsoft/droid4me/download/CoreBitmapDownloader.java @@ -615,8 +615,9 @@ public void rememberBinding(ViewClass view) { if (otherUsedBitmap.getBitmap() instanceof BitmapableGif) { - otherUsedBitmap.getBitmap().recycle(); + ((BitmapableGif) otherUsedBitmap.getBitmap()).getGif().endAnimation(); } + otherUsedBitmap.bindingCount--; if (IS_DEBUG_TRACE && log.isDebugEnabled()) { diff --git a/library/src/main/java/com/smartnsoft/droid4me/download/DownloadInstructions.java b/library/src/main/java/com/smartnsoft/droid4me/download/DownloadInstructions.java index 224a12d1..aadebe03 100755 --- a/library/src/main/java/com/smartnsoft/droid4me/download/DownloadInstructions.java +++ b/library/src/main/java/com/smartnsoft/droid4me/download/DownloadInstructions.java @@ -139,6 +139,7 @@ public BitmapableGif(Gif gif) bitmap = gif.getBitmap(0); } + @Override public int getSizeInBytes() { if (gif == null) @@ -151,13 +152,30 @@ public int getSizeInBytes() } } + @Override public void recycle() + { + if (gif != null && gif.getBitmaps().isEmpty() == false) + { + for (Bitmap bitmap : gif.getBitmaps()) + { + bitmap.recycle(); + } + } + } + + public void endAnimation() { if (gif != null) { gif.endAnimation(); } } + + public Gif getGif() + { + return gif; + } } /** @@ -372,7 +390,7 @@ public InputStream onInputStreamDownloaded(String bitmapUid, Object imageSpecs, } - public static abstract class GifInstructions + public static abstract class GifAbstractInstructions implements BasisDownloadInstructions.Instructions { @@ -471,8 +489,8 @@ protected abstract boolean onBindGif(boolean downloaded, View view, Gif bitmap, } - public static class GifAbstractInstructions - extends GifInstructions + public static class GifAbstractAbstractInstructions + extends GifAbstractInstructions { @Override @@ -496,15 +514,17 @@ public InputStream downloadInputStream(String bitmapUid, Object imageSpecs, Stri @Override public BitmapableGif convert(InputStream inputStream, String bitmapUid, Object imageSpecs, String url) { - final long start = System.currentTimeMillis(); + long start = 0L; + boolean isDebug = CoreBitmapDownloader.IS_DEBUG_TRACE && CoreBitmapDownloader.log.isDebugEnabled(); + if (isDebug) + { + start = System.currentTimeMillis(); + } final Gif theGif = convertInputStreamToGif(inputStream, url); - if (theGif != null) + if (isDebug && theGif != null) { - if (CoreBitmapDownloader.IS_DEBUG_TRACE && CoreBitmapDownloader.log.isDebugEnabled()) - { - final long stop = System.currentTimeMillis(); - CoreBitmapDownloader.log.debug("The thread '" + Thread.currentThread().getName() + "' decoded in " + (stop - start) + " relative to the URL '" + url + "'"); - } + final long stop = System.currentTimeMillis(); + CoreBitmapDownloader.log.debug("The thread '" + Thread.currentThread().getName() + "' decoded in " + (stop - start) + " relative to the URL '" + url + "'"); } return theGif == null ? null : new BitmapableGif(theGif); } @@ -554,12 +574,6 @@ protected void onGifReady(boolean allright, View view, Gif bitmap, String bitmap } - @Override - public void onOver(boolean aborted, ViewableView view, String bitmapUid, Object imageSpecs) - { - super.onOver(aborted, view, bitmapUid, imageSpecs); - } - @Override protected boolean onBindGif(boolean downloaded, View view, Gif gif, String bitmapUid, Object imageSpecs) { diff --git a/library/src/main/java/com/smartnsoft/droid4me/download/gif/Gif.java b/library/src/main/java/com/smartnsoft/droid4me/download/gif/Gif.java index f3bade3a..d41a749a 100755 --- a/library/src/main/java/com/smartnsoft/droid4me/download/gif/Gif.java +++ b/library/src/main/java/com/smartnsoft/droid4me/download/gif/Gif.java @@ -70,6 +70,7 @@ public void onViewAttachedToWindow(View view) @Override public void onViewDetachedFromWindow(View view) { + this.imageView.removeOnAttachStateChangeListener(this); end(); } @@ -90,12 +91,12 @@ public void endAnimation() public int getHeight() { - return bitmaps.size() < 1 ? 0 : bitmaps.get(0).getHeight(); + return bitmaps.isEmpty() ? 0 : bitmaps.get(0).getHeight(); } public int getWidth() { - return bitmaps.size() < 1 ? 0 : bitmaps.get(0).getWidth(); + return bitmaps.isEmpty() ? 0 : bitmaps.get(0).getWidth(); } public int getFramesCount() @@ -108,6 +109,11 @@ public Bitmap getBitmap(int index) return bitmaps.get(index); } + public List getBitmaps() + { + return bitmaps; + } + public int getDuration() { return duration; @@ -157,7 +163,11 @@ private void decodeGif(final InputStream inputStream, final String url) { final GifDecoder gifDecoder; { - final long milliseconds = System.currentTimeMillis(); + long milliseconds = 0L; + if (log.isInfoEnabled()) + { + milliseconds = System.currentTimeMillis(); + } gifDecoder = new GifDecoder(); if (gifDecoder.read(inputStream, 2 * 8192) != GifDecoder.STATUS_OK) diff --git a/library/src/main/java/com/smartnsoft/droid4me/support/v7/widget/SmartAppCompatImageView.java b/library/src/main/java/com/smartnsoft/droid4me/support/v7/widget/SmartAppCompatImageView.java index 8e5ea787..3c5cc767 100755 --- a/library/src/main/java/com/smartnsoft/droid4me/support/v7/widget/SmartAppCompatImageView.java +++ b/library/src/main/java/com/smartnsoft/droid4me/support/v7/widget/SmartAppCompatImageView.java @@ -33,8 +33,6 @@ import com.smartnsoft.droid4me.widget.SmartRelativeLayout; import com.smartnsoft.droid4me.widget.SmartViewExtension; -import static android.support.v7.appcompat.R.styleable.AppCompatImageView; - /** * Enables to receive an event when the {@link ImageView} size has changed, set an automatic ratio between its width and its height, and discard the * layout requests. From 66906f63ab4d0114c31fe2d39b8609a573c01737 Mon Sep 17 00:00:00 2001 From: Antoine Gerard Date: Fri, 9 Feb 2018 17:25:01 +0100 Subject: [PATCH 12/19] Renamed class --- .../com/smartnsoft/droid4me/download/DownloadInstructions.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/src/main/java/com/smartnsoft/droid4me/download/DownloadInstructions.java b/library/src/main/java/com/smartnsoft/droid4me/download/DownloadInstructions.java index aadebe03..01fd2527 100755 --- a/library/src/main/java/com/smartnsoft/droid4me/download/DownloadInstructions.java +++ b/library/src/main/java/com/smartnsoft/droid4me/download/DownloadInstructions.java @@ -489,7 +489,7 @@ protected abstract boolean onBindGif(boolean downloaded, View view, Gif bitmap, } - public static class GifAbstractAbstractInstructions + public static class GifInstructions extends GifAbstractInstructions { From 627cfca9161d517b159ebb46e87815cbcff4765c Mon Sep 17 00:00:00 2001 From: Antoine Gerard Date: Thu, 22 Feb 2018 18:21:04 +0100 Subject: [PATCH 13/19] Added reviews from Raphael --- library/build.gradle | 50 +++++++++---------- .../download/BasisBitmapDownloader.java | 2 +- .../download/DownloadInstructions.java | 18 +------ .../smartnsoft/droid4me/download/gif/Gif.java | 37 +++++++------- .../droid4me/download/gif/GifDecoder.java | 4 +- .../droid4me/download/gif/GifFrame.java | 11 ++-- .../droid4me/download/gif/GifHeader.java | 11 ++-- .../download/gif/GifHeaderParser.java | 35 ++++++------- .../download/gif/SimpleBitmapProvider.java | 3 -- 9 files changed, 76 insertions(+), 95 deletions(-) diff --git a/library/build.gradle b/library/build.gradle index f09b5803..d4b49001 100755 --- a/library/build.gradle +++ b/library/build.gradle @@ -126,31 +126,31 @@ publishing.publications.all } } -//bintray -//{ -// user = bintrayUsername -// key = bintrayKey -// -// publications = ["ReleasePublication"] -// -// pkg -// { -// repo = "maven" -// name = "droid4me" -// userOrg = "smartnsoft" -// licenses = ["MIT"] -// vcsUrl = "https://github.com/smartnsoft/droid4me.git" -// publish = true -// -// version -// { -// name = android.defaultConfig.versionName -// desc = "droid4me is a framework library dedicated to the development of Android applications" -// released = new Date() -// vcsTag = "droid4me-" + android.defaultConfig.versionName -// } -// } -//} +bintray +{ + user = bintrayUsername + key = bintrayKey + + publications = ["ReleasePublication"] + + pkg + { + repo = "maven" + name = "droid4me" + userOrg = "smartnsoft" + licenses = ["MIT"] + vcsUrl = "https://github.com/smartnsoft/droid4me.git" + publish = true + + version + { + name = android.defaultConfig.versionName + desc = "droid4me is a framework library dedicated to the development of Android applications" + released = new Date() + vcsTag = "droid4me-" + android.defaultConfig.versionName + } + } +} uploadArchives { diff --git a/library/src/main/java/com/smartnsoft/droid4me/download/BasisBitmapDownloader.java b/library/src/main/java/com/smartnsoft/droid4me/download/BasisBitmapDownloader.java index 03d434c0..e714e5a7 100755 --- a/library/src/main/java/com/smartnsoft/droid4me/download/BasisBitmapDownloader.java +++ b/library/src/main/java/com/smartnsoft/droid4me/download/BasisBitmapDownloader.java @@ -1321,7 +1321,7 @@ protected InputStream onInputStreamDownloaded(InputStream inputStream) /** * This method assumes that the provided inputStream is not {@code null}. * - * @param inputStream an input stream corresponding to a bitmap + * @param inputStream an input stream corresponding to a bitmap or a gif * @return {@code null} if the input stream could not be properly converted ; a valid bitmap otherwise */ protected BitmapClass fromInputStreamToBitmapable(InputStream inputStream) diff --git a/library/src/main/java/com/smartnsoft/droid4me/download/DownloadInstructions.java b/library/src/main/java/com/smartnsoft/droid4me/download/DownloadInstructions.java index 01fd2527..b3c42223 100755 --- a/library/src/main/java/com/smartnsoft/droid4me/download/DownloadInstructions.java +++ b/library/src/main/java/com/smartnsoft/droid4me/download/DownloadInstructions.java @@ -132,7 +132,6 @@ public final static class BitmapableGif private final Bitmap bitmap; - public BitmapableGif(Gif gif) { this.gif = gif; @@ -429,7 +428,6 @@ public InputStream downloadInputStream(String bitmapUid, Object imageSpecs, Stri @Override public BitmapableGif convert(InputStream inputStream, String bitmapUid, Object imageSpecs, String url) { - return null; } @@ -585,7 +583,7 @@ protected boolean onBindGif(boolean downloaded, View view, Gif gif, String bitma { if (log.isInfoEnabled() == true) { - log.info("Gif animation is available from API 11"); + log.info("Gif animation is only available from API 11"); } } return true; @@ -753,20 +751,6 @@ protected Bitmap convertInputStreamToBitmap(InputStream inputStream, String bitm } - /** - * Return the downloaded InputStream - * - * @param inputStream - * @param bitmaUid - * @param imageSpecs - * @param url - * @return - */ - protected InputStream rawInputStream(InputStream inputStream, String bitmaUid, Object imageSpecs, String url) - { - return inputStream; - } - /** * We do not want that container class to be instantiated. */ diff --git a/library/src/main/java/com/smartnsoft/droid4me/download/gif/Gif.java b/library/src/main/java/com/smartnsoft/droid4me/download/gif/Gif.java index d41a749a..8c101421 100755 --- a/library/src/main/java/com/smartnsoft/droid4me/download/gif/Gif.java +++ b/library/src/main/java/com/smartnsoft/droid4me/download/gif/Gif.java @@ -18,7 +18,6 @@ import com.smartnsoft.droid4me.log.Logger; import com.smartnsoft.droid4me.log.LoggerFactory; - /** * @author Antoine Gerard * @since 2017.10.18 @@ -88,7 +87,6 @@ public void endAnimation() end(); } - public int getHeight() { return bitmaps.isEmpty() ? 0 : bitmaps.get(0).getHeight(); @@ -186,27 +184,26 @@ private void decodeGif(final InputStream inputStream, final String url) } final int framesCount = gifDecoder.getFrameCount(); + + final long milliseconds = System.currentTimeMillis(); + while (bitmaps.size() < framesCount) { - final long milliseconds = System.currentTimeMillis(); - while (bitmaps.size() < framesCount) - { - gifDecoder.advance(); - final Bitmap nextBitmap = gifDecoder.getNextFrame(); - // We need to deep copy the bitmap - duration += gifDecoder.getDelay(gifDecoder.getCurrentFrameIndex()); - final Bitmap bitmap = nextBitmap.copy(nextBitmap.getConfig(), true); - if (bitmap == null) - { - break; - } - bitmaps.add(bitmap); - } - if (log.isInfoEnabled()) + gifDecoder.advance(); + final Bitmap nextBitmap = gifDecoder.getNextFrame(); + // We need to deep copy the bitmap + duration += gifDecoder.getDelay(gifDecoder.getCurrentFrameIndex()); + final Bitmap bitmap = nextBitmap.copy(nextBitmap.getConfig(), true); + if (bitmap == null) { - log.info("Prepared the individual images belonging to the animated GIF with URL '" + url + "' in " + (System.currentTimeMillis() - milliseconds) + " ms"); + break; } - - gifDecoder.clear(); + bitmaps.add(bitmap); } + if (log.isInfoEnabled()) + { + log.info("Prepared the individual images belonging to the animated GIF with URL '" + url + "' in " + (System.currentTimeMillis() - milliseconds) + " ms"); + } + + gifDecoder.clear(); } } diff --git a/library/src/main/java/com/smartnsoft/droid4me/download/gif/GifDecoder.java b/library/src/main/java/com/smartnsoft/droid4me/download/gif/GifDecoder.java index db097ea3..789f910d 100755 --- a/library/src/main/java/com/smartnsoft/droid4me/download/gif/GifDecoder.java +++ b/library/src/main/java/com/smartnsoft/droid4me/download/gif/GifDecoder.java @@ -439,7 +439,7 @@ synchronized Bitmap getNextFrame() } // Set the appropriate color table. - act = currentFrame.lct != null ? currentFrame.lct : header.gct; + act = currentFrame.localColorTable != null ? currentFrame.localColorTable : header.gct; if (act == null) { if (Log.isLoggable(TAG, Log.DEBUG)) @@ -645,7 +645,7 @@ private Bitmap setPixels(GifFrame currentFrame, GifFrame previousFrame) if (!currentFrame.transparency) { c = header.bgColor; - if (currentFrame.lct != null && header.bgIndex == currentFrame.transIndex) + if (currentFrame.localColorTable != null && header.bgIndex == currentFrame.transIndex) { c = 0; } diff --git a/library/src/main/java/com/smartnsoft/droid4me/download/gif/GifFrame.java b/library/src/main/java/com/smartnsoft/droid4me/download/gif/GifFrame.java index 99eef774..f6605480 100755 --- a/library/src/main/java/com/smartnsoft/droid4me/download/gif/GifFrame.java +++ b/library/src/main/java/com/smartnsoft/droid4me/download/gif/GifFrame.java @@ -3,14 +3,17 @@ /** * @author Antoine Gerard * @since 2017.10.18 - */ - -/** + *

* Inner model class housing metadata for each frame. + * Taken From : https://gist.github.com/devunwired/4479231 */ + public final class GifFrame { + /** + * Size of the frame + */ int ix, iy, iw, ih; /** @@ -46,5 +49,5 @@ public final class GifFrame /** * Local Color Table. */ - int[] lct; + int[] localColorTable; } diff --git a/library/src/main/java/com/smartnsoft/droid4me/download/gif/GifHeader.java b/library/src/main/java/com/smartnsoft/droid4me/download/gif/GifHeader.java index 483d2930..58d0e312 100755 --- a/library/src/main/java/com/smartnsoft/droid4me/download/gif/GifHeader.java +++ b/library/src/main/java/com/smartnsoft/droid4me/download/gif/GifHeader.java @@ -1,17 +1,16 @@ package com.smartnsoft.droid4me.download.gif; -/** - * @author Antoine Gerard - * @since 2017.10.18 - */ - -import java.util.ArrayList; import java.util.List; +import java.util.ArrayList; /** + * @author Antoine Gerard + * @since 2017.10.18 * A header object containing the number of frames in an animated GIF image as well as basic * metadata like width and height that can be used to decode each individual frame of the GIF. Can * be shared by one or more {@link GifDecoder}s to play the same animated GIF in multiple views. + *

+ * Source : https://github.com/bumptech/glide/blob/master/third_party/gif_decoder/src/main/java/com/bumptech/glide/gifdecoder/GifHeader.java */ public final class GifHeader { diff --git a/library/src/main/java/com/smartnsoft/droid4me/download/gif/GifHeaderParser.java b/library/src/main/java/com/smartnsoft/droid4me/download/gif/GifHeaderParser.java index 1fe66d6e..51df2b09 100755 --- a/library/src/main/java/com/smartnsoft/droid4me/download/gif/GifHeaderParser.java +++ b/library/src/main/java/com/smartnsoft/droid4me/download/gif/GifHeaderParser.java @@ -1,19 +1,20 @@ package com.smartnsoft.droid4me.download.gif; -import android.util.Log; - import java.nio.BufferUnderflowException; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.util.Arrays; + +import android.util.Log; + /** * @author Antoine Gerard * @since 2017.10.18 - */ - -/** + *

* A class responsible for creating {@link GifHeader}s from data * representing animated gifs. + *

+ * Source : https://github.com/bumptech/glide/blob/master/third_party/gif_decoder/src/main/java/com/bumptech/glide/gifdecoder/GifHeaderParser.java */ public final class GifHeaderParser { @@ -21,11 +22,11 @@ public final class GifHeaderParser public static final String TAG = "GifHeaderParser"; // The minimum frame delay in hundredths of a second. - static final int MIN_FRAME_DELAY = 2; + private static final int MIN_FRAME_DELAY = 2; // The default frame delay in hundredths of a second for GIFs with frame delays less than the // minimum. - static final int DEFAULT_FRAME_DELAY = 10; + private static final int DEFAULT_FRAME_DELAY = 10; private static final int MAX_BLOCK_SIZE = 256; @@ -81,13 +82,13 @@ public GifHeader parseHeader() { throw new IllegalStateException("You must call setData() before parseHeader()"); } - if (err()) + if (error()) { return header; } readHeader(); - if (!err()) + if (!error()) { readContents(); if (header.frameCount < 0) @@ -106,7 +107,7 @@ public GifHeader parseHeader() public boolean isAnimated() { readHeader(); - if (!err()) + if (!error()) { readContents(2 /* maxFrames */); } @@ -128,7 +129,7 @@ private void readContents(int maxFrames) { // Read GIF file content blocks. boolean done = false; - while (!(done || err() || header.frameCount > maxFrames)) + while (!(done || error() || header.frameCount > maxFrames)) { int code = read(); switch (code) @@ -253,12 +254,12 @@ private void readBitmap() if (lctFlag) { // Read table. - header.currentFrame.lct = readColorTable(lctSize); + header.currentFrame.localColorTable = readColorTable(lctSize); } else { // No local color table. - header.currentFrame.lct = null; + header.currentFrame.localColorTable = null; } // Save this as the decoding position pointer. @@ -267,7 +268,7 @@ private void readBitmap() // False decode pixel data to advance buffer. skipImageData(); - if (err()) + if (error()) { return; } @@ -296,7 +297,7 @@ private void readNetscapeExt() header.loopCount = GifDecoder.LOOP_FOREVER; } } - } while ((blockSize > 0) && !err()); + } while ((blockSize > 0) && !error()); } @@ -316,7 +317,7 @@ private void readHeader() return; } readLSD(); - if (header.gctFlag && !err()) + if (header.gctFlag && !error()) { header.gct = readColorTable(header.gctSize); header.bgColor = header.gct[header.bgIndex]; @@ -477,7 +478,7 @@ private int readShort() return rawData.getShort(); } - private boolean err() + private boolean error() { return header.status != GifDecoder.STATUS_OK; } diff --git a/library/src/main/java/com/smartnsoft/droid4me/download/gif/SimpleBitmapProvider.java b/library/src/main/java/com/smartnsoft/droid4me/download/gif/SimpleBitmapProvider.java index ee48e6cf..d06193e7 100755 --- a/library/src/main/java/com/smartnsoft/droid4me/download/gif/SimpleBitmapProvider.java +++ b/library/src/main/java/com/smartnsoft/droid4me/download/gif/SimpleBitmapProvider.java @@ -6,9 +6,6 @@ /** * @author Antoine Gerard * @since 2017.10.18 - */ - -/** * Util class for creating a Bitmap */ public final class SimpleBitmapProvider From 1c15c099f622d01ded3020cd4e7a8ab42dfbf815 Mon Sep 17 00:00:00 2001 From: Antoine Gerard Date: Mon, 26 Feb 2018 10:59:40 +0100 Subject: [PATCH 14/19] Added reviews from Raphael --- .../main/java/com/smartnsoft/droid4me/download/gif/GifFrame.java | 1 - 1 file changed, 1 deletion(-) diff --git a/library/src/main/java/com/smartnsoft/droid4me/download/gif/GifFrame.java b/library/src/main/java/com/smartnsoft/droid4me/download/gif/GifFrame.java index f6605480..457fbba5 100755 --- a/library/src/main/java/com/smartnsoft/droid4me/download/gif/GifFrame.java +++ b/library/src/main/java/com/smartnsoft/droid4me/download/gif/GifFrame.java @@ -3,7 +3,6 @@ /** * @author Antoine Gerard * @since 2017.10.18 - *

* Inner model class housing metadata for each frame. * Taken From : https://gist.github.com/devunwired/4479231 */ From 894e7aeef546e07458aee5886ea3fbf1bb8daba1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Raphae=CC=88l=20Kiffer?= Date: Fri, 2 Mar 2018 11:45:48 +0100 Subject: [PATCH 15/19] Fix files permissions. --- .gitignore | 0 LICENSE | 0 README.md | 0 gradle/wrapper/gradle-wrapper.jar | Bin gradle/wrapper/gradle-wrapper.properties | 0 gradlew.bat | 0 library/.gitignore | 0 library/build.gradle | 0 library/proguard-rules.pro | 0 library/src/main/AndroidManifest.xml | 0 .../com/smartnsoft/droid4me/AndroidLifeCycle.java | 0 .../java/com/smartnsoft/droid4me/LifeCycle.java | 0 .../droid4me/analytics/AnalyticsLogger.java | 0 .../droid4me/analytics/AnalyticsSender.java | 0 .../smartnsoft/droid4me/analytics/package-info.java | 0 .../droid4me/animation/SimpleAnimationListener.java | 0 .../droid4me/animation/SimpleAnimatorListener.java | 0 .../smartnsoft/droid4me/animation/package-info.java | 0 .../smartnsoft/droid4me/app/ActivityController.java | 0 .../com/smartnsoft/droid4me/app/AppInternals.java | 0 .../com/smartnsoft/droid4me/app/AppPublics.java | 0 .../droid4me/app/ConnectivityListener.java | 0 .../com/smartnsoft/droid4me/app/Droid4mizer.java | 0 .../smartnsoft/droid4me/app/ExceptionHandlers.java | 0 .../droid4me/app/ForBusinessObjectActivity.java | 0 .../smartnsoft/droid4me/app/ProgressHandler.java | 0 .../com/smartnsoft/droid4me/app/SmartActivity.java | 0 .../smartnsoft/droid4me/app/SmartApplication.java | 0 .../com/smartnsoft/droid4me/app/SmartCommands.java | 0 .../droid4me/app/SmartDialogFragment.java | 0 .../com/smartnsoft/droid4me/app/SmartFragment.java | 0 .../smartnsoft/droid4me/app/SmartIntentService.java | 0 .../droid4me/app/SmartPreferenceActivity.java | 0 .../droid4me/app/SmartSplashScreenActivity.java | 0 .../java/com/smartnsoft/droid4me/app/Smartable.java | 0 .../smartnsoft/droid4me/app/SmartableActivity.java | 0 .../java/com/smartnsoft/droid4me/app/Smarted.java | 0 .../com/smartnsoft/droid4me/app/package-info.java | 0 .../java/com/smartnsoft/droid4me/bo/Business.java | 0 .../com/smartnsoft/droid4me/bo/package-info.java | 0 .../java/com/smartnsoft/droid4me/cache/Cacher.java | 0 .../smartnsoft/droid4me/cache/DbPersistence.java | 0 .../smartnsoft/droid4me/cache/FilePersistence.java | 0 .../com/smartnsoft/droid4me/cache/MemoryCacher.java | 0 .../smartnsoft/droid4me/cache/NullPersistence.java | 0 .../com/smartnsoft/droid4me/cache/Persistence.java | 0 .../java/com/smartnsoft/droid4me/cache/Values.java | 0 .../com/smartnsoft/droid4me/cache/package-info.java | 0 .../droid4me/config/AssetsConfigurationLoader.java | 0 .../droid4me/config/ConfigurationLoader.java | 0 .../config/InternalStorageConfigurationLoader.java | 0 .../config/ResourcesConfigurationLoader.java | 0 .../smartnsoft/droid4me/config/package-info.java | 0 .../droid4me/content/SmartBroadcastReceiver.java | 0 .../smartnsoft/droid4me/content/TokenKeeper.java | 0 .../smartnsoft/droid4me/content/package-info.java | 0 .../droid4me/debug/Droid4meDebugInterceptor.java | 0 .../com/smartnsoft/droid4me/debug/package-info.java | 0 .../droid4me/download/BasisBitmapDownloader.java | 0 .../download/BasisDownloadInstructions.java | 0 .../droid4me/download/BitmapDownloader.java | 0 .../droid4me/download/CoreBitmapDownloader.java | 0 .../droid4me/download/DownloadContracts.java | 0 .../droid4me/download/DownloadInstructions.java | 0 .../smartnsoft/droid4me/download/DownloadSpecs.java | 0 .../com/smartnsoft/droid4me/download/gif/Gif.java | 0 .../droid4me/download/gif/GifDecoder.java | 0 .../smartnsoft/droid4me/download/gif/GifFrame.java | 0 .../smartnsoft/droid4me/download/gif/GifHeader.java | 0 .../droid4me/download/gif/GifHeaderParser.java | 0 .../droid4me/download/gif/SimpleBitmapProvider.java | 0 .../smartnsoft/droid4me/download/package-info.java | 0 .../droid4me/framework/BusinessObjectLifeCycle.java | 0 .../droid4me/framework/DetailsProvider.java | 0 .../com/smartnsoft/droid4me/framework/Events.java | 0 .../framework/ForBusinessObjectImplementation.java | 0 .../droid4me/framework/SmartAdapters.java | 0 .../smartnsoft/droid4me/framework/package-info.java | 0 .../graphics/drawable/BasicBitmapDrawable.java | 0 .../droid4me/graphics/drawable/package-info.java | 0 .../com/smartnsoft/droid4me/log/AndroidLogger.java | 0 .../java/com/smartnsoft/droid4me/log/Logger.java | 0 .../com/smartnsoft/droid4me/log/LoggerFactory.java | 0 .../com/smartnsoft/droid4me/log/LoggerWrapper.java | 0 .../com/smartnsoft/droid4me/log/Loggerable.java | 0 .../com/smartnsoft/droid4me/log/NativeLogger.java | 0 .../com/smartnsoft/droid4me/log/package-info.java | 0 .../java/com/smartnsoft/droid4me/package-info.java | 0 .../support/v4/app/SmartDialogFragment.java | 0 .../droid4me/support/v4/app/SmartFragment.java | 0 .../support/v4/app/SmartFragmentActivity.java | 0 .../support/v4/content/LocalBroadcastManager.java | 0 .../droid4me/support/v4/package-info.java | 0 .../support/v7/app/SmartAppCompatActivity.java | 0 .../v7/app/SmartPreferenceFragmentCompat.java | 0 .../droid4me/support/v7/package-info.java | 0 .../support/v7/widget/SmartAppCompatImageView.java | 0 .../droid4me/ui/SimpleWrappedListView.java | 0 .../com/smartnsoft/droid4me/ui/WrappedListView.java | 0 .../com/smartnsoft/droid4me/ui/package-info.java | 0 .../com/smartnsoft/droid4me/util/BitmapToolbox.java | 0 .../com/smartnsoft/droid4me/util/SendLogsTask.java | 0 .../droid4me/util/StatefulDefaultHandler.java | 0 .../com/smartnsoft/droid4me/util/package-info.java | 0 .../droid4me/widget/OnSizeChangedListener.java | 0 .../droid4me/widget/SmartFrameLayout.java | 0 .../droid4me/widget/SmartLinearLayout.java | 0 .../droid4me/widget/SmartPageIndicator.java | 0 .../droid4me/widget/SmartRelativeLayout.java | 0 .../droid4me/widget/SmartViewExtension.java | 0 .../smartnsoft/droid4me/widget/SmartViewPager.java | 0 .../smartnsoft/droid4me/widget/package-info.java | 0 .../droid4me/ws/URLConnectionWebServiceCaller.java | 0 .../smartnsoft/droid4me/ws/WSUriStreamParser.java | 0 .../smartnsoft/droid4me/ws/WebServiceCaller.java | 0 .../smartnsoft/droid4me/ws/WebServiceClient.java | 0 .../droid4me/ws/WithCacheWSUriStreamParser.java | 0 .../com/smartnsoft/droid4me/ws/package-info.java | 0 .../droid4me/wscache/BackedWSUriStreamParser.java | 0 .../smartnsoft/droid4me/wscache/package-info.java | 0 library/src/main/javadoc/overview.html | 0 .../droid4me/cache/test/PersistenceTest.java | 0 .../download/test/BitmapDownloaderTest.java | 0 .../com/smartnsoft/droid4me/test/BasisTests.java | 0 sample/.gitignore | 0 sample/proguard-rules.pro | 0 sample/src/main/AndroidManifest.xml | 0 sample/src/main/assets/about.css | 0 sample/src/main/assets/application_logo.png | Bin sample/src/main/assets/background.png | Bin sample/src/main/assets/droid4me_inside_large.png | Bin sample/src/main/assets/smartnsoft_logo.png | Bin .../com/smartnsoft/droid4sample/AboutActivity.java | 0 .../java/com/smartnsoft/droid4sample/Constants.java | 0 .../droid4sample/Droid4SampleApplication.java | 0 .../Droid4SampleSplashScreenActivity.java | 0 .../smartnsoft/droid4sample/SettingsActivity.java | 0 .../java/com/smartnsoft/droid4sample/TitleBar.java | 0 .../droid4sample/ws/Droid4SampleServices.java | 0 .../src/main/res/drawable-hdpi/droid4me_inside.png | Bin .../res/drawable-hdpi/droid4sample_splash_logo.png | Bin sample/src/main/res/drawable-hdpi/icon.png | Bin .../main/res/drawable-hdpi/poweredby_smartnsoft.png | Bin .../res/drawable-hdpi/smartnsoft_illustration.png | Bin .../src/main/res/drawable-hdpi/title_bar_home.png | Bin .../main/res/drawable-hdpi/title_bar_refresh.png | Bin .../title_bar_button_background_disabled.png | Bin .../title_bar_button_background_pressed.png | Bin .../title_bar_button_background_selected.png | Bin .../res/drawable/title_bar_button_background.xml | 0 sample/src/main/res/layout/about.xml | 0 .../main/res/layout/droid4sample_splash_screen.xml | 0 sample/src/main/res/layout/main_sample.xml | 0 sample/src/main/res/layout/title_bar.xml | 0 sample/src/main/res/raw/about.html | 0 sample/src/main/res/values-fr/strings.xml | 0 sample/src/main/res/values/array.xml | 0 sample/src/main/res/values/attrs.xml | 0 sample/src/main/res/values/colors.xml | 0 sample/src/main/res/values/dimen.xml | 0 sample/src/main/res/values/strings.xml | 0 sample/src/main/res/values/styles.xml | 0 sample/src/main/res/values/themes.xml | 0 sample/src/main/res/xml/settings.xml | 0 164 files changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 .gitignore mode change 100755 => 100644 LICENSE mode change 100755 => 100644 README.md mode change 100755 => 100644 gradle/wrapper/gradle-wrapper.jar mode change 100755 => 100644 gradle/wrapper/gradle-wrapper.properties mode change 100755 => 100644 gradlew.bat mode change 100755 => 100644 library/.gitignore mode change 100755 => 100644 library/build.gradle mode change 100755 => 100644 library/proguard-rules.pro mode change 100755 => 100644 library/src/main/AndroidManifest.xml mode change 100755 => 100644 library/src/main/java/com/smartnsoft/droid4me/AndroidLifeCycle.java mode change 100755 => 100644 library/src/main/java/com/smartnsoft/droid4me/LifeCycle.java mode change 100755 => 100644 library/src/main/java/com/smartnsoft/droid4me/analytics/AnalyticsLogger.java mode change 100755 => 100644 library/src/main/java/com/smartnsoft/droid4me/analytics/AnalyticsSender.java mode change 100755 => 100644 library/src/main/java/com/smartnsoft/droid4me/analytics/package-info.java mode change 100755 => 100644 library/src/main/java/com/smartnsoft/droid4me/animation/SimpleAnimationListener.java mode change 100755 => 100644 library/src/main/java/com/smartnsoft/droid4me/animation/SimpleAnimatorListener.java mode change 100755 => 100644 library/src/main/java/com/smartnsoft/droid4me/animation/package-info.java mode change 100755 => 100644 library/src/main/java/com/smartnsoft/droid4me/app/ActivityController.java mode change 100755 => 100644 library/src/main/java/com/smartnsoft/droid4me/app/AppInternals.java mode change 100755 => 100644 library/src/main/java/com/smartnsoft/droid4me/app/AppPublics.java mode change 100755 => 100644 library/src/main/java/com/smartnsoft/droid4me/app/ConnectivityListener.java mode change 100755 => 100644 library/src/main/java/com/smartnsoft/droid4me/app/Droid4mizer.java mode change 100755 => 100644 library/src/main/java/com/smartnsoft/droid4me/app/ExceptionHandlers.java mode change 100755 => 100644 library/src/main/java/com/smartnsoft/droid4me/app/ForBusinessObjectActivity.java mode change 100755 => 100644 library/src/main/java/com/smartnsoft/droid4me/app/ProgressHandler.java mode change 100755 => 100644 library/src/main/java/com/smartnsoft/droid4me/app/SmartActivity.java mode change 100755 => 100644 library/src/main/java/com/smartnsoft/droid4me/app/SmartApplication.java mode change 100755 => 100644 library/src/main/java/com/smartnsoft/droid4me/app/SmartCommands.java mode change 100755 => 100644 library/src/main/java/com/smartnsoft/droid4me/app/SmartDialogFragment.java mode change 100755 => 100644 library/src/main/java/com/smartnsoft/droid4me/app/SmartFragment.java mode change 100755 => 100644 library/src/main/java/com/smartnsoft/droid4me/app/SmartIntentService.java mode change 100755 => 100644 library/src/main/java/com/smartnsoft/droid4me/app/SmartPreferenceActivity.java mode change 100755 => 100644 library/src/main/java/com/smartnsoft/droid4me/app/SmartSplashScreenActivity.java mode change 100755 => 100644 library/src/main/java/com/smartnsoft/droid4me/app/Smartable.java mode change 100755 => 100644 library/src/main/java/com/smartnsoft/droid4me/app/SmartableActivity.java mode change 100755 => 100644 library/src/main/java/com/smartnsoft/droid4me/app/Smarted.java mode change 100755 => 100644 library/src/main/java/com/smartnsoft/droid4me/app/package-info.java mode change 100755 => 100644 library/src/main/java/com/smartnsoft/droid4me/bo/Business.java mode change 100755 => 100644 library/src/main/java/com/smartnsoft/droid4me/bo/package-info.java mode change 100755 => 100644 library/src/main/java/com/smartnsoft/droid4me/cache/Cacher.java mode change 100755 => 100644 library/src/main/java/com/smartnsoft/droid4me/cache/DbPersistence.java mode change 100755 => 100644 library/src/main/java/com/smartnsoft/droid4me/cache/FilePersistence.java mode change 100755 => 100644 library/src/main/java/com/smartnsoft/droid4me/cache/MemoryCacher.java mode change 100755 => 100644 library/src/main/java/com/smartnsoft/droid4me/cache/NullPersistence.java mode change 100755 => 100644 library/src/main/java/com/smartnsoft/droid4me/cache/Persistence.java mode change 100755 => 100644 library/src/main/java/com/smartnsoft/droid4me/cache/Values.java mode change 100755 => 100644 library/src/main/java/com/smartnsoft/droid4me/cache/package-info.java mode change 100755 => 100644 library/src/main/java/com/smartnsoft/droid4me/config/AssetsConfigurationLoader.java mode change 100755 => 100644 library/src/main/java/com/smartnsoft/droid4me/config/ConfigurationLoader.java mode change 100755 => 100644 library/src/main/java/com/smartnsoft/droid4me/config/InternalStorageConfigurationLoader.java mode change 100755 => 100644 library/src/main/java/com/smartnsoft/droid4me/config/ResourcesConfigurationLoader.java mode change 100755 => 100644 library/src/main/java/com/smartnsoft/droid4me/config/package-info.java mode change 100755 => 100644 library/src/main/java/com/smartnsoft/droid4me/content/SmartBroadcastReceiver.java mode change 100755 => 100644 library/src/main/java/com/smartnsoft/droid4me/content/TokenKeeper.java mode change 100755 => 100644 library/src/main/java/com/smartnsoft/droid4me/content/package-info.java mode change 100755 => 100644 library/src/main/java/com/smartnsoft/droid4me/debug/Droid4meDebugInterceptor.java mode change 100755 => 100644 library/src/main/java/com/smartnsoft/droid4me/debug/package-info.java mode change 100755 => 100644 library/src/main/java/com/smartnsoft/droid4me/download/BasisBitmapDownloader.java mode change 100755 => 100644 library/src/main/java/com/smartnsoft/droid4me/download/BasisDownloadInstructions.java mode change 100755 => 100644 library/src/main/java/com/smartnsoft/droid4me/download/BitmapDownloader.java mode change 100755 => 100644 library/src/main/java/com/smartnsoft/droid4me/download/CoreBitmapDownloader.java mode change 100755 => 100644 library/src/main/java/com/smartnsoft/droid4me/download/DownloadContracts.java mode change 100755 => 100644 library/src/main/java/com/smartnsoft/droid4me/download/DownloadInstructions.java mode change 100755 => 100644 library/src/main/java/com/smartnsoft/droid4me/download/DownloadSpecs.java mode change 100755 => 100644 library/src/main/java/com/smartnsoft/droid4me/download/gif/Gif.java mode change 100755 => 100644 library/src/main/java/com/smartnsoft/droid4me/download/gif/GifDecoder.java mode change 100755 => 100644 library/src/main/java/com/smartnsoft/droid4me/download/gif/GifFrame.java mode change 100755 => 100644 library/src/main/java/com/smartnsoft/droid4me/download/gif/GifHeader.java mode change 100755 => 100644 library/src/main/java/com/smartnsoft/droid4me/download/gif/GifHeaderParser.java mode change 100755 => 100644 library/src/main/java/com/smartnsoft/droid4me/download/gif/SimpleBitmapProvider.java mode change 100755 => 100644 library/src/main/java/com/smartnsoft/droid4me/download/package-info.java mode change 100755 => 100644 library/src/main/java/com/smartnsoft/droid4me/framework/BusinessObjectLifeCycle.java mode change 100755 => 100644 library/src/main/java/com/smartnsoft/droid4me/framework/DetailsProvider.java mode change 100755 => 100644 library/src/main/java/com/smartnsoft/droid4me/framework/Events.java mode change 100755 => 100644 library/src/main/java/com/smartnsoft/droid4me/framework/ForBusinessObjectImplementation.java mode change 100755 => 100644 library/src/main/java/com/smartnsoft/droid4me/framework/SmartAdapters.java mode change 100755 => 100644 library/src/main/java/com/smartnsoft/droid4me/framework/package-info.java mode change 100755 => 100644 library/src/main/java/com/smartnsoft/droid4me/graphics/drawable/BasicBitmapDrawable.java mode change 100755 => 100644 library/src/main/java/com/smartnsoft/droid4me/graphics/drawable/package-info.java mode change 100755 => 100644 library/src/main/java/com/smartnsoft/droid4me/log/AndroidLogger.java mode change 100755 => 100644 library/src/main/java/com/smartnsoft/droid4me/log/Logger.java mode change 100755 => 100644 library/src/main/java/com/smartnsoft/droid4me/log/LoggerFactory.java mode change 100755 => 100644 library/src/main/java/com/smartnsoft/droid4me/log/LoggerWrapper.java mode change 100755 => 100644 library/src/main/java/com/smartnsoft/droid4me/log/Loggerable.java mode change 100755 => 100644 library/src/main/java/com/smartnsoft/droid4me/log/NativeLogger.java mode change 100755 => 100644 library/src/main/java/com/smartnsoft/droid4me/log/package-info.java mode change 100755 => 100644 library/src/main/java/com/smartnsoft/droid4me/package-info.java mode change 100755 => 100644 library/src/main/java/com/smartnsoft/droid4me/support/v4/app/SmartDialogFragment.java mode change 100755 => 100644 library/src/main/java/com/smartnsoft/droid4me/support/v4/app/SmartFragment.java mode change 100755 => 100644 library/src/main/java/com/smartnsoft/droid4me/support/v4/app/SmartFragmentActivity.java mode change 100755 => 100644 library/src/main/java/com/smartnsoft/droid4me/support/v4/content/LocalBroadcastManager.java mode change 100755 => 100644 library/src/main/java/com/smartnsoft/droid4me/support/v4/package-info.java mode change 100755 => 100644 library/src/main/java/com/smartnsoft/droid4me/support/v7/app/SmartAppCompatActivity.java mode change 100755 => 100644 library/src/main/java/com/smartnsoft/droid4me/support/v7/app/SmartPreferenceFragmentCompat.java mode change 100755 => 100644 library/src/main/java/com/smartnsoft/droid4me/support/v7/package-info.java mode change 100755 => 100644 library/src/main/java/com/smartnsoft/droid4me/support/v7/widget/SmartAppCompatImageView.java mode change 100755 => 100644 library/src/main/java/com/smartnsoft/droid4me/ui/SimpleWrappedListView.java mode change 100755 => 100644 library/src/main/java/com/smartnsoft/droid4me/ui/WrappedListView.java mode change 100755 => 100644 library/src/main/java/com/smartnsoft/droid4me/ui/package-info.java mode change 100755 => 100644 library/src/main/java/com/smartnsoft/droid4me/util/BitmapToolbox.java mode change 100755 => 100644 library/src/main/java/com/smartnsoft/droid4me/util/SendLogsTask.java mode change 100755 => 100644 library/src/main/java/com/smartnsoft/droid4me/util/StatefulDefaultHandler.java mode change 100755 => 100644 library/src/main/java/com/smartnsoft/droid4me/util/package-info.java mode change 100755 => 100644 library/src/main/java/com/smartnsoft/droid4me/widget/OnSizeChangedListener.java mode change 100755 => 100644 library/src/main/java/com/smartnsoft/droid4me/widget/SmartFrameLayout.java mode change 100755 => 100644 library/src/main/java/com/smartnsoft/droid4me/widget/SmartLinearLayout.java mode change 100755 => 100644 library/src/main/java/com/smartnsoft/droid4me/widget/SmartPageIndicator.java mode change 100755 => 100644 library/src/main/java/com/smartnsoft/droid4me/widget/SmartRelativeLayout.java mode change 100755 => 100644 library/src/main/java/com/smartnsoft/droid4me/widget/SmartViewExtension.java mode change 100755 => 100644 library/src/main/java/com/smartnsoft/droid4me/widget/SmartViewPager.java mode change 100755 => 100644 library/src/main/java/com/smartnsoft/droid4me/widget/package-info.java mode change 100755 => 100644 library/src/main/java/com/smartnsoft/droid4me/ws/URLConnectionWebServiceCaller.java mode change 100755 => 100644 library/src/main/java/com/smartnsoft/droid4me/ws/WSUriStreamParser.java mode change 100755 => 100644 library/src/main/java/com/smartnsoft/droid4me/ws/WebServiceCaller.java mode change 100755 => 100644 library/src/main/java/com/smartnsoft/droid4me/ws/WebServiceClient.java mode change 100755 => 100644 library/src/main/java/com/smartnsoft/droid4me/ws/WithCacheWSUriStreamParser.java mode change 100755 => 100644 library/src/main/java/com/smartnsoft/droid4me/ws/package-info.java mode change 100755 => 100644 library/src/main/java/com/smartnsoft/droid4me/wscache/BackedWSUriStreamParser.java mode change 100755 => 100644 library/src/main/java/com/smartnsoft/droid4me/wscache/package-info.java mode change 100755 => 100644 library/src/main/javadoc/overview.html mode change 100755 => 100644 library/src/test/java/com/smartnsoft/droid4me/cache/test/PersistenceTest.java mode change 100755 => 100644 library/src/test/java/com/smartnsoft/droid4me/download/test/BitmapDownloaderTest.java mode change 100755 => 100644 library/src/test/java/com/smartnsoft/droid4me/test/BasisTests.java mode change 100755 => 100644 sample/.gitignore mode change 100755 => 100644 sample/proguard-rules.pro mode change 100755 => 100644 sample/src/main/AndroidManifest.xml mode change 100755 => 100644 sample/src/main/assets/about.css mode change 100755 => 100644 sample/src/main/assets/application_logo.png mode change 100755 => 100644 sample/src/main/assets/background.png mode change 100755 => 100644 sample/src/main/assets/droid4me_inside_large.png mode change 100755 => 100644 sample/src/main/assets/smartnsoft_logo.png mode change 100755 => 100644 sample/src/main/java/com/smartnsoft/droid4sample/AboutActivity.java mode change 100755 => 100644 sample/src/main/java/com/smartnsoft/droid4sample/Constants.java mode change 100755 => 100644 sample/src/main/java/com/smartnsoft/droid4sample/Droid4SampleApplication.java mode change 100755 => 100644 sample/src/main/java/com/smartnsoft/droid4sample/Droid4SampleSplashScreenActivity.java mode change 100755 => 100644 sample/src/main/java/com/smartnsoft/droid4sample/SettingsActivity.java mode change 100755 => 100644 sample/src/main/java/com/smartnsoft/droid4sample/TitleBar.java mode change 100755 => 100644 sample/src/main/java/com/smartnsoft/droid4sample/ws/Droid4SampleServices.java mode change 100755 => 100644 sample/src/main/res/drawable-hdpi/droid4me_inside.png mode change 100755 => 100644 sample/src/main/res/drawable-hdpi/droid4sample_splash_logo.png mode change 100755 => 100644 sample/src/main/res/drawable-hdpi/icon.png mode change 100755 => 100644 sample/src/main/res/drawable-hdpi/poweredby_smartnsoft.png mode change 100755 => 100644 sample/src/main/res/drawable-hdpi/smartnsoft_illustration.png mode change 100755 => 100644 sample/src/main/res/drawable-hdpi/title_bar_home.png mode change 100755 => 100644 sample/src/main/res/drawable-hdpi/title_bar_refresh.png mode change 100755 => 100644 sample/src/main/res/drawable-nodpi/title_bar_button_background_disabled.png mode change 100755 => 100644 sample/src/main/res/drawable-nodpi/title_bar_button_background_pressed.png mode change 100755 => 100644 sample/src/main/res/drawable-nodpi/title_bar_button_background_selected.png mode change 100755 => 100644 sample/src/main/res/drawable/title_bar_button_background.xml mode change 100755 => 100644 sample/src/main/res/layout/about.xml mode change 100755 => 100644 sample/src/main/res/layout/droid4sample_splash_screen.xml mode change 100755 => 100644 sample/src/main/res/layout/main_sample.xml mode change 100755 => 100644 sample/src/main/res/layout/title_bar.xml mode change 100755 => 100644 sample/src/main/res/raw/about.html mode change 100755 => 100644 sample/src/main/res/values-fr/strings.xml mode change 100755 => 100644 sample/src/main/res/values/array.xml mode change 100755 => 100644 sample/src/main/res/values/attrs.xml mode change 100755 => 100644 sample/src/main/res/values/colors.xml mode change 100755 => 100644 sample/src/main/res/values/dimen.xml mode change 100755 => 100644 sample/src/main/res/values/strings.xml mode change 100755 => 100644 sample/src/main/res/values/styles.xml mode change 100755 => 100644 sample/src/main/res/values/themes.xml mode change 100755 => 100644 sample/src/main/res/xml/settings.xml diff --git a/.gitignore b/.gitignore old mode 100755 new mode 100644 diff --git a/LICENSE b/LICENSE old mode 100755 new mode 100644 diff --git a/README.md b/README.md old mode 100755 new mode 100644 diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar old mode 100755 new mode 100644 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties old mode 100755 new mode 100644 diff --git a/gradlew.bat b/gradlew.bat old mode 100755 new mode 100644 diff --git a/library/.gitignore b/library/.gitignore old mode 100755 new mode 100644 diff --git a/library/build.gradle b/library/build.gradle old mode 100755 new mode 100644 diff --git a/library/proguard-rules.pro b/library/proguard-rules.pro old mode 100755 new mode 100644 diff --git a/library/src/main/AndroidManifest.xml b/library/src/main/AndroidManifest.xml old mode 100755 new mode 100644 diff --git a/library/src/main/java/com/smartnsoft/droid4me/AndroidLifeCycle.java b/library/src/main/java/com/smartnsoft/droid4me/AndroidLifeCycle.java old mode 100755 new mode 100644 diff --git a/library/src/main/java/com/smartnsoft/droid4me/LifeCycle.java b/library/src/main/java/com/smartnsoft/droid4me/LifeCycle.java old mode 100755 new mode 100644 diff --git a/library/src/main/java/com/smartnsoft/droid4me/analytics/AnalyticsLogger.java b/library/src/main/java/com/smartnsoft/droid4me/analytics/AnalyticsLogger.java old mode 100755 new mode 100644 diff --git a/library/src/main/java/com/smartnsoft/droid4me/analytics/AnalyticsSender.java b/library/src/main/java/com/smartnsoft/droid4me/analytics/AnalyticsSender.java old mode 100755 new mode 100644 diff --git a/library/src/main/java/com/smartnsoft/droid4me/analytics/package-info.java b/library/src/main/java/com/smartnsoft/droid4me/analytics/package-info.java old mode 100755 new mode 100644 diff --git a/library/src/main/java/com/smartnsoft/droid4me/animation/SimpleAnimationListener.java b/library/src/main/java/com/smartnsoft/droid4me/animation/SimpleAnimationListener.java old mode 100755 new mode 100644 diff --git a/library/src/main/java/com/smartnsoft/droid4me/animation/SimpleAnimatorListener.java b/library/src/main/java/com/smartnsoft/droid4me/animation/SimpleAnimatorListener.java old mode 100755 new mode 100644 diff --git a/library/src/main/java/com/smartnsoft/droid4me/animation/package-info.java b/library/src/main/java/com/smartnsoft/droid4me/animation/package-info.java old mode 100755 new mode 100644 diff --git a/library/src/main/java/com/smartnsoft/droid4me/app/ActivityController.java b/library/src/main/java/com/smartnsoft/droid4me/app/ActivityController.java old mode 100755 new mode 100644 diff --git a/library/src/main/java/com/smartnsoft/droid4me/app/AppInternals.java b/library/src/main/java/com/smartnsoft/droid4me/app/AppInternals.java old mode 100755 new mode 100644 diff --git a/library/src/main/java/com/smartnsoft/droid4me/app/AppPublics.java b/library/src/main/java/com/smartnsoft/droid4me/app/AppPublics.java old mode 100755 new mode 100644 diff --git a/library/src/main/java/com/smartnsoft/droid4me/app/ConnectivityListener.java b/library/src/main/java/com/smartnsoft/droid4me/app/ConnectivityListener.java old mode 100755 new mode 100644 diff --git a/library/src/main/java/com/smartnsoft/droid4me/app/Droid4mizer.java b/library/src/main/java/com/smartnsoft/droid4me/app/Droid4mizer.java old mode 100755 new mode 100644 diff --git a/library/src/main/java/com/smartnsoft/droid4me/app/ExceptionHandlers.java b/library/src/main/java/com/smartnsoft/droid4me/app/ExceptionHandlers.java old mode 100755 new mode 100644 diff --git a/library/src/main/java/com/smartnsoft/droid4me/app/ForBusinessObjectActivity.java b/library/src/main/java/com/smartnsoft/droid4me/app/ForBusinessObjectActivity.java old mode 100755 new mode 100644 diff --git a/library/src/main/java/com/smartnsoft/droid4me/app/ProgressHandler.java b/library/src/main/java/com/smartnsoft/droid4me/app/ProgressHandler.java old mode 100755 new mode 100644 diff --git a/library/src/main/java/com/smartnsoft/droid4me/app/SmartActivity.java b/library/src/main/java/com/smartnsoft/droid4me/app/SmartActivity.java old mode 100755 new mode 100644 diff --git a/library/src/main/java/com/smartnsoft/droid4me/app/SmartApplication.java b/library/src/main/java/com/smartnsoft/droid4me/app/SmartApplication.java old mode 100755 new mode 100644 diff --git a/library/src/main/java/com/smartnsoft/droid4me/app/SmartCommands.java b/library/src/main/java/com/smartnsoft/droid4me/app/SmartCommands.java old mode 100755 new mode 100644 diff --git a/library/src/main/java/com/smartnsoft/droid4me/app/SmartDialogFragment.java b/library/src/main/java/com/smartnsoft/droid4me/app/SmartDialogFragment.java old mode 100755 new mode 100644 diff --git a/library/src/main/java/com/smartnsoft/droid4me/app/SmartFragment.java b/library/src/main/java/com/smartnsoft/droid4me/app/SmartFragment.java old mode 100755 new mode 100644 diff --git a/library/src/main/java/com/smartnsoft/droid4me/app/SmartIntentService.java b/library/src/main/java/com/smartnsoft/droid4me/app/SmartIntentService.java old mode 100755 new mode 100644 diff --git a/library/src/main/java/com/smartnsoft/droid4me/app/SmartPreferenceActivity.java b/library/src/main/java/com/smartnsoft/droid4me/app/SmartPreferenceActivity.java old mode 100755 new mode 100644 diff --git a/library/src/main/java/com/smartnsoft/droid4me/app/SmartSplashScreenActivity.java b/library/src/main/java/com/smartnsoft/droid4me/app/SmartSplashScreenActivity.java old mode 100755 new mode 100644 diff --git a/library/src/main/java/com/smartnsoft/droid4me/app/Smartable.java b/library/src/main/java/com/smartnsoft/droid4me/app/Smartable.java old mode 100755 new mode 100644 diff --git a/library/src/main/java/com/smartnsoft/droid4me/app/SmartableActivity.java b/library/src/main/java/com/smartnsoft/droid4me/app/SmartableActivity.java old mode 100755 new mode 100644 diff --git a/library/src/main/java/com/smartnsoft/droid4me/app/Smarted.java b/library/src/main/java/com/smartnsoft/droid4me/app/Smarted.java old mode 100755 new mode 100644 diff --git a/library/src/main/java/com/smartnsoft/droid4me/app/package-info.java b/library/src/main/java/com/smartnsoft/droid4me/app/package-info.java old mode 100755 new mode 100644 diff --git a/library/src/main/java/com/smartnsoft/droid4me/bo/Business.java b/library/src/main/java/com/smartnsoft/droid4me/bo/Business.java old mode 100755 new mode 100644 diff --git a/library/src/main/java/com/smartnsoft/droid4me/bo/package-info.java b/library/src/main/java/com/smartnsoft/droid4me/bo/package-info.java old mode 100755 new mode 100644 diff --git a/library/src/main/java/com/smartnsoft/droid4me/cache/Cacher.java b/library/src/main/java/com/smartnsoft/droid4me/cache/Cacher.java old mode 100755 new mode 100644 diff --git a/library/src/main/java/com/smartnsoft/droid4me/cache/DbPersistence.java b/library/src/main/java/com/smartnsoft/droid4me/cache/DbPersistence.java old mode 100755 new mode 100644 diff --git a/library/src/main/java/com/smartnsoft/droid4me/cache/FilePersistence.java b/library/src/main/java/com/smartnsoft/droid4me/cache/FilePersistence.java old mode 100755 new mode 100644 diff --git a/library/src/main/java/com/smartnsoft/droid4me/cache/MemoryCacher.java b/library/src/main/java/com/smartnsoft/droid4me/cache/MemoryCacher.java old mode 100755 new mode 100644 diff --git a/library/src/main/java/com/smartnsoft/droid4me/cache/NullPersistence.java b/library/src/main/java/com/smartnsoft/droid4me/cache/NullPersistence.java old mode 100755 new mode 100644 diff --git a/library/src/main/java/com/smartnsoft/droid4me/cache/Persistence.java b/library/src/main/java/com/smartnsoft/droid4me/cache/Persistence.java old mode 100755 new mode 100644 diff --git a/library/src/main/java/com/smartnsoft/droid4me/cache/Values.java b/library/src/main/java/com/smartnsoft/droid4me/cache/Values.java old mode 100755 new mode 100644 diff --git a/library/src/main/java/com/smartnsoft/droid4me/cache/package-info.java b/library/src/main/java/com/smartnsoft/droid4me/cache/package-info.java old mode 100755 new mode 100644 diff --git a/library/src/main/java/com/smartnsoft/droid4me/config/AssetsConfigurationLoader.java b/library/src/main/java/com/smartnsoft/droid4me/config/AssetsConfigurationLoader.java old mode 100755 new mode 100644 diff --git a/library/src/main/java/com/smartnsoft/droid4me/config/ConfigurationLoader.java b/library/src/main/java/com/smartnsoft/droid4me/config/ConfigurationLoader.java old mode 100755 new mode 100644 diff --git a/library/src/main/java/com/smartnsoft/droid4me/config/InternalStorageConfigurationLoader.java b/library/src/main/java/com/smartnsoft/droid4me/config/InternalStorageConfigurationLoader.java old mode 100755 new mode 100644 diff --git a/library/src/main/java/com/smartnsoft/droid4me/config/ResourcesConfigurationLoader.java b/library/src/main/java/com/smartnsoft/droid4me/config/ResourcesConfigurationLoader.java old mode 100755 new mode 100644 diff --git a/library/src/main/java/com/smartnsoft/droid4me/config/package-info.java b/library/src/main/java/com/smartnsoft/droid4me/config/package-info.java old mode 100755 new mode 100644 diff --git a/library/src/main/java/com/smartnsoft/droid4me/content/SmartBroadcastReceiver.java b/library/src/main/java/com/smartnsoft/droid4me/content/SmartBroadcastReceiver.java old mode 100755 new mode 100644 diff --git a/library/src/main/java/com/smartnsoft/droid4me/content/TokenKeeper.java b/library/src/main/java/com/smartnsoft/droid4me/content/TokenKeeper.java old mode 100755 new mode 100644 diff --git a/library/src/main/java/com/smartnsoft/droid4me/content/package-info.java b/library/src/main/java/com/smartnsoft/droid4me/content/package-info.java old mode 100755 new mode 100644 diff --git a/library/src/main/java/com/smartnsoft/droid4me/debug/Droid4meDebugInterceptor.java b/library/src/main/java/com/smartnsoft/droid4me/debug/Droid4meDebugInterceptor.java old mode 100755 new mode 100644 diff --git a/library/src/main/java/com/smartnsoft/droid4me/debug/package-info.java b/library/src/main/java/com/smartnsoft/droid4me/debug/package-info.java old mode 100755 new mode 100644 diff --git a/library/src/main/java/com/smartnsoft/droid4me/download/BasisBitmapDownloader.java b/library/src/main/java/com/smartnsoft/droid4me/download/BasisBitmapDownloader.java old mode 100755 new mode 100644 diff --git a/library/src/main/java/com/smartnsoft/droid4me/download/BasisDownloadInstructions.java b/library/src/main/java/com/smartnsoft/droid4me/download/BasisDownloadInstructions.java old mode 100755 new mode 100644 diff --git a/library/src/main/java/com/smartnsoft/droid4me/download/BitmapDownloader.java b/library/src/main/java/com/smartnsoft/droid4me/download/BitmapDownloader.java old mode 100755 new mode 100644 diff --git a/library/src/main/java/com/smartnsoft/droid4me/download/CoreBitmapDownloader.java b/library/src/main/java/com/smartnsoft/droid4me/download/CoreBitmapDownloader.java old mode 100755 new mode 100644 diff --git a/library/src/main/java/com/smartnsoft/droid4me/download/DownloadContracts.java b/library/src/main/java/com/smartnsoft/droid4me/download/DownloadContracts.java old mode 100755 new mode 100644 diff --git a/library/src/main/java/com/smartnsoft/droid4me/download/DownloadInstructions.java b/library/src/main/java/com/smartnsoft/droid4me/download/DownloadInstructions.java old mode 100755 new mode 100644 diff --git a/library/src/main/java/com/smartnsoft/droid4me/download/DownloadSpecs.java b/library/src/main/java/com/smartnsoft/droid4me/download/DownloadSpecs.java old mode 100755 new mode 100644 diff --git a/library/src/main/java/com/smartnsoft/droid4me/download/gif/Gif.java b/library/src/main/java/com/smartnsoft/droid4me/download/gif/Gif.java old mode 100755 new mode 100644 diff --git a/library/src/main/java/com/smartnsoft/droid4me/download/gif/GifDecoder.java b/library/src/main/java/com/smartnsoft/droid4me/download/gif/GifDecoder.java old mode 100755 new mode 100644 diff --git a/library/src/main/java/com/smartnsoft/droid4me/download/gif/GifFrame.java b/library/src/main/java/com/smartnsoft/droid4me/download/gif/GifFrame.java old mode 100755 new mode 100644 diff --git a/library/src/main/java/com/smartnsoft/droid4me/download/gif/GifHeader.java b/library/src/main/java/com/smartnsoft/droid4me/download/gif/GifHeader.java old mode 100755 new mode 100644 diff --git a/library/src/main/java/com/smartnsoft/droid4me/download/gif/GifHeaderParser.java b/library/src/main/java/com/smartnsoft/droid4me/download/gif/GifHeaderParser.java old mode 100755 new mode 100644 diff --git a/library/src/main/java/com/smartnsoft/droid4me/download/gif/SimpleBitmapProvider.java b/library/src/main/java/com/smartnsoft/droid4me/download/gif/SimpleBitmapProvider.java old mode 100755 new mode 100644 diff --git a/library/src/main/java/com/smartnsoft/droid4me/download/package-info.java b/library/src/main/java/com/smartnsoft/droid4me/download/package-info.java old mode 100755 new mode 100644 diff --git a/library/src/main/java/com/smartnsoft/droid4me/framework/BusinessObjectLifeCycle.java b/library/src/main/java/com/smartnsoft/droid4me/framework/BusinessObjectLifeCycle.java old mode 100755 new mode 100644 diff --git a/library/src/main/java/com/smartnsoft/droid4me/framework/DetailsProvider.java b/library/src/main/java/com/smartnsoft/droid4me/framework/DetailsProvider.java old mode 100755 new mode 100644 diff --git a/library/src/main/java/com/smartnsoft/droid4me/framework/Events.java b/library/src/main/java/com/smartnsoft/droid4me/framework/Events.java old mode 100755 new mode 100644 diff --git a/library/src/main/java/com/smartnsoft/droid4me/framework/ForBusinessObjectImplementation.java b/library/src/main/java/com/smartnsoft/droid4me/framework/ForBusinessObjectImplementation.java old mode 100755 new mode 100644 diff --git a/library/src/main/java/com/smartnsoft/droid4me/framework/SmartAdapters.java b/library/src/main/java/com/smartnsoft/droid4me/framework/SmartAdapters.java old mode 100755 new mode 100644 diff --git a/library/src/main/java/com/smartnsoft/droid4me/framework/package-info.java b/library/src/main/java/com/smartnsoft/droid4me/framework/package-info.java old mode 100755 new mode 100644 diff --git a/library/src/main/java/com/smartnsoft/droid4me/graphics/drawable/BasicBitmapDrawable.java b/library/src/main/java/com/smartnsoft/droid4me/graphics/drawable/BasicBitmapDrawable.java old mode 100755 new mode 100644 diff --git a/library/src/main/java/com/smartnsoft/droid4me/graphics/drawable/package-info.java b/library/src/main/java/com/smartnsoft/droid4me/graphics/drawable/package-info.java old mode 100755 new mode 100644 diff --git a/library/src/main/java/com/smartnsoft/droid4me/log/AndroidLogger.java b/library/src/main/java/com/smartnsoft/droid4me/log/AndroidLogger.java old mode 100755 new mode 100644 diff --git a/library/src/main/java/com/smartnsoft/droid4me/log/Logger.java b/library/src/main/java/com/smartnsoft/droid4me/log/Logger.java old mode 100755 new mode 100644 diff --git a/library/src/main/java/com/smartnsoft/droid4me/log/LoggerFactory.java b/library/src/main/java/com/smartnsoft/droid4me/log/LoggerFactory.java old mode 100755 new mode 100644 diff --git a/library/src/main/java/com/smartnsoft/droid4me/log/LoggerWrapper.java b/library/src/main/java/com/smartnsoft/droid4me/log/LoggerWrapper.java old mode 100755 new mode 100644 diff --git a/library/src/main/java/com/smartnsoft/droid4me/log/Loggerable.java b/library/src/main/java/com/smartnsoft/droid4me/log/Loggerable.java old mode 100755 new mode 100644 diff --git a/library/src/main/java/com/smartnsoft/droid4me/log/NativeLogger.java b/library/src/main/java/com/smartnsoft/droid4me/log/NativeLogger.java old mode 100755 new mode 100644 diff --git a/library/src/main/java/com/smartnsoft/droid4me/log/package-info.java b/library/src/main/java/com/smartnsoft/droid4me/log/package-info.java old mode 100755 new mode 100644 diff --git a/library/src/main/java/com/smartnsoft/droid4me/package-info.java b/library/src/main/java/com/smartnsoft/droid4me/package-info.java old mode 100755 new mode 100644 diff --git a/library/src/main/java/com/smartnsoft/droid4me/support/v4/app/SmartDialogFragment.java b/library/src/main/java/com/smartnsoft/droid4me/support/v4/app/SmartDialogFragment.java old mode 100755 new mode 100644 diff --git a/library/src/main/java/com/smartnsoft/droid4me/support/v4/app/SmartFragment.java b/library/src/main/java/com/smartnsoft/droid4me/support/v4/app/SmartFragment.java old mode 100755 new mode 100644 diff --git a/library/src/main/java/com/smartnsoft/droid4me/support/v4/app/SmartFragmentActivity.java b/library/src/main/java/com/smartnsoft/droid4me/support/v4/app/SmartFragmentActivity.java old mode 100755 new mode 100644 diff --git a/library/src/main/java/com/smartnsoft/droid4me/support/v4/content/LocalBroadcastManager.java b/library/src/main/java/com/smartnsoft/droid4me/support/v4/content/LocalBroadcastManager.java old mode 100755 new mode 100644 diff --git a/library/src/main/java/com/smartnsoft/droid4me/support/v4/package-info.java b/library/src/main/java/com/smartnsoft/droid4me/support/v4/package-info.java old mode 100755 new mode 100644 diff --git a/library/src/main/java/com/smartnsoft/droid4me/support/v7/app/SmartAppCompatActivity.java b/library/src/main/java/com/smartnsoft/droid4me/support/v7/app/SmartAppCompatActivity.java old mode 100755 new mode 100644 diff --git a/library/src/main/java/com/smartnsoft/droid4me/support/v7/app/SmartPreferenceFragmentCompat.java b/library/src/main/java/com/smartnsoft/droid4me/support/v7/app/SmartPreferenceFragmentCompat.java old mode 100755 new mode 100644 diff --git a/library/src/main/java/com/smartnsoft/droid4me/support/v7/package-info.java b/library/src/main/java/com/smartnsoft/droid4me/support/v7/package-info.java old mode 100755 new mode 100644 diff --git a/library/src/main/java/com/smartnsoft/droid4me/support/v7/widget/SmartAppCompatImageView.java b/library/src/main/java/com/smartnsoft/droid4me/support/v7/widget/SmartAppCompatImageView.java old mode 100755 new mode 100644 diff --git a/library/src/main/java/com/smartnsoft/droid4me/ui/SimpleWrappedListView.java b/library/src/main/java/com/smartnsoft/droid4me/ui/SimpleWrappedListView.java old mode 100755 new mode 100644 diff --git a/library/src/main/java/com/smartnsoft/droid4me/ui/WrappedListView.java b/library/src/main/java/com/smartnsoft/droid4me/ui/WrappedListView.java old mode 100755 new mode 100644 diff --git a/library/src/main/java/com/smartnsoft/droid4me/ui/package-info.java b/library/src/main/java/com/smartnsoft/droid4me/ui/package-info.java old mode 100755 new mode 100644 diff --git a/library/src/main/java/com/smartnsoft/droid4me/util/BitmapToolbox.java b/library/src/main/java/com/smartnsoft/droid4me/util/BitmapToolbox.java old mode 100755 new mode 100644 diff --git a/library/src/main/java/com/smartnsoft/droid4me/util/SendLogsTask.java b/library/src/main/java/com/smartnsoft/droid4me/util/SendLogsTask.java old mode 100755 new mode 100644 diff --git a/library/src/main/java/com/smartnsoft/droid4me/util/StatefulDefaultHandler.java b/library/src/main/java/com/smartnsoft/droid4me/util/StatefulDefaultHandler.java old mode 100755 new mode 100644 diff --git a/library/src/main/java/com/smartnsoft/droid4me/util/package-info.java b/library/src/main/java/com/smartnsoft/droid4me/util/package-info.java old mode 100755 new mode 100644 diff --git a/library/src/main/java/com/smartnsoft/droid4me/widget/OnSizeChangedListener.java b/library/src/main/java/com/smartnsoft/droid4me/widget/OnSizeChangedListener.java old mode 100755 new mode 100644 diff --git a/library/src/main/java/com/smartnsoft/droid4me/widget/SmartFrameLayout.java b/library/src/main/java/com/smartnsoft/droid4me/widget/SmartFrameLayout.java old mode 100755 new mode 100644 diff --git a/library/src/main/java/com/smartnsoft/droid4me/widget/SmartLinearLayout.java b/library/src/main/java/com/smartnsoft/droid4me/widget/SmartLinearLayout.java old mode 100755 new mode 100644 diff --git a/library/src/main/java/com/smartnsoft/droid4me/widget/SmartPageIndicator.java b/library/src/main/java/com/smartnsoft/droid4me/widget/SmartPageIndicator.java old mode 100755 new mode 100644 diff --git a/library/src/main/java/com/smartnsoft/droid4me/widget/SmartRelativeLayout.java b/library/src/main/java/com/smartnsoft/droid4me/widget/SmartRelativeLayout.java old mode 100755 new mode 100644 diff --git a/library/src/main/java/com/smartnsoft/droid4me/widget/SmartViewExtension.java b/library/src/main/java/com/smartnsoft/droid4me/widget/SmartViewExtension.java old mode 100755 new mode 100644 diff --git a/library/src/main/java/com/smartnsoft/droid4me/widget/SmartViewPager.java b/library/src/main/java/com/smartnsoft/droid4me/widget/SmartViewPager.java old mode 100755 new mode 100644 diff --git a/library/src/main/java/com/smartnsoft/droid4me/widget/package-info.java b/library/src/main/java/com/smartnsoft/droid4me/widget/package-info.java old mode 100755 new mode 100644 diff --git a/library/src/main/java/com/smartnsoft/droid4me/ws/URLConnectionWebServiceCaller.java b/library/src/main/java/com/smartnsoft/droid4me/ws/URLConnectionWebServiceCaller.java old mode 100755 new mode 100644 diff --git a/library/src/main/java/com/smartnsoft/droid4me/ws/WSUriStreamParser.java b/library/src/main/java/com/smartnsoft/droid4me/ws/WSUriStreamParser.java old mode 100755 new mode 100644 diff --git a/library/src/main/java/com/smartnsoft/droid4me/ws/WebServiceCaller.java b/library/src/main/java/com/smartnsoft/droid4me/ws/WebServiceCaller.java old mode 100755 new mode 100644 diff --git a/library/src/main/java/com/smartnsoft/droid4me/ws/WebServiceClient.java b/library/src/main/java/com/smartnsoft/droid4me/ws/WebServiceClient.java old mode 100755 new mode 100644 diff --git a/library/src/main/java/com/smartnsoft/droid4me/ws/WithCacheWSUriStreamParser.java b/library/src/main/java/com/smartnsoft/droid4me/ws/WithCacheWSUriStreamParser.java old mode 100755 new mode 100644 diff --git a/library/src/main/java/com/smartnsoft/droid4me/ws/package-info.java b/library/src/main/java/com/smartnsoft/droid4me/ws/package-info.java old mode 100755 new mode 100644 diff --git a/library/src/main/java/com/smartnsoft/droid4me/wscache/BackedWSUriStreamParser.java b/library/src/main/java/com/smartnsoft/droid4me/wscache/BackedWSUriStreamParser.java old mode 100755 new mode 100644 diff --git a/library/src/main/java/com/smartnsoft/droid4me/wscache/package-info.java b/library/src/main/java/com/smartnsoft/droid4me/wscache/package-info.java old mode 100755 new mode 100644 diff --git a/library/src/main/javadoc/overview.html b/library/src/main/javadoc/overview.html old mode 100755 new mode 100644 diff --git a/library/src/test/java/com/smartnsoft/droid4me/cache/test/PersistenceTest.java b/library/src/test/java/com/smartnsoft/droid4me/cache/test/PersistenceTest.java old mode 100755 new mode 100644 diff --git a/library/src/test/java/com/smartnsoft/droid4me/download/test/BitmapDownloaderTest.java b/library/src/test/java/com/smartnsoft/droid4me/download/test/BitmapDownloaderTest.java old mode 100755 new mode 100644 diff --git a/library/src/test/java/com/smartnsoft/droid4me/test/BasisTests.java b/library/src/test/java/com/smartnsoft/droid4me/test/BasisTests.java old mode 100755 new mode 100644 diff --git a/sample/.gitignore b/sample/.gitignore old mode 100755 new mode 100644 diff --git a/sample/proguard-rules.pro b/sample/proguard-rules.pro old mode 100755 new mode 100644 diff --git a/sample/src/main/AndroidManifest.xml b/sample/src/main/AndroidManifest.xml old mode 100755 new mode 100644 diff --git a/sample/src/main/assets/about.css b/sample/src/main/assets/about.css old mode 100755 new mode 100644 diff --git a/sample/src/main/assets/application_logo.png b/sample/src/main/assets/application_logo.png old mode 100755 new mode 100644 diff --git a/sample/src/main/assets/background.png b/sample/src/main/assets/background.png old mode 100755 new mode 100644 diff --git a/sample/src/main/assets/droid4me_inside_large.png b/sample/src/main/assets/droid4me_inside_large.png old mode 100755 new mode 100644 diff --git a/sample/src/main/assets/smartnsoft_logo.png b/sample/src/main/assets/smartnsoft_logo.png old mode 100755 new mode 100644 diff --git a/sample/src/main/java/com/smartnsoft/droid4sample/AboutActivity.java b/sample/src/main/java/com/smartnsoft/droid4sample/AboutActivity.java old mode 100755 new mode 100644 diff --git a/sample/src/main/java/com/smartnsoft/droid4sample/Constants.java b/sample/src/main/java/com/smartnsoft/droid4sample/Constants.java old mode 100755 new mode 100644 diff --git a/sample/src/main/java/com/smartnsoft/droid4sample/Droid4SampleApplication.java b/sample/src/main/java/com/smartnsoft/droid4sample/Droid4SampleApplication.java old mode 100755 new mode 100644 diff --git a/sample/src/main/java/com/smartnsoft/droid4sample/Droid4SampleSplashScreenActivity.java b/sample/src/main/java/com/smartnsoft/droid4sample/Droid4SampleSplashScreenActivity.java old mode 100755 new mode 100644 diff --git a/sample/src/main/java/com/smartnsoft/droid4sample/SettingsActivity.java b/sample/src/main/java/com/smartnsoft/droid4sample/SettingsActivity.java old mode 100755 new mode 100644 diff --git a/sample/src/main/java/com/smartnsoft/droid4sample/TitleBar.java b/sample/src/main/java/com/smartnsoft/droid4sample/TitleBar.java old mode 100755 new mode 100644 diff --git a/sample/src/main/java/com/smartnsoft/droid4sample/ws/Droid4SampleServices.java b/sample/src/main/java/com/smartnsoft/droid4sample/ws/Droid4SampleServices.java old mode 100755 new mode 100644 diff --git a/sample/src/main/res/drawable-hdpi/droid4me_inside.png b/sample/src/main/res/drawable-hdpi/droid4me_inside.png old mode 100755 new mode 100644 diff --git a/sample/src/main/res/drawable-hdpi/droid4sample_splash_logo.png b/sample/src/main/res/drawable-hdpi/droid4sample_splash_logo.png old mode 100755 new mode 100644 diff --git a/sample/src/main/res/drawable-hdpi/icon.png b/sample/src/main/res/drawable-hdpi/icon.png old mode 100755 new mode 100644 diff --git a/sample/src/main/res/drawable-hdpi/poweredby_smartnsoft.png b/sample/src/main/res/drawable-hdpi/poweredby_smartnsoft.png old mode 100755 new mode 100644 diff --git a/sample/src/main/res/drawable-hdpi/smartnsoft_illustration.png b/sample/src/main/res/drawable-hdpi/smartnsoft_illustration.png old mode 100755 new mode 100644 diff --git a/sample/src/main/res/drawable-hdpi/title_bar_home.png b/sample/src/main/res/drawable-hdpi/title_bar_home.png old mode 100755 new mode 100644 diff --git a/sample/src/main/res/drawable-hdpi/title_bar_refresh.png b/sample/src/main/res/drawable-hdpi/title_bar_refresh.png old mode 100755 new mode 100644 diff --git a/sample/src/main/res/drawable-nodpi/title_bar_button_background_disabled.png b/sample/src/main/res/drawable-nodpi/title_bar_button_background_disabled.png old mode 100755 new mode 100644 diff --git a/sample/src/main/res/drawable-nodpi/title_bar_button_background_pressed.png b/sample/src/main/res/drawable-nodpi/title_bar_button_background_pressed.png old mode 100755 new mode 100644 diff --git a/sample/src/main/res/drawable-nodpi/title_bar_button_background_selected.png b/sample/src/main/res/drawable-nodpi/title_bar_button_background_selected.png old mode 100755 new mode 100644 diff --git a/sample/src/main/res/drawable/title_bar_button_background.xml b/sample/src/main/res/drawable/title_bar_button_background.xml old mode 100755 new mode 100644 diff --git a/sample/src/main/res/layout/about.xml b/sample/src/main/res/layout/about.xml old mode 100755 new mode 100644 diff --git a/sample/src/main/res/layout/droid4sample_splash_screen.xml b/sample/src/main/res/layout/droid4sample_splash_screen.xml old mode 100755 new mode 100644 diff --git a/sample/src/main/res/layout/main_sample.xml b/sample/src/main/res/layout/main_sample.xml old mode 100755 new mode 100644 diff --git a/sample/src/main/res/layout/title_bar.xml b/sample/src/main/res/layout/title_bar.xml old mode 100755 new mode 100644 diff --git a/sample/src/main/res/raw/about.html b/sample/src/main/res/raw/about.html old mode 100755 new mode 100644 diff --git a/sample/src/main/res/values-fr/strings.xml b/sample/src/main/res/values-fr/strings.xml old mode 100755 new mode 100644 diff --git a/sample/src/main/res/values/array.xml b/sample/src/main/res/values/array.xml old mode 100755 new mode 100644 diff --git a/sample/src/main/res/values/attrs.xml b/sample/src/main/res/values/attrs.xml old mode 100755 new mode 100644 diff --git a/sample/src/main/res/values/colors.xml b/sample/src/main/res/values/colors.xml old mode 100755 new mode 100644 diff --git a/sample/src/main/res/values/dimen.xml b/sample/src/main/res/values/dimen.xml old mode 100755 new mode 100644 diff --git a/sample/src/main/res/values/strings.xml b/sample/src/main/res/values/strings.xml old mode 100755 new mode 100644 diff --git a/sample/src/main/res/values/styles.xml b/sample/src/main/res/values/styles.xml old mode 100755 new mode 100644 diff --git a/sample/src/main/res/values/themes.xml b/sample/src/main/res/values/themes.xml old mode 100755 new mode 100644 diff --git a/sample/src/main/res/xml/settings.xml b/sample/src/main/res/xml/settings.xml old mode 100755 new mode 100644 From 2d0574e709032b5be209ef002a0255cb754a1da6 Mon Sep 17 00:00:00 2001 From: Antoine Gerard Date: Fri, 2 Mar 2018 14:45:26 +0100 Subject: [PATCH 16/19] Merge branch 'dev' into bitmapdownloader-gif, reviewed my files header # Conflicts: # library/build.gradle --- .../droid4me/ws/URLConnectionWebServiceCaller.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/library/src/main/java/com/smartnsoft/droid4me/ws/URLConnectionWebServiceCaller.java b/library/src/main/java/com/smartnsoft/droid4me/ws/URLConnectionWebServiceCaller.java index e8471e41..bc6b07b9 100644 --- a/library/src/main/java/com/smartnsoft/droid4me/ws/URLConnectionWebServiceCaller.java +++ b/library/src/main/java/com/smartnsoft/droid4me/ws/URLConnectionWebServiceCaller.java @@ -197,6 +197,7 @@ protected int getConnectTimeout() * @param callType the type of the HTTP method * @param postParameters the body (as form-data fields) of the HTTP method when its a {@link CallType#Post} or a {@link CallType#Put} ; {@code null} * otherwise + * @param headers the original headers of the request. They can be edited in order to manage some scenarios with tokens * @param body the body (as form-data fields) of the HTTP method when its a {@link CallType#Post} or a {@link CallType#Put} ; {@code null} * otherwise * @param httpURLConnection the HttpURLConnection object @@ -206,7 +207,8 @@ protected int getConnectTimeout() * @return {@code true} if you want the request to be re-run if it has failed * @throws CallException if you want the call to be considered as not OK */ - protected boolean onStatusCodeNotOk(String uri, CallType callType, Map postParameters, String body, + protected boolean onStatusCodeNotOk(String uri, CallType callType, Map postParameters, + Map headers, String body, HttpURLConnection httpURLConnection, URL url, int statusCode, String statusMessage, int attemptsCount) throws CallException { @@ -472,7 +474,8 @@ protected HttpURLConnection performHttpRequest(String uri, CallType callType, Ma return performHttpRequest(uri, callType, headers, parameters, body, files, 0); } - protected boolean shouldTryToConsumeErrorInputstream(int statusCode, String uri, CallType callType, Map headers, + protected boolean shouldTryToConsumeErrorInputstream(int statusCode, String uri, CallType callType, + Map headers, Map parameters, String body, List files) { return false; @@ -733,7 +736,7 @@ else if (paramaters != null && paramaters.size() > 0) if (!(responseCode >= HttpURLConnection.HTTP_OK && responseCode < HttpURLConnection.HTTP_MULT_CHOICE)) { - if (onStatusCodeNotOk(uri, callType, paramaters, body, httpURLConnection, url, responseCode, responseMessage, + if (onStatusCodeNotOk(uri, callType, paramaters, headers, body, httpURLConnection, url, responseCode, responseMessage, attemptsCount + 1) == true) { return performHttpRequest(uri, callType, headers, paramaters, body, files, attemptsCount + 1); From 9a3e601cea953b4500ef2075c88cad81fb82153b Mon Sep 17 00:00:00 2001 From: Antoine Gerard Date: Fri, 2 Mar 2018 14:45:39 +0100 Subject: [PATCH 17/19] Merge in progress --- library/build.gradle | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/library/build.gradle b/library/build.gradle index d4b49001..7ebe148d 100644 --- a/library/build.gradle +++ b/library/build.gradle @@ -17,7 +17,7 @@ android minSdkVersion 14 targetSdkVersion 27 - versionCode 21 + versionCode 22 versionName "2.7-SNAPSHOT" } @@ -128,9 +128,6 @@ publishing.publications.all bintray { - user = bintrayUsername - key = bintrayKey - publications = ["ReleasePublication"] pkg From 121ad8724375a85292f3121826ae6c8eeb1f1192 Mon Sep 17 00:00:00 2001 From: Antoine Gerard Date: Fri, 2 Mar 2018 14:46:35 +0100 Subject: [PATCH 18/19] Merge in progress --- library/build.gradle | 2 +- sample/build.gradle | 7 +++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/library/build.gradle b/library/build.gradle index 7ebe148d..8c5664d8 100644 --- a/library/build.gradle +++ b/library/build.gradle @@ -5,7 +5,7 @@ apply plugin: "maven-publish" ext { - appCompatVersion = "27.0.1" + appCompatVersion = "27.0.2" } android diff --git a/sample/build.gradle b/sample/build.gradle index e7628eef..ad4526f6 100644 --- a/sample/build.gradle +++ b/sample/build.gradle @@ -2,15 +2,14 @@ apply plugin: 'com.android.application' android { - compileSdkVersion 26 - buildToolsVersion "26.0.2" + compileSdkVersion 27 defaultConfig { applicationId "com.smartnsoft.sample" minSdkVersion 16 - targetSdkVersion 26 + targetSdkVersion 27 versionCode 1 versionName "1.0" @@ -29,6 +28,6 @@ android dependencies { - implementation ("com.android.support:appcompat-v7:27.0.1") + implementation ("com.android.support:appcompat-v7:27.0.2") implementation (project(":library")) } From cd0e80699a69e4e18787d17022f2529909bcbc07 Mon Sep 17 00:00:00 2001 From: Antoine Gerard Date: Fri, 2 Mar 2018 16:25:24 +0100 Subject: [PATCH 19/19] Updated version name --- library/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/build.gradle b/library/build.gradle index 8c5664d8..dfa4c290 100644 --- a/library/build.gradle +++ b/library/build.gradle @@ -17,8 +17,8 @@ android minSdkVersion 14 targetSdkVersion 27 - versionCode 22 - versionName "2.7-SNAPSHOT" + versionCode 23 + versionName "2.8.0" } buildTypes