Gallery2: support GIF animation

This change implements a Java GIF decoder.

Change-Id: I72b6e8eb25572bba77a2a46e1754d8db8c47a0cc
Signed-off-by: Xiaojing Zhang <zhangx@codeaurora.org>
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 95beee1..5204889 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -297,6 +297,16 @@
                 android:theme="@style/Theme.Gallery"
                 android:configChanges="orientation|keyboardHidden|screenSize" />
 
+        <activity android:name="com.android.gallery3d.util.ViewGifImage"
+                android:theme="@android:style/Theme.Black.NoTitleBar.Fullscreen"
+                android:configChanges="orientation|keyboardHidden|screenSize|keyboard|navigation">
+            <intent-filter>
+                <action android:name="com.android.gallery3d.VIEW_GIF" />
+                <data android:mimeType="image/gif" />
+                <category android:name="android.intent.category.DEFAULT" />
+            </intent-filter>
+        </activity>
+
         <provider android:name="com.android.gallery3d.provider.GalleryProvider"
                 android:syncable="false"
                 android:grantUriPermissions="true"
diff --git a/res/layout/view_gif_image.xml b/res/layout/view_gif_image.xml
old mode 100755
new mode 100644
index bceb16f..976549a
--- a/res/layout/view_gif_image.xml
+++ b/res/layout/view_gif_image.xml
@@ -1,46 +1,17 @@
 <?xml version="1.0" encoding="utf-8"?>
 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent">
-    
-	<LinearLayout 
-	    android:id="@+id/image_absoluteLayout"
-	    android:layout_height="match_parent" 
-		android:layout_width="match_parent">
-		<ImageView android:id="@+id/image_dispaly_area" 
-			android:layout_height="wrap_content" 
-			android:layout_width="wrap_content" 
-			android:clickable="true">
-		</ImageView>
-	</LinearLayout>
+        android:layout_width="match_parent"
+        android:layout_height="match_parent">
 
-<!--	
-	<ImageView android:layout_width="wrap_content" 
-		android:layout_height="wrap_content" 
-		android:id="@+id/arrow_left" 
-		android:layout_centerVertical="true" 
-		android:clickable="true" 
-		android:src="@drawable/arrow_left">
-	</ImageView>
-	
-	<ImageView android:layout_width="wrap_content" 
-		android:layout_height="wrap_content" 
-		android:id="@+id/arrow_right" 
-		android:layout_alignParentRight="true" 
-		android:layout_centerVertical="true" 
-		android:clickable="true" 
-		android:src="@drawable/arrow_right">
-	</ImageView>
-	
-	<TextView android:id="@+id/tv_count" 
-		android:layout_width="wrap_content" 
-		android:layout_height="wrap_content" 
-		android:layout_centerHorizontal="true" 
-		android:textSize="18sp"
-		android:textColor="#ffffffff"
-		android:layout_marginTop="5dip"
-		android:background="@drawable/text_frame">
-	</TextView>
--->	
+    <LinearLayout
+            android:id="@+id/image_absoluteLayout"
+            android:layout_height="match_parent"
+            android:layout_width="match_parent">
+        <ImageView android:id="@+id/image_display_area"
+                android:layout_height="wrap_content"
+                android:layout_width="wrap_content"
+                android:clickable="true">
+        </ImageView>
+    </LinearLayout>
+
 </RelativeLayout>
-
diff --git a/src/com/android/gallery3d/app/PhotoDataAdapter.java b/src/com/android/gallery3d/app/PhotoDataAdapter.java
old mode 100644
new mode 100755
index fd3a7cf..40967a1
--- a/src/com/android/gallery3d/app/PhotoDataAdapter.java
+++ b/src/com/android/gallery3d/app/PhotoDataAdapter.java
@@ -512,6 +512,13 @@
     }
 
     @Override
+    public boolean isGif(int offset) {
+        MediaItem item = getItem(mCurrentIndex + offset);
+        return (item != null) &&
+                MediaItem.MIME_TYPE_GIF.equalsIgnoreCase(item.getMimeType());
+    }
+
+    @Override
     public boolean isDeletable(int offset) {
         MediaItem item = getItem(mCurrentIndex + offset);
         return (item == null)
diff --git a/src/com/android/gallery3d/app/PhotoPage.java b/src/com/android/gallery3d/app/PhotoPage.java
old mode 100644
new mode 100755
index 915fdab..667ab38
--- a/src/com/android/gallery3d/app/PhotoPage.java
+++ b/src/com/android/gallery3d/app/PhotoPage.java
@@ -72,6 +72,7 @@
 import com.android.gallery3d.ui.SynchronizedHandler;
 import com.android.gallery3d.util.GalleryUtils;
 import com.android.gallery3d.util.UsageStatistics;
+import com.android.gallery3d.util.ViewGifImage;
 
 public abstract class PhotoPage extends ActivityState implements
         PhotoView.Listener, AppBridge.Server, ShareActionProvider.OnShareTargetSelectedListener,
@@ -1136,6 +1137,10 @@
             // item is not ready or it is camera preview, ignore
             return;
         }
+        if (item.getMimeType().equals(MediaItem.MIME_TYPE_GIF)) {
+            viewAnimateGif((Activity) mActivity, item.getContentUri());
+            return;
+        }
 
         int supported = item.getSupportedOperations();
         boolean playVideo = ((supported & MediaItem.SUPPORT_PLAY) != 0);
@@ -1530,4 +1535,8 @@
         }
     }
 
+    private static void viewAnimateGif(Activity activity, Uri uri) {
+        Intent intent = new Intent(ViewGifImage.VIEW_GIF_ACTION, uri);
+        activity.startActivity(intent);
+    }
 }
diff --git a/src/com/android/gallery3d/app/SinglePhotoDataAdapter.java b/src/com/android/gallery3d/app/SinglePhotoDataAdapter.java
old mode 100644
new mode 100755
index 00f2fe7..fe39e4e
--- a/src/com/android/gallery3d/app/SinglePhotoDataAdapter.java
+++ b/src/com/android/gallery3d/app/SinglePhotoDataAdapter.java
@@ -227,6 +227,11 @@
     }
 
     @Override
+    public boolean isGif(int offset) {
+        return MediaItem.MIME_TYPE_GIF.equalsIgnoreCase(mItem.getMimeType());
+    }
+
+    @Override
     public boolean isDeletable(int offset) {
         return (mItem.getSupportedOperations() & MediaItem.SUPPORT_DELETE) != 0;
     }
diff --git a/src/com/android/gallery3d/data/MediaItem.java b/src/com/android/gallery3d/data/MediaItem.java
index 59ea865..92ac88d 100644
--- a/src/com/android/gallery3d/data/MediaItem.java
+++ b/src/com/android/gallery3d/data/MediaItem.java
@@ -37,6 +37,7 @@
     public static final int IMAGE_ERROR = -1;
 
     public static final String MIME_TYPE_JPEG = "image/jpeg";
+    public static final String MIME_TYPE_GIF = "image/gif";
 
     private static final int BYTESBUFFE_POOL_SIZE = 4;
     private static final int BYTESBUFFER_SIZE = 200 * 1024;
diff --git a/src/com/android/gallery3d/ui/PhotoView.java b/src/com/android/gallery3d/ui/PhotoView.java
old mode 100644
new mode 100755
index 7afa203..5647e36
--- a/src/com/android/gallery3d/ui/PhotoView.java
+++ b/src/com/android/gallery3d/ui/PhotoView.java
@@ -93,6 +93,9 @@
         // Returns true if the item is a Video.
         public boolean isVideo(int offset);
 
+        // Returns true if the item is a Gif.
+        public boolean isGif(int offset);
+
         // Returns true if the item can be deleted.
         public boolean isDeletable(int offset);
 
@@ -594,7 +597,6 @@
         private boolean mIsCamera;
         private boolean mIsPanorama;
         private boolean mIsStaticCamera;
-        private boolean mIsVideo;
         private boolean mIsDeletable;
         private int mLoadingState = Model.LOADING_INIT;
         private Size mSize = new Size();
@@ -607,7 +609,6 @@
             mIsCamera = mModel.isCamera(0);
             mIsPanorama = mModel.isPanorama(0);
             mIsStaticCamera = mModel.isStaticCamera(0);
-            mIsVideo = mModel.isVideo(0);
             mIsDeletable = mModel.isDeletable(0);
             mLoadingState = mModel.getLoadingState(0);
             setScreenNail(mModel.getScreenNail(0));
@@ -732,8 +733,11 @@
             // Draw the play video icon and the message.
             canvas.translate((int) (cx + 0.5f), (int) (cy + 0.5f));
             int s = (int) (scale * Math.min(r.width(), r.height()) + 0.5f);
-            if (mIsVideo) drawVideoPlayIcon(canvas, s);
-            if (mLoadingState == Model.LOADING_FAIL) {
+            //Full pic locates at index 0 of the array in PhotoDataAdapter
+            if (mModel.isVideo(0) || mModel.isGif(0)) {
+                drawVideoPlayIcon(canvas, s);
+            }
+            if (mLoadingState == Model.LOADING_FAIL ) {
                 drawLoadingFailMessage(canvas);
             }
 
@@ -775,7 +779,6 @@
         private boolean mIsCamera;
         private boolean mIsPanorama;
         private boolean mIsStaticCamera;
-        private boolean mIsVideo;
         private boolean mIsDeletable;
         private int mLoadingState = Model.LOADING_INIT;
         private Size mSize = new Size();
@@ -789,7 +792,6 @@
             mIsCamera = mModel.isCamera(mIndex);
             mIsPanorama = mModel.isPanorama(mIndex);
             mIsStaticCamera = mModel.isStaticCamera(mIndex);
-            mIsVideo = mModel.isVideo(mIndex);
             mIsDeletable = mModel.isDeletable(mIndex);
             mLoadingState = mModel.getLoadingState(mIndex);
             setScreenNail(mModel.getScreenNail(mIndex));
@@ -853,8 +855,10 @@
                 invalidate();
             }
             int s = Math.min(drawW, drawH);
-            if (mIsVideo) drawVideoPlayIcon(canvas, s);
-            if (mLoadingState == Model.LOADING_FAIL) {
+            if (mModel.isVideo(mIndex) || mModel.isGif(mIndex)) {
+                drawVideoPlayIcon(canvas, s);
+            }
+            if (mLoadingState == Model.LOADING_FAIL ) {
                 drawLoadingFailMessage(canvas);
             }
             canvas.restore();
@@ -1855,4 +1859,5 @@
         }
         return effect;
     }
+
 }
diff --git a/src/com/android/gallery3d/util/GIFView.java b/src/com/android/gallery3d/util/GIFView.java
index 0e71aa3..fd4a5b2 100755
--- a/src/com/android/gallery3d/util/GIFView.java
+++ b/src/com/android/gallery3d/util/GIFView.java
@@ -1,300 +1,211 @@
 package com.android.gallery3d.util;
 
-import java.io.InputStream;
+import com.android.gallery3d.R;
+
 import android.content.Context;
+import android.content.ContentResolver;
+import android.content.res.AssetManager;
+import android.database.Cursor;
 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.net.Uri;
-import android.content.res.AssetManager;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import android.database.Cursor;
 import android.widget.ImageView;
-import java.io.FileInputStream;
-
-import com.android.gallery3d.R;
-
-import android.content.ContentResolver;
 import android.widget.Toast;
 
-public class GIFView extends ImageView implements GifAction{
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.InputStream;
+import java.io.IOException;
 
-    private static final String TAG = "GIFView";
-	
-    private GifDecoder gifDecoder = null;
+public class GIFView extends ImageView implements GifAction {
 
-    private Bitmap currentImage = null;
-	
-    private static boolean isRun = false;
-	
-    private static boolean pause = true;
+    private static final String  TAG            = "GIFView";
+    private static final float   SCALE_LIMIT    = 4;
+    private static final long    FRAME_DELAY    = 200; //milliseconds
 
-    private int W;
-    
-    private int H;
-	
-    private DrawThread drawThread = null;
+    private GifDecoder           mGifDecoder    = null;
+    private Bitmap               mCurrentImage  = null;
+    private DrawThread           mDrawThread    = null;
 
-    Uri mUri;
-    private Context mContext;
-	
+    private Uri                  mUri;
+    private Context              mContext;
+
     public GIFView(Context context) {
         super(context);
-        mContext=context;
-   
+        mContext = context;
     }
 
-    public boolean setDrawable(Uri uri){
-        if (null == uri){
+    public boolean setDrawable(Uri uri) {
+        if (null == uri) {
             return false;
         }
-        isRun = true;
-        pause = false;
         mUri = uri;
-        int mSize = 0;
-        ContentResolver cr = mContext.getContentResolver();
-        InputStream input = null;
+
+        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 {
-            input = cr.openInputStream(uri);
-            
-            if (input instanceof FileInputStream) {
-                FileInputStream f = (FileInputStream) input;
-                mSize = (int) f.getChannel().size();
+            if (is instanceof FileInputStream) {
+                FileInputStream f = (FileInputStream) is;
+                size = (int) f.getChannel().size();
             } else {
-                while (-1 != input.read()) {
-                    mSize++;
+                while (-1 != is.read()) {
+                    size++;
                 }
             }
 
         } catch (IOException e) {
-            
-        } finally {
-           
-        }
-        //wss , return if file is invalid
-        if(mSize == 0){
-        	return false;
+            Log.e(TAG, "catch exception:" + e);
         }
 
-        if(mSize > 1024*1024){  //gif must be smaller than 1MB
-            if (null != input) {
-                try {
-                    input.close();
-                } catch (IOException e) {
-                }
-            }
-            Toast.makeText(mContext, R.string.gif_image_too_large, Toast.LENGTH_LONG).show();
-            return false;
+        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);
         }
-        
-		setGifDecoderImage(input);
-        
-        
-		
-        android.content.ContentResolver resolver = mContext.getContentResolver();
-        Cursor c = resolver.query(uri, new String[]{"_data"}, null, null, null);
-		
-//        if ( c != null && 1 == c.getCount()){
-//            c.moveToFirst();
-//            
-//            AssetManager am = mContext.getAssets();
-//            try{
-//            	System.out.println(">>>>>>>>>1 "+c.getString(0));
-//                setGifDecoderImage(am.open(c.getString(0), AssetManager.ACCESS_RANDOM));
-//            }catch(FileNotFoundException e){
-//                Log.v(TAG, "e:" + e);
-//            }catch(IOException e){
-//                Log.v(TAG, "e:" + e);
-//            }finally{
-//                c.close();
-//            }
-//            
-//            return true;
-//        }
-//        else{
-//        	AssetManager am1 = mContext.getAssets();                           
-//            try {
-//            	System.out.println(">>>>>>>>2 "+mUri.getPath());
-//    			setGifDecoderImage(am1.open(mUri.getPath(), AssetManager.ACCESS_UNKNOWN));
-//    		} catch (IOException e1) {
-//    			e1.printStackTrace();
-//    		}
-//    		return true;
-//        }
-        return true;
+        return input;
     }
-    
-    private void setGifDecoderImage(InputStream is){
-    	 if(gifDecoder != null){
-            gifDecoder.free();
-            gifDecoder= null;
-    	 }
-    	 gifDecoder = new GifDecoder(is,this);
-    	 gifDecoder.start();
+
+    private void startDecode(InputStream is) {
+        freeGifDecoder();
+        mGifDecoder = new GifDecoder(is, this);
+        mGifDecoder.start();
     }
-    
+
     protected void onDraw(Canvas canvas) {
         super.onDraw(canvas);
-        //wangmiao add
-        W = ViewGifImage.dm.widthPixels;//480;
-        H = ViewGifImage.dm.heightPixels;//800;
-        //Log.w(TAG,"the width is "+W +"the hight is "+H);
-        if(gifDecoder == null){
+        if (mGifDecoder == null) {
             return;
         }
-            
-        if(currentImage == null){
-            currentImage = gifDecoder.getImage();
+
+        if (mCurrentImage == null) {
+            mCurrentImage = mGifDecoder.getImage();
         }
-        if(currentImage == null){
-            setImageURI(mUri);  // if can not play this gif, we just try to show it as jpg by parsing mUri, bug: T81-4307
+        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());
-        //canvas.drawBitmap(currentImage, (W - currentImage.getWidth()) / 2, (H - currentImage.getHeight())/2, null);
-        Rect sRect = null;        
+        Rect sRect = null;
         Rect dRect = null;
-        
-        int imageHeight = currentImage.getHeight();
-        int imageWidth = currentImage.getWidth();
 
-        //int newHeight = H/2;
-        int newHeight = H;        
-        int newWidth = W;
-        
-        if (newWidth < imageWidth)
-        {
-            if (newHeight < imageHeight)
-            {
-                //h big, w big;                            
-                //Log.w(TAG," h big, w big");
-                if (imageHeight*W > imageWidth*H)
-                {
-                   //too height                
-                   //newHeight = H/2;
-                   newWidth = (imageWidth * newHeight)/imageHeight;    
-                   //Log.w(TAG," h too big = "+ newHeight+" w big = "+newWidth);                
-                }
-                else
-                {
-                    //newWidth = W;
-                    newHeight = (imageHeight * newWidth)/imageWidth;   
-                    //Log.w(TAG," h big = "+ newHeight+" w too big = "+newWidth);
-                }                
-                
-                //sRect = new Rect(0, 0, currentImage.getWidth(), currentImage.getHeight());                
-                dRect = new Rect((W - newWidth) / 2, 0, (W + newWidth) / 2, newHeight);
+        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
-            {
-                //h small, w big;
-                newHeight = (imageHeight * newWidth)/imageWidth;
-                dRect = new Rect(0, 0, newWidth, newHeight);
-            }
-            canvas.drawBitmap(currentImage, sRect, dRect, null);
-            
+        } 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);
         }
-        else if (newHeight < imageHeight)
-        {
-            //h big, w small;        
-            newWidth = (imageWidth * newHeight)/imageHeight;
-            dRect = new Rect((W - newWidth) / 2, 0, 
-                (W + newWidth) / 2, newHeight);    
-            canvas.drawBitmap(currentImage, sRect, dRect, null);                
-        }
-        else
-        {
-            //h small, w small;
-            canvas.drawBitmap(currentImage, (W - imageWidth) / 2, (H - imageHeight) / 2, null);
-        }
-        
+        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){
-            if(gifDecoder != null){
-                if(frameIndex == -1){
-                    if(gifDecoder.getFrameCount() > 1){  
-                        if(drawThread == null){
-                            drawThread = new DrawThread();
-                        } else{
-                            drawThread = null;
-                            drawThread = new DrawThread();
-                        }
-                        drawThread.start();
-                    }
+
+    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("gif","parse error");
+        } else {
+            Log.e(TAG, "parse error");
         }
     }
 
-    private Handler redrawHandler = new Handler(){
-    	public void handleMessage(Message msg) {
-           invalidate();
-    	}
+    private Handler mRedrawHandler = new Handler() {
+        public void handleMessage(Message msg) {
+            invalidate();
+        }
     };
-    
-    private class DrawThread extends Thread{
-        public void run(){
-            if(gifDecoder == null){
+
+    private class DrawThread extends Thread {
+        public void run() {
+            if (mGifDecoder == null) {
                 return;
             }
-			
-            while(isRun){
-                if(pause == false){
-                    if(!isShown()){
-                        isRun = false;
-                        pause = true;
-                        break;
-                    }
-                    GifFrame frame = gifDecoder.next();
-                    currentImage = frame.image;
-                    long sp = frame.delay;
-                    if(sp == 0) sp = 200;  //wangmiao add merge from T92
-                    if(redrawHandler != null){
-                        Message msg = redrawHandler.obtainMessage();
-                        redrawHandler.sendMessage(msg);
-                        try{
-                            Thread.sleep(sp);
-                        } catch(InterruptedException e){}
-                    }else{
-                        break;
-                    }
-                } else{
+
+            while (true) {
+                if (!isShown() || mRedrawHandler == null) {
                     break;
                 }
+                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);
+                }
             }
-            isRun = true;
-            pause = false;
         }
+
     }
-    public void freeMemory()
-    {
-        isRun = false;
-        pause = true;
-        if (drawThread != null)
-        {
-            //drawThread.isStop = true;
-            drawThread = null;
+
+    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;
         }
-        if (gifDecoder != null)
-        {   
-            Log.w(TAG," free");
-            gifDecoder.free();
-            gifDecoder = null;
+
+    }
+
+    public void freeMemory() {
+        if (mDrawThread != null) {
+            mDrawThread = null;
         }
+        freeGifDecoder();
     }
 }
-
-
-
diff --git a/src/com/android/gallery3d/util/GifAction.java b/src/com/android/gallery3d/util/GifAction.java
old mode 100755
new mode 100644
index b273a17..88e3cde
--- a/src/com/android/gallery3d/util/GifAction.java
+++ b/src/com/android/gallery3d/util/GifAction.java
@@ -1,5 +1,5 @@
 package com.android.gallery3d.util;
 
 public interface GifAction {
-    public void parseOk(boolean parseStatus,int frameIndex);
+    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
index 60bc198..4235fc5 100755
--- a/src/com/android/gallery3d/util/GifDecoder.java
+++ b/src/com/android/gallery3d/util/GifDecoder.java
@@ -1,697 +1,723 @@
 package com.android.gallery3d.util;
 
-import java.io.ByteArrayInputStream;
-import java.io.InputStream;
-
 import android.graphics.Bitmap;
 import android.graphics.Bitmap.Config;
 import android.util.Log;
 
-public class GifDecoder extends Thread{
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
 
-	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 in;
-	private int status;
+public class GifDecoder extends Thread {
 
-	public int width; // full image width
-	public int height; // full image height
-	private boolean gctFlag; // global color table used
-	private int gctSize; // size of global color table
-	private int loopCount = 1; // iterations; 0 = repeat forever
+    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 int[] gct; // global color table
-	private int[] lct; // local color table
-	private int[] act; // active color table
+    private InputStream mIS;
+    private int mStatus;
 
-	private int bgIndex; // background color index
-	private int bgColor; // background color
-	private int lastBgColor; // previous bg color
-	private int pixelAspect; // pixel aspect ratio
+    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 boolean lctFlag; // local color table flag
-	private boolean interlace; // interlace flag
-	private int lctSize; // local color table size
+    private int[] mGct; // global color table
+    private int[] mLct; // local color table
+    private int[] mAct; // active color table
 
-	private int ix, iy, iw, ih; // current image rectangle
-	private int lrx, lry, lrw, lrh;
-	private Bitmap image; // current frame
-	private Bitmap lastImage; // previous frame
-	private GifFrame currentFrame = null;
+    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 isShow = false;
-	
+    private boolean mLctFlag; // local color table flag
+    private boolean mInterlace; // interlace flag
+    private int mLctSize; // local color table size
 
-	private byte[] block = new byte[256]; // current data block
-	private int blockSize = 0; // block size
-	private int dispose = 0;
-	private int lastDispose = 0;
-	private boolean transparency = false; // use transparent color
-	private int delay = 0; // delay in milliseconds
-	private int transIndex; // transparent color index
+    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 static final int MaxStackSize = 4096;
-	// max decoder pixel stack size
+    private boolean mIsShow = false;
 
-	// LZW decoder working arrays
-	private short[] prefix;
-	private byte[] suffix;
-	private byte[] pixelStack;
-	private byte[] pixels;
+    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
 
-	private GifFrame gifFrame; // frames read from current file
-	private int frameCount;
+    // max decoder pixel stack size
+    private static final int MaxStackSize = 4096;
 
-	private GifAction action = null;
-	
-	
-	private byte[] gifData = null;
+    // LZW decoder working arrays
+    private short[] mPrefix;
+    private byte[] mSuffix;
+    private byte[] mPixelStack;
+    private byte[] mPixels;
 
-	
-	public GifDecoder(byte[] data,GifAction act){
-		gifData = data;
-		action = act;
-	}
-	
-	public GifDecoder(InputStream is,GifAction act){
-		in = is;
-		action = act;
-	}
+    private GifFrame mGifFrame; // frames read from current file
+    private int mFrameCount;
 
-	public void run(){
-		if(in != null){
-                  readStream();
-		}else if(gifData != null){
-                  readByte();
-		}
-	}
-	
-	public void free(){
-		GifFrame fg = gifFrame;
-		while(fg != null){
-            if (fg.image != null) {
-                fg.image.recycle();
+    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;
             }
-			fg.image = null;
-			fg = null;
-			gifFrame = gifFrame.nextFrame;
-			fg = gifFrame;
-		}
-		if(in != null){
-			try{
-			in.close();
-			}catch(Exception ex){}
-			in = null;
-		}
-		gifData = null;
-		if (image != null)
-		{
-            image.recycle();
-            image = null;
-		}
-		if (lastImage != null)
-		{
-            lastImage.recycle();
-            lastImage = null;
-		}		
-	}
-	
-	public int getStatus(){
-		return status;
-	}
-	
-	public boolean parseOk(){
-		return status == STATUS_FINISH;
-	}
-	
-	public int getDelay(int n) {
-		delay = -1;
-		if ((n >= 0) && (n < frameCount)) {
-			GifFrame f = getFrame(n);
-			if (f != null)
-				delay = f.delay;
-		}
-		return delay;
-	}
-	
-	public int[] getDelays(){
-		GifFrame f = gifFrame;
-		int[] d = new int[frameCount];
-		int i = 0;
-		while(f != null && i < frameCount){
-			d[i] = f.delay;
-			f = f.nextFrame;
-			i++;
-		}
-		return d;
-	}
-	
-	public int getFrameCount() {
-		return frameCount;
-	}
+        }
+        return mDelay;
+    }
 
-	public Bitmap getImage() {
-		return getFrameImage(0);
-	}
+    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 getLoopCount() {
-		return loopCount;
-	}
+    public int getFrameCount() {
+        return mFrameCount;
+    }
 
-	private void setPixels() {
-		int[] dest = new int[width * height];
-		// fill in starting image contents based on last image's dispose code
-		if (lastDispose > 0) {
-			if (lastDispose == 3) {
-				// use image before last
-				int n = frameCount - 2;
-				if (n > 0) {
-					lastImage = getFrameImage(n - 1);
-				} else {
-					lastImage = null;
-				}
-			}
-			if (lastImage != null) {
-				lastImage.getPixels(dest, 0, width, 0, 0, width, height);
-				// copy pixels
-				if (lastDispose == 2) {
-					// fill last image rect area with background color
-					int c = 0;
-					if (!transparency) {
-						c = lastBgColor;
-					}
-					for (int i = 0; i < lrh; i++) {
-						int n1 = (lry + i) * width + lrx;
-						int n2 = n1 + lrw;
-						for (int k = n1; k < n2; k++) {
-							dest[k] = c;
-						}
-					}
-				}
-			}
-		}
+    public Bitmap getImage() {
+        return getFrameImage(0);
+    }
 
-		// 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 < ih; i++) {
-			int line = i;
-			if (interlace) {
-				if (iline >= ih) {
-					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 += iy;
-			if (line < height) {
-				int k = line * width;
-				int dx = k + ix; // start of line in dest
-				int dlim = dx + iw; // end of dest line
-				if ((k + width) < dlim) {
-					dlim = k + width; // past dest edge
-				}
-				int sx = i * iw; // start of line in source
-				while (dx < dlim) {
-					// map color and insert in destination
-					int index = ((int) pixels[sx++]) & 0xff;
-					int c = act[index];
-					if (c != 0) {
-						dest[dx] = c;
-					}
-					dx++;
-				}
-			}
-		}
-		image = Bitmap.createBitmap(dest, width, height, Config.ARGB_4444);
-	}
+    public int getLoopCount() {
+        return mLoopCount;
+    }
 
-	public Bitmap getFrameImage(int n) {
-		GifFrame frame = getFrame(n);	
-		if (frame == null)
-			return null;
-		else
-			return frame.image;
-	}
+    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;
+                        }
+                    }
+                }
+            }
+        }
 
-	public GifFrame getCurrentFrame(){
-		return currentFrame;
-	}
-	
-	public GifFrame getFrame(int n) {
-		GifFrame frame = gifFrame;
-		int i = 0;
-		while (frame != null) {
-			if (i == n) {
-				return frame;
-			} else {
-				frame = frame.nextFrame;
-			}
-			i++;
-		}
-		return null;
-	}
+        // 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 void reset(){
-		currentFrame = gifFrame;
-	}
-	
-	public GifFrame next() {	
-		if(isShow == false){
-			isShow = true;
-			return gifFrame;
-		}else{	
-			if(status == STATUS_PARSING){
-				if(currentFrame.nextFrame != null)
-					currentFrame = currentFrame.nextFrame;			
-				//currentFrame = gifFrame;
-			}else{			
-				currentFrame = currentFrame.nextFrame;
-				if (currentFrame == null) {
-					currentFrame = gifFrame;
-				}
-			}
-			return currentFrame;
-		}
-	}
+    public Bitmap getFrameImage(int n) {
+        GifFrame frame = getFrame(n);
+        if (frame == null) {
+            return null;
+        } else {
+            return frame.mImage;
+        }
+    }
 
-	private int readByte(){
-		in = new ByteArrayInputStream(gifData);
-		gifData = null;
-		return readStream();
-	}
-	
-	private int readStream(){
-		init();
-		if(in != null){
-			readHeader();
-			if(!err()){
-				readContents();
-				if(frameCount < 0){
-					status = STATUS_FORMAT_ERROR;
-					action.parseOk(false,-1);
-				}else{
-					status = STATUS_FINISH;
-					action.parseOk(true,-1);
-				}
-			}
-			try {
-				in.close();
-			} catch (Exception e) {
-				e.printStackTrace();
-			}
-			
-		}else {
-			status = STATUS_OPEN_ERROR;
-			action.parseOk(false,-1);
-		}
-		return status;
-	}
+    public GifFrame getCurrentFrame() {
+        return mCurrentFrame;
+    }
 
-	private void decodeImageData() {
-		int NullCode = -1;
-		int npix = iw * 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;
+    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;
+    }
 
-		if ((pixels == null) || (pixels.length < npix)) {
-			pixels = new byte[npix]; // allocate new pixel array
-		}
-		if (prefix == null) {
-			prefix = new short[MaxStackSize];
-		}
-		if (suffix == null) {
-			suffix = new byte[MaxStackSize];
-		}
-		if (pixelStack == null) {
-			pixelStack = 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++) {
-			prefix[code] = 0;
-			suffix[code] = (byte) code;
-		}
+    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;
+    }
 
-		// 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) block[bi]) & 0xff) << bits;
-					bits += 8;
-					bi++;
-					count--;
-					continue;
-				}
-				// Get the next code.
-				code = datum & code_mask;
-				datum >>= code_size;
-				bits -= code_size;
+    public void reset() {
+        mCurrentFrame = mGifFrame;
+    }
 
-				// 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 = ((int) suffix[code]) & 0xff;
-				// Add a new string to the string table,
-				if (available >= MaxStackSize) {
-					break;
-				}
-				pixelStack[top++] = (byte) first;
-				prefix[available] = (short) old_code;
-				suffix[available] = (byte) first;
-				available++;
-				if (((available & code_mask) == 0)
-						&& (available < MaxStackSize)) {
-					code_size++;
-					code_mask += available;
-				}
-				old_code = in_code;
-			}
+    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;
+        }
+    }
 
-			// Pop a pixel off the pixel stack.
-			top--;
-			pixels[pi++] = pixelStack[top];
-			i++;
-		}
-		for (i = pi; i < npix; i++) {
-			pixels[i] = 0; // clear missing pixels
-		}
-	}
+    private int readByte() {
+        mIS = new ByteArrayInputStream(mGifData);
+        mGifData = null;
+        return readStream();
+    }
 
-	private boolean err() {
-		return status != STATUS_PARSING;
-	}
+    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 init() {
-		status = STATUS_PARSING;
-		frameCount = 0;
-		gifFrame = null;
-		gct = null;
-		lct = null;
-	}
+    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;
 
-	private int read() {
-		int curByte = 0;
-		try {
-			
-			curByte = in.read();
-		} catch (Exception e) {
-			status = STATUS_FORMAT_ERROR;
-		}
-		return curByte;
-	}
-	
-	private int readBlock() {
-		blockSize = read();
-		int n = 0;
-		if (blockSize > 0) {
-			try {
-				int count = 0;
-				while (n < blockSize) {
-					count = in.read(block, n, blockSize - n);
-					if (count == -1) {
-						break;
-					}
-					n += count;
-				}
-			} catch (Exception e) {
-				e.printStackTrace();
-			}
-			if (n < blockSize) {
-				status = STATUS_FORMAT_ERROR;
-			}
-		}
-		return n;
-	}
+        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;
+        }
 
-	private int[] readColorTable(int ncolors) {
-		int nbytes = 3 * ncolors;
-		int[] tab = null;
-		byte[] c = new byte[nbytes];
-		int n = 0;
-		try {
-			n = in.read(c);
-		} catch (Exception e) {
-			e.printStackTrace();
-		}
-		if (n < nbytes) {
-			status = 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;
-	}
+        // 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;
 
-	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) block[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:
-				status = STATUS_FORMAT_ERROR;
-			}
-		}
-	}
+                // 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;
+            }
 
-	private void readGraphicControlExt() {
-		read(); // block size
-		int packed = read(); // packed fields
-		dispose = (packed & 0x1c) >> 2; // disposal method
-		if (dispose == 0) {
-			dispose = 1; // elect to keep old image if discretionary
-		}
-		transparency = (packed & 1) != 0;
-		delay = readShort() * 10; // delay in milliseconds
-		transIndex = read(); // transparent color index
-		read(); // block terminator
-	}
+            // 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 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];
-		}
-	}
+    private boolean err() {
+        return mStatus != STATUS_PARSING;
+    }
 
-	private void readImage() {
-		ix = readShort(); // (sub)image position & size
-		iy = readShort();
-		iw = readShort();
-		ih = readShort();
-		int packed = read();
-		lctFlag = (packed & 0x80) != 0; // 1 - local color table flag
-		interlace = (packed & 0x40) != 0; // 2 - interlace flag
-		// 3 - sort flag
-		// 4-5 - reserved
-		lctSize = 2 << (packed & 7); // 6-8 - local color table size
-		if (lctFlag) {
-			lct = readColorTable(lctSize); // read table
-			act = lct; // make local table active
-		} else {
-			act = gct; // make global table active
-			if (bgIndex == transIndex) {
-				bgColor = 0;
-			}
-		}
-		int save = 0;
-		if (transparency) {
-			save = act[transIndex];
-			act[transIndex] = 0; // set transparent color if specified
-		}
-		if (act == null) {
-			status = STATUS_FORMAT_ERROR; // no color table defined
-		}
-		if (err()) {
-			return;
-		}
+    private void init() {
+        mStatus = STATUS_PARSING;
+        mFrameCount = 0;
+        mGifFrame = null;
+        mGct = null;
+        mLct = null;
+    }
+
+    private int read() {
+        int curByte = 0;
         try {
-    		decodeImageData(); // decode pixel data
-    		skip();
-    		if (err()) {
-    			return;
-    		}
-    		frameCount++;
-    		// create new image to receive frame data
-    		image = Bitmap.createBitmap(width, height, Config.ARGB_4444);
-    		// createImage(width, height);
-    		setPixels(); // transfer pixel data to image
-    		if (gifFrame == null) {
-    			gifFrame = new GifFrame(image, delay);
-    			currentFrame = gifFrame;
-    		} else {
-    			GifFrame f = gifFrame;
-    			while(f.nextFrame != null){
-    				f = f.nextFrame;
-    			}
-    			f.nextFrame = new GifFrame(image, delay);
-    		}
-    		// frames.addElement(new GifFrame(image, delay)); // add image to frame
-    		// list
-    		if (transparency) {
-    			act[transIndex] = save;
-    		}
-    		resetFrame();
-    		action.parseOk(true, frameCount);
-        }catch (OutOfMemoryError e) {
+            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
-		width = readShort();
-		height = readShort();
-		// packed fields
-		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
-	}
+    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 (block[0] == 1) {
-				// loop count sub-block
-				int b1 = ((int) block[1]) & 0xff;
-				int b2 = ((int) block[2]) & 0xff;
-				loopCount = (b2 << 8) | b1;
-			}
-		} while ((blockSize > 0) && !err());
-	}
+    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 int readShort() {
+        // read 16-bit value, LSB first
+        return read() | (read() << 8);
+    }
 
-	private void resetFrame() {
-		lastDispose = dispose;
-		lrx = ix;
-		lry = iy;
-		lrw = iw;
-		lrh = ih;
-		lastImage = image;
-		lastBgColor = bgColor;
-		dispose = 0;
-		transparency = false;
-		delay = 0;
-		lct = null;
-	}
+    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 ((blockSize > 0) && !err());
-	}
+    /**
+     * 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
index 926ed57..87d58a4 100755
--- a/src/com/android/gallery3d/util/GifFrame.java
+++ b/src/com/android/gallery3d/util/GifFrame.java
@@ -3,12 +3,15 @@
 import android.graphics.Bitmap;
 
 public class GifFrame {
-    public GifFrame(Bitmap im, int del) {
-        image = im;
-        delay = del;
+
+    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;
     }
-	
-    public Bitmap image;
-    public int delay;
-    public GifFrame nextFrame = null;
 }
diff --git a/src/com/android/gallery3d/util/ViewGifImage.java b/src/com/android/gallery3d/util/ViewGifImage.java
index b157e2f..cdd5092 100755
--- a/src/com/android/gallery3d/util/ViewGifImage.java
+++ b/src/com/android/gallery3d/util/ViewGifImage.java
@@ -1,111 +1,67 @@
-/**
- * File property dialog
- *
- * @Author wangxuguang
- * 
- * caozhe add this file, for displya gif image, 2011.3.28
- */
-
 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.widget.ImageView;
-
-import com.android.gallery3d.R;
-import android.net.Uri;
-
-import android.view.ViewGroup.LayoutParams;
-import android.widget.LinearLayout;
 import android.util.DisplayMetrics;
-import android.content.res.Configuration;
+import android.view.ViewGroup.LayoutParams;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
 
-public class ViewGifImage extends Activity
-{
-    public static final String TAG = "ViewGifImage";
-    private String mFileDir;
-    public static DisplayMetrics dm;
-    ImageView gifView;
+public class ViewGifImage extends Activity {
+    private static final String TAG       = "ViewGifImage";
+    public  static final String VIEW_GIF_ACTION = "com.android.gallery3d.VIEW_GIF";
 
-    static final int WIDTH = 320;
-    static final int HEIGHT = 480;
+    public  static DisplayMetrics mDM;
 
-    
-    private Handler mHandler = new Handler() {
-        public void handleMessage(Message msg)
-        {
-            super.handleMessage(msg);
-        }
-    };
+    private ImageView mGifView;
 
     @Override
-    public void onCreate(Bundle savedInstanceState) 
-    {   
-        //android.util.Log.d(TAG, "=== onCreate() ===");
+    public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         setContentView(R.layout.view_gif_image);
-        dm = new DisplayMetrics();
-        getWindowManager().getDefaultDisplay().getMetrics(dm);
-        //add end
-        if(getIntent().getAction() != null 
-            && getIntent().getAction().equals("hisense.view_gif_image")){
-            // i am called by gallery3D or other apps who want to show a 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);
-
-            return;
         }
-
-        mFileDir = getIntent().getStringExtra("file_dir");
-        Uri gifUri = getIntent().getData();
-
-
-         showGifPicture(gifUri);
-        
-
     }
 
     @Override
-    public void onResume() 
-    {   
-        super.onResume();
-    }
-
-    @Override
-    protected void onStop() 
-    {
+    protected void onStop() {
         super.onStop();
         finish();
     }
-    
-    @Override
-	protected void onDestroy() {
-		if (gifView != null){
-            if (gifView instanceof GIFView)
-            {
-                ((GIFView)gifView).freeMemory();
-                 gifView = null;
-            }
-       }
-		super.onDestroy();
-	}
 
-    private void showGifPicture(Uri gifUri){
-        gifView = new GIFView(this);
-        ((LinearLayout)findViewById(R.id.image_absoluteLayout)).addView(gifView, new LayoutParams(
-                    LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
-        if(!((GIFView)gifView).setDrawable(gifUri))
-        	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(dm);
+        getWindowManager().getDefaultDisplay().getMetrics(mDM);
         super.onConfigurationChanged(newConfig);
     }
-   
-
 }