/* 
 * Copyright 2015 eje inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.eje_c.meganekko.scene_objects;

import android.annotation.SuppressLint;
import android.graphics.Canvas;
import android.graphics.SurfaceTexture;
import android.view.Surface;

import com.eje_c.meganekko.Material;
import com.eje_c.meganekko.RenderData;
import com.eje_c.meganekko.SceneObject;
import com.eje_c.meganekko.VrFrame;

/**
 * A {@linkplain SceneObject scene object} that renders like a standard Android
 * Views. You have to call {@link #setCanvasSize(int, int)} to set Canvas size.
 * Actual drawing is done with subclass of {@link OnDrawListener}.
 */
public class CanvasSceneObject extends SceneObject {

    private final Surface mSurface;
    private final SurfaceTexture mSurfaceTexture;
    private OnDrawListener mOnDrawListener;

    public CanvasSceneObject() {

        Material material = new Material();
        mSurfaceTexture = material.getSurfaceTexture();

        RenderData renderData = new RenderData();
        renderData.setMaterial(material);

        attachRenderData(renderData);

        mSurface = new Surface(mSurfaceTexture);
    }

    /**
     * Must be called before start drawing.
     *
     * @param width  Internal texture width. This value can be get with
     *               {@code Canvas#getWidth()} on drawing.
     * @param height Internal texture height. This value can be get with
     *               {@code Canvas#getHeight()} on drawing.
     */
    public void setCanvasSize(int width, int height) {
        mSurfaceTexture.setDefaultBufferSize(width, height);
    }

    @SuppressLint("WrongCall")
    @Override
    public void update(VrFrame vrFrame) {

        if (mOnDrawListener != null && mOnDrawListener.isDirty()) {

            Canvas canvas = null;

            try {
                canvas = mSurface.lockCanvas(null);
                mOnDrawListener.onDraw(this, canvas, vrFrame);
            } finally {
                if (canvas != null)
                    mSurface.unlockCanvasAndPost(canvas);
            }

            mSurfaceTexture.updateTexImage();
        }

        super.update(vrFrame);
    }

    /**
     * Get an {@code OnDrawListener} for rendering.
     *
     * @return
     */
    public OnDrawListener getOnDrawListener() {
        return mOnDrawListener;
    }

    /**
     * Set an {@code OnDrawListener} for rendering. Pass null to unregister
     * listener.
     *
     * @param onDrawListener
     */
    public void setOnDrawListener(OnDrawListener onDrawListener) {
        this.mOnDrawListener = onDrawListener;
    }

    /**
     * Equivalent call to {@code setOnDrawListener(null)}.
     */
    public void clearOnDrawListener() {
        setOnDrawListener(null);
    }

    public interface OnDrawListener {
        /**
         * Called before onDraw is called. If this method returns true, canvas
         * is refreshed with onDraw method. If this method returns false, onDraw
         * will not be called.
         *
         * @return Refreshing canvas is required.
         */
        boolean isDirty();

        /**
         * Called at each frame update. Use {@code VrFrame#getDeltaSeconds()}
         * and {@code VrFrame#getPredictedDisplayTimeInSeconds()} to implement
         * time based animation.
         *
         * @param object  Target object.
         * @param canvas  Rendering canvas.
         * @param vrFrame Current frame information passed from native framework.
         */
        void onDraw(CanvasSceneObject object, Canvas canvas, VrFrame vrFrame);
    }
}

@@ -1219,44 +1219,8 @@
  %7B%0A%0A
-    private final Surface mSurface;%0A
     
@@ -1579,58 +1579,8 @@
 ta);
-%0A%0A        mSurface = new Surface(mSurfaceTexture);
 %0A   
@@ -2232,26 +2232,118 @@
 ll;%0A
-%0A            try %7B
+            Surface surface = null;%0A%0A            try %7B%0A                surface = new Surface(mSurfaceTexture);
 %0A   
@@ -2364,18 +2364,17 @@
 anvas = 
-mS
+s
 urface.l
@@ -2473,24 +2473,67 @@
 %7D finally %7B%0A
+                if (surface != null) %7B%0A    
             
@@ -2555,17 +2555,21 @@
 != null)
-%0A
+ %7B%0A  
         
@@ -2576,26 +2576,27 @@
             
-mS
+  s
 urface.unloc
@@ -2619,16 +2619,95 @@
 anvas);%0A
+                    %7D%0A                    surface.release();%0A                %7D%0A
         

Improve Surface handling in CanvasSceneObject. Surface will be released in every time in update.