diff options
Diffstat (limited to 'src/com/android/gallery3d/util')
-rwxr-xr-x | src/com/android/gallery3d/util/GIFView.java | 234 | ||||
-rw-r--r-- | src/com/android/gallery3d/util/GalleryUtils.java | 21 | ||||
-rw-r--r-- | src/com/android/gallery3d/util/GifAction.java | 5 | ||||
-rwxr-xr-x | src/com/android/gallery3d/util/GifDecoder.java | 723 | ||||
-rwxr-xr-x | src/com/android/gallery3d/util/GifFrame.java | 17 | ||||
-rw-r--r-- | src/com/android/gallery3d/util/MediaSetUtils.java | 21 | ||||
-rwxr-xr-x | src/com/android/gallery3d/util/ViewGifImage.java | 67 |
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); + } +} |