/**
* galaxy inc.
* meetup client for android
*/
package com.galaxy.meetup.client.util;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.ColorFilter;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.drawable.Animatable;
import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.os.Handler.Callback;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.Message;
import android.os.SystemClock;
import android.util.Log;
import com.galaxy.meetup.client.android.EsApplication;
import com.galaxy.meetup.client.android.common.Recyclable;
/**
*
* @author sihai
*
*/
public class GifDrawable extends Drawable implements Animatable, Callback,
Recyclable, Runnable {
private static final byte NETSCAPE2_0[] = "NETSCAPE2.0".getBytes();
private static Handler sDecoderHandler;
private static DecoderThread sDecoderThread;
private static Paint sPaint;
private static Paint sScalePaint;
private int mActiveColorTable[];
private boolean mAnimationEnabled;
private int mBackgroundColor;
private int mBackup[];
private boolean mBackupSaved;
private Bitmap mBitmap;
private byte mBlock[];
private int mColors[];
private final byte mData[];
private int mDisposalMethod;
private boolean mDone;
private volatile boolean mError;
private boolean mFirstFrameReady;
private int mFrameCount;
private int mFrameDelay;
private int mFrameHeight;
private int mFrameWidth;
private int mFrameX;
private int mFrameY;
private final GifImage mGifImage;
private final Handler mHandler = new Handler(Looper.getMainLooper(), this);
private int mHeight;
private boolean mInterlace;
private volatile int mIntrinsicHeight;
private volatile int mIntrinsicWidth;
private int mLocalColorTable[];
private int mLocalColorTableSize;
private boolean mLocalColorTableUsed;
private byte mPixelStack[];
private byte mPixels[];
private volatile int mPosition;
private short mPrefix[];
private boolean mRecycled;
private boolean mRunning;
private boolean mScale;
private float mScaleFactor;
private boolean mScheduled;
private byte mSuffix[];
private boolean mTransparency;
private int mTransparentColorIndex;
private int mWidth;
public GifDrawable(GifImage gifimage) {
mBlock = new byte[256];
mDisposalMethod = 2;
mPrefix = new short[4096];
mSuffix = new byte[4096];
mPixelStack = new byte[4097];
mAnimationEnabled = true;
if (sDecoderThread == null) {
DecoderThread decoderthread = new DecoderThread();
sDecoderThread = decoderthread;
decoderthread.start();
sDecoderHandler = new Handler(sDecoderThread.getLooper(),
sDecoderThread);
}
if (sPaint == null) {
sPaint = new Paint(2);
Paint paint = new Paint(2);
sScalePaint = paint;
paint.setFilterBitmap(true);
}
mGifImage = gifimage;
mData = gifimage.getData();
mPosition = mGifImage.mHeaderSize;
int i = gifimage.getWidth();
mIntrinsicWidth = i;
mFrameWidth = i;
int j = gifimage.getHeight();
mIntrinsicHeight = j;
mFrameHeight = j;
mBackgroundColor = mGifImage.mBackgroundColor;
mError = mGifImage.mError;
if (!mError)
try {
int k = mIntrinsicWidth;
int l = mIntrinsicHeight;
int i1 = EsApplication.sMemoryClass;
boolean flag = false;
if (i1 < 64)
flag = true;
android.graphics.Bitmap.Config config;
int j1;
if (flag)
config = android.graphics.Bitmap.Config.ARGB_4444;
else
config = android.graphics.Bitmap.Config.ARGB_8888;
mBitmap = Bitmap.createBitmap(k, l, config);
j1 = mIntrinsicWidth * mIntrinsicHeight;
mColors = new int[j1];
mPixels = new byte[j1];
mWidth = mIntrinsicHeight;
mHeight = mIntrinsicHeight;
sDecoderHandler.sendMessage(sDecoderHandler.obtainMessage(0,
this));
} catch (OutOfMemoryError outofmemoryerror) {
mError = true;
}
}
private void backupFrame() {
if (!mBackupSaved) {
if (mBackup == null) {
try {
mBackup = new int[mColors.length];
} catch (OutOfMemoryError outofmemoryerror) {
Log.e("GifDrawable",
"GifDrawable.backupFrame threw an OOME",
outofmemoryerror);
}
}
if (mBackup != null) {
System.arraycopy(mColors, 0, mBackup, 0, mColors.length);
mBackupSaved = true;
}
}
}
private int readBlock() {
byte abyte0[] = mData;
int i = mPosition;
mPosition = i + 1;
int j = 0xff & abyte0[i];
if (j > 0) {
System.arraycopy(mData, mPosition, mBlock, 0, j);
mPosition = j + mPosition;
}
return j;
}
private int readShort() {
byte abyte0[] = mData;
int i = mPosition;
mPosition = i + 1;
int j = 0xff & abyte0[i];
byte abyte1[] = mData;
int k = mPosition;
mPosition = k + 1;
return j | (0xff & abyte1[k]) << 8;
}
private void reset() {
sDecoderHandler.sendMessage(sDecoderHandler.obtainMessage(7, this));
mFrameCount = 0;
mScheduled = false;
}
private void skip() {
int j;
do {
int i = mPosition;
mPosition = i + 1;
j = 0xff & mData[i];
mPosition = j + mPosition;
} while (j > 0);
}
@Override
public void run() {
if (!this.mRecycled) {
if (this.mDone) {
if (this.mFrameCount > 1) {
this.mDone = false;
reset();
}
} else {
sDecoderHandler.sendMessage(sDecoderHandler.obtainMessage(2,
this));
}
stop();
}
}
@Override
public boolean handleMessage(Message message) {
boolean flag = false;
switch (message.what) {
case 1:
mError = true;
flag = true;
break;
case 2:
break;
case 3:
mDone = true;
flag = true;
break;
case 4:
mScheduled = false;
invalidateSelf();
flag = true;
break;
case 5:
if (mBitmap != null) {
mBitmap.setPixels(mColors, 0, mIntrinsicWidth, 0, 0,
mIntrinsicWidth, mIntrinsicHeight);
mFirstFrameReady = true;
invalidateSelf();
}
flag = true;
break;
case 6:
mFrameCount = 1 + mFrameCount;
flag = true;
break;
default:
break;
}
return flag;
}
@Override
public boolean isRunning() {
return mRunning;
}
public final void start() {
if (!isRunning()) {
mRunning = true;
run();
}
}
public final void stop() {
if (isRunning())
unscheduleSelf(this);
}
@Override
public void draw(Canvas canvas) {
if (!mError && mWidth != 0 && mHeight != 0 && !mRecycled
&& mFirstFrameReady) {
if (mScale) {
canvas.save();
canvas.scale(mScaleFactor, mScaleFactor, 0.0F, 0.0F);
canvas.drawBitmap(mBitmap, 0.0F, 0.0F, sScalePaint);
canvas.restore();
} else {
canvas.drawBitmap(mBitmap, 0.0F, 0.0F, sPaint);
}
if (mRunning) {
if (!mScheduled)
scheduleSelf(this, SystemClock.uptimeMillis()
+ (long) mFrameDelay);
} else if (!mDone)
start();
else
unscheduleSelf(this);
}
}
public final int getIntrinsicHeight() {
return mIntrinsicHeight;
}
public final int getIntrinsicWidth() {
return mIntrinsicWidth;
}
@Override
public int getOpacity() {
return 0;
}
@Override
public void setAlpha(int arg0) {
// TODO Auto-generated method stub
}
@Override
public void setColorFilter(ColorFilter arg0) {
// TODO Auto-generated method stub
}
public final boolean isValid() {
boolean flag;
if (!mError && mFirstFrameReady)
flag = true;
else
flag = false;
return flag;
}
protected final void onBoundsChange(Rect rect) {
super.onBoundsChange(rect);
mWidth = rect.width();
mHeight = rect.height();
boolean flag;
if(mWidth != mIntrinsicWidth && mHeight != mIntrinsicHeight)
flag = true;
else
flag = false;
mScale = flag;
if(mScale)
mScaleFactor = Math.max((float)mWidth / (float)mIntrinsicWidth, (float)mHeight / (float)mIntrinsicHeight);
reset();
}
public final void onRecycle() {
if(mBitmap != null)
mBitmap.recycle();
mBitmap = null;
mRecycled = true;
}
public final void scheduleSelf(Runnable runnable, long l) {
if(mAnimationEnabled) {
super.scheduleSelf(runnable, l);
mScheduled = true;
}
}
public final void setAnimationEnabled(boolean flag)
{
if(mAnimationEnabled != flag)
{
mAnimationEnabled = flag;
if(mAnimationEnabled)
start();
else
stop();
}
}
public final boolean setVisible(boolean flag, boolean flag1)
{
boolean flag2 = super.setVisible(flag, flag1);
if(flag)
{
if(flag2 || flag1)
start();
} else
{
stop();
}
return flag2;
}
public final void unscheduleSelf(Runnable runnable)
{
super.unscheduleSelf(runnable);
mRunning = false;
}
private static final class DecoderThread extends HandlerThread implements Handler.Callback {
public DecoderThread() {
super("GifDecoder");
}
public final boolean handleMessage(Message message) {
boolean flag = true;
GifDrawable gifdrawable = (GifDrawable) message.obj;
switch (message.what) {
case 0:
try {
// FIXME
//GifDrawable.access$000(gifdrawable);
} catch (ArrayIndexOutOfBoundsException arrayindexoutofboundsexception1) {
gifdrawable.mHandler.sendEmptyMessage(0);
}
break;
case 2:
try {
// FIXME
//GifDrawable.access$000(gifdrawable);
} catch (ArrayIndexOutOfBoundsException arrayindexoutofboundsexception) {
gifdrawable.mHandler.sendEmptyMessage(3);
}
gifdrawable.mHandler.sendEmptyMessage(4);
break;
case 7:
gifdrawable.mPosition = gifdrawable.mGifImage.mHeaderSize;
gifdrawable.mBackupSaved = false;
gifdrawable.mDisposalMethod = 0;
break;
default:
flag = false;
break;
}
return flag;
}
}
}