package com.glview.hwui; import java.util.List; import android.util.Log; import android.util.LogPrinter; import android.util.Printer; import android.view.Surface; import com.glview.animation.Animator; import com.glview.graphics.Bitmap; import com.glview.hwui.task.Task; import com.glview.hwui.task.TaskHandler; import com.glview.view.GLRootView; public final class RenderPolicy { private final static String TAG = "RenderPolicy"; private final static boolean DEBUG = true; private final static boolean DEBUG_LOOPER = false; private final static boolean DEBUG_DRAW = false; Printer pw = new LogPrinter(Log.DEBUG, TAG); CanvasContext mCanvasContext = null; RenderNode mRootNode; /** * This is the render thread's message handler. * It handle out render thread's messages. * @see #RenderPolicy(RenderNode) * @see #initialize(Surface) * @see #destroy(boolean) * @see #syncAndDrawFrame() */ TaskHandler mHandler; /** * If the render thread {@link #mHandler} has been exited. * We do nothing after it's exited. */ boolean mExited = false; /** * Draw frame task, it's a sync task, called from the GLThread {@link GLRootView#onDrawFrame()}. * Our GLThread may be blocked by the render thread. * @see #syncAndDrawFrame() */ DrawTask mDrawTask = new DrawTask(); public RenderPolicy(RenderNode rootRenderNode) { mRootNode = rootRenderNode; init(); } private void init() { mExited = false; mHandler = new TaskHandler(RenderThread.getRenderThreadLooper()); mHandler.postAndWait(new PolicyTask(PolicyTask.TASK_CREATE_CONTEXT, 0, 0, mRootNode)); } public void initialize(Object surface) { if (mExited) { init(); } mHandler.postAndWait(new PolicyTask(PolicyTask.TASK_INITIALIZE, 0, 0, surface)); } public void startAnimation(List<Animator> animators) { if (mExited) return; mCanvasContext.startAnimation(animators); } public void stopAnimation(List<Animator> animators) { if (mExited) return; mCanvasContext.stopAnimation(animators); } public Bitmap buildDrawingCache(RenderNode renderNode) { if (mExited) return null; BuildDrawingCacheTask task = new BuildDrawingCacheTask(renderNode); mHandler.postAndWait(task); return task.mDrawingCache; } public void setSize(Object surface, int width, int height) { if (mExited) return; mHandler.postAndWait(new PolicyTask(PolicyTask.TASK_SETSIZE, width, height, surface)); } public void destroy(boolean full) { if (DEBUG) Log.d(TAG, "destroy called full=" + full); mHandler.removeCallbacksAndMessages(null); mHandler.postAtFrontOfQueueAndWait(new PolicyTask(PolicyTask.TASK_DESTROY, 0, 0, full)); if (full) { mExited = true; mHandler = null; } if (DEBUG) Log.d(TAG, "destroy called end"); } public void syncAndDrawFrame() { if (mExited) return; if (isEnable()) { if (DEBUG_DRAW) Log.d(TAG, "sync and draw frame begin!"); mHandler.postAndWait(mDrawTask); if (DEBUG_DRAW) Log.d(TAG, "sync and draw frame end!"); // scheduleAnimatingDrawTask(); } } public boolean isEnable() { return mCanvasContext != null && mCanvasContext.isEnable(); } private void innerDraw(boolean fromGLThread) { if (DEBUG_LOOPER) mHandler.getLooper().dump(pw, "looper"); /*if (mCanvasContext.draw()) { if (mAnimating && mThread.checkThreadState()) { scheduleAnimatingDrawTask(); } }*/ if (mCanvasContext.draw() && fromGLThread) { // mHandler.remove(mDrawTask); } } class PolicyTask extends Task { final static int TASK_CREATE_CONTEXT = 0; final static int TASK_INITIALIZE = 1; final static int TASK_SETSIZE = 2; final static int TASK_DESTROY = 3; int what; int arg1; int arg2; Object obj; PolicyTask(int what, int arg1, int arg2, Object obj) { this.what = what; this.arg1 = arg1; this.arg2 = arg2; this.obj = obj; } @Override public void doTask() { if (DEBUG) Log.d(TAG, "PolicyTask doTask what=" + what + ", arg1=" + arg1 + ", arg2=" + arg2 + ", obj=" + obj + ", tid=" + Thread.currentThread().getId()); switch (what) { case TASK_CREATE_CONTEXT: mCanvasContext = new CanvasContext((RenderNode) obj); break; case TASK_INITIALIZE: mCanvasContext.initialize(obj); break; case TASK_SETSIZE: mCanvasContext.setSize(obj, arg1, arg2); break; case TASK_DESTROY: mCanvasContext.destroy((Boolean) obj); break; default: break; } } } class DrawTask extends Task { @Override public void doTask() { innerDraw(true); } } class BuildDrawingCacheTask extends Task { RenderNode mRenderNode; Bitmap mDrawingCache; public BuildDrawingCacheTask(RenderNode renderNode) { mRenderNode = renderNode; } @Override public void doTask() { if (mRenderNode != null) { mDrawingCache = mCanvasContext.buildDrawingCache(mRenderNode); } } } public static void trimMemory(int level) { CanvasContext.trimMemory(level); } }