Bug 1464096 - 6. Add TextInputDelegate support in GeckoSessionTestRule; r=me draft
authorJim Chen <nchen@mozilla.com>
Tue, 05 Jun 2018 17:49:01 -0400
changeset 804397 b0d6155e6a597ea5b4e99070f038a24bae17ed87
parent 804396 b8344ac27299449346821e0b359c34a469b59736
push id112368
push userbmo:nchen@mozilla.com
push dateTue, 05 Jun 2018 21:49:45 +0000
reviewersme
bugs1464096
milestone62.0a1
Bug 1464096 - 6. Add TextInputDelegate support in GeckoSessionTestRule; r=me Support TextInputDelegate for use in tests. MozReview-Commit-ID: DHnzKktsSOU
mobile/android/geckoview/src/androidTest/java/android/view/inputmethod/CursorAnchorInfo.java
mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/rule/GeckoSessionTestRule.java
mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/util/Callbacks.kt
new file mode 100644
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/java/android/view/inputmethod/CursorAnchorInfo.java
@@ -0,0 +1,15 @@
+/* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil; -*-
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+package android.view.inputmethod;
+
+/**
+ * This dummy class is used when running tests on Android versions prior to 21,
+ * when the CursorAnchorInfo class was first introduced. Without this class,
+ * tests will crash with ClassNotFoundException when the test rule uses reflection
+ * to access the TextInputDelegate interface.
+ */
+public class CursorAnchorInfo {
+}
--- a/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/rule/GeckoSessionTestRule.java
+++ b/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/rule/GeckoSessionTestRule.java
@@ -7,16 +7,17 @@ package org.mozilla.geckoview.test.rule;
 
 import org.mozilla.gecko.gfx.GeckoDisplay;
 import org.mozilla.geckoview.BuildConfig;
 import org.mozilla.geckoview.GeckoResponse;
 import org.mozilla.geckoview.GeckoRuntime;
 import org.mozilla.geckoview.GeckoRuntimeSettings;
 import org.mozilla.geckoview.GeckoSession;
 import org.mozilla.geckoview.GeckoSessionSettings;
+import org.mozilla.geckoview.SessionTextInput;
 import org.mozilla.geckoview.test.rdp.Actor;
 import org.mozilla.geckoview.test.rdp.Promise;
 import org.mozilla.geckoview.test.rdp.RDPConnection;
 import org.mozilla.geckoview.test.rdp.Tab;
 import org.mozilla.geckoview.test.util.Callbacks;
 
 import static org.hamcrest.Matchers.*;
 import static org.junit.Assert.assertThat;
@@ -988,24 +989,36 @@ public class GeckoSessionTestRule extend
      * Get the runtime set up for the current test.
      *
      * @return GeckoRuntime object.
      */
     public @NonNull GeckoRuntime getRuntime() {
         return sRuntime;
     }
 
-    protected static Method getCallbackSetter(final @NonNull Class<?> cls)
-            throws NoSuchMethodException {
-        return GeckoSession.class.getMethod("set" + cls.getSimpleName(), cls);
+    protected static Object setDelegate(final @NonNull Class<?> cls,
+                                        final @NonNull GeckoSession session,
+                                        final @Nullable Object delegate)
+            throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
+        if (cls == GeckoSession.TextInputDelegate.class) {
+            return SessionTextInput.class.getMethod("setDelegate",
+                                                    cls).invoke(session.getTextInput(), delegate);
+        }
+        return GeckoSession.class.getMethod("set" + cls.getSimpleName(),
+                                            cls).invoke(session, delegate);
     }
 
-    protected static Method getCallbackGetter(final @NonNull Class<?> cls)
-            throws NoSuchMethodException {
-        return GeckoSession.class.getMethod("get" + cls.getSimpleName());
+    protected static Object getDelegate(final @NonNull Class<?> cls,
+                                        final @NonNull GeckoSession session)
+            throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
+        if (cls == GeckoSession.TextInputDelegate.class) {
+            return SessionTextInput.class.getMethod("getDelegate")
+                                         .invoke(session.getTextInput());
+        }
+        return GeckoSession.class.getMethod("get" + cls.getSimpleName()).invoke(session);
     }
 
     @NonNull
     private Set<Class<?>> getCurrentDelegates() {
         final List<ExternalDelegate<?>> waitDelegates = mWaitScopeDelegates.getExternalDelegates();
         final List<ExternalDelegate<?>> testDelegates = mTestScopeDelegates.getExternalDelegates();
 
         if (waitDelegates.isEmpty() && testDelegates.isEmpty()) {
@@ -1242,18 +1255,17 @@ public class GeckoSessionTestRule extend
             }
         } else if (!mClosedSession) {
             openSession(mMainSession);
         }
     }
 
     protected void prepareSession(final GeckoSession session) throws Throwable {
         for (final Class<?> cls : DEFAULT_DELEGATES) {
-            getCallbackSetter(cls).invoke(
-                    session, mNullDelegates.contains(cls) ? null : mCallbackProxy);
+            setDelegate(cls, session, mNullDelegates.contains(cls) ? null : mCallbackProxy);
         }
     }
 
     /**
      * Call open() on a session, and ensure it's ready for use by the test. In particular,
      * remove any extra calls recorded as part of opening the session.
      *
      * @param session Session to open.
@@ -1644,17 +1656,17 @@ public class GeckoSessionTestRule extend
         }
 
         // Make sure all handlers are set though #delegateUntilTestEnd or #delegateDuringNextWait,
         // instead of through GeckoSession directly, so that we can still record calls even with
         // custom handlers set.
         for (final Class<?> ifce : DEFAULT_DELEGATES) {
             final Object callback;
             try {
-                callback = getCallbackGetter(ifce).invoke(session == null ? mMainSession : session);
+                callback = getDelegate(ifce, session == null ? mMainSession : session);
             } catch (final NoSuchMethodException | IllegalAccessException |
                     InvocationTargetException e) {
                 throw unwrapRuntimeException(e);
             }
             if (mNullDelegates.contains(ifce)) {
                 // Null-delegates are initially null but are allowed to be any value.
                 continue;
             }
--- a/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/util/Callbacks.kt
+++ b/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/util/Callbacks.kt
@@ -3,24 +3,26 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.geckoview.test.util
 
 import org.mozilla.geckoview.GeckoResponse
 import org.mozilla.geckoview.GeckoSession
 
+import android.view.inputmethod.CursorAnchorInfo
+import android.view.inputmethod.ExtractedText
+import android.view.inputmethod.ExtractedTextRequest
+
 class Callbacks private constructor() {
-    object Default : All {
-    }
+    object Default : All
 
     interface All : ContentDelegate, NavigationDelegate, PermissionDelegate, ProgressDelegate,
-                    PromptDelegate, ScrollDelegate, SelectionActionDelegate,
-                    TrackingProtectionDelegate {
-    }
+                    PromptDelegate, ScrollDelegate, SelectionActionDelegate, TextInputDelegate,
+                    TrackingProtectionDelegate
 
     interface ContentDelegate : GeckoSession.ContentDelegate {
         override fun onTitleChange(session: GeckoSession, title: String) {
         }
 
         override fun onFocusRequest(session: GeckoSession) {
         }
 
@@ -129,9 +131,29 @@ class Callbacks private constructor() {
 
     interface SelectionActionDelegate : GeckoSession.SelectionActionDelegate {
         override fun onShowActionRequest(session: GeckoSession, selection: GeckoSession.SelectionActionDelegate.Selection, actions: Array<out String>, response: GeckoResponse<String>) {
         }
 
         override fun onHideAction(session: GeckoSession, reason: Int) {
         }
     }
+
+    interface TextInputDelegate : GeckoSession.TextInputDelegate {
+        override fun restartInput(session: GeckoSession, reason: Int) {
+        }
+
+        override fun showSoftInput(session: GeckoSession) {
+        }
+
+        override fun hideSoftInput(session: GeckoSession) {
+        }
+
+        override fun updateSelection(session: GeckoSession, selStart: Int, selEnd: Int, compositionStart: Int, compositionEnd: Int) {
+        }
+
+        override fun updateExtractedText(session: GeckoSession, request: ExtractedTextRequest, text: ExtractedText) {
+        }
+
+        override fun updateCursorAnchorInfo(session: GeckoSession, info: CursorAnchorInfo) {
+        }
+    }
 }