Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8c7fe642 authored by Likai Ding's avatar Likai Ding Committed by Arne Coucheron
Browse files

Gallery2: Support GIF animation



This change implements a Java GIF decoder.

Change-Id: I227cef76cbacd66b7e87bc59b4f07d518b70a859
Signed-off-by: default avatarXiaojing Zhang <zhangx@codeaurora.org>
parent b923c258
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -307,6 +307,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"
+17 −0
Original line number Diff line number Diff line
<?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_display_area"
                android:layout_height="wrap_content"
                android:layout_width="wrap_content"
                android:clickable="true">
        </ImageView>
    </LinearLayout>

</RelativeLayout>
+10 −0
Original line number Diff line number Diff line
@@ -79,6 +79,7 @@ import com.android.gallery3d.ui.SynchronizedHandler;
import com.android.gallery3d.util.GDepth;
import com.android.gallery3d.util.GalleryUtils;
import com.android.gallery3d.util.UsageStatistics;
import com.android.gallery3d.util.ViewGifImage;

import java.util.List;
import java.util.Locale;
@@ -1330,6 +1331,10 @@ public abstract class PhotoPage extends ActivityState implements
            // 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);
@@ -1795,4 +1800,9 @@ public abstract class PhotoPage extends ActivityState implements
            m3DButton.refresh();
        }
    }

    private static void viewAnimateGif(Activity activity, Uri uri) {
        Intent intent = new Intent(ViewGifImage.VIEW_GIF_ACTION, uri);
        activity.startActivity(intent);
    }
}
+2 −2
Original line number Diff line number Diff line
@@ -735,7 +735,7 @@ public class PhotoView extends GLView {
            canvas.translate((int) (cx + 0.5f), (int) (cy + 0.5f));
            int s = (int) (scale * Math.min(r.width(), r.height()) + 0.5f);
            //Full pic locates at index 0 of the array in PhotoDataAdapter
            if (mModel.isVideo(0)) {
            if (mModel.isVideo(0) || mModel.isGif(0)) {
                drawVideoPlayIcon(canvas, s);
            }
            if (mLoadingState == Model.LOADING_FAIL ) {
@@ -865,7 +865,7 @@ public class PhotoView extends GLView {
                invalidate();
            }
            int s = Math.min(drawW, drawH);
            if (mModel.isVideo(mIndex)) {
            if (mModel.isVideo(mIndex) || mModel.isGif(mIndex)) {
                drawVideoPlayIcon(canvas, s);
            }

+207 −0
Original line number Diff line number Diff line
package com.android.gallery3d.util;

import org.codeaurora.gallery.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.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;

        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();
    }

    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() {
            while (true) {
                if (mGifDecoder == null || !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);
                }
            }
        }

    }

    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();
    }
}
Loading