Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(652)

Side by Side Diff: content/browser/android/ime_adapter_android.cc

Issue 2931443003: Add support for Android spellcheck menu in Chrome/WebViews (Closed)
Patch Set: Created 3 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2017 The Chromium Authors. All rights reserved. 1 // Copyright 2017 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "content/browser/android/ime_adapter_android.h" 5 #include "content/browser/android/ime_adapter_android.h"
6 6
7 #include <android/input.h> 7 #include <android/input.h>
8 #include <algorithm> 8 #include <algorithm>
9 #include <vector> 9 #include <vector>
10 10
11 #include "base/android/jni_android.h" 11 #include "base/android/jni_android.h"
12 #include "base/android/jni_array.h" 12 #include "base/android/jni_array.h"
13 #include "base/android/jni_string.h" 13 #include "base/android/jni_string.h"
14 #include "base/android/scoped_java_ref.h" 14 #include "base/android/scoped_java_ref.h"
15 #include "base/strings/utf_string_conversions.h" 15 #include "base/strings/utf_string_conversions.h"
16 #include "base/time/time.h" 16 #include "base/time/time.h"
17 #include "content/browser/android/text_suggestion_host_impl.h"
17 #include "content/browser/frame_host/render_frame_host_impl.h" 18 #include "content/browser/frame_host/render_frame_host_impl.h"
18 #include "content/browser/renderer_host/render_view_host_delegate.h" 19 #include "content/browser/renderer_host/render_view_host_delegate.h"
19 #include "content/browser/renderer_host/render_widget_host_impl.h" 20 #include "content/browser/renderer_host/render_widget_host_impl.h"
20 #include "content/browser/renderer_host/render_widget_host_view_android.h" 21 #include "content/browser/renderer_host/render_widget_host_view_android.h"
21 #include "content/common/input_messages.h" 22 #include "content/common/input_messages.h"
22 #include "content/common/view_messages.h" 23 #include "content/common/view_messages.h"
23 #include "content/public/browser/browser_thread.h" 24 #include "content/public/browser/browser_thread.h"
24 #include "content/public/browser/native_web_keyboard_event.h" 25 #include "content/public/browser/native_web_keyboard_event.h"
25 #include "content/public/browser/web_contents.h" 26 #include "content/public/browser/web_contents.h"
26 #include "jni/ImeAdapter_jni.h" 27 #include "jni/ImeAdapter_jni.h"
28 #include "services/service_manager/public/cpp/interface_provider.h"
27 #include "third_party/WebKit/public/platform/WebInputEvent.h" 29 #include "third_party/WebKit/public/platform/WebInputEvent.h"
28 #include "third_party/WebKit/public/platform/WebTextInputType.h" 30 #include "third_party/WebKit/public/platform/WebTextInputType.h"
29 #include "third_party/WebKit/public/web/WebCompositionUnderline.h" 31 #include "third_party/WebKit/public/web/WebCompositionUnderline.h"
30 32
31 using base::android::AttachCurrentThread; 33 using base::android::AttachCurrentThread;
32 using base::android::ConvertJavaStringToUTF16; 34 using base::android::ConvertJavaStringToUTF16;
33 using base::android::ConvertUTF8ToJavaString; 35 using base::android::ConvertUTF8ToJavaString;
34 using base::android::JavaParamRef; 36 using base::android::JavaParamRef;
35 using base::android::ScopedJavaLocalRef; 37 using base::android::ScopedJavaLocalRef;
36 38
37 namespace content { 39 namespace content {
38 namespace { 40 namespace {
39 41
42 int kDoubleTapTimeoutInMilliseconds = 300;
yosin_UTC9 2017/06/07 01:34:14 nit: s/int/const int/
43
40 // Maps a java KeyEvent into a NativeWebKeyboardEvent. 44 // Maps a java KeyEvent into a NativeWebKeyboardEvent.
41 // |java_key_event| is used to maintain a globalref for KeyEvent. 45 // |java_key_event| is used to maintain a globalref for KeyEvent.
42 // |type| will determine the WebInputEvent type. 46 // |type| will determine the WebInputEvent type.
43 // type, |modifiers|, |time_ms|, |key_code|, |unicode_char| is used to create 47 // type, |modifiers|, |time_ms|, |key_code|, |unicode_char| is used to create
44 // WebKeyboardEvent. |key_code| is also needed ad need to treat the enter key 48 // WebKeyboardEvent. |key_code| is also needed ad need to treat the enter key
45 // as a key press of character \r. 49 // as a key press of character \r.
46 NativeWebKeyboardEvent NativeWebKeyboardEventFromKeyEvent( 50 NativeWebKeyboardEvent NativeWebKeyboardEventFromKeyEvent(
47 JNIEnv* env, 51 JNIEnv* env,
48 const base::android::JavaRef<jobject>& java_key_event, 52 const base::android::JavaRef<jobject>& java_key_event,
49 int type, 53 int type,
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after
107 reinterpret_cast<std::vector<blink::WebCompositionUnderline>*>( 111 reinterpret_cast<std::vector<blink::WebCompositionUnderline>*>(
108 underlines_ptr); 112 underlines_ptr);
109 underlines->push_back(blink::WebCompositionUnderline( 113 underlines->push_back(blink::WebCompositionUnderline(
110 static_cast<unsigned>(start), static_cast<unsigned>(end), SK_ColorBLACK, 114 static_cast<unsigned>(start), static_cast<unsigned>(end), SK_ColorBLACK,
111 false, SK_ColorTRANSPARENT)); 115 false, SK_ColorTRANSPARENT));
112 } 116 }
113 117
114 ImeAdapterAndroid::ImeAdapterAndroid(JNIEnv* env, 118 ImeAdapterAndroid::ImeAdapterAndroid(JNIEnv* env,
115 const JavaParamRef<jobject>& obj, 119 const JavaParamRef<jobject>& obj,
116 WebContents* web_contents) 120 WebContents* web_contents)
117 : RenderWidgetHostConnector(web_contents), rwhva_(nullptr) { 121 : RenderWidgetHostConnector(web_contents),
122 rwhva_(nullptr),
123 java_ime_adapter_(JavaObjectWeakGlobalRef(env, obj)),
124 spellcheck_menu_timeout_(
125 base::Bind(&ImeAdapterAndroid::OnSpellCheckMenuTimeout,
126 base::Unretained(this))) {
118 java_ime_adapter_ = JavaObjectWeakGlobalRef(env, obj); 127 java_ime_adapter_ = JavaObjectWeakGlobalRef(env, obj);
128
129 RenderFrameHost* rfh = GetFocusedFrame();
130 if (!rfh)
131 return;
132
133 rfh->GetInterfaceRegistry()->AddInterface(
134 base::Bind(&TextSuggestionHostImpl::Create, base::Unretained(this)));
119 } 135 }
120 136
121 ImeAdapterAndroid::~ImeAdapterAndroid() { 137 ImeAdapterAndroid::~ImeAdapterAndroid() {
122 JNIEnv* env = AttachCurrentThread(); 138 JNIEnv* env = AttachCurrentThread();
123 ScopedJavaLocalRef<jobject> obj = java_ime_adapter_.get(env); 139 ScopedJavaLocalRef<jobject> obj = java_ime_adapter_.get(env);
124 if (!obj.is_null()) 140 if (!obj.is_null())
125 Java_ImeAdapter_destroy(env, obj); 141 Java_ImeAdapter_destroy(env, obj);
126 } 142 }
127 143
128 void ImeAdapterAndroid::UpdateRenderProcessConnection( 144 void ImeAdapterAndroid::UpdateRenderProcessConnection(
(...skipping 146 matching lines...) Expand 10 before | Expand all | Expand 10 after
275 if (!obj.is_null()) 291 if (!obj.is_null())
276 Java_ImeAdapter_cancelComposition(env, obj); 292 Java_ImeAdapter_cancelComposition(env, obj);
277 } 293 }
278 294
279 void ImeAdapterAndroid::FocusedNodeChanged(bool is_editable_node) { 295 void ImeAdapterAndroid::FocusedNodeChanged(bool is_editable_node) {
280 JNIEnv* env = AttachCurrentThread(); 296 JNIEnv* env = AttachCurrentThread();
281 ScopedJavaLocalRef<jobject> obj = java_ime_adapter_.get(env); 297 ScopedJavaLocalRef<jobject> obj = java_ime_adapter_.get(env);
282 if (!obj.is_null()) { 298 if (!obj.is_null()) {
283 Java_ImeAdapter_focusedNodeChanged(env, obj, is_editable_node); 299 Java_ImeAdapter_focusedNodeChanged(env, obj, is_editable_node);
284 } 300 }
301
302 RenderFrameHost* rfh = GetFocusedFrame();
303 if (rfh) {
yosin_UTC9 2017/06/07 01:34:15 nit: early-return style is better as L130. Or chan
304 rfh->GetInterfaceRegistry()->AddInterface(
305 base::Bind(&TextSuggestionHostImpl::Create, base::Unretained(this)));
306 }
285 } 307 }
286 308
287 void ImeAdapterAndroid::SetEditableSelectionOffsets( 309 void ImeAdapterAndroid::SetEditableSelectionOffsets(
288 JNIEnv*, 310 JNIEnv*,
289 const JavaParamRef<jobject>&, 311 const JavaParamRef<jobject>&,
290 int start, 312 int start,
291 int end) { 313 int end) {
292 RenderFrameHost* rfh = GetFocusedFrame(); 314 RenderFrameHost* rfh = GetFocusedFrame();
293 if (!rfh) 315 if (!rfh)
294 return; 316 return;
(...skipping 17 matching lines...) Expand all
312 coordinates_array[coordinates_array_index + 1] = rect.y(); 334 coordinates_array[coordinates_array_index + 1] = rect.y();
313 coordinates_array[coordinates_array_index + 2] = rect.right(); 335 coordinates_array[coordinates_array_index + 2] = rect.right();
314 coordinates_array[coordinates_array_index + 3] = rect.bottom(); 336 coordinates_array[coordinates_array_index + 3] = rect.bottom();
315 } 337 }
316 Java_ImeAdapter_setCharacterBounds( 338 Java_ImeAdapter_setCharacterBounds(
317 env, obj, 339 env, obj,
318 base::android::ToJavaFloatArray(env, coordinates_array.get(), 340 base::android::ToJavaFloatArray(env, coordinates_array.get(),
319 coordinates_array_size)); 341 coordinates_array_size));
320 } 342 }
321 343
344 void ImeAdapterAndroid::StartSpellCheckMenuTimer() {
345 spellcheck_menu_timeout_.Stop();
346 spellcheck_menu_timeout_.Start(
347 base::TimeDelta::FromMilliseconds(kDoubleTapTimeoutInMilliseconds));
348 }
349
350 void ImeAdapterAndroid::StopSpellCheckMenuTimer() {
351 spellcheck_menu_timeout_.Stop();
352 }
353
354 void ImeAdapterAndroid::ShowSpellCheckSuggestionMenu(
355 double caret_x,
356 double caret_y,
357 const std::string& marked_text,
358 const std::vector<blink::mojom::SpellCheckSuggestionPtr>& suggestions) {
359 std::vector<std::string> suggestion_strings;
360 for (const blink::mojom::SpellCheckSuggestionPtr& suggestion_ptr :
yosin_UTC9 2017/06/07 01:34:14 I think |const auto&| is enough since we know the
361 suggestions)
362 suggestion_strings.push_back(suggestion_ptr->suggestion);
363
364 JNIEnv* env = AttachCurrentThread();
365 ScopedJavaLocalRef<jobject> obj = java_ime_adapter_.get(env);
366 Java_ImeAdapter_showSpellCheckSuggestionMenu(
367 env, obj, caret_x, caret_y, ConvertUTF8ToJavaString(env, marked_text),
368 base::android::ToJavaArrayOfStrings(env, suggestion_strings));
369 }
370
322 void ImeAdapterAndroid::SetComposingRegion(JNIEnv*, 371 void ImeAdapterAndroid::SetComposingRegion(JNIEnv*,
323 const JavaParamRef<jobject>&, 372 const JavaParamRef<jobject>&,
324 int start, 373 int start,
325 int end) { 374 int end) {
326 RenderFrameHost* rfh = GetFocusedFrame(); 375 RenderFrameHost* rfh = GetFocusedFrame();
327 if (!rfh) 376 if (!rfh)
328 return; 377 return;
329 378
330 std::vector<ui::CompositionUnderline> underlines; 379 std::vector<ui::CompositionUnderline> underlines;
331 underlines.push_back(ui::CompositionUnderline(0, end - start, SK_ColorBLACK, 380 underlines.push_back(ui::CompositionUnderline(0, end - start, SK_ColorBLACK,
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
373 const base::android::JavaParamRef<jobject>& obj, 422 const base::android::JavaParamRef<jobject>& obj,
374 bool immediate_request, 423 bool immediate_request,
375 bool monitor_request) { 424 bool monitor_request) {
376 RenderWidgetHostImpl* rwhi = GetFocusedWidget(); 425 RenderWidgetHostImpl* rwhi = GetFocusedWidget();
377 if (!rwhi) 426 if (!rwhi)
378 return; 427 return;
379 rwhi->Send(new InputMsg_RequestCompositionUpdates( 428 rwhi->Send(new InputMsg_RequestCompositionUpdates(
380 rwhi->GetRoutingID(), immediate_request, monitor_request)); 429 rwhi->GetRoutingID(), immediate_request, monitor_request));
381 } 430 }
382 431
432 void ImeAdapterAndroid::ApplySpellCheckSuggestion(
433 JNIEnv* env,
434 const JavaParamRef<jobject>&,
435 const base::android::JavaParamRef<jstring>& replacement) {
436 const blink::mojom::TextSuggestionBackendPtr& text_suggestion_backend =
437 GetTextSuggestionBackend();
438 if (!text_suggestion_backend)
439 return;
440 text_suggestion_backend->ApplySpellCheckSuggestion(
441 ConvertJavaStringToUTF8(env, replacement));
442 }
443
444 void ImeAdapterAndroid::DeleteActiveSuggestionRange(
445 JNIEnv*,
446 const JavaParamRef<jobject>&) {
447 const blink::mojom::TextSuggestionBackendPtr& text_suggestion_backend =
448 GetTextSuggestionBackend();
449 if (!text_suggestion_backend)
450 return;
451 text_suggestion_backend->DeleteActiveSuggestionRange();
452 }
453
454 void ImeAdapterAndroid::NewWordAddedToDictionary(
455 JNIEnv* env,
456 const JavaParamRef<jobject>&,
457 const base::android::JavaParamRef<jstring>& word) {
458 const blink::mojom::TextSuggestionBackendPtr& text_suggestion_backend =
459 GetTextSuggestionBackend();
460 if (!text_suggestion_backend)
461 return;
462 text_suggestion_backend->NewWordAddedToDictionary(
463 ConvertJavaStringToUTF8(env, word));
464 }
465
466 void ImeAdapterAndroid::SuggestionMenuClosed(JNIEnv*,
467 const JavaParamRef<jobject>&) {
468 const blink::mojom::TextSuggestionBackendPtr& text_suggestion_backend =
469 GetTextSuggestionBackend();
470 if (!text_suggestion_backend)
471 return;
472 text_suggestion_backend->SuggestionMenuClosed();
473 }
474
383 RenderWidgetHostImpl* ImeAdapterAndroid::GetFocusedWidget() { 475 RenderWidgetHostImpl* ImeAdapterAndroid::GetFocusedWidget() {
384 DCHECK_CURRENTLY_ON(BrowserThread::UI); 476 DCHECK_CURRENTLY_ON(BrowserThread::UI);
385 return rwhva_ ? rwhva_->GetFocusedWidget() : nullptr; 477 return rwhva_ ? rwhva_->GetFocusedWidget() : nullptr;
386 } 478 }
387 479
388 RenderFrameHost* ImeAdapterAndroid::GetFocusedFrame() { 480 RenderFrameHost* ImeAdapterAndroid::GetFocusedFrame() {
389 DCHECK_CURRENTLY_ON(BrowserThread::UI); 481 DCHECK_CURRENTLY_ON(BrowserThread::UI);
390 // We get the focused frame from the WebContents of the page. Although 482 // We get the focused frame from the WebContents of the page. Although
391 // |rwhva_->GetFocusedWidget()| does a similar thing, there is no direct way 483 // |rwhva_->GetFocusedWidget()| does a similar thing, there is no direct way
392 // to get a RenderFrameHost from its RWH. 484 // to get a RenderFrameHost from its RWH.
(...skipping 22 matching lines...) Expand all
415 // AppendBackgroundColorSpan()), and populate |underlines|. 507 // AppendBackgroundColorSpan()), and populate |underlines|.
416 Java_ImeAdapter_populateUnderlinesFromSpans( 508 Java_ImeAdapter_populateUnderlinesFromSpans(
417 env, obj, text, reinterpret_cast<jlong>(&underlines)); 509 env, obj, text, reinterpret_cast<jlong>(&underlines));
418 510
419 // Sort spans by |.startOffset|. 511 // Sort spans by |.startOffset|.
420 std::sort(underlines.begin(), underlines.end()); 512 std::sort(underlines.begin(), underlines.end());
421 513
422 return underlines; 514 return underlines;
423 } 515 }
424 516
517 const blink::mojom::TextSuggestionBackendPtr&
518 ImeAdapterAndroid::GetTextSuggestionBackend() {
519 if (!text_suggestion_backend_) {
520 RenderFrameHost* rfh = GetFocusedFrame();
yosin_UTC9 2017/06/07 01:34:14 nit: We can put |rfh| in if-statement. if (Render
521 if (rfh) {
522 rfh->GetRemoteInterfaces()->GetInterface(
523 mojo::MakeRequest(&text_suggestion_backend_));
524 }
525 }
526
527 return text_suggestion_backend_;
528 }
529
530 void ImeAdapterAndroid::OnSpellCheckMenuTimeout() {
531 const blink::mojom::TextSuggestionBackendPtr& text_suggestion_backend =
532 GetTextSuggestionBackend();
533 if (!text_suggestion_backend)
534 return;
535 text_suggestion_backend->SpellCheckMenuTimeoutCallback();
536 }
537
425 } // namespace content 538 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698