summaryrefslogtreecommitdiffstats
path: root/src/com/android/gallery3d/util
diff options
context:
space:
mode:
Diffstat (limited to 'src/com/android/gallery3d/util')
-rwxr-xr-xsrc/com/android/gallery3d/util/GIFView.java234
-rw-r--r--src/com/android/gallery3d/util/GalleryUtils.java21
-rw-r--r--src/com/android/gallery3d/util/GifAction.java5
-rwxr-xr-xsrc/com/android/gallery3d/util/GifDecoder.java723
-rwxr-xr-xsrc/com/android/gallery3d/util/GifFrame.java17
-rw-r--r--src/com/android/gallery3d/util/MediaSetUtils.java21
-rwxr-xr-xsrc/com/android/gallery3d/util/ViewGifImage.java67
7 files changed, 1076 insertions, 12 deletions
diff --git a/src/com/android/gallery3d/util/GIFView.java b/src/com/android/gallery3d/util/GIFView.java
new file mode 100755
index 000000000..c80625b41
--- /dev/null
+++ b/src/com/android/gallery3d/util/GIFView.java
@@ -0,0 +1,234 @@
+package com.android.gallery3d.util;
+
+import com.android.gallery3d.R;
+
+import android.content.Context;
+import android.content.ContentResolver;
+import android.content.res.AssetManager;
+import android.database.Cursor;
+import android.drm.DrmHelper;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Rect;
+import android.net.Uri;
+import android.os.Handler;
+import android.os.Message;
+import android.util.Log;
+import android.widget.ImageView;
+import android.widget.Toast;
+
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.InputStream;
+import java.io.IOException;
+
+public class GIFView extends ImageView implements GifAction {
+
+ private static final String TAG = "GIFView";
+ private static final float SCALE_LIMIT = 4;
+ private static final long FRAME_DELAY = 200; //milliseconds
+
+ private GifDecoder mGifDecoder = null;
+ private Bitmap mCurrentImage = null;
+ private DrawThread mDrawThread = null;
+
+ private Uri mUri;
+ private Context mContext;
+
+ public GIFView(Context context) {
+ super(context);
+ mContext = context;
+ }
+
+ public boolean setDrawable(Uri uri) {
+ if (null == uri) {
+ return false;
+ }
+ mUri = uri;
+
+ // Let decode the GIF image from byte stream instead of file stream
+ String filepath = DrmHelper.getFilePath(mContext, mUri);
+ if (DrmHelper.isDrmFile(filepath)) {
+ byte[] bytes = DrmHelper.getDrmImageBytes(filepath);
+ DrmHelper.manageDrmLicense(mContext, this.getHandler(), filepath,
+ "image/gif");
+ if (bytes == null) {
+ return false;
+ }
+ startDecode(bytes);
+ return true;
+ }
+
+ InputStream is = getInputStream(uri);
+ if (is == null || (getFileSize (is) == 0)) {
+ return false;
+ }
+ startDecode(is);
+ return true;
+ }
+
+ private int getFileSize (InputStream is) {
+ if(is == null) return 0;
+
+ int size = 0;
+ try {
+ if (is instanceof FileInputStream) {
+ FileInputStream f = (FileInputStream) is;
+ size = (int) f.getChannel().size();
+ } else {
+ while (-1 != is.read()) {
+ size++;
+ }
+ }
+
+ } catch (IOException e) {
+ Log.e(TAG, "catch exception:" + e);
+ }
+
+ return size;
+
+ }
+
+ private InputStream getInputStream (Uri uri) {
+ ContentResolver cr = mContext.getContentResolver();
+ InputStream input = null;
+ try {
+ input = cr.openInputStream(uri);
+ } catch (IOException e) {
+ Log.e(TAG, "catch exception:" + e);
+ }
+ return input;
+ }
+
+ private void startDecode(InputStream is) {
+ freeGifDecoder();
+ mGifDecoder = new GifDecoder(is, this);
+ mGifDecoder.start();
+ }
+
+ private void startDecode(byte[] bytes) {
+ freeGifDecoder();
+ mGifDecoder = new GifDecoder(bytes, this);
+ mGifDecoder.start();
+ }
+
+ protected void onDraw(Canvas canvas) {
+ super.onDraw(canvas);
+ if (mGifDecoder == null) {
+ return;
+ }
+
+ if (mCurrentImage == null) {
+ mCurrentImage = mGifDecoder.getImage();
+ }
+ if (mCurrentImage == null) {
+ // if this gif can not be displayed, just try to show it as jpg by parsing mUri
+ setImageURI(mUri);
+ return;
+ }
+ setImageURI(null);
+ int saveCount = canvas.getSaveCount();
+ canvas.save();
+ canvas.translate(getPaddingLeft(), getPaddingTop());
+ Rect sRect = null;
+ Rect dRect = null;
+
+ int imageHeight = mCurrentImage.getHeight();
+ int imageWidth = mCurrentImage.getWidth();
+
+ int displayHeight = ViewGifImage.mDM.heightPixels;
+ int displayWidth = ViewGifImage.mDM.widthPixels;
+
+ int width, height;
+ if (imageWidth >= displayWidth || imageHeight >= displayHeight) {
+ // scale-down the image
+ if (imageWidth * displayHeight > displayWidth * imageHeight) {
+ width = displayWidth;
+ height = (imageHeight * width) / imageWidth;
+ } else {
+ height = displayHeight;
+ width = (imageWidth * height) / imageHeight;
+ }
+ } else {
+ // scale-up the image
+ float scale = Math.min(SCALE_LIMIT, Math.min(displayWidth / (float) imageWidth,
+ displayHeight / (float) imageHeight));
+ width = (int) (imageWidth * scale);
+ height = (int) (imageHeight * scale);
+ }
+ dRect = new Rect((displayWidth - width) / 2, (displayHeight - height) / 2,
+ (displayWidth + width) / 2, (displayHeight + height) / 2);
+ canvas.drawBitmap(mCurrentImage, sRect, dRect, null);
+ canvas.restoreToCount(saveCount);
+ }
+
+ public void parseOk(boolean parseStatus, int frameIndex) {
+ if (parseStatus) {
+ //indicates the start of a new GIF
+ if (mGifDecoder != null && frameIndex == -1
+ && mGifDecoder.getFrameCount() > 1) {
+ if (mDrawThread != null) {
+ mDrawThread = null;
+ }
+ mDrawThread = new DrawThread();
+ mDrawThread.start();
+ }
+ } else {
+ Log.e(TAG, "parse error");
+ }
+ }
+
+ private Handler mRedrawHandler = new Handler() {
+ public void handleMessage(Message msg) {
+ invalidate();
+ }
+ };
+
+ private class DrawThread extends Thread {
+ public void run() {
+ if (mGifDecoder == null) {
+ return;
+ }
+
+ while (true) {
+ if (!isShown() || mRedrawHandler == null) {
+ break;
+ }
+ if (mGifDecoder == null) {
+ return;
+ }
+ GifFrame frame = mGifDecoder.next();
+ mCurrentImage = frame.mImage;
+
+ Message msg = mRedrawHandler.obtainMessage();
+ mRedrawHandler.sendMessage(msg);
+ try {
+ Thread.sleep(getDelay(frame));
+ } catch (InterruptedException e) {
+ Log.e(TAG, "catch exception:" + e);
+ }
+ }
+ }
+
+ }
+
+ private long getDelay (GifFrame frame) {
+ //in milliseconds
+ return frame.mDelayInMs == 0 ? FRAME_DELAY : frame.mDelayInMs;
+ }
+
+ private void freeGifDecoder () {
+ if (mGifDecoder != null) {
+ mGifDecoder.free();
+ mGifDecoder = null;
+ }
+
+ }
+
+ public void freeMemory() {
+ if (mDrawThread != null) {
+ mDrawThread = null;
+ }
+ freeGifDecoder();
+ }
+}
diff --git a/src/com/android/gallery3d/util/GalleryUtils.java b/src/com/android/gallery3d/util/GalleryUtils.java
index 8fb926c0b..8e4ebb714 100644
--- a/src/com/android/gallery3d/util/GalleryUtils.java
+++ b/src/com/android/gallery3d/util/GalleryUtils.java
@@ -17,6 +17,7 @@
package com.android.gallery3d.util;
import android.annotation.TargetApi;
+import android.app.Activity;
import android.content.ActivityNotFoundException;
import android.content.ComponentName;
import android.content.Context;
@@ -35,6 +36,7 @@ import android.provider.MediaStore;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.WindowManager;
+import android.widget.Toast;
import com.android.gallery3d.R;
import com.android.gallery3d.app.GalleryActivity;
@@ -275,7 +277,7 @@ public class GalleryUtils {
return String.format(Locale.ENGLISH, format, latitude, longitude);
}
- public static void showOnMap(Context context, double latitude, double longitude) {
+ public static void showOnMap(final Context context, double latitude, double longitude) {
try {
// We don't use "geo:latitude,longitude" because it only centers
// the MapView to the specified location, but we need a marker
@@ -292,8 +294,21 @@ public class GalleryUtils {
// Use the "geo intent" if no GMM is installed
Log.e(TAG, "GMM activity not found!", e);
String url = formatLatitudeLongitude("geo:%f,%f", latitude, longitude);
- Intent mapsIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
- context.startActivity(mapsIntent);
+ try {
+ Intent mapsIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
+ context.startActivity(mapsIntent);
+ } catch (ActivityNotFoundException ex) {
+ Log.e(TAG, "Map view activity not found! url = " + url, ex);
+ ((Activity)context).runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ Toast.makeText(context,
+ context.getString(R.string.map_activity_not_found_err),
+ Toast.LENGTH_SHORT).show();
+ }
+ });
+
+ }
}
}
diff --git a/src/com/android/gallery3d/util/GifAction.java b/src/com/android/gallery3d/util/GifAction.java
new file mode 100644
index 000000000..88e3cdee0
--- /dev/null
+++ b/src/com/android/gallery3d/util/GifAction.java
@@ -0,0 +1,5 @@
+package com.android.gallery3d.util;
+
+public interface GifAction {
+ public void parseOk(boolean parseStatus, int frameIndex);
+}
diff --git a/src/com/android/gallery3d/util/GifDecoder.java b/src/com/android/gallery3d/util/GifDecoder.java
new file mode 100755
index 000000000..4235fc5a5
--- /dev/null
+++ b/src/com/android/gallery3d/util/GifDecoder.java
@@ -0,0 +1,723 @@
+package com.android.gallery3d.util;
+
+import android.graphics.Bitmap;
+import android.graphics.Bitmap.Config;
+import android.util.Log;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+
+public class GifDecoder extends Thread {
+
+ public static final int STATUS_PARSING = 0;
+ public static final int STATUS_FORMAT_ERROR = 1;
+ public static final int STATUS_OPEN_ERROR = 2;
+ public static final int STATUS_FINISH = -1;
+
+ private InputStream mIS;
+ private int mStatus;
+
+ public int mWidth; // full image width
+ public int mHeight; // full image height
+ private boolean mGctFlag; // global color table used
+ private int mGctSize; // size of global color table
+ private int mLoopCount = 1; // iterations; 0 = repeat forever
+
+ private int[] mGct; // global color table
+ private int[] mLct; // local color table
+ private int[] mAct; // active color table
+
+ private int mBgIndex; // background color index
+ private int mBgColor; // background color
+ private int mLastBgColor; // previous bg color
+ private int mPixelAspect; // pixel aspect ratio
+
+ private boolean mLctFlag; // local color table flag
+ private boolean mInterlace; // interlace flag
+ private int mLctSize; // local color table size
+
+ private int mIx, mIy, mIw, mIh; // current image rectangle
+ private int mLrx, mLry, mLrw, mLrh;
+ private Bitmap mImage; // current frame
+ private Bitmap mLastImage; // previous frame
+ private GifFrame mCurrentFrame = null;
+
+ private boolean mIsShow = false;
+
+ private byte[] mBlock = new byte[256]; // current data block
+ private int mBlockSize = 0; // block size
+ private int mDispose = 0;
+ private int mLastDispose = 0;
+ private boolean mTransparency = false; // use transparent color
+ private int mDelay = 0; // delay in milliseconds
+ private int mTransIndex; // transparent color index
+
+ // max decoder pixel stack size
+ private static final int MaxStackSize = 4096;
+
+ // LZW decoder working arrays
+ private short[] mPrefix;
+ private byte[] mSuffix;
+ private byte[] mPixelStack;
+ private byte[] mPixels;
+
+ private GifFrame mGifFrame; // frames read from current file
+ private int mFrameCount;
+
+ private GifAction mGifAction = null;
+
+ private byte[] mGifData = null;
+
+ public GifDecoder(byte[] data, GifAction act) {
+ mGifData = data;
+ mGifAction = act;
+ }
+
+ public GifDecoder(InputStream is, GifAction act) {
+ mIS = is;
+ mGifAction = act;
+ }
+
+ public void run() {
+ if (mIS != null) {
+ readStream();
+ } else if (mGifData != null) {
+ readByte();
+ }
+ }
+
+ public void free() {
+ freeFrame();
+ freeIS();
+ freeImage();
+ }
+
+ public int getStatus() {
+ return mStatus;
+ }
+
+ public boolean parseOk() {
+ return mStatus == STATUS_FINISH;
+ }
+
+ public int getDelay(int n) {
+ mDelay = -1;
+ if ((n >= 0) && (n < mFrameCount)) {
+ GifFrame f = getFrame(n);
+ if (f != null) {
+ mDelay = f.mDelayInMs;
+ }
+ }
+ return mDelay;
+ }
+
+ public int[] getDelays() {
+ GifFrame f = mGifFrame;
+ int[] d = new int[mFrameCount];
+ int i = 0;
+ while (f != null && i < mFrameCount) {
+ d[i] = f.mDelayInMs;
+ f = f.mNextFrame;
+ i++;
+ }
+ return d;
+ }
+
+ public int getFrameCount() {
+ return mFrameCount;
+ }
+
+ public Bitmap getImage() {
+ return getFrameImage(0);
+ }
+
+ public int getLoopCount() {
+ return mLoopCount;
+ }
+
+ private void setPixels() {
+ int[] dest = new int[mWidth * mHeight];
+ // fill in starting image contents based on last image's dispose code
+ if (mLastDispose > 0) {
+ if (mLastDispose == 3) {
+ // use image before last
+ int n = mFrameCount - 2;
+ if (n > 0) {
+ mLastImage = getPreUndisposedImage(n - 1);
+ } else {
+ mLastImage = null;
+ }
+ }
+ if (mLastImage != null) {
+ mLastImage.getPixels(dest, 0, mWidth, 0, 0, mWidth, mHeight);
+ // copy pixels
+ if (mLastDispose == 2) {
+ // fill last image rect area with background color
+ int c = 0;
+ if (!mTransparency) {
+ c = mLastBgColor;
+ }
+ for (int i = 0; i < mLrh; i++) {
+ int n1 = (mLry + i) * mWidth + mLrx;
+ int n2 = n1 + mLrw;
+ for (int k = n1; k < n2; k++) {
+ dest[k] = c;
+ }
+ }
+ }
+ }
+ }
+
+ // 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 < mIh; i++) {
+ int line = i;
+ if (mInterlace) {
+ if (iline >= mIh) {
+ pass++;
+ switch (pass) {
+ case 2:
+ iline = 4;
+ break;
+ case 3:
+ iline = 2;
+ inc = 4;
+ break;
+ case 4:
+ iline = 1;
+ inc = 2;
+ }
+ }
+ line = iline;
+ iline += inc;
+ }
+ line += mIy;
+ if (line < mHeight) {
+ int k = line * mWidth;
+ int dx = k + mIx; // start of line in dest
+ int dlim = dx + mIw; // end of dest line
+ if ((k + mWidth) < dlim) {
+ dlim = k + mWidth; // past dest edge
+ }
+ int sx = i * mIw; // start of line in source
+ while (dx < dlim) {
+ // map color and insert in destination
+ int index = ((int) mPixels[sx++]) & 0xff;
+ int c = mAct[index];
+ if (c != 0) {
+ dest[dx] = c;
+ }
+ dx++;
+ }
+ }
+ }
+ mImage = Bitmap.createBitmap(dest, mWidth, mHeight, Config.ARGB_4444);
+ }
+
+ public Bitmap getFrameImage(int n) {
+ GifFrame frame = getFrame(n);
+ if (frame == null) {
+ return null;
+ } else {
+ return frame.mImage;
+ }
+ }
+
+ public GifFrame getCurrentFrame() {
+ return mCurrentFrame;
+ }
+
+ public GifFrame getFrame(int n) {
+ GifFrame frame = mGifFrame;
+ int i = 0;
+ while (frame != null) {
+ if (i == n) {
+ return frame;
+ } else {
+ frame = frame.mNextFrame;
+ }
+ i++;
+ }
+ return null;
+ }
+
+ private Bitmap getPreUndisposedImage(int n) {
+ Bitmap preUndisposedImage = null;
+ GifFrame frame = mGifFrame;
+ int i = 0;
+ while (frame != null && i <= n) {
+ if (frame.mDispose == 1) {
+ preUndisposedImage = frame.mImage;
+ } else {
+ frame = frame.mNextFrame;
+ }
+ i++;
+ }
+ return preUndisposedImage;
+ }
+
+ public void reset() {
+ mCurrentFrame = mGifFrame;
+ }
+
+ public GifFrame next() {
+ if (mIsShow == false) {
+ mIsShow = true;
+ return mGifFrame;
+ } else {
+ if (mStatus == STATUS_PARSING) {
+ if (mCurrentFrame.mNextFrame != null) {
+ mCurrentFrame = mCurrentFrame.mNextFrame;
+ }
+ } else {
+ mCurrentFrame = mCurrentFrame.mNextFrame;
+ if (mCurrentFrame == null) {
+ mCurrentFrame = mGifFrame;
+ }
+ }
+ return mCurrentFrame;
+ }
+ }
+
+ private int readByte() {
+ mIS = new ByteArrayInputStream(mGifData);
+ mGifData = null;
+ return readStream();
+ }
+
+ private int readStream() {
+ init();
+ if (mIS != null) {
+ readHeader();
+ if (!err()) {
+ readContents();
+ if (mFrameCount < 0) {
+ mStatus = STATUS_FORMAT_ERROR;
+ mGifAction.parseOk(false, -1);
+ } else {
+ mStatus = STATUS_FINISH;
+ mGifAction.parseOk(true, -1);
+ }
+ }
+ try {
+ mIS.close();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ } else {
+ mStatus = STATUS_OPEN_ERROR;
+ mGifAction.parseOk(false, -1);
+ }
+ return mStatus;
+ }
+
+ private void decodeImageData() {
+ int NullCode = -1;
+ int npix = mIw * mIh;
+ 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 ((mPixels == null) || (mPixels.length < npix)) {
+ mPixels = new byte[npix]; // allocate new pixel array
+ }
+ if (mPrefix == null) {
+ mPrefix = new short[MaxStackSize];
+ }
+ if (mSuffix == null) {
+ mSuffix = new byte[MaxStackSize];
+ }
+ if (mPixelStack == null) {
+ mPixelStack = new byte[MaxStackSize + 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++) {
+ mPrefix[code] = 0;
+ mSuffix[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 += (((int) mBlock[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) {
+ mPixelStack[top++] = mSuffix[code];
+ old_code = code;
+ first = code;
+ continue;
+ }
+ in_code = code;
+ if (code == available) {
+ mPixelStack[top++] = (byte) first;
+ code = old_code;
+ }
+ while (code > clear) {
+ mPixelStack[top++] = mSuffix[code];
+ code = mPrefix[code];
+ }
+ first = ((int) mSuffix[code]) & 0xff;
+ // Add a new string to the string table,
+ if (available >= MaxStackSize) {
+ break;
+ }
+ mPixelStack[top++] = (byte) first;
+ mPrefix[available] = (short) old_code;
+ mSuffix[available] = (byte) first;
+ available++;
+ if (((available & code_mask) == 0)
+ && (available < MaxStackSize)) {
+ code_size++;
+ code_mask += available;
+ }
+ old_code = in_code;
+ }
+
+ // Pop a pixel off the pixel stack.
+ top--;
+ mPixels[pi++] = mPixelStack[top];
+ i++;
+ }
+ for (i = pi; i < npix; i++) {
+ mPixels[i] = 0; // clear missing pixels
+ }
+ }
+
+ private boolean err() {
+ return mStatus != STATUS_PARSING;
+ }
+
+ private void init() {
+ mStatus = STATUS_PARSING;
+ mFrameCount = 0;
+ mGifFrame = null;
+ mGct = null;
+ mLct = null;
+ }
+
+ private int read() {
+ int curByte = 0;
+ try {
+ curByte = mIS.read();
+ } catch (Exception e) {
+ mStatus = STATUS_FORMAT_ERROR;
+ }
+ return curByte;
+ }
+
+ private int readBlock() {
+ mBlockSize = read();
+ int n = 0;
+ if (mBlockSize > 0) {
+ try {
+ int count = 0;
+ while (n < mBlockSize) {
+ count = mIS.read(mBlock, n, mBlockSize - n);
+ if (count == -1) {
+ break;
+ }
+ n += count;
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ if (n < mBlockSize) {
+ mStatus = STATUS_FORMAT_ERROR;
+ }
+ }
+ return n;
+ }
+
+ private int[] readColorTable(int ncolors) {
+ int nbytes = 3 * ncolors;
+ int[] tab = null;
+ byte[] c = new byte[nbytes];
+ int n = 0;
+ try {
+ n = mIS.read(c);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ if (n < nbytes) {
+ mStatus = STATUS_FORMAT_ERROR;
+ } else {
+ tab = new int[256]; // max size to avoid bounds checks
+ 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;
+ }
+ }
+ return tab;
+ }
+
+ private void readContents() {
+ // read GIF file content blocks
+ boolean done = false;
+ while (!(done || err())) {
+ int code = read();
+ switch (code) {
+ case 0x2C: // image separator
+ readImage();
+ break;
+ case 0x21: // extension
+ code = read();
+ switch (code) {
+ case 0xf9: // graphics control extension
+ readGraphicControlExt();
+ break;
+ case 0xff: // application extension
+ readBlock();
+ String app = "";
+ for (int i = 0; i < 11; i++) {
+ app += (char) mBlock[i];
+ }
+ if (app.equals("NETSCAPE2.0")) {
+ readNetscapeExt();
+ } else {
+ skip(); // don't care
+ }
+ 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:
+ mStatus = STATUS_FORMAT_ERROR;
+ }
+ }
+ }
+
+ private void readGraphicControlExt() {
+ read(); // block size
+ int packed = read(); // packed fields
+ mDispose = (packed & 0x1c) >> 2; // disposal method
+ if (mDispose == 0) {
+ mDispose = 1; // elect to keep old image if discretionary
+ }
+ mTransparency = (packed & 1) != 0;
+ mDelay = readShort() * 10; // delay in milliseconds
+ mTransIndex = read(); // transparent color index
+ read(); // block terminator
+ }
+
+ private void readHeader() {
+ String id = "";
+ for (int i = 0; i < 6; i++) {
+ id += (char) read();
+ }
+ if (!id.startsWith("GIF")) {
+ mStatus = STATUS_FORMAT_ERROR;
+ return;
+ }
+ readLSD();
+ if (mGctFlag && !err()) {
+ mGct = readColorTable(mGctSize);
+ mBgColor = mGct[mBgIndex];
+ }
+ }
+
+ private void readImage() {
+ mIx = readShort(); // (sub)image position & size
+ mIy = readShort();
+ mIw = readShort();
+ mIh = readShort();
+ int packed = read();
+ mLctFlag = (packed & 0x80) != 0; // 1 - local color table flag
+ mInterlace = (packed & 0x40) != 0; // 2 - interlace flag
+ // 3 - sort flag
+ // 4-5 - reserved
+ mLctSize = 2 << (packed & 7); // 6-8 - local color table size
+ if (mLctFlag) {
+ mLct = readColorTable(mLctSize); // read table
+ mAct = mLct; // make local table active
+ } else {
+ mAct = mGct; // make global table active
+ if (mBgIndex == mTransIndex) {
+ mBgColor = 0;
+ }
+ }
+ int save = 0;
+ if (mTransparency) {
+ save = mAct[mTransIndex];
+ mAct[mTransIndex] = 0; // set transparent color if specified
+ }
+ if (mAct == null) {
+ mStatus = STATUS_FORMAT_ERROR; // no color table defined
+ }
+ if (err()) {
+ return;
+ }
+ try {
+ decodeImageData(); // decode pixel data
+ skip();
+ if (err()) {
+ return;
+ }
+ mFrameCount++;
+ // create new image to receive frame data
+ mImage = Bitmap.createBitmap(mWidth, mHeight, Config.ARGB_4444);
+ // createImage(mWidth, mHeight);
+ setPixels(); // transfer pixel data to image
+ if (mGifFrame == null) {
+ mGifFrame = new GifFrame(mImage, mDelay, mDispose);
+ mCurrentFrame = mGifFrame;
+ } else {
+ GifFrame f = mGifFrame;
+ while (f.mNextFrame != null) {
+ f = f.mNextFrame;
+ }
+ f.mNextFrame = new GifFrame(mImage, mDelay, mDispose);
+ }
+ // frames.addElement(new GifFrame(image, delay)); // add image to
+ // frame
+ // list
+ if (mTransparency) {
+ mAct[mTransIndex] = save;
+ }
+ resetFrame();
+ mGifAction.parseOk(true, mFrameCount);
+ } catch (OutOfMemoryError e) {
+ Log.e("GifDecoder", ">>> log : " + e.toString());
+ e.printStackTrace();
+ }
+ }
+
+ private void readLSD() {
+ // logical screen size
+ mWidth = readShort();
+ mHeight = readShort();
+ // packed fields
+ int packed = read();
+ mGctFlag = (packed & 0x80) != 0; // 1 : global color table flag
+ // 2-4 : color resolution
+ // 5 : gct sort flag
+ mGctSize = 2 << (packed & 7); // 6-8 : gct size
+ mBgIndex = read(); // background color index
+ mPixelAspect = read(); // pixel aspect ratio
+ }
+
+ private void readNetscapeExt() {
+ do {
+ readBlock();
+ if (mBlock[0] == 1) {
+ // loop count sub-block
+ int b1 = ((int) mBlock[1]) & 0xff;
+ int b2 = ((int) mBlock[2]) & 0xff;
+ mLoopCount = (b2 << 8) | b1;
+ }
+ } while ((mBlockSize > 0) && !err());
+ }
+
+ private int readShort() {
+ // read 16-bit value, LSB first
+ return read() | (read() << 8);
+ }
+
+ private void resetFrame() {
+ mLastDispose = mDispose;
+ mLrx = mIx;
+ mLry = mIy;
+ mLrw = mIw;
+ mLrh = mIh;
+ mLastImage = mImage;
+ mLastBgColor = mBgColor;
+ mDispose = 0;
+ mTransparency = false;
+ mDelay = 0;
+ mLct = null;
+ }
+
+ /**
+ * Skips variable length blocks up to and including next zero length block.
+ */
+ private void skip() {
+ do {
+ readBlock();
+ } while ((mBlockSize > 0) && !err());
+ }
+
+ private void freeFrame() {
+ GifFrame fg = mGifFrame;
+ while (fg != null) {
+ if (fg.mImage != null) {
+ fg.mImage.recycle();
+ }
+ fg.mImage = null;
+ fg = null;
+ mGifFrame = mGifFrame.mNextFrame;
+ fg = mGifFrame;
+ }
+ }
+
+ private void freeIS() {
+ if (mIS != null) {
+ try {
+ mIS.close();
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ }
+ mIS = null;
+ }
+ mGifData = null;
+ }
+
+ private void freeImage() {
+ if (mImage != null) {
+ mImage.recycle();
+ mImage = null;
+ }
+ if (mLastImage != null) {
+ mLastImage.recycle();
+ mLastImage = null;
+ }
+ }
+}
diff --git a/src/com/android/gallery3d/util/GifFrame.java b/src/com/android/gallery3d/util/GifFrame.java
new file mode 100755
index 000000000..87d58a40d
--- /dev/null
+++ b/src/com/android/gallery3d/util/GifFrame.java
@@ -0,0 +1,17 @@
+package com.android.gallery3d.util;
+
+import android.graphics.Bitmap;
+
+public class GifFrame {
+
+ public Bitmap mImage;
+ public int mDelayInMs; //in milliseconds
+ public int mDispose;
+ public GifFrame mNextFrame = null;
+
+ public GifFrame(Bitmap bitmap, int delay, int dispose) {
+ mImage = bitmap;
+ mDelayInMs = delay;
+ mDispose = dispose;
+ }
+}
diff --git a/src/com/android/gallery3d/util/MediaSetUtils.java b/src/com/android/gallery3d/util/MediaSetUtils.java
index 043800561..35a4dff04 100644
--- a/src/com/android/gallery3d/util/MediaSetUtils.java
+++ b/src/com/android/gallery3d/util/MediaSetUtils.java
@@ -28,9 +28,12 @@ import java.util.Comparator;
public class MediaSetUtils {
public static final Comparator<MediaSet> NAME_COMPARATOR = new NameComparator();
- public static final int CAMERA_BUCKET_ID = GalleryUtils.getBucketId(
- Environment.getExternalStorageDirectory().toString() + "/"
- + BucketNames.CAMERA);
+ private static String mRoot = Environment.getExternalStorageDirectory().toString();
+
+ public static void setRoot(String root) {
+ mRoot = root;
+ }
+
public static final int DOWNLOAD_BUCKET_ID = GalleryUtils.getBucketId(
Environment.getExternalStorageDirectory().toString() + "/"
+ BucketNames.DOWNLOAD);
@@ -44,14 +47,14 @@ public class MediaSetUtils {
Environment.getExternalStorageDirectory().toString() +
"/" + BucketNames.SCREENSHOTS);
- private static final Path[] CAMERA_PATHS = {
- Path.fromString("/local/all/" + CAMERA_BUCKET_ID),
- Path.fromString("/local/image/" + CAMERA_BUCKET_ID),
- Path.fromString("/local/video/" + CAMERA_BUCKET_ID)};
+ public static int getCameraBucketId() {
+ return GalleryUtils.getBucketId(mRoot + "/" + BucketNames.CAMERA);
+ }
public static boolean isCameraSource(Path path) {
- return CAMERA_PATHS[0] == path || CAMERA_PATHS[1] == path
- || CAMERA_PATHS[2] == path;
+ return path.equalsIgnoreCase("/local/all/" + getCameraBucketId())
+ || path.equalsIgnoreCase("/local/image/" + getCameraBucketId())
+ || path.equalsIgnoreCase("/local/video/" + getCameraBucketId());
}
// Sort MediaSets by name
diff --git a/src/com/android/gallery3d/util/ViewGifImage.java b/src/com/android/gallery3d/util/ViewGifImage.java
new file mode 100755
index 000000000..cdd509280
--- /dev/null
+++ b/src/com/android/gallery3d/util/ViewGifImage.java
@@ -0,0 +1,67 @@
+package com.android.gallery3d.util;
+
+import com.android.gallery3d.R;
+
+import android.app.Activity;
+import android.content.res.Configuration;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.util.DisplayMetrics;
+import android.view.ViewGroup.LayoutParams;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+
+public class ViewGifImage extends Activity {
+ private static final String TAG = "ViewGifImage";
+ public static final String VIEW_GIF_ACTION = "com.android.gallery3d.VIEW_GIF";
+
+ public static DisplayMetrics mDM;
+
+ private ImageView mGifView;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.view_gif_image);
+ mDM = new DisplayMetrics();
+ getWindowManager().getDefaultDisplay().getMetrics(mDM);
+ if (getIntent().getAction() != null
+ && getIntent().getAction().equals(VIEW_GIF_ACTION)) {
+ Uri gifUri = getIntent().getData();
+ showGifPicture(gifUri);
+ }
+ }
+
+ @Override
+ protected void onStop() {
+ super.onStop();
+ finish();
+ }
+
+ @Override
+ protected void onDestroy() {
+ if (mGifView != null && mGifView instanceof GIFView) {
+ ((GIFView) mGifView).freeMemory();
+ mGifView = null;
+ }
+ super.onDestroy();
+ }
+
+ private void showGifPicture(Uri uri) {
+ mGifView = new GIFView(this);
+ ((LinearLayout) findViewById(R.id.image_absoluteLayout)).addView(mGifView,
+ new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
+ if (((GIFView) mGifView).setDrawable(uri)) return;
+
+ finish();
+
+ }
+
+ @Override
+ public void onConfigurationChanged(Configuration newConfig) {
+ getWindowManager().getDefaultDisplay().getMetrics(mDM);
+ super.onConfigurationChanged(newConfig);
+ }
+}