Bug 1209574 - Switch GeckoInputConnection for each new GeckoView; r=esawin
authorJim Chen <nchen@mozilla.com>
Thu, 08 Oct 2015 15:25:49 -0400
changeset 266985 d68116719755ae6f51be5198ae2a91916741f7cd
parent 266984 64460d7a57db2fbdb05213ddbb538636adcb0637
child 266986 39ccbc9935c23400d960223012dbcf846008a810
push id29504
push usercbook@mozilla.com
push dateFri, 09 Oct 2015 09:43:23 +0000
treeherdermozilla-central@d01dd42e654b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersesawin
bugs1209574
milestone44.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1209574 - Switch GeckoInputConnection for each new GeckoView; r=esawin The GeckoEditable instance doesn't change for each nsWindow instance. However, because a GeckoInputConnection is associated with a GeckoView, when we create a new GeckoView, we need to attach a new GeckoInputConnection to the existing nsWindow's GeckoEditable. This patch makes us do that inside nsWindow::Natives::Open by calling GeckoEditable.OnViewChange.
mobile/android/base/GeckoEditable.java
mobile/android/base/GeckoView.java
widget/android/GeneratedJNIWrappers.cpp
widget/android/GeneratedJNIWrappers.h
widget/android/nsWindow.cpp
--- a/mobile/android/base/GeckoEditable.java
+++ b/mobile/android/base/GeckoEditable.java
@@ -361,20 +361,49 @@ final class GeckoEditable
         mText = new SpannableStringBuilder();
         mChangedText = new SpannableStringBuilder();
 
         final Class<?>[] PROXY_INTERFACES = { Editable.class };
         mProxy = (Editable)Proxy.newProxyInstance(
                 Editable.class.getClassLoader(),
                 PROXY_INTERFACES, this);
 
-        LayerView v = GeckoAppShell.getLayerView();
-        mListener = GeckoInputConnection.create(v, this);
+        mIcRunHandler = mIcPostHandler = ThreadUtils.getUiHandler();
+    }
+
+    @WrapForJNI
+    /* package */ void onViewChange(final GeckoView v) {
+        if (DEBUG) {
+            // Called by nsWindow.
+            ThreadUtils.assertOnGeckoThread();
+            Log.d(LOGTAG, "onViewChange(" + v + ")");
+        }
 
-        mIcRunHandler = mIcPostHandler = ThreadUtils.getUiHandler();
+        final GeckoEditableListener newListener = GeckoInputConnection.create(v, this);
+        geckoPostToIc(new Runnable() {
+            @Override
+            public void run() {
+                if (DEBUG) {
+                    Log.d(LOGTAG, "onViewChange (set listener)");
+                }
+                // Make sure there are no other things going on
+                mActionQueue.syncWithGecko();
+                mListener = newListener;
+            }
+        });
+
+        ThreadUtils.postToUiThread(new Runnable() {
+            @Override
+            public void run() {
+                if (DEBUG) {
+                    Log.d(LOGTAG, "onViewChange (set IC)");
+                }
+                v.setInputConnectionListener((InputConnectionListener) newListener);
+            }
+        });
     }
 
     private boolean onIcThread() {
         return mIcRunHandler.getLooper() == Looper.myLooper();
     }
 
     private void assertOnIcThread() {
         ThreadUtils.assertOnThread(mIcRunHandler.getLooper().getThread(), AssertBehavior.THROW);
@@ -858,27 +887,17 @@ final class GeckoEditable
             ThreadUtils.assertOnGeckoThread();
             Log.d(LOGTAG, "notifyIMEContext(" +
                           getConstantName(GeckoEditableListener.class, "IME_STATE_", state) +
                           ", \"" + typeHint + "\", \"" + modeHint + "\", \"" + actionHint + "\")");
         }
         geckoPostToIc(new Runnable() {
             @Override
             public void run() {
-                // Make sure there are no other things going on
-                mActionQueue.syncWithGecko();
-                // Set InputConnectionHandler in notifyIMEContext because
-                // GeckoInputConnection.notifyIMEContext calls restartInput() which will invoke
-                // InputConnectionHandler.onCreateInputConnection
-                GeckoView v = (GeckoView) GeckoAppShell.getLayerView();
-                if (v != null) {
-                    mListener = GeckoInputConnection.create(v, GeckoEditable.this);
-                    v.setInputConnectionListener((InputConnectionListener) mListener);
-                    mListener.notifyIMEContext(state, typeHint, modeHint, actionHint);
-                }
+                mListener.notifyIMEContext(state, typeHint, modeHint, actionHint);
             }
         });
     }
 
     @WrapForJNI @Override
     public void onSelectionChange(final int start, final int end) {
         if (DEBUG) {
             // GeckoEditableListener methods should all be called from the Gecko thread
--- a/mobile/android/base/GeckoView.java
+++ b/mobile/android/base/GeckoView.java
@@ -110,17 +110,17 @@ public class GeckoView extends LayerView
             } catch (Exception e) {
                 Log.w(LOGTAG, "handleMessage threw for " + event, e);
             }
         }
     };
 
     @WrapForJNI
     private static final class Window extends JNIObject {
-        static native void open(Window instance, int width, int height);
+        static native void open(Window instance, GeckoView view, int width, int height);
         static native void setLayerClient(Object client);
         @Override protected native void disposeNative();
     }
 
     private final Window window = new Window();
 
     public GeckoView(Context context) {
         super(context);
@@ -220,20 +220,21 @@ public class GeckoView extends LayerView
     @Override
     public void onAttachedToWindow()
     {
         super.onAttachedToWindow();
 
         final DisplayMetrics metrics = getContext().getResources().getDisplayMetrics();
 
         if (GeckoThread.isStateAtLeast(GeckoThread.State.PROFILE_READY)) {
-            Window.open(window, metrics.widthPixels, metrics.heightPixels);
+            Window.open(window, this, metrics.widthPixels, metrics.heightPixels);
         } else {
             GeckoThread.queueNativeCallUntil(GeckoThread.State.PROFILE_READY, Window.class,
-                    "open", window, metrics.widthPixels, metrics.heightPixels);
+                    "open", window, GeckoView.class, this,
+                    metrics.widthPixels, metrics.heightPixels);
         }
     }
 
     @Override
     public void onDetachedFromWindow()
     {
         super.onDetachedFromWindow();
         window.disposeNative();
--- a/widget/android/GeneratedJNIWrappers.cpp
+++ b/widget/android/GeneratedJNIWrappers.cpp
@@ -755,16 +755,24 @@ auto GeckoEditable::OnSelectionChange(in
 constexpr char GeckoEditable::OnTextChange_t::name[];
 constexpr char GeckoEditable::OnTextChange_t::signature[];
 
 auto GeckoEditable::OnTextChange(mozilla::jni::String::Param a0, int32_t a1, int32_t a2, int32_t a3) const -> void
 {
     return mozilla::jni::Method<OnTextChange_t>::Call(this, nullptr, a0, a1, a2, a3);
 }
 
+constexpr char GeckoEditable::OnViewChange_t::name[];
+constexpr char GeckoEditable::OnViewChange_t::signature[];
+
+auto GeckoEditable::OnViewChange(mozilla::jni::Object::Param a0) const -> void
+{
+    return mozilla::jni::Method<OnViewChange_t>::Call(this, nullptr, a0);
+}
+
 constexpr char GeckoEditableListener::name[];
 
 constexpr char GeckoJavaSampler::name[];
 
 constexpr char GeckoJavaSampler::GetFrameNameJavaProfilingWrapper_t::name[];
 constexpr char GeckoJavaSampler::GetFrameNameJavaProfilingWrapper_t::signature[];
 
 auto GeckoJavaSampler::GetFrameNameJavaProfilingWrapper(int32_t a0, int32_t a1, int32_t a2) -> mozilla::jni::String::LocalRef
--- a/widget/android/GeneratedJNIWrappers.h
+++ b/widget/android/GeneratedJNIWrappers.h
@@ -1809,16 +1809,34 @@ public:
         static const bool isStatic = false;
         static const bool isMultithreaded = false;
         static const mozilla::jni::ExceptionMode exceptionMode =
                 mozilla::jni::ExceptionMode::ABORT;
     };
 
     auto OnTextChange(mozilla::jni::String::Param, int32_t, int32_t, int32_t) const -> void;
 
+public:
+    struct OnViewChange_t {
+        typedef GeckoEditable Owner;
+        typedef void ReturnType;
+        typedef void SetterType;
+        typedef mozilla::jni::Args<
+                mozilla::jni::Object::Param> Args;
+        static constexpr char name[] = "onViewChange";
+        static constexpr char signature[] =
+                "(Lorg/mozilla/gecko/GeckoView;)V";
+        static const bool isStatic = false;
+        static const bool isMultithreaded = false;
+        static const mozilla::jni::ExceptionMode exceptionMode =
+                mozilla::jni::ExceptionMode::ABORT;
+    };
+
+    auto OnViewChange(mozilla::jni::Object::Param) const -> void;
+
 };
 
 class GeckoEditableListener : public mozilla::jni::Class<GeckoEditableListener>
 {
 public:
     typedef mozilla::jni::Ref<GeckoEditableListener> Ref;
     typedef mozilla::jni::LocalRef<GeckoEditableListener> LocalRef;
     typedef mozilla::jni::GlobalRef<GeckoEditableListener> GlobalRef;
@@ -2718,21 +2736,22 @@ public:
 
 public:
     struct Open_t {
         typedef Window Owner;
         typedef void ReturnType;
         typedef void SetterType;
         typedef mozilla::jni::Args<
                 Window::Param,
+                GeckoView::Param,
                 int32_t,
                 int32_t> Args;
         static constexpr char name[] = "open";
         static constexpr char signature[] =
-                "(Lorg/mozilla/gecko/GeckoView$Window;II)V";
+                "(Lorg/mozilla/gecko/GeckoView$Window;Lorg/mozilla/gecko/GeckoView;II)V";
         static const bool isStatic = true;
         static const bool isMultithreaded = true;
         static const mozilla::jni::ExceptionMode exceptionMode =
                 mozilla::jni::ExceptionMode::ABORT;
     };
 
 public:
     struct SetLayerClient_t {
--- a/widget/android/nsWindow.cpp
+++ b/widget/android/nsWindow.cpp
@@ -181,40 +181,46 @@ public:
     Natives(nsWindow* w) : window(*w) {}
 
     // Detach and destroy the window that we created in Open().
     void DisposeNative(const GeckoView::Window::LocalRef& instance);
 
     // Create and attach a window.
     static void Open(const jni::ClassObject::LocalRef& cls,
                      GeckoView::Window::Param gvWindow,
+                     GeckoView::Param view,
                      int32_t width, int32_t height);
 
     // Set the active layer client object
     static void SetLayerClient(jni::Object::Param client)
     {
         MOZ_ASSERT(NS_IsMainThread());
         AndroidBridge::Bridge()->SetLayerClient(
                 widget::GeckoLayerClient::Ref::From(client.Get()));
     }
 };
 
 void
 nsWindow::Natives::Open(const jni::ClassObject::LocalRef& cls,
                         GeckoView::Window::Param gvWindow,
+                        GeckoView::Param view,
                         int32_t width, int32_t height)
 {
     MOZ_ASSERT(NS_IsMainThread());
 
     PROFILER_LABEL("nsWindow", "Natives::Open",
                    js::ProfileEntry::Category::OTHER);
 
     if (gGeckoViewWindow) {
         // Should have been created the first time.
         MOZ_ASSERT(gGeckoViewWindow->mNatives);
+
+        // Associate our previous GeckoEditable with the new GeckoView.
+        gGeckoViewWindow->mEditable->OnViewChange(view);
+
         AttachNative(GeckoView::Window::LocalRef(cls.Env(), gvWindow),
                      gGeckoViewWindow->mNatives.get());
         return;
     }
 
     nsCOMPtr<nsIWindowWatcher> ww = do_GetService(NS_WINDOWWATCHER_CONTRACTID);
     MOZ_ASSERT(ww);
 
@@ -247,16 +253,17 @@ nsWindow::Natives::Open(const jni::Class
     nsCOMPtr<nsIWidget> widget = WidgetUtils::DOMWindowToWidget(window);
     MOZ_ASSERT(widget);
 
     gGeckoViewWindow = static_cast<nsWindow*>(widget.get());
     gGeckoViewWindow->mNatives = mozilla::MakeUnique<Natives>(gGeckoViewWindow);
 
     // Create GeckoEditable for the new nsWindow/GeckoView pair.
     gGeckoViewWindow->mEditable = GeckoEditable::New();
+    gGeckoViewWindow->mEditable->OnViewChange(view);
 
     AttachNative(GeckoView::Window::LocalRef(cls.Env(), gvWindow),
                  gGeckoViewWindow->mNatives.get());
 }
 
 void
 nsWindow::Natives::DisposeNative(const GeckoView::Window::LocalRef& instance)
 {