/******************************************************************************* * This file is part of RedReader. * * RedReader is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * RedReader is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with RedReader. If not, see <http://www.gnu.org/licenses/>. ******************************************************************************/ package org.quantumbadger.redreader.image; import android.graphics.Bitmap; import android.os.Handler; import android.os.Looper; import android.os.Message; import android.widget.ImageView; import java.io.InputStream; import java.util.concurrent.atomic.AtomicBoolean; import jp.tomorrowkey.android.gifplayer.GifDecoder; public class GifDecoderThread extends Thread { private volatile boolean playing = true; private final InputStream is; private ImageView view; private final OnGifLoadedListener listener; public void setView(ImageView view) { this.view = view; } public interface OnGifLoadedListener { void onGifLoaded(); void onOutOfMemory(); void onGifInvalid(); } private final Handler handler = new Handler(Looper.getMainLooper()) { @Override public void handleMessage(Message msg) { if(playing && view != null) view.setImageBitmap((Bitmap)msg.obj); } }; public GifDecoderThread(InputStream is, OnGifLoadedListener listener) { super("GIF playing thread"); this.is = is; this.listener = listener; } public void stopPlaying() { playing = false; interrupt(); try { is.close(); } catch(Throwable t) {} } @Override public void run() { final AtomicBoolean loaded = new AtomicBoolean(false); final AtomicBoolean failed = new AtomicBoolean(false); final GifDecoder decoder = new GifDecoder(); new Thread("GIF decoding thread") { @Override public void run() { try { decoder.read(is); loaded.set(true); } catch(Throwable t) { t.printStackTrace(); failed.set(true); } } }.start(); try { if(!playing) return; listener.onGifLoaded(); int frame = 0; while(playing) { while(decoder.getFrameCount() <= frame + 1 && !loaded.get() && !failed.get()) { try { sleep(100); } catch(InterruptedException e) { return; } } frame = frame % decoder.getFrameCount(); final Bitmap img = decoder.getFrame(frame); final Message msg = Message.obtain(); msg.obj = img; handler.sendMessage(msg); try { sleep(Math.max(32, decoder.getDelay(frame))); } catch(InterruptedException e) { return; } if(failed.get()) { listener.onGifInvalid(); return; } frame++; } } catch(OutOfMemoryError e) { listener.onOutOfMemory(); } catch(Throwable t) { listener.onGifInvalid(); } } }