Updating samplePlugin to use java surface views.

Change-Id: I1b925ce3a6aeb0bd5464a7d5711449029944d7de
diff --git a/samples/BrowserPlugin/jni/Android.mk b/samples/BrowserPlugin/jni/Android.mk
index f296a1d..b888d54 100644
--- a/samples/BrowserPlugin/jni/Android.mk
+++ b/samples/BrowserPlugin/jni/Android.mk
@@ -35,7 +35,7 @@
 	background/BackgroundPlugin.cpp \
 	form/FormPlugin.cpp \
 	paint/PaintPlugin.cpp \
-	hello-jni.cpp \
+	jni-bridge.cpp \
 
 LOCAL_C_INCLUDES += \
 	$(JNI_H_INCLUDE) \
diff --git a/samples/BrowserPlugin/jni/PluginObject.h b/samples/BrowserPlugin/jni/PluginObject.h
index 82f6f48..61486d5 100644
--- a/samples/BrowserPlugin/jni/PluginObject.h
+++ b/samples/BrowserPlugin/jni/PluginObject.h
@@ -35,6 +35,7 @@
 #define PluginObject__DEFINED
 
 #include "main.h"
+#include <jni.h>
 
 class SubPlugin {
 public:
@@ -49,6 +50,16 @@
     NPP m_inst;
 };
 
+class SurfaceSubPlugin : public SubPlugin {
+public:
+    SurfaceSubPlugin(NPP inst) : SubPlugin(inst) {}
+    virtual ~SurfaceSubPlugin() {}
+    virtual bool isFixedSurface() = 0;
+    virtual void surfaceCreated(JNIEnv*, jobject) = 0;
+    virtual void surfaceChanged(int format, int width, int height) = 0;
+    virtual void surfaceDestroyed() = 0;
+};
+
 enum PluginTypes {
     kAnimation_PluginType  = 1,
     kAudio_PluginType      = 2,
diff --git a/samples/BrowserPlugin/jni/background/BackgroundPlugin.cpp b/samples/BrowserPlugin/jni/background/BackgroundPlugin.cpp
index eac5db2..2a65b4f 100644
--- a/samples/BrowserPlugin/jni/background/BackgroundPlugin.cpp
+++ b/samples/BrowserPlugin/jni/background/BackgroundPlugin.cpp
@@ -50,13 +50,11 @@
 
 ///////////////////////////////////////////////////////////////////////////////
 
-BackgroundPlugin::BackgroundPlugin(NPP inst) : SubPlugin(inst) {
+BackgroundPlugin::BackgroundPlugin(NPP inst) : SurfaceSubPlugin(inst) {
 
     // initialize the drawing surface
-    m_surfaceReady = false;
-    m_surface = gSurfaceI.newRasterSurface(inst, kRGB_565_ANPBitmapFormat, false);
-    if(!m_surface)
-        gLogI.log(inst, kError_ANPLogType, "----%p Unable to create RGBA surface", inst);
+    m_surface = NULL;
+    m_vm = NULL;
 
     //initialize bitmap transparency variables
     mFinishedStageOne   = false;
@@ -71,14 +69,33 @@
     test_javascript();
 }
 
-BackgroundPlugin::~BackgroundPlugin() {
-    gSurfaceI.deleteSurface(m_surface);
-}
+BackgroundPlugin::~BackgroundPlugin() { }
 
 bool BackgroundPlugin::supportsDrawingModel(ANPDrawingModel model) {
     return (model == kSurface_ANPDrawingModel);
 }
 
+bool BackgroundPlugin::isFixedSurface() {
+    return false;
+}
+
+void BackgroundPlugin::surfaceCreated(JNIEnv* env, jobject surface) {
+    env->GetJavaVM(&m_vm);
+    m_surface = env->NewGlobalRef(surface);
+}
+
+void BackgroundPlugin::surfaceChanged(int format, int width, int height) {
+    drawPlugin(width, height);
+}
+
+void BackgroundPlugin::surfaceDestroyed() {
+    JNIEnv* env = NULL;
+    if (m_surface && m_vm->GetEnv((void**) &env, JNI_VERSION_1_4) == JNI_OK) {
+        env->DeleteGlobalRef(m_surface);
+        m_surface = NULL;
+    }
+}
+
 void BackgroundPlugin::drawPlugin(int surfaceWidth, int surfaceHeight) {
 
     // get the plugin's dimensions according to the DOM
@@ -101,7 +118,9 @@
 
     // lock the surface
     ANPBitmap bitmap;
-    if (!m_surfaceReady || !gSurfaceI.lock(m_surface, &bitmap, NULL)) {
+    JNIEnv* env = NULL;
+    if (!m_surface || m_vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK ||
+        !gSurfaceI.lock(env, m_surface, &bitmap, NULL)) {
         gLogI.log(inst(), kError_ANPLogType, " ------ %p unable to lock the plugin", inst());
         return;
     }
@@ -129,7 +148,7 @@
     // clean up variables and unlock the surface
     gPaintI.deletePaint(paint);
     gCanvasI.deleteCanvas(canvas);
-    gSurfaceI.unlock(m_surface);
+    gSurfaceI.unlock(env, m_surface);
 }
 
 int16 BackgroundPlugin::handleEvent(const ANPEvent* evt) {
@@ -137,20 +156,6 @@
         case kDraw_ANPEventType:
             gLogI.log(inst(), kError_ANPLogType, " ------ %p the plugin did not request draw events", inst());
             break;
-        case kSurface_ANPEventType:
-                    switch (evt->data.surface.action) {
-                        case kCreated_ANPSurfaceAction:
-                            m_surfaceReady = true;
-                            return 1;
-                        case kDestroyed_ANPSurfaceAction:
-                            m_surfaceReady = false;
-                            return 1;
-                        case kChanged_ANPSurfaceAction:
-                            drawPlugin(evt->data.surface.data.changed.width,
-                                       evt->data.surface.data.changed.height);
-                            return 1;
-                    }
-                    break;
         case kLifecycle_ANPEventType:
             if (evt->data.lifecycle.action == kOnLoad_ANPLifecycleAction) {
                 gLogI.log(inst(), kDebug_ANPLogType, " ------ %p the plugin received an onLoad event", inst());
diff --git a/samples/BrowserPlugin/jni/background/BackgroundPlugin.h b/samples/BrowserPlugin/jni/background/BackgroundPlugin.h
index ed428b5..3b9c7ba 100644
--- a/samples/BrowserPlugin/jni/background/BackgroundPlugin.h
+++ b/samples/BrowserPlugin/jni/background/BackgroundPlugin.h
@@ -28,12 +28,16 @@
 #ifndef backgroundPlugin__DEFINED
 #define backgroundPlugin__DEFINED
 
-class BackgroundPlugin : public SubPlugin {
+class BackgroundPlugin : public SurfaceSubPlugin {
 public:
     BackgroundPlugin(NPP inst);
     virtual ~BackgroundPlugin();
     virtual bool supportsDrawingModel(ANPDrawingModel);
     virtual int16 handleEvent(const ANPEvent* evt);
+    virtual void surfaceCreated(JNIEnv* env, jobject surface);
+    virtual void surfaceChanged(int format, int width, int height);
+    virtual void surfaceDestroyed();
+    virtual bool isFixedSurface();
 
     // Timer Testing Variables
     uint32_t mStartTime;
@@ -50,8 +54,8 @@
 private:
     void drawPlugin(int surfaceWidth, int surfaceHeight);
 
-    bool        m_surfaceReady;
-    ANPSurface* m_surface;
+    jobject     m_surface;
+    JavaVM*     m_vm;
 
     void test_logging();
     void test_timers();
diff --git a/samples/BrowserPlugin/jni/jni-bridge.cpp b/samples/BrowserPlugin/jni/jni-bridge.cpp
new file mode 100644
index 0000000..45ecd54
--- /dev/null
+++ b/samples/BrowserPlugin/jni/jni-bridge.cpp
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * 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.
+ *
+ */
+#include <string.h>
+#include <jni.h>
+#include <JNIHelp.h>
+#include <utils/Log.h>
+
+#include "PluginObject.h"
+
+#define EXPORT __attribute__((visibility("default")))
+
+static SurfaceSubPlugin* getPluginObject(int npp) {
+    NPP instance = (NPP)npp;
+    PluginObject* obj = static_cast<PluginObject*>(instance->pdata);
+    if (obj && obj->activePlugin
+            && obj->activePlugin->supportsDrawingModel(kSurface_ANPDrawingModel)) {
+        return static_cast<SurfaceSubPlugin*>(obj->activePlugin);
+    }
+    return NULL;
+}
+
+static void surfaceCreated(JNIEnv* env, jobject thiz, jint npp, jobject surface) {
+    SurfaceSubPlugin* obj = getPluginObject(npp);
+
+    //TODO why is this VM different from the one in NP_INIT...
+    JavaVM* vm = NULL;
+    env->GetJavaVM(&vm);
+
+    obj->surfaceCreated(env, surface);
+}
+
+static void surfaceChanged(JNIEnv* env, jobject thiz, jint npp, jint format, jint width, jint height) {
+    SurfaceSubPlugin* obj = getPluginObject(npp);
+    obj->surfaceChanged(format, width, height);
+}
+
+static void surfaceDestroyed(JNIEnv* env, jobject thiz, jint npp) {
+    SurfaceSubPlugin* obj = getPluginObject(npp);
+    if (obj) {
+        obj->surfaceDestroyed();
+    }
+}
+
+static jboolean isFixedSurface(JNIEnv* env, jobject thiz, jint npp) {
+    SurfaceSubPlugin* obj = getPluginObject(npp);
+    return obj->isFixedSurface();
+}
+
+/*
+ * JNI registration.
+ */
+static JNINativeMethod gJavaSamplePluginStubMethods[] = {
+    { "nativeSurfaceCreated", "(ILandroid/view/View;)V", (void*) surfaceCreated },
+    { "nativeSurfaceChanged", "(IIII)V", (void*) surfaceChanged },
+    { "nativeSurfaceDestroyed", "(I)V", (void*) surfaceDestroyed },
+    { "nativeIsFixedSurface", "(I)Z", (void*) isFixedSurface },
+};
+
+EXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) {
+
+    JNIEnv* env = NULL;
+
+    if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
+        return -1;
+    }
+
+    jniRegisterNativeMethods(env, "com/android/sampleplugin/SamplePluginStub",
+                             gJavaSamplePluginStubMethods, NELEM(gJavaSamplePluginStubMethods));
+
+    return JNI_VERSION_1_4;
+}
diff --git a/samples/BrowserPlugin/jni/main.cpp b/samples/BrowserPlugin/jni/main.cpp
index b5aea95..7f7496b 100644
--- a/samples/BrowserPlugin/jni/main.cpp
+++ b/samples/BrowserPlugin/jni/main.cpp
@@ -33,7 +33,6 @@
 #include "BackgroundPlugin.h"
 #include "FormPlugin.h"
 #include "PaintPlugin.h"
-#include "android_npapi.h"
 
 NPNetscapeFuncs* browser;
 #define EXPORT __attribute__((visibility("default")))
@@ -173,6 +172,15 @@
         }
     }
 
+    // notify the plugin API of the location of the java interface
+    char* className = "com.android.sampleplugin.SamplePluginStub";
+    NPError npErr = browser->setvalue(instance, kSetJavaClassName_ANPSetValue,
+                                reinterpret_cast<void*>(className));
+    if (npErr) {
+        gLogI.log(instance, kError_ANPLogType, "set class err %d", npErr);
+        return npErr;
+    }
+
     // notify the plugin API of the drawing model we wish to use. This must be
     // done prior to creating certain subPlugin objects (e.g. surfaceViews)
     NPError err = browser->setvalue(instance, kRequestDrawingModel_ANPSetValue,
diff --git a/samples/BrowserPlugin/jni/main.h b/samples/BrowserPlugin/jni/main.h
index 4532911..8ad2cce 100644
--- a/samples/BrowserPlugin/jni/main.h
+++ b/samples/BrowserPlugin/jni/main.h
@@ -27,5 +27,6 @@
 #include <npfunctions.h>
 #include <npruntime.h>
 #include "android_npapi.h"
+#include "ANPSurface_npapi.h"
 
 extern NPNetscapeFuncs* browser;
diff --git a/samples/BrowserPlugin/jni/paint/PaintPlugin.cpp b/samples/BrowserPlugin/jni/paint/PaintPlugin.cpp
index a34870f..5b00dba 100644
--- a/samples/BrowserPlugin/jni/paint/PaintPlugin.cpp
+++ b/samples/BrowserPlugin/jni/paint/PaintPlugin.cpp
@@ -39,7 +39,7 @@
 
 ///////////////////////////////////////////////////////////////////////////////
 
-PaintPlugin::PaintPlugin(NPP inst) : SubPlugin(inst) {
+PaintPlugin::PaintPlugin(NPP inst) : SurfaceSubPlugin(inst) {
 
     m_isTouchActive = false;
     m_isTouchCurrentInput = true;
@@ -51,10 +51,8 @@
     memset(&m_clearSurface,  0, sizeof(m_clearSurface));
 
     // initialize the drawing surface
-    m_surfaceReady = false;
-    m_surface = gSurfaceI.newRasterSurface(inst, kRGBA_8888_ANPBitmapFormat, true);
-    if(!m_surface)
-        gLogI.log(inst, kError_ANPLogType, "----%p Unable to create RGBA surface", inst);
+    m_surface = NULL;
+    m_vm = NULL;
 
     // initialize the path
     m_touchPath = gPathI.newPath();
@@ -85,10 +83,10 @@
 }
 
 PaintPlugin::~PaintPlugin() {
-    gSurfaceI.deleteSurface(m_surface);
     gPathI.deletePath(m_touchPath);
     gPaintI.deletePaint(m_paintSurface);
     gPaintI.deletePaint(m_paintButton);
+    surfaceDestroyed();
 }
 
 bool PaintPlugin::supportsDrawingModel(ANPDrawingModel model) {
@@ -98,8 +96,11 @@
 ANPCanvas* PaintPlugin::getCanvas(ANPRectI* dirtyRect) {
 
     ANPBitmap bitmap;
-    if (!m_surfaceReady || !gSurfaceI.lock(m_surface, &bitmap, dirtyRect))
-        return NULL;
+    JNIEnv* env = NULL;
+    if (!m_surface || m_vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK ||
+        !gSurfaceI.lock(env, m_surface, &bitmap, dirtyRect)) {
+            return NULL;
+        }
 
     ANPCanvas* canvas = gCanvasI.newCanvas(&bitmap);
 
@@ -130,7 +131,10 @@
 }
 
 void PaintPlugin::releaseCanvas(ANPCanvas* canvas) {
-    gSurfaceI.unlock(m_surface);
+    JNIEnv* env = NULL;
+    if (m_surface && m_vm->GetEnv((void**) &env, JNI_VERSION_1_4) == JNI_OK) {
+        gSurfaceI.unlock(env, m_surface);
+    }
     gCanvasI.deleteCanvas(canvas);
 }
 
@@ -208,33 +212,37 @@
         return "Red";
 }
 
+bool PaintPlugin::isFixedSurface() {
+    return true;
+}
+
+void PaintPlugin::surfaceCreated(JNIEnv* env, jobject surface) {
+    env->GetJavaVM(&m_vm);
+    m_surface = env->NewGlobalRef(surface);
+    drawCleanPlugin();
+}
+
+void PaintPlugin::surfaceChanged(int format, int width, int height) {
+    // get the plugin's dimensions according to the DOM
+    PluginObject *obj = (PluginObject*) inst()->pdata;
+    const int pW = obj->window->width;
+    const int pH = obj->window->height;
+    // compare to the plugin's surface dimensions
+    if (pW != width || pH != height)
+        gLogI.log(inst(), kError_ANPLogType,
+                  "----%p Invalid Surface Dimensions (%d,%d):(%d,%d)",
+                  inst(), pW, pH, width, height);
+}
+void PaintPlugin::surfaceDestroyed() {
+    JNIEnv* env = NULL;
+    if (m_surface && m_vm->GetEnv((void**) &env, JNI_VERSION_1_4) == JNI_OK) {
+        env->DeleteGlobalRef(m_surface);
+        m_surface = NULL;
+    }
+}
+
 int16 PaintPlugin::handleEvent(const ANPEvent* evt) {
     switch (evt->eventType) {
-        case kSurface_ANPEventType:
-            switch (evt->data.surface.action) {
-                case kCreated_ANPSurfaceAction:
-                    m_surfaceReady = true;
-                    drawCleanPlugin();
-                    return 1;
-                case kDestroyed_ANPSurfaceAction:
-                    m_surfaceReady = false;
-                    return 1;
-                case kChanged_ANPSurfaceAction:
-                    // get the plugin's dimensions according to the DOM
-                    PluginObject *obj = (PluginObject*) inst()->pdata;
-                    const int pW = obj->window->width;
-                    const int pH = obj->window->height;
-                    // get the plugin's surface dimensions
-                    const int sW = evt->data.surface.data.changed.width;
-                    const int sH = evt->data.surface.data.changed.height;
-                    if (pW != sW || pH != sH)
-                        gLogI.log(inst(), kError_ANPLogType,
-                                  "----%p Invalid Surface Dimensions (%d,%d):(%d,%d)",
-                                  inst(), pW, pH, sW, sH);
-                    return 1;
-            }
-            break;
-
         case kTouch_ANPEventType: {
             float x = (float) evt->data.touch.x;
             float y = (float) evt->data.touch.y;
diff --git a/samples/BrowserPlugin/jni/paint/PaintPlugin.h b/samples/BrowserPlugin/jni/paint/PaintPlugin.h
index 7e6f235..8ff561c 100644
--- a/samples/BrowserPlugin/jni/paint/PaintPlugin.h
+++ b/samples/BrowserPlugin/jni/paint/PaintPlugin.h
@@ -29,12 +29,17 @@
 #ifndef paintPlugin__DEFINED
 #define paintPlugin__DEFINED
 
-class PaintPlugin : public SubPlugin {
+class PaintPlugin : public SurfaceSubPlugin {
 public:
     PaintPlugin(NPP inst);
     virtual ~PaintPlugin();
     virtual bool supportsDrawingModel(ANPDrawingModel);
     virtual int16 handleEvent(const ANPEvent* evt);
+    virtual void surfaceCreated(JNIEnv* env, jobject surface);
+    virtual void surfaceChanged(int format, int width, int height);
+    virtual void surfaceDestroyed();
+    virtual bool isFixedSurface();
+
 private:
     void        drawCleanPlugin(ANPCanvas* canvas = NULL);
     ANPCanvas*  getCanvas(ANPRectI* dirtyRect = NULL);
@@ -49,9 +54,9 @@
 
     bool        m_isTouchActive;
     bool        m_isTouchCurrentInput;
-    bool        m_surfaceReady;
 
-    ANPSurface* m_surface;
+    JavaVM*     m_vm;
+    jobject     m_surface;
     ANPPath*    m_touchPath;
 
     ANPRectF    m_drawingSurface;
diff --git a/samples/BrowserPlugin/src/com/android/sampleplugin/SamplePluginStub.java b/samples/BrowserPlugin/src/com/android/sampleplugin/SamplePluginStub.java
index 0b474a4..3c0a0c7 100644
--- a/samples/BrowserPlugin/src/com/android/sampleplugin/SamplePluginStub.java
+++ b/samples/BrowserPlugin/src/com/android/sampleplugin/SamplePluginStub.java
@@ -19,8 +19,11 @@
 import android.content.Context;
 import android.graphics.PixelFormat;
 import android.opengl.GLSurfaceView;
+import android.view.SurfaceHolder;
+import android.view.SurfaceView;
 import android.view.View;
 import android.view.WindowManager;
+import android.view.SurfaceHolder.Callback;
 import android.view.ViewGroup.LayoutParams;
 import android.webkit.PluginStub;
 import android.widget.FrameLayout;
@@ -28,29 +31,53 @@
 import android.widget.VideoView;
 import com.android.sampleplugin.graphics.CubeRenderer;
 
-public class SamplePluginStub extends PluginStub {
+public class SamplePluginStub implements PluginStub {
 
-    private int npp; 
-    
-    public SamplePluginStub(int npp) { 
-        super(npp);
-        this.npp = npp;
-    }
-
-    public View getEmbeddedView(Context context) {
-        // TODO Auto-generated method stub
-        return null;
+    static {
+        //needed for jni calls
+        System.loadLibrary("sampleplugin");
     }
     
-    public View getFullScreenView(Context context) {
+    public View getEmbeddedView(final int npp, Context context) {
+        
+        final SurfaceView view = new SurfaceView(context);
+
+        /* You can do all sorts of interesting operations on the surface view
+         * here. We illustrate a few of the important operations below.
+         */
+        
+        //TODO get pixel format from the subplugin (via jni)
+        view.getHolder().setFormat(PixelFormat.RGBA_8888);
+        view.getHolder().addCallback(new Callback() {
+
+            public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
+                nativeSurfaceChanged(npp, format, width, height);
+            }
+
+            public void surfaceCreated(SurfaceHolder holder) {
+                nativeSurfaceCreated(npp, view);
+            }
+
+            public void surfaceDestroyed(SurfaceHolder holder) {
+                nativeSurfaceDestroyed(npp);
+            }
+            
+        });
+        
+        if (nativeIsFixedSurface(npp)) {
+            //TODO get the fixed dimensions from the plugin 
+            //view.getHolder().setFixedSize(width, height);
+        }
+        
+        return view;
+    }
+    
+    public View getFullScreenView(int npp, Context context) {
         
         /* TODO make this aware of the plugin instance and get the video file
          * from the plugin.
          */
         
-        //needed for jni calls
-        System.loadLibrary("sampleplugin");
-        
         FrameLayout layout = new FrameLayout(context);
         LayoutParams fp = new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT);
         layout.setLayoutParams(fp);
@@ -84,6 +111,8 @@
         return layout;
     }
     
-    public native String  nativeStringFromJNI();
-
+    private native void nativeSurfaceCreated(int npp, View surfaceView);
+    private native void nativeSurfaceChanged(int npp, int format, int width, int height);
+    private native void nativeSurfaceDestroyed(int npp);
+    private native boolean nativeIsFixedSurface(int npp);
 }