Commit 1717ee11 authored by Jinsuk Kim's avatar Jinsuk Kim Committed by Commit Bot

Android: Create Java TextSuggestionHost lazily

This CL addresses the reported bug by undoing the quick fix
http://crrev.com/595608 and lazily initializing Java side
TextSuggestionHost properly. Native side still needs to be
established eagerly to get the IPC to work. Now Java layer
is created before suggestion menu is requested to be shown
for the first time.

Bug: 884214
Change-Id: I1bbe9b2e3a5898d6dd082f8784951215a4a9ab91
Reviewed-on: https://chromium-review.googlesource.com/c/1256383
Commit-Queue: Jinsuk Kim <jinsukkim@chromium.org>
Reviewed-by: default avatarTed Choc <tedchoc@chromium.org>
Cr-Commit-Position: refs/heads/master@{#596487}
parent 5fd3b79e
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include "base/android/scoped_java_ref.h" #include "base/android/scoped_java_ref.h"
#include "base/strings/utf_string_conversions.h" #include "base/strings/utf_string_conversions.h"
#include "base/time/time.h" #include "base/time/time.h"
#include "content/browser/android/text_suggestion_host_android.h"
#include "content/browser/frame_host/render_frame_host_impl.h" #include "content/browser/frame_host/render_frame_host_impl.h"
#include "content/browser/renderer_host/render_view_host_delegate.h" #include "content/browser/renderer_host/render_view_host_delegate.h"
#include "content/browser/renderer_host/render_widget_host_impl.h" #include "content/browser/renderer_host/render_widget_host_impl.h"
...@@ -144,6 +145,10 @@ ImeAdapterAndroid::ImeAdapterAndroid(JNIEnv* env, ...@@ -144,6 +145,10 @@ ImeAdapterAndroid::ImeAdapterAndroid(JNIEnv* env,
WebContents* web_contents) WebContents* web_contents)
: RenderWidgetHostConnector(web_contents), rwhva_(nullptr) { : RenderWidgetHostConnector(web_contents), rwhva_(nullptr) {
java_ime_adapter_ = JavaObjectWeakGlobalRef(env, obj); java_ime_adapter_ = JavaObjectWeakGlobalRef(env, obj);
// Set up mojo client for TextSuggestionHost in advance. Java side is
// initialized lazily right before showing the menu first time.
TextSuggestionHostAndroid::Create(env, web_contents);
} }
ImeAdapterAndroid::~ImeAdapterAndroid() { ImeAdapterAndroid::~ImeAdapterAndroid() {
......
...@@ -34,25 +34,17 @@ const size_t kMaxNumberOfSuggestions = 5; ...@@ -34,25 +34,17 @@ const size_t kMaxNumberOfSuggestions = 5;
} // namespace } // namespace
jlong JNI_TextSuggestionHost_Init(JNIEnv* env, void TextSuggestionHostAndroid::Create(JNIEnv* env, WebContents* web_contents) {
const JavaParamRef<jobject>& obj, auto* text_suggestion_host = new TextSuggestionHostAndroid(env, web_contents);
const JavaParamRef<jobject>& jweb_contents) {
WebContents* web_contents = WebContents::FromJavaWebContents(jweb_contents);
DCHECK(web_contents);
auto* text_suggestion_host =
new TextSuggestionHostAndroid(env, obj, web_contents);
text_suggestion_host->Initialize(); text_suggestion_host->Initialize();
return reinterpret_cast<intptr_t>(text_suggestion_host);
} }
TextSuggestionHostAndroid::TextSuggestionHostAndroid( TextSuggestionHostAndroid::TextSuggestionHostAndroid(
JNIEnv* env, JNIEnv* env,
const JavaParamRef<jobject>& obj,
WebContents* web_contents) WebContents* web_contents)
: RenderWidgetHostConnector(web_contents), : RenderWidgetHostConnector(web_contents),
WebContentsObserver(web_contents), WebContentsObserver(web_contents),
rwhva_(nullptr), rwhva_(nullptr),
java_text_suggestion_host_(JavaObjectWeakGlobalRef(env, obj)),
suggestion_menu_timeout_( suggestion_menu_timeout_(
base::Bind(&TextSuggestionHostAndroid::OnSuggestionMenuTimeout, base::Bind(&TextSuggestionHostAndroid::OnSuggestionMenuTimeout,
base::Unretained(this))) { base::Unretained(this))) {
...@@ -144,6 +136,19 @@ double TextSuggestionHostAndroid::DpToPxIfNeeded(double value) { ...@@ -144,6 +136,19 @@ double TextSuggestionHostAndroid::DpToPxIfNeeded(double value) {
return value; return value;
} }
ScopedJavaLocalRef<jobject>
TextSuggestionHostAndroid::GetJavaTextSuggestionHost() {
JNIEnv* env = AttachCurrentThread();
ScopedJavaLocalRef<jobject> obj = java_text_suggestion_host_.get(env);
if (obj.is_null()) {
obj = Java_TextSuggestionHost_create(
env, WebContentsObserver::web_contents()->GetJavaWebContents(),
reinterpret_cast<intptr_t>(this));
java_text_suggestion_host_ = JavaObjectWeakGlobalRef(env, obj);
}
return obj;
}
void TextSuggestionHostAndroid::ShowSpellCheckSuggestionMenu( void TextSuggestionHostAndroid::ShowSpellCheckSuggestionMenu(
double caret_x, double caret_x,
double caret_y, double caret_y,
...@@ -155,7 +160,7 @@ void TextSuggestionHostAndroid::ShowSpellCheckSuggestionMenu( ...@@ -155,7 +160,7 @@ void TextSuggestionHostAndroid::ShowSpellCheckSuggestionMenu(
for (size_t i = 0; i < suggestions.size() && i < kMaxNumberOfSuggestions; ++i) for (size_t i = 0; i < suggestions.size() && i < kMaxNumberOfSuggestions; ++i)
suggestion_strings.push_back(suggestions[i]->suggestion); suggestion_strings.push_back(suggestions[i]->suggestion);
JNIEnv* env = AttachCurrentThread(); JNIEnv* env = AttachCurrentThread();
ScopedJavaLocalRef<jobject> obj = java_text_suggestion_host_.get(env); ScopedJavaLocalRef<jobject> obj = GetJavaTextSuggestionHost();
if (obj.is_null()) if (obj.is_null())
return; return;
...@@ -173,7 +178,9 @@ void TextSuggestionHostAndroid::ShowTextSuggestionMenu( ...@@ -173,7 +178,9 @@ void TextSuggestionHostAndroid::ShowTextSuggestionMenu(
const std::string& marked_text, const std::string& marked_text,
const std::vector<blink::mojom::TextSuggestionPtr>& suggestions) { const std::vector<blink::mojom::TextSuggestionPtr>& suggestions) {
JNIEnv* env = AttachCurrentThread(); JNIEnv* env = AttachCurrentThread();
ScopedJavaLocalRef<jobject> obj = java_text_suggestion_host_.get(env); ScopedJavaLocalRef<jobject> obj = GetJavaTextSuggestionHost();
if (obj.is_null())
return;
// Enforce kMaxNumberOfSuggestions here in case the renderer is hijacked and // Enforce kMaxNumberOfSuggestions here in case the renderer is hijacked and
// tries to send bad input. // tries to send bad input.
......
...@@ -18,13 +18,13 @@ namespace content { ...@@ -18,13 +18,13 @@ namespace content {
// misspelled word. This class creates the Android implementation of // misspelled word. This class creates the Android implementation of
// mojom::TextSuggestionHost, which is used to communicate back-and-forth with // mojom::TextSuggestionHost, which is used to communicate back-and-forth with
// Blink side code (these are separate classes due to lifecycle considerations; // Blink side code (these are separate classes due to lifecycle considerations;
// this class needs to be constructed from Java code, but Mojo code wants to // this class is created by ImeAdapterAndroid ctor and destroyed together with
// take ownership of mojom::TextSuggestionHost). // WebContents. Mojo code takes ownership of mojom::TextSuggestionHost).
class TextSuggestionHostAndroid : public RenderWidgetHostConnector, class TextSuggestionHostAndroid : public RenderWidgetHostConnector,
public WebContentsObserver { public WebContentsObserver {
public: public:
static void Create(JNIEnv* env, WebContents* web_contents);
TextSuggestionHostAndroid(JNIEnv* env, TextSuggestionHostAndroid(JNIEnv* env,
const base::android::JavaParamRef<jobject>& obj,
WebContents* web_contents); WebContents* web_contents);
~TextSuggestionHostAndroid() override; ~TextSuggestionHostAndroid() override;
...@@ -95,6 +95,7 @@ class TextSuggestionHostAndroid : public RenderWidgetHostConnector, ...@@ -95,6 +95,7 @@ class TextSuggestionHostAndroid : public RenderWidgetHostConnector,
private: private:
RenderFrameHost* GetFocusedFrame(); RenderFrameHost* GetFocusedFrame();
base::android::ScopedJavaLocalRef<jobject> GetJavaTextSuggestionHost();
const blink::mojom::TextSuggestionBackendPtr& GetTextSuggestionBackend(); const blink::mojom::TextSuggestionBackendPtr& GetTextSuggestionBackend();
// Used by the spell check menu timer to notify Blink that the timer has // Used by the spell check menu timer to notify Blink that the timer has
// expired. // expired.
......
...@@ -48,11 +48,19 @@ public class TextSuggestionHost implements WindowEventObserver, HideablePopup, U ...@@ -48,11 +48,19 @@ public class TextSuggestionHost implements WindowEventObserver, HideablePopup, U
* @param webContents {@link WebContents} object. * @param webContents {@link WebContents} object.
* @return {@link TextSuggestionHost} object. * @return {@link TextSuggestionHost} object.
*/ */
public static TextSuggestionHost fromWebContents(WebContents webContents) { @VisibleForTesting
static TextSuggestionHost fromWebContents(WebContents webContents) {
return ((WebContentsImpl) webContents) return ((WebContentsImpl) webContents)
.getOrSetUserData(TextSuggestionHost.class, UserDataFactoryLazyHolder.INSTANCE); .getOrSetUserData(TextSuggestionHost.class, UserDataFactoryLazyHolder.INSTANCE);
} }
@CalledByNative
private static TextSuggestionHost create(WebContents webContents, long nativePtr) {
TextSuggestionHost host = fromWebContents(webContents);
host.setNativePtr(nativePtr);
return host;
}
/** /**
* Create {@link TextSuggestionHost} instance. * Create {@link TextSuggestionHost} instance.
* @param webContents WebContents instance. * @param webContents WebContents instance.
...@@ -63,11 +71,14 @@ public class TextSuggestionHost implements WindowEventObserver, HideablePopup, U ...@@ -63,11 +71,14 @@ public class TextSuggestionHost implements WindowEventObserver, HideablePopup, U
mWindowAndroid = mWebContents.getTopLevelNativeWindow(); mWindowAndroid = mWebContents.getTopLevelNativeWindow();
mViewDelegate = mWebContents.getViewAndroidDelegate(); mViewDelegate = mWebContents.getViewAndroidDelegate();
assert mViewDelegate != null; assert mViewDelegate != null;
mNativeTextSuggestionHost = nativeInit(mWebContents);
PopupController.register(mWebContents, this); PopupController.register(mWebContents, this);
WindowEventObserverManager.from(mWebContents).addObserver(this); WindowEventObserverManager.from(mWebContents).addObserver(this);
} }
private void setNativePtr(long nativePtr) {
mNativeTextSuggestionHost = nativePtr;
}
private float getContentOffsetYPix() { private float getContentOffsetYPix() {
return mWebContents.getRenderCoordinates().getContentOffsetYPix(); return mWebContents.getRenderCoordinates().getContentOffsetYPix();
} }
...@@ -221,7 +232,6 @@ public class TextSuggestionHost implements WindowEventObserver, HideablePopup, U ...@@ -221,7 +232,6 @@ public class TextSuggestionHost implements WindowEventObserver, HideablePopup, U
return mSpellCheckPopupWindow; return mSpellCheckPopupWindow;
} }
private native long nativeInit(WebContents webContents);
private native void nativeApplySpellCheckSuggestion( private native void nativeApplySpellCheckSuggestion(
long nativeTextSuggestionHostAndroid, String suggestion); long nativeTextSuggestionHostAndroid, String suggestion);
private native void nativeApplyTextSuggestion( private native void nativeApplyTextSuggestion(
......
...@@ -34,7 +34,6 @@ import org.chromium.content.browser.WindowEventObserverManager; ...@@ -34,7 +34,6 @@ import org.chromium.content.browser.WindowEventObserverManager;
import org.chromium.content.browser.accessibility.WebContentsAccessibilityImpl; import org.chromium.content.browser.accessibility.WebContentsAccessibilityImpl;
import org.chromium.content.browser.framehost.RenderFrameHostDelegate; import org.chromium.content.browser.framehost.RenderFrameHostDelegate;
import org.chromium.content.browser.framehost.RenderFrameHostImpl; import org.chromium.content.browser.framehost.RenderFrameHostImpl;
import org.chromium.content.browser.input.TextSuggestionHost;
import org.chromium.content.browser.selection.SelectionPopupControllerImpl; import org.chromium.content.browser.selection.SelectionPopupControllerImpl;
import org.chromium.content_public.browser.AccessibilitySnapshotCallback; import org.chromium.content_public.browser.AccessibilitySnapshotCallback;
import org.chromium.content_public.browser.AccessibilitySnapshotNode; import org.chromium.content_public.browser.AccessibilitySnapshotNode;
...@@ -230,7 +229,6 @@ public class WebContentsImpl implements WebContents, RenderFrameHostDelegate, Wi ...@@ -230,7 +229,6 @@ public class WebContentsImpl implements WebContents, RenderFrameHostDelegate, Wi
ViewEventSinkImpl.from(this).setAccessDelegate(accessDelegate); ViewEventSinkImpl.from(this).setAccessDelegate(accessDelegate);
getRenderCoordinates().setDeviceScaleFactor(windowAndroid.getDisplay().getDipScale()); getRenderCoordinates().setDeviceScaleFactor(windowAndroid.getDisplay().getDipScale());
TextSuggestionHost.fromWebContents(this);
} }
@Nullable @Nullable
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment