Bug 769269 - Update the graphics code to be able to deal with blowing away the layer controller, client, and view and creating them afresh. r=ajuma
authorKartikaya Gupta <kgupta@mozilla.com>
Fri, 13 Jul 2012 10:19:46 -0400
changeset 101908 1dd671e62713e98043e87a4686759c66f255a4d6
parent 101907 3ce3068cb1dfa6d21bc623e69c40aa8762e4a667
child 101909 88dd29d90c52fa37354bbe30bff57b49986c74c5
push idunknown
push userunknown
push dateunknown
reviewersajuma
bugs769269
milestone16.0a1
Bug 769269 - Update the graphics code to be able to deal with blowing away the layer controller, client, and view and creating them afresh. r=ajuma
mobile/android/base/gfx/GLController.java
mobile/android/base/gfx/LayerView.java
mobile/android/chrome/content/browser.js
widget/android/AndroidBridge.cpp
widget/android/AndroidBridge.h
widget/android/AndroidJNI.cpp
widget/android/AndroidLayerViewWrapper.cpp
widget/android/AndroidLayerViewWrapper.h
--- a/mobile/android/base/gfx/GLController.java
+++ b/mobile/android/base/gfx/GLController.java
@@ -71,18 +71,25 @@ public class GLController {
         }
 
         mEGLDisplay = null;
         mEGLConfig = null;
         mEGLSurface = null;
         return true;
     }
 
+    // This function is invoked by JNI
+    public synchronized void resumeCompositorIfValid() {
+        if (mSurfaceValid) {
+            mView.getListener().compositionResumeRequested(mWidth, mHeight);
+        }
+    }
+
     // Wait until we are allowed to use EGL functions on the Surface backing
-    // this window.
+    // this window. This function is invoked by JNI
     public synchronized void waitForValidSurface() {
         while (!mSurfaceValid) {
             try {
                 wait();
             } catch (InterruptedException e) {
                 throw new RuntimeException(e);
             }
         }
--- a/mobile/android/base/gfx/LayerView.java
+++ b/mobile/android/base/gfx/LayerView.java
@@ -199,16 +199,20 @@ public class LayerView extends SurfaceVi
     public LayerRenderer getRenderer() {
         return mRenderer;
     }
 
     public void setListener(Listener listener) {
         mListener = listener;
     }
 
+    Listener getListener() {
+        return mListener;
+    }
+
     public GLController getGLController() {
         return mGLController;
     }
 
     /** Implementation of SurfaceHolder.Callback */
     public synchronized void surfaceChanged(SurfaceHolder holder, int format, int width,
                                             int height) {
         mGLController.surfaceChanged(width, height);
--- a/mobile/android/chrome/content/browser.js
+++ b/mobile/android/chrome/content/browser.js
@@ -4438,16 +4438,18 @@ var ViewportHandler = {
     }
   },
 
   observe: function(aSubject, aTopic, aData) {
     switch (aTopic) {
       case "Window:Resize":
         if (window.outerWidth == gScreenWidth && window.outerHeight == gScreenHeight)
           break;
+        if (window.outerWidth == 0 || window.outerHeight == 0)
+          break;
 
         let oldScreenWidth = gScreenWidth;
         gScreenWidth = window.outerWidth;
         gScreenHeight = window.outerHeight;
         let tabs = BrowserApp.tabs;
         for (let i = 0; i < tabs.length; i++)
           tabs[i].updateViewportSize(oldScreenWidth);
         break;
--- a/widget/android/AndroidBridge.cpp
+++ b/widget/android/AndroidBridge.cpp
@@ -1103,21 +1103,38 @@ AndroidBridge::GetShowPasswordSetting()
 
 void
 AndroidBridge::SetSurfaceView(jobject obj)
 {
     mSurfaceView.Init(obj);
 }
 
 void
-AndroidBridge::SetLayerClient(jobject obj)
+AndroidBridge::SetLayerClient(JNIEnv* env, jobject jobj)
 {
+    // if resetting is true, that means Android destroyed our GeckoApp activity
+    // and we had to recreate it, but all the Gecko-side things were not destroyed.
+    // We therefore need to link up the new java objects to Gecko, and that's what
+    // we do here.
+    bool resetting = (mLayerClient != NULL);
+
+    if (resetting) {
+        // clear out the old layer client
+        env->DeleteGlobalRef(mLayerClient->wrappedObject());
+        delete mLayerClient;
+        mLayerClient = NULL;
+    }
+
     AndroidGeckoLayerClient *client = new AndroidGeckoLayerClient();
-    client->Init(obj);
+    client->Init(env->NewGlobalRef(jobj));
     mLayerClient = client;
+
+    if (resetting) {
+        RegisterCompositor(env, true);
+    }
 }
 
 void
 AndroidBridge::ShowInputMethodPicker()
 {
     ALOG_BRIDGE("AndroidBridge::ShowInputMethodPicker");
 
     JNIEnv *env = GetJNIEnv();
@@ -1178,33 +1195,38 @@ AndroidBridge::CallEglCreateWindowSurfac
     jint realSurface = env->GetIntField(surf, sfield);
 
     return (void*) realSurface;
 }
 
 static AndroidGLController sController;
 
 void
-AndroidBridge::RegisterCompositor()
+AndroidBridge::RegisterCompositor(JNIEnv *env, bool resetting)
 {
     ALOG_BRIDGE("AndroidBridge::RegisterCompositor");
-    JNIEnv *env = GetJNIForCompositorThread();
+    if (!env)
+        env = GetJNIForCompositorThread();
     if (!env)
         return;
 
     AutoLocalJNIFrame jniFrame(env);
 
     jmethodID registerCompositor = env->GetStaticMethodID(jLayerView, "registerCxxCompositor", "()Lorg/mozilla/gecko/gfx/GLController;");
 
     jobject glController = env->CallStaticObjectMethod(jLayerView, registerCompositor);
     if (jniFrame.CheckForException())
         return;
 
-    sController.Acquire(env, glController);
-    sController.SetGLVersion(2);
+    if (resetting) {
+        sController.Reacquire(env, glController);
+    } else {
+        sController.Acquire(env, glController);
+        sController.SetGLVersion(2);
+    }
 }
 
 EGLSurface
 AndroidBridge::ProvideEGLSurface()
 {
     sController.WaitForValidSurface();
     return sController.ProvideEGLSurface();
 }
--- a/widget/android/AndroidBridge.h
+++ b/widget/android/AndroidBridge.h
@@ -211,17 +211,17 @@ public:
     void DisableSensor(int aSensorType);
 
     void ReturnIMEQueryResult(const PRUnichar *aResult, PRUint32 aLen, int aSelStart, int aSelLen);
 
     void NotifyXreExit();
 
     void ScheduleRestart();
 
-    void SetLayerClient(jobject jobj);
+    void SetLayerClient(JNIEnv* env, jobject jobj);
     AndroidGeckoLayerClient &GetLayerClient() { return *mLayerClient; }
 
     void SetSurfaceView(jobject jobj);
     AndroidGeckoSurfaceView& SurfaceView() { return mSurfaceView; }
 
     bool GetHandlersForURL(const char *aURL, 
                              nsIMutableArray* handlersArray = nsnull,
                              nsIHandlerApp **aDefaultApp = nsnull,
@@ -297,17 +297,17 @@ public:
     bool GetShowPasswordSetting();
 
     void FireAndWaitForTracerEvent();
 
     /* See GLHelpers.java as to why this is needed */
     void *CallEglCreateWindowSurface(void *dpy, void *config, AndroidGeckoSurfaceView& surfaceView);
 
     // Switch Java to composite with the Gecko Compositor thread
-    void RegisterCompositor();
+    void RegisterCompositor(JNIEnv* env = NULL, bool resetting = false);
     EGLSurface ProvideEGLSurface();
 
     bool GetStaticStringField(const char *classID, const char *field, nsAString &result, JNIEnv* env = nsnull);
 
     bool GetStaticIntField(const char *className, const char *fieldName, PRInt32* aInt, JNIEnv* env = nsnull);
 
     void SetKeepScreenOn(bool on);
 
--- a/widget/android/AndroidJNI.cpp
+++ b/widget/android/AndroidJNI.cpp
@@ -75,17 +75,17 @@ NS_EXPORT void JNICALL
 Java_org_mozilla_gecko_GeckoAppShell_setSurfaceView(JNIEnv *jenv, jclass, jobject obj)
 {
     AndroidBridge::Bridge()->SetSurfaceView(jenv->NewGlobalRef(obj));
 }
 
 NS_EXPORT void JNICALL
 Java_org_mozilla_gecko_GeckoAppShell_setLayerClient(JNIEnv *jenv, jclass, jobject obj)
 {
-    AndroidBridge::Bridge()->SetLayerClient(jenv->NewGlobalRef(obj));
+    AndroidBridge::Bridge()->SetLayerClient(jenv, obj);
 }
 
 NS_EXPORT void JNICALL
 Java_org_mozilla_gecko_GeckoAppShell_onLowMemory(JNIEnv *jenv, jclass jc)
 {
     if (nsAppShell::gAppShell) {
         nsAppShell::gAppShell->NotifyObservers(nsnull,
                                                "memory-pressure",
--- a/widget/android/AndroidLayerViewWrapper.cpp
+++ b/widget/android/AndroidLayerViewWrapper.cpp
@@ -19,25 +19,27 @@ void AndroidEGLObject::Init(JNIEnv* aJEn
     jClass = reinterpret_cast<jclass>
         (aJEnv->NewGlobalRef(aJEnv->FindClass("com/google/android/gles_jni/EGLSurfaceImpl")));
     jEGLSurfacePointerField = aJEnv->GetFieldID(jClass, "mEGLSurface", "I");
 }
 
 jmethodID AndroidGLController::jSetGLVersionMethod = 0;
 jmethodID AndroidGLController::jWaitForValidSurfaceMethod = 0;
 jmethodID AndroidGLController::jProvideEGLSurfaceMethod = 0;
+jmethodID AndroidGLController::jResumeCompositorIfValidMethod = 0;
 
 void
 AndroidGLController::Init(JNIEnv* aJEnv)
 {
     jclass jClass = reinterpret_cast<jclass>(aJEnv->NewGlobalRef(aJEnv->FindClass("org/mozilla/gecko/gfx/GLController")));
 
     jSetGLVersionMethod = aJEnv->GetMethodID(jClass, "setGLVersion", "(I)V");
     jProvideEGLSurfaceMethod = aJEnv->GetMethodID(jClass, "provideEGLSurface",
                                                   "()Ljavax/microedition/khronos/egl/EGLSurface;");
+    jResumeCompositorIfValidMethod = aJEnv->GetMethodID(jClass, "resumeCompositorIfValid", "()V");
     jWaitForValidSurfaceMethod = aJEnv->GetMethodID(jClass, "waitForValidSurface", "()V");
 }
 
 void
 AndroidGLController::Acquire(JNIEnv* aJEnv, jobject aJObj)
 {
     mJEnv = aJEnv;
     mThread = pthread_self();
@@ -47,16 +49,26 @@ AndroidGLController::Acquire(JNIEnv* aJE
 void
 AndroidGLController::SetGLVersion(int aVersion)
 {
     ASSERT_THREAD();
     AutoLocalJNIFrame jniFrame(mJEnv, 0);
     mJEnv->CallVoidMethod(mJObj, jSetGLVersionMethod, aVersion);
 }
 
+void
+AndroidGLController::Reacquire(JNIEnv *aJEnv, jobject aJObj)
+{
+    aJEnv->DeleteGlobalRef(mJObj);
+    mJObj = aJEnv->NewGlobalRef(aJObj);
+
+    AutoLocalJNIFrame jniFrame(aJEnv, 0);
+    aJEnv->CallVoidMethod(mJObj, jResumeCompositorIfValidMethod);
+}
+
 EGLSurface
 AndroidGLController::ProvideEGLSurface()
 {
     ASSERT_THREAD();
     AutoLocalJNIFrame jniFrame(mJEnv);
     jobject jObj = mJEnv->CallObjectMethod(mJObj, jProvideEGLSurfaceMethod);
     if (jniFrame.CheckForException())
         return NULL;
--- a/widget/android/AndroidLayerViewWrapper.h
+++ b/widget/android/AndroidLayerViewWrapper.h
@@ -17,23 +17,25 @@ public:
 typedef void* EGLSurface;
 
 class AndroidGLController {
 public:
     static void Init(JNIEnv* aJEnv);
 
     void Acquire(JNIEnv* aJEnv, jobject aJObj);
     void SetGLVersion(int aVersion);
+    void Reacquire(JNIEnv* aJEnv, jobject aJObj);
     EGLSurface ProvideEGLSurface();
     void WaitForValidSurface();
 
 private:
     static jmethodID jSetGLVersionMethod;
     static jmethodID jWaitForValidSurfaceMethod;
     static jmethodID jProvideEGLSurfaceMethod;
+    static jmethodID jResumeCompositorIfValidMethod;
 
     // the JNIEnv for the compositor thread
     JNIEnv* mJEnv;
     pthread_t mThread;
     jobject mJObj;
 };
 
 #endif