1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "content/browser/web_contents/web_contents_android.h"
6
7 #include <stdint.h>
8 #include <string>
9 #include <unordered_set>
10 #include <utility>
11 #include <vector>
12
13 #include "base/android/jni_android.h"
14 #include "base/android/jni_array.h"
15 #include "base/android/jni_string.h"
16 #include "base/bind.h"
17 #include "base/callback_helpers.h"
18 #include "base/json/json_writer.h"
19 #include "base/lazy_instance.h"
20 #include "base/logging.h"
21 #include "base/metrics/user_metrics.h"
22 #include "base/task/post_task.h"
23 #include "base/threading/scoped_blocking_call.h"
24 #include "content/browser/accessibility/browser_accessibility_android.h"
25 #include "content/browser/accessibility/browser_accessibility_manager_android.h"
26 #include "content/browser/android/java/gin_java_bridge_dispatcher_host.h"
27 #include "content/browser/media/media_web_contents_observer.h"
28 #include "content/browser/renderer_host/render_view_host_impl.h"
29 #include "content/browser/web_contents/web_contents_impl.h"
30 #include "content/browser/web_contents/web_contents_view_android.h"
31 #include "content/common/frame.mojom.h"
32 #include "content/common/frame_messages.h"
33 #include "content/common/input_messages.h"
34 #include "content/public/android/content_jni_headers/WebContentsImpl_jni.h"
35 #include "content/public/browser/browser_context.h"
36 #include "content/public/browser/browser_thread.h"
37 #include "content/public/browser/message_port_provider.h"
38 #include "content/public/browser/render_widget_host.h"
39 #include "content/public/browser/web_contents.h"
40 #include "content/public/common/content_switches.h"
41 #include "ui/accessibility/ax_assistant_structure.h"
42 #include "ui/accessibility/ax_node_data.h"
43 #include "ui/accessibility/mojom/ax_assistant_structure.mojom.h"
44 #include "ui/android/overscroll_refresh_handler.h"
45 #include "ui/android/window_android.h"
46 #include "ui/gfx/android/java_bitmap.h"
47 #include "ui/gfx/geometry/point.h"
48 #include "ui/gfx/geometry/rect.h"
49 #include "url/android/gurl_android.h"
50 #include "url/gurl.h"
51
52 using base::android::AttachCurrentThread;
53 using base::android::ConvertJavaStringToUTF8;
54 using base::android::ConvertJavaStringToUTF16;
55 using base::android::ConvertUTF8ToJavaString;
56 using base::android::ConvertUTF16ToJavaString;
57 using base::android::JavaParamRef;
58 using base::android::JavaRef;
59 using base::android::ScopedJavaGlobalRef;
60 using base::android::ScopedJavaLocalRef;
61 using base::android::ToJavaIntArray;
62
63 namespace content {
64
65 namespace {
66
67 // Track all WebContentsAndroid objects here so that we don't deserialize a
68 // destroyed WebContents object.
69 base::LazyInstance<std::unordered_set<WebContentsAndroid*>>::Leaky
70 g_allocated_web_contents_androids = LAZY_INSTANCE_INITIALIZER;
71
JavaScriptResultCallback(const ScopedJavaGlobalRef<jobject> & callback,base::Value result)72 void JavaScriptResultCallback(const ScopedJavaGlobalRef<jobject>& callback,
73 base::Value result) {
74 JNIEnv* env = base::android::AttachCurrentThread();
75 std::string json;
76 base::JSONWriter::Write(result, &json);
77 ScopedJavaLocalRef<jstring> j_json = ConvertUTF8ToJavaString(env, json);
78 Java_WebContentsImpl_onEvaluateJavaScriptResult(env, j_json, callback);
79 }
80
SmartClipCallback(const ScopedJavaGlobalRef<jobject> & callback,const base::string16 & text,const base::string16 & html,const gfx::Rect & clip_rect)81 void SmartClipCallback(const ScopedJavaGlobalRef<jobject>& callback,
82 const base::string16& text,
83 const base::string16& html,
84 const gfx::Rect& clip_rect) {
85 JNIEnv* env = base::android::AttachCurrentThread();
86 ScopedJavaLocalRef<jstring> j_text = ConvertUTF16ToJavaString(env, text);
87 ScopedJavaLocalRef<jstring> j_html = ConvertUTF16ToJavaString(env, html);
88 Java_WebContentsImpl_onSmartClipDataExtracted(
89 env, j_text, j_html, clip_rect.x(), clip_rect.y(), clip_rect.right(),
90 clip_rect.bottom(), callback);
91 }
92
JNI_WebContentsImpl_CreateJavaAXSnapshot(JNIEnv * env,const ui::AssistantTree * tree,const ui::AssistantNode * node,bool is_root)93 ScopedJavaLocalRef<jobject> JNI_WebContentsImpl_CreateJavaAXSnapshot(
94 JNIEnv* env,
95 const ui::AssistantTree* tree,
96 const ui::AssistantNode* node,
97 bool is_root) {
98 ScopedJavaLocalRef<jstring> j_text =
99 ConvertUTF16ToJavaString(env, node->text);
100 ScopedJavaLocalRef<jstring> j_class =
101 ConvertUTF8ToJavaString(env, node->class_name);
102 ScopedJavaLocalRef<jobject> j_node =
103 Java_WebContentsImpl_createAccessibilitySnapshotNode(
104 env, node->rect.x(), node->rect.y(), node->rect.width(),
105 node->rect.height(), is_root, j_text, node->color, node->bgcolor,
106 node->text_size, node->bold, node->italic, node->underline,
107 node->line_through, j_class);
108
109 if (node->selection.has_value()) {
110 Java_WebContentsImpl_setAccessibilitySnapshotSelection(
111 env, j_node, node->selection->start(), node->selection->end());
112 }
113
114 for (int child : node->children_indices) {
115 Java_WebContentsImpl_addAccessibilityNodeAsChild(
116 env, j_node,
117 JNI_WebContentsImpl_CreateJavaAXSnapshot(
118 env, tree, tree->nodes[child].get(), false));
119 }
120 return j_node;
121 }
122
123 // Walks over the AXTreeUpdate and creates a light weight snapshot.
AXTreeSnapshotCallback(const ScopedJavaGlobalRef<jobject> & callback,const ui::AXTreeUpdate & result)124 void AXTreeSnapshotCallback(const ScopedJavaGlobalRef<jobject>& callback,
125 const ui::AXTreeUpdate& result) {
126 JNIEnv* env = base::android::AttachCurrentThread();
127 if (result.nodes.empty()) {
128 Java_WebContentsImpl_onAccessibilitySnapshot(env, nullptr, callback);
129 return;
130 }
131 std::unique_ptr<BrowserAccessibilityManagerAndroid> manager(
132 static_cast<BrowserAccessibilityManagerAndroid*>(
133 BrowserAccessibilityManager::Create(result, nullptr)));
134 std::unique_ptr<ui::AssistantTree> assistant_tree =
135 ui::CreateAssistantTree(result, manager->ShouldExposePasswordText());
136 ScopedJavaLocalRef<jobject> j_root = JNI_WebContentsImpl_CreateJavaAXSnapshot(
137 env, assistant_tree.get(), assistant_tree->nodes.front().get(), true);
138 Java_WebContentsImpl_onAccessibilitySnapshot(env, j_root, callback);
139 }
140
141 } // namespace
142
143 // static
FromJavaWebContents(const JavaRef<jobject> & jweb_contents_android)144 WebContents* WebContents::FromJavaWebContents(
145 const JavaRef<jobject>& jweb_contents_android) {
146 DCHECK_CURRENTLY_ON(BrowserThread::UI);
147 if (jweb_contents_android.is_null())
148 return NULL;
149
150 WebContentsAndroid* web_contents_android =
151 reinterpret_cast<WebContentsAndroid*>(
152 Java_WebContentsImpl_getNativePointer(AttachCurrentThread(),
153 jweb_contents_android));
154 if (!web_contents_android)
155 return NULL;
156 return web_contents_android->web_contents();
157 }
158
159 // static
JNI_WebContentsImpl_DestroyWebContents(JNIEnv * env,jlong jweb_contents_android_ptr)160 static void JNI_WebContentsImpl_DestroyWebContents(
161 JNIEnv* env,
162 jlong jweb_contents_android_ptr) {
163 WebContentsAndroid* web_contents_android =
164 reinterpret_cast<WebContentsAndroid*>(jweb_contents_android_ptr);
165 if (!web_contents_android)
166 return;
167
168 WebContents* web_contents = web_contents_android->web_contents();
169 if (!web_contents)
170 return;
171
172 delete web_contents;
173 }
174
175 // static
JNI_WebContentsImpl_FromNativePtr(JNIEnv * env,jlong web_contents_ptr)176 ScopedJavaLocalRef<jobject> JNI_WebContentsImpl_FromNativePtr(
177 JNIEnv* env,
178 jlong web_contents_ptr) {
179 WebContentsAndroid* web_contents_android =
180 reinterpret_cast<WebContentsAndroid*>(web_contents_ptr);
181
182 if (!web_contents_android)
183 return ScopedJavaLocalRef<jobject>();
184
185 // Check to make sure this object hasn't been destroyed.
186 if (g_allocated_web_contents_androids.Get().find(web_contents_android) ==
187 g_allocated_web_contents_androids.Get().end()) {
188 return ScopedJavaLocalRef<jobject>();
189 }
190
191 return web_contents_android->GetJavaObject();
192 }
193
WebContentsAndroid(WebContentsImpl * web_contents)194 WebContentsAndroid::WebContentsAndroid(WebContentsImpl* web_contents)
195 : web_contents_(web_contents),
196 navigation_controller_(&(web_contents->GetController())) {
197 g_allocated_web_contents_androids.Get().insert(this);
198 JNIEnv* env = AttachCurrentThread();
199 obj_.Reset(env,
200 Java_WebContentsImpl_create(env, reinterpret_cast<intptr_t>(this),
201 navigation_controller_.GetJavaObject())
202 .obj());
203 }
204
~WebContentsAndroid()205 WebContentsAndroid::~WebContentsAndroid() {
206 DCHECK(g_allocated_web_contents_androids.Get().find(this) !=
207 g_allocated_web_contents_androids.Get().end());
208 g_allocated_web_contents_androids.Get().erase(this);
209 for (auto& observer : destruction_observers_)
210 observer.WebContentsAndroidDestroyed(this);
211 Java_WebContentsImpl_clearNativePtr(AttachCurrentThread(), obj_);
212 }
213
214 base::android::ScopedJavaLocalRef<jobject>
GetJavaObject()215 WebContentsAndroid::GetJavaObject() {
216 return base::android::ScopedJavaLocalRef<jobject>(obj_);
217 }
218
ClearNativeReference(JNIEnv * env,const base::android::JavaParamRef<jobject> & obj)219 void WebContentsAndroid::ClearNativeReference(
220 JNIEnv* env,
221 const base::android::JavaParamRef<jobject>& obj) {
222 return web_contents_->ClearWebContentsAndroid();
223 }
224
AddDestructionObserver(DestructionObserver * observer)225 void WebContentsAndroid::AddDestructionObserver(DestructionObserver* observer) {
226 destruction_observers_.AddObserver(observer);
227 }
228
RemoveDestructionObserver(DestructionObserver * observer)229 void WebContentsAndroid::RemoveDestructionObserver(
230 DestructionObserver* observer) {
231 destruction_observers_.RemoveObserver(observer);
232 }
233
234 base::android::ScopedJavaLocalRef<jobject>
GetTopLevelNativeWindow(JNIEnv * env,const JavaParamRef<jobject> & obj)235 WebContentsAndroid::GetTopLevelNativeWindow(JNIEnv* env,
236 const JavaParamRef<jobject>& obj) {
237 ui::WindowAndroid* window_android = web_contents_->GetTopLevelNativeWindow();
238 if (!window_android)
239 return nullptr;
240 return window_android->GetJavaObject();
241 }
242
SetTopLevelNativeWindow(JNIEnv * env,const JavaParamRef<jobject> & obj,const JavaParamRef<jobject> & jwindow_android)243 void WebContentsAndroid::SetTopLevelNativeWindow(
244 JNIEnv* env,
245 const JavaParamRef<jobject>& obj,
246 const JavaParamRef<jobject>& jwindow_android) {
247 ui::WindowAndroid* window =
248 ui::WindowAndroid::FromJavaWindowAndroid(jwindow_android);
249 auto* old_window = web_contents_->GetTopLevelNativeWindow();
250 if (window == old_window)
251 return;
252
253 auto* view = web_contents_->GetNativeView();
254 if (old_window)
255 view->RemoveFromParent();
256 if (window)
257 window->AddChild(view);
258 }
259
SetViewAndroidDelegate(JNIEnv * env,const JavaParamRef<jobject> & obj,const JavaParamRef<jobject> & jview_delegate)260 void WebContentsAndroid::SetViewAndroidDelegate(
261 JNIEnv* env,
262 const JavaParamRef<jobject>& obj,
263 const JavaParamRef<jobject>& jview_delegate) {
264 ui::ViewAndroid* view_android = web_contents_->GetView()->GetNativeView();
265 view_android->SetDelegate(jview_delegate);
266 }
267
GetMainFrame(JNIEnv * env,const JavaParamRef<jobject> & obj) const268 ScopedJavaLocalRef<jobject> WebContentsAndroid::GetMainFrame(
269 JNIEnv* env,
270 const JavaParamRef<jobject>& obj) const {
271 return web_contents_->GetMainFrame()->GetJavaRenderFrameHost();
272 }
273
GetFocusedFrame(JNIEnv * env,const JavaParamRef<jobject> & obj) const274 ScopedJavaLocalRef<jobject> WebContentsAndroid::GetFocusedFrame(
275 JNIEnv* env,
276 const JavaParamRef<jobject>& obj) const {
277 RenderFrameHostImpl* rfh = web_contents_->GetFocusedFrame();
278 if (!rfh)
279 return nullptr;
280 return rfh->GetJavaRenderFrameHost();
281 }
282
GetRenderFrameHostFromId(JNIEnv * env,jint render_process_id,jint render_frame_id) const283 ScopedJavaLocalRef<jobject> WebContentsAndroid::GetRenderFrameHostFromId(
284 JNIEnv* env,
285 jint render_process_id,
286 jint render_frame_id) const {
287 RenderFrameHost* rfh =
288 RenderFrameHost::FromID(render_process_id, render_frame_id);
289 if (!rfh)
290 return nullptr;
291 return rfh->GetJavaRenderFrameHost();
292 }
293
GetTitle(JNIEnv * env,const JavaParamRef<jobject> & obj) const294 ScopedJavaLocalRef<jstring> WebContentsAndroid::GetTitle(
295 JNIEnv* env,
296 const JavaParamRef<jobject>& obj) const {
297 return base::android::ConvertUTF16ToJavaString(env,
298 web_contents_->GetTitle());
299 }
300
GetVisibleURL(JNIEnv * env,const JavaParamRef<jobject> & obj) const301 ScopedJavaLocalRef<jobject> WebContentsAndroid::GetVisibleURL(
302 JNIEnv* env,
303 const JavaParamRef<jobject>& obj) const {
304 return url::GURLAndroid::FromNativeGURL(env, web_contents_->GetVisibleURL());
305 }
306
IsLoading(JNIEnv * env,const JavaParamRef<jobject> & obj) const307 bool WebContentsAndroid::IsLoading(JNIEnv* env,
308 const JavaParamRef<jobject>& obj) const {
309 return web_contents_->IsLoading();
310 }
311
IsLoadingToDifferentDocument(JNIEnv * env,const JavaParamRef<jobject> & obj) const312 bool WebContentsAndroid::IsLoadingToDifferentDocument(
313 JNIEnv* env,
314 const JavaParamRef<jobject>& obj) const {
315 return web_contents_->IsLoadingToDifferentDocument();
316 }
317
DispatchBeforeUnload(JNIEnv * env,const JavaParamRef<jobject> & obj,bool auto_cancel)318 void WebContentsAndroid::DispatchBeforeUnload(JNIEnv* env,
319 const JavaParamRef<jobject>& obj,
320 bool auto_cancel) {
321 web_contents_->DispatchBeforeUnload(auto_cancel);
322 }
323
Stop(JNIEnv * env,const JavaParamRef<jobject> & obj)324 void WebContentsAndroid::Stop(JNIEnv* env, const JavaParamRef<jobject>& obj) {
325 web_contents_->Stop();
326 }
327
Cut(JNIEnv * env,const JavaParamRef<jobject> & obj)328 void WebContentsAndroid::Cut(JNIEnv* env, const JavaParamRef<jobject>& obj) {
329 web_contents_->Cut();
330 }
331
Copy(JNIEnv * env,const JavaParamRef<jobject> & obj)332 void WebContentsAndroid::Copy(JNIEnv* env, const JavaParamRef<jobject>& obj) {
333 web_contents_->Copy();
334 }
335
Paste(JNIEnv * env,const JavaParamRef<jobject> & obj)336 void WebContentsAndroid::Paste(JNIEnv* env, const JavaParamRef<jobject>& obj) {
337 web_contents_->Paste();
338 }
339
PasteAsPlainText(JNIEnv * env,const JavaParamRef<jobject> & obj)340 void WebContentsAndroid::PasteAsPlainText(JNIEnv* env,
341 const JavaParamRef<jobject>& obj) {
342 // Paste as if user typed the characters, which should match current style of
343 // the caret location.
344 web_contents_->PasteAndMatchStyle();
345 }
346
Replace(JNIEnv * env,const JavaParamRef<jobject> & obj,const JavaParamRef<jstring> & jstr)347 void WebContentsAndroid::Replace(JNIEnv* env,
348 const JavaParamRef<jobject>& obj,
349 const JavaParamRef<jstring>& jstr) {
350 web_contents_->Replace(base::android::ConvertJavaStringToUTF16(env, jstr));
351 }
352
SelectAll(JNIEnv * env,const JavaParamRef<jobject> & obj)353 void WebContentsAndroid::SelectAll(JNIEnv* env,
354 const JavaParamRef<jobject>& obj) {
355 web_contents_->SelectAll();
356 }
357
CollapseSelection(JNIEnv * env,const JavaParamRef<jobject> & obj)358 void WebContentsAndroid::CollapseSelection(JNIEnv* env,
359 const JavaParamRef<jobject>& obj) {
360 web_contents_->CollapseSelection();
361 }
362
GetRenderWidgetHostView(JNIEnv * env,const JavaParamRef<jobject> & obj)363 ScopedJavaLocalRef<jobject> WebContentsAndroid::GetRenderWidgetHostView(
364 JNIEnv* env,
365 const JavaParamRef<jobject>& obj) {
366 RenderWidgetHostViewAndroid* rwhva = GetRenderWidgetHostViewAndroid();
367 if (!rwhva)
368 return nullptr;
369 return rwhva->GetJavaObject();
370 }
371
GetInnerWebContents(JNIEnv * env,const JavaParamRef<jobject> & obj)372 ScopedJavaLocalRef<jobjectArray> WebContentsAndroid::GetInnerWebContents(
373 JNIEnv* env,
374 const JavaParamRef<jobject>& obj) {
375 std::vector<WebContents*> inner_web_contents =
376 web_contents_->GetInnerWebContents();
377 jclass clazz =
378 org_chromium_content_browser_webcontents_WebContentsImpl_clazz(env);
379 jobjectArray array =
380 env->NewObjectArray(inner_web_contents.size(), clazz, nullptr);
381 for (size_t i = 0; i < inner_web_contents.size(); i++) {
382 ScopedJavaLocalRef<jobject> contents_java =
383 inner_web_contents[i]->GetJavaWebContents();
384 env->SetObjectArrayElement(array, i, contents_java.obj());
385 }
386 return ScopedJavaLocalRef<jobjectArray>(env, array);
387 }
388
GetVisibility(JNIEnv * env)389 jint WebContentsAndroid::GetVisibility(JNIEnv* env) {
390 return static_cast<jint>(web_contents_->GetVisibility());
391 }
392
393 RenderWidgetHostViewAndroid*
GetRenderWidgetHostViewAndroid()394 WebContentsAndroid::GetRenderWidgetHostViewAndroid() {
395 RenderWidgetHostView* rwhv = NULL;
396 rwhv = web_contents_->GetRenderWidgetHostView();
397 return static_cast<RenderWidgetHostViewAndroid*>(rwhv);
398 }
399
GetBackgroundColor(JNIEnv * env,const JavaParamRef<jobject> & obj)400 jint WebContentsAndroid::GetBackgroundColor(JNIEnv* env,
401 const JavaParamRef<jobject>& obj) {
402 RenderWidgetHostViewAndroid* rwhva = GetRenderWidgetHostViewAndroid();
403
404 // Return transparent as an indicator that the web content background color
405 // is not specified, and a default background color will be used on the Java
406 // side.
407 if (!rwhva || !rwhva->GetCachedBackgroundColor())
408 return SK_ColorTRANSPARENT;
409 return *rwhva->GetCachedBackgroundColor();
410 }
411
GetLastCommittedURL(JNIEnv * env,const JavaParamRef<jobject> &) const412 ScopedJavaLocalRef<jstring> WebContentsAndroid::GetLastCommittedURL(
413 JNIEnv* env,
414 const JavaParamRef<jobject>&) const {
415 return ConvertUTF8ToJavaString(env,
416 web_contents_->GetLastCommittedURL().spec());
417 }
418
IsIncognito(JNIEnv * env,const JavaParamRef<jobject> & obj)419 jboolean WebContentsAndroid::IsIncognito(JNIEnv* env,
420 const JavaParamRef<jobject>& obj) {
421 return web_contents_->GetBrowserContext()->IsOffTheRecord();
422 }
423
ResumeLoadingCreatedWebContents(JNIEnv * env,const JavaParamRef<jobject> & obj)424 void WebContentsAndroid::ResumeLoadingCreatedWebContents(
425 JNIEnv* env,
426 const JavaParamRef<jobject>& obj) {
427 web_contents_->ResumeLoadingCreatedWebContents();
428 }
429
OnHide(JNIEnv * env,const JavaParamRef<jobject> & obj)430 void WebContentsAndroid::OnHide(JNIEnv* env, const JavaParamRef<jobject>& obj) {
431 web_contents_->WasHidden();
432 }
433
OnShow(JNIEnv * env,const JavaParamRef<jobject> & obj)434 void WebContentsAndroid::OnShow(JNIEnv* env, const JavaParamRef<jobject>& obj) {
435 web_contents_->WasShown();
436 }
437
SetImportance(JNIEnv * env,const base::android::JavaParamRef<jobject> & obj,jint main_frame_importance)438 void WebContentsAndroid::SetImportance(
439 JNIEnv* env,
440 const base::android::JavaParamRef<jobject>& obj,
441 jint main_frame_importance) {
442 web_contents_->SetMainFrameImportance(
443 static_cast<ChildProcessImportance>(main_frame_importance));
444 }
445
SuspendAllMediaPlayers(JNIEnv * env,const JavaParamRef<jobject> & jobj)446 void WebContentsAndroid::SuspendAllMediaPlayers(
447 JNIEnv* env,
448 const JavaParamRef<jobject>& jobj) {
449 web_contents_->media_web_contents_observer()->SuspendAllMediaPlayers();
450 }
451
SetAudioMuted(JNIEnv * env,const JavaParamRef<jobject> & jobj,jboolean mute)452 void WebContentsAndroid::SetAudioMuted(JNIEnv* env,
453 const JavaParamRef<jobject>& jobj,
454 jboolean mute) {
455 web_contents_->SetAudioMuted(mute);
456 }
457
FocusLocationBarByDefault(JNIEnv * env,const JavaParamRef<jobject> & obj)458 jboolean WebContentsAndroid::FocusLocationBarByDefault(
459 JNIEnv* env,
460 const JavaParamRef<jobject>& obj) {
461 return web_contents_->FocusLocationBarByDefault();
462 }
463
IsFullscreenForCurrentTab(JNIEnv * env,const JavaParamRef<jobject> & obj)464 bool WebContentsAndroid::IsFullscreenForCurrentTab(
465 JNIEnv* env,
466 const JavaParamRef<jobject>& obj) {
467 return web_contents_->IsFullscreen();
468 }
469
ExitFullscreen(JNIEnv * env,const JavaParamRef<jobject> & obj)470 void WebContentsAndroid::ExitFullscreen(JNIEnv* env,
471 const JavaParamRef<jobject>& obj) {
472 web_contents_->ExitFullscreen(/*will_cause_resize=*/false);
473 }
474
ScrollFocusedEditableNodeIntoView(JNIEnv * env,const JavaParamRef<jobject> & obj)475 void WebContentsAndroid::ScrollFocusedEditableNodeIntoView(
476 JNIEnv* env,
477 const JavaParamRef<jobject>& obj) {
478 auto* input_handler = web_contents_->GetFocusedFrameWidgetInputHandler();
479 if (!input_handler)
480 return;
481 RenderFrameHostImpl* rfh = web_contents_->GetMainFrame();
482 bool should_overlay_content =
483 rfh && rfh->ShouldVirtualKeyboardOverlayContent();
484 if (!should_overlay_content)
485 input_handler->ScrollFocusedEditableNodeIntoRect(gfx::Rect());
486 }
487
SelectWordAroundCaretAck(bool did_select,int start_adjust,int end_adjust)488 void WebContentsAndroid::SelectWordAroundCaretAck(bool did_select,
489 int start_adjust,
490 int end_adjust) {
491 RenderWidgetHostViewAndroid* rwhva = GetRenderWidgetHostViewAndroid();
492 if (rwhva)
493 rwhva->SelectWordAroundCaretAck(did_select, start_adjust, end_adjust);
494 }
495
SelectWordAroundCaret(JNIEnv * env,const JavaParamRef<jobject> & obj)496 void WebContentsAndroid::SelectWordAroundCaret(
497 JNIEnv* env,
498 const JavaParamRef<jobject>& obj) {
499 auto* input_handler = web_contents_->GetFocusedFrameWidgetInputHandler();
500 if (!input_handler)
501 return;
502 input_handler->SelectWordAroundCaret(
503 base::BindOnce(&WebContentsAndroid::SelectWordAroundCaretAck,
504 weak_factory_.GetWeakPtr()));
505 }
506
AdjustSelectionByCharacterOffset(JNIEnv * env,const JavaParamRef<jobject> & obj,jint start_adjust,jint end_adjust,jboolean show_selection_menu)507 void WebContentsAndroid::AdjustSelectionByCharacterOffset(
508 JNIEnv* env,
509 const JavaParamRef<jobject>& obj,
510 jint start_adjust,
511 jint end_adjust,
512 jboolean show_selection_menu) {
513 web_contents_->AdjustSelectionByCharacterOffset(start_adjust, end_adjust,
514 show_selection_menu);
515 }
516
InitializeRenderFrameForJavaScript()517 bool WebContentsAndroid::InitializeRenderFrameForJavaScript() {
518 if (!web_contents_->GetFrameTree()
519 ->root()
520 ->render_manager()
521 ->InitializeMainRenderFrameForImmediateUse()) {
522 LOG(ERROR) << "Failed to initialize RenderFrame to evaluate javascript";
523 return false;
524 }
525 return true;
526 }
527
EvaluateJavaScript(JNIEnv * env,const JavaParamRef<jobject> & obj,const JavaParamRef<jstring> & script,const JavaParamRef<jobject> & callback)528 void WebContentsAndroid::EvaluateJavaScript(
529 JNIEnv* env,
530 const JavaParamRef<jobject>& obj,
531 const JavaParamRef<jstring>& script,
532 const JavaParamRef<jobject>& callback) {
533 RenderViewHost* rvh = web_contents_->GetRenderViewHost();
534 DCHECK(rvh);
535
536 if (!InitializeRenderFrameForJavaScript())
537 return;
538
539 if (!callback) {
540 // No callback requested.
541 web_contents_->GetMainFrame()->ExecuteJavaScript(
542 ConvertJavaStringToUTF16(env, script), base::NullCallback());
543 return;
544 }
545
546 // Secure the Java callback in a scoped object and give ownership of it to the
547 // base::Callback.
548 ScopedJavaGlobalRef<jobject> j_callback;
549 j_callback.Reset(env, callback);
550
551 web_contents_->GetMainFrame()->ExecuteJavaScript(
552 ConvertJavaStringToUTF16(env, script),
553 base::BindOnce(&JavaScriptResultCallback, j_callback));
554 }
555
EvaluateJavaScriptForTests(JNIEnv * env,const JavaParamRef<jobject> & obj,const JavaParamRef<jstring> & script,const JavaParamRef<jobject> & callback)556 void WebContentsAndroid::EvaluateJavaScriptForTests(
557 JNIEnv* env,
558 const JavaParamRef<jobject>& obj,
559 const JavaParamRef<jstring>& script,
560 const JavaParamRef<jobject>& callback) {
561 RenderViewHost* rvh = web_contents_->GetRenderViewHost();
562 DCHECK(rvh);
563
564 if (!InitializeRenderFrameForJavaScript())
565 return;
566
567 if (!callback) {
568 // No callback requested.
569 web_contents_->GetMainFrame()->ExecuteJavaScriptForTests(
570 ConvertJavaStringToUTF16(env, script), base::NullCallback());
571 return;
572 }
573
574 // Secure the Java callback in a scoped object and give ownership of it to the
575 // base::Callback.
576 ScopedJavaGlobalRef<jobject> j_callback;
577 j_callback.Reset(env, callback);
578
579 web_contents_->GetMainFrame()->ExecuteJavaScriptForTests(
580 ConvertJavaStringToUTF16(env, script),
581 base::BindOnce(&JavaScriptResultCallback, j_callback));
582 }
583
AddMessageToDevToolsConsole(JNIEnv * env,const JavaParamRef<jobject> & jobj,jint level,const JavaParamRef<jstring> & message)584 void WebContentsAndroid::AddMessageToDevToolsConsole(
585 JNIEnv* env,
586 const JavaParamRef<jobject>& jobj,
587 jint level,
588 const JavaParamRef<jstring>& message) {
589 DCHECK_GE(level, 0);
590 DCHECK_LE(level, static_cast<int>(blink::mojom::ConsoleMessageLevel::kError));
591
592 web_contents_->GetMainFrame()->AddMessageToConsole(
593 static_cast<blink::mojom::ConsoleMessageLevel>(level),
594 ConvertJavaStringToUTF8(env, message));
595 }
596
PostMessageToMainFrame(JNIEnv * env,const JavaParamRef<jobject> & obj,const JavaParamRef<jstring> & jmessage,const JavaParamRef<jstring> & jsource_origin,const JavaParamRef<jstring> & jtarget_origin,const JavaParamRef<jobjectArray> & jports)597 void WebContentsAndroid::PostMessageToMainFrame(
598 JNIEnv* env,
599 const JavaParamRef<jobject>& obj,
600 const JavaParamRef<jstring>& jmessage,
601 const JavaParamRef<jstring>& jsource_origin,
602 const JavaParamRef<jstring>& jtarget_origin,
603 const JavaParamRef<jobjectArray>& jports) {
604 content::MessagePortProvider::PostMessageToFrame(
605 web_contents_, env, jsource_origin, jtarget_origin, jmessage, jports);
606 }
607
HasAccessedInitialDocument(JNIEnv * env,const JavaParamRef<jobject> & jobj)608 jboolean WebContentsAndroid::HasAccessedInitialDocument(
609 JNIEnv* env,
610 const JavaParamRef<jobject>& jobj) {
611 return static_cast<WebContentsImpl*>(web_contents_)->
612 HasAccessedInitialDocument();
613 }
614
GetThemeColor(JNIEnv * env,const JavaParamRef<jobject> & obj)615 jint WebContentsAndroid::GetThemeColor(JNIEnv* env,
616 const JavaParamRef<jobject>& obj) {
617 return web_contents_->GetThemeColor().value_or(SK_ColorTRANSPARENT);
618 }
619
GetLoadProgress(JNIEnv * env,const JavaParamRef<jobject> & obj)620 jfloat WebContentsAndroid::GetLoadProgress(JNIEnv* env,
621 const JavaParamRef<jobject>& obj) {
622 return web_contents_->GetLoadProgress();
623 }
624
RequestSmartClipExtract(JNIEnv * env,const JavaParamRef<jobject> & obj,const JavaParamRef<jobject> & callback,jint x,jint y,jint width,jint height)625 void WebContentsAndroid::RequestSmartClipExtract(
626 JNIEnv* env,
627 const JavaParamRef<jobject>& obj,
628 const JavaParamRef<jobject>& callback,
629 jint x,
630 jint y,
631 jint width,
632 jint height) {
633 // Secure the Java callback in a scoped object and give ownership of it to the
634 // base::Callback.
635 ScopedJavaGlobalRef<jobject> j_callback;
636 j_callback.Reset(env, callback);
637
638 web_contents_->GetMainFrame()->RequestSmartClipExtract(
639 base::BindOnce(&SmartClipCallback, j_callback),
640 gfx::Rect(x, y, width, height));
641 }
642
RequestAccessibilitySnapshot(JNIEnv * env,const JavaParamRef<jobject> & obj,const JavaParamRef<jobject> & callback)643 void WebContentsAndroid::RequestAccessibilitySnapshot(
644 JNIEnv* env,
645 const JavaParamRef<jobject>& obj,
646 const JavaParamRef<jobject>& callback) {
647 // Secure the Java callback in a scoped object and give ownership of it to the
648 // base::Callback.
649 ScopedJavaGlobalRef<jobject> j_callback;
650 j_callback.Reset(env, callback);
651
652 static_cast<WebContentsImpl*>(web_contents_)
653 ->RequestAXTreeSnapshot(
654 base::BindOnce(&AXTreeSnapshotCallback, j_callback),
655 ui::kAXModeComplete);
656 }
657
GetEncoding(JNIEnv * env,const JavaParamRef<jobject> & obj) const658 ScopedJavaLocalRef<jstring> WebContentsAndroid::GetEncoding(
659 JNIEnv* env,
660 const JavaParamRef<jobject>& obj) const {
661 return base::android::ConvertUTF8ToJavaString(env,
662 web_contents_->GetEncoding());
663 }
664
SetOverscrollRefreshHandler(JNIEnv * env,const base::android::JavaParamRef<jobject> & obj,const base::android::JavaParamRef<jobject> & overscroll_refresh_handler)665 void WebContentsAndroid::SetOverscrollRefreshHandler(
666 JNIEnv* env,
667 const base::android::JavaParamRef<jobject>& obj,
668 const base::android::JavaParamRef<jobject>& overscroll_refresh_handler) {
669 WebContentsViewAndroid* view =
670 static_cast<WebContentsViewAndroid*>(web_contents_->GetView());
671 view->SetOverscrollRefreshHandler(
672 std::make_unique<ui::OverscrollRefreshHandler>(
673 overscroll_refresh_handler));
674 }
675
SetSpatialNavigationDisabled(JNIEnv * env,const base::android::JavaParamRef<jobject> & obj,bool disabled)676 void WebContentsAndroid::SetSpatialNavigationDisabled(
677 JNIEnv* env,
678 const base::android::JavaParamRef<jobject>& obj,
679 bool disabled) {
680 web_contents_->SetSpatialNavigationDisabled(disabled);
681 }
682
DownloadImage(JNIEnv * env,const base::android::JavaParamRef<jobject> & obj,const base::android::JavaParamRef<jstring> & jurl,jboolean is_fav_icon,jint max_bitmap_size,jboolean bypass_cache,const base::android::JavaParamRef<jobject> & jcallback)683 int WebContentsAndroid::DownloadImage(
684 JNIEnv* env,
685 const base::android::JavaParamRef<jobject>& obj,
686 const base::android::JavaParamRef<jstring>& jurl,
687 jboolean is_fav_icon,
688 jint max_bitmap_size,
689 jboolean bypass_cache,
690 const base::android::JavaParamRef<jobject>& jcallback) {
691 GURL url(base::android::ConvertJavaStringToUTF8(env, jurl));
692 const uint32_t preferred_size = 0;
693 return web_contents_->DownloadImage(
694 url, is_fav_icon, preferred_size, max_bitmap_size, bypass_cache,
695 base::BindOnce(&WebContentsAndroid::OnFinishDownloadImage,
696 weak_factory_.GetWeakPtr(),
697 ScopedJavaGlobalRef<jobject>(env, obj),
698 ScopedJavaGlobalRef<jobject>(env, jcallback)));
699 }
700
SetHasPersistentVideo(JNIEnv * env,const base::android::JavaParamRef<jobject> & obj,jboolean value)701 void WebContentsAndroid::SetHasPersistentVideo(
702 JNIEnv* env,
703 const base::android::JavaParamRef<jobject>& obj,
704 jboolean value) {
705 web_contents_->SetHasPersistentVideo(value);
706 }
707
HasActiveEffectivelyFullscreenVideo(JNIEnv * env,const base::android::JavaParamRef<jobject> & obj)708 bool WebContentsAndroid::HasActiveEffectivelyFullscreenVideo(
709 JNIEnv* env,
710 const base::android::JavaParamRef<jobject>& obj) {
711 return web_contents_->HasActiveEffectivelyFullscreenVideo();
712 }
713
IsPictureInPictureAllowedForFullscreenVideo(JNIEnv * env,const base::android::JavaParamRef<jobject> & obj)714 bool WebContentsAndroid::IsPictureInPictureAllowedForFullscreenVideo(
715 JNIEnv* env,
716 const base::android::JavaParamRef<jobject>& obj) {
717 return web_contents_->IsPictureInPictureAllowedForFullscreenVideo();
718 }
719
720 base::android::ScopedJavaLocalRef<jobject>
GetFullscreenVideoSize(JNIEnv * env,const base::android::JavaParamRef<jobject> & obj)721 WebContentsAndroid::GetFullscreenVideoSize(
722 JNIEnv* env,
723 const base::android::JavaParamRef<jobject>& obj) {
724 if (!web_contents_->GetFullscreenVideoSize())
725 return ScopedJavaLocalRef<jobject>(); // Return null.
726
727 gfx::Size size = web_contents_->GetFullscreenVideoSize().value();
728 return Java_WebContentsImpl_createSize(env, size.width(), size.height());
729 }
730
SetSize(JNIEnv * env,const base::android::JavaParamRef<jobject> & obj,jint width,jint height)731 void WebContentsAndroid::SetSize(
732 JNIEnv* env,
733 const base::android::JavaParamRef<jobject>& obj,
734 jint width,
735 jint height) {
736 web_contents_->GetNativeView()->OnSizeChanged(width, height);
737 }
738
GetWidth(JNIEnv * env,const base::android::JavaParamRef<jobject> & obj)739 int WebContentsAndroid::GetWidth(
740 JNIEnv* env,
741 const base::android::JavaParamRef<jobject>& obj) {
742 return web_contents_->GetNativeView()->GetSize().width();
743 }
744
GetHeight(JNIEnv * env,const base::android::JavaParamRef<jobject> & obj)745 int WebContentsAndroid::GetHeight(
746 JNIEnv* env,
747 const base::android::JavaParamRef<jobject>& obj) {
748 return web_contents_->GetNativeView()->GetSize().height();
749 }
750
GetOrCreateEventForwarder(JNIEnv * env,const base::android::JavaParamRef<jobject> & obj)751 ScopedJavaLocalRef<jobject> WebContentsAndroid::GetOrCreateEventForwarder(
752 JNIEnv* env,
753 const base::android::JavaParamRef<jobject>& obj) {
754 gfx::NativeView native_view = web_contents_->GetView()->GetNativeView();
755 return native_view->GetEventForwarder();
756 }
757
OnFinishDownloadImage(const JavaRef<jobject> & obj,const JavaRef<jobject> & callback,int id,int http_status_code,const GURL & url,const std::vector<SkBitmap> & bitmaps,const std::vector<gfx::Size> & sizes)758 void WebContentsAndroid::OnFinishDownloadImage(
759 const JavaRef<jobject>& obj,
760 const JavaRef<jobject>& callback,
761 int id,
762 int http_status_code,
763 const GURL& url,
764 const std::vector<SkBitmap>& bitmaps,
765 const std::vector<gfx::Size>& sizes) {
766 JNIEnv* env = base::android::AttachCurrentThread();
767 ScopedJavaLocalRef<jobject> jbitmaps =
768 Java_WebContentsImpl_createBitmapList(env);
769 ScopedJavaLocalRef<jobject> jsizes =
770 Java_WebContentsImpl_createSizeList(env);
771 ScopedJavaLocalRef<jstring> jurl =
772 base::android::ConvertUTF8ToJavaString(env, url.spec());
773
774 for (const SkBitmap& bitmap : bitmaps) {
775 // WARNING: convering to java bitmaps results in duplicate memory
776 // allocations, which increases the chance of OOMs if DownloadImage() is
777 // misused.
778 ScopedJavaLocalRef<jobject> jbitmap = gfx::ConvertToJavaBitmap(bitmap);
779 Java_WebContentsImpl_addToBitmapList(env, jbitmaps, jbitmap);
780 }
781 for (const gfx::Size& size : sizes) {
782 Java_WebContentsImpl_createSizeAndAddToList(env, jsizes, size.width(),
783 size.height());
784 }
785 Java_WebContentsImpl_onDownloadImageFinished(
786 env, obj, callback, id, http_status_code, jurl, jbitmaps, jsizes);
787 }
788
SetMediaSession(const ScopedJavaLocalRef<jobject> & j_media_session)789 void WebContentsAndroid::SetMediaSession(
790 const ScopedJavaLocalRef<jobject>& j_media_session) {
791 JNIEnv* env = base::android::AttachCurrentThread();
792 Java_WebContentsImpl_setMediaSession(env, obj_, j_media_session);
793 }
794
SendOrientationChangeEvent(JNIEnv * env,const JavaParamRef<jobject> & obj,jint orientation)795 void WebContentsAndroid::SendOrientationChangeEvent(
796 JNIEnv* env,
797 const JavaParamRef<jobject>& obj,
798 jint orientation) {
799 base::RecordAction(base::UserMetricsAction("ScreenOrientationChange"));
800 WebContentsViewAndroid* view =
801 static_cast<WebContentsViewAndroid*>(web_contents_->GetView());
802 view->set_device_orientation(orientation);
803 RenderWidgetHostViewAndroid* rwhva = GetRenderWidgetHostViewAndroid();
804 if (rwhva)
805 rwhva->UpdateScreenInfo(web_contents_->GetView()->GetNativeView());
806
807 web_contents_->OnScreenOrientationChange();
808 }
809
OnScaleFactorChanged(JNIEnv * env,const JavaParamRef<jobject> & obj)810 void WebContentsAndroid::OnScaleFactorChanged(
811 JNIEnv* env,
812 const JavaParamRef<jobject>& obj) {
813 RenderWidgetHostViewAndroid* rwhva = GetRenderWidgetHostViewAndroid();
814 if (rwhva) {
815 // |SendScreenRects()| indirectly calls GetViewSize() that asks Java layer.
816 web_contents_->SendScreenRects();
817 rwhva->SynchronizeVisualProperties(cc::DeadlinePolicy::UseDefaultDeadline(),
818 base::nullopt);
819 }
820 }
821
SetFocus(JNIEnv * env,const JavaParamRef<jobject> & obj,jboolean focused)822 void WebContentsAndroid::SetFocus(JNIEnv* env,
823 const JavaParamRef<jobject>& obj,
824 jboolean focused) {
825 WebContentsViewAndroid* view =
826 static_cast<WebContentsViewAndroid*>(web_contents_->GetView());
827 view->SetFocus(focused);
828 }
829
IsBeingDestroyed(JNIEnv * env,const JavaParamRef<jobject> & obj)830 bool WebContentsAndroid::IsBeingDestroyed(JNIEnv* env,
831 const JavaParamRef<jobject>& obj) {
832 return web_contents_->IsBeingDestroyed();
833 }
834
SetDisplayCutoutSafeArea(JNIEnv * env,const base::android::JavaParamRef<jobject> & obj,int top,int left,int bottom,int right)835 void WebContentsAndroid::SetDisplayCutoutSafeArea(
836 JNIEnv* env,
837 const base::android::JavaParamRef<jobject>& obj,
838 int top,
839 int left,
840 int bottom,
841 int right) {
842 web_contents()->SetDisplayCutoutSafeArea(
843 gfx::Insets(top, left, bottom, right));
844 }
845
NotifyRendererPreferenceUpdate(JNIEnv * env,const base::android::JavaParamRef<jobject> & obj)846 void WebContentsAndroid::NotifyRendererPreferenceUpdate(
847 JNIEnv* env,
848 const base::android::JavaParamRef<jobject>& obj) {
849 web_contents_->OnWebPreferencesChanged();
850 }
851
NotifyBrowserControlsHeightChanged(JNIEnv * env,const base::android::JavaParamRef<jobject> & obj)852 void WebContentsAndroid::NotifyBrowserControlsHeightChanged(
853 JNIEnv* env,
854 const base::android::JavaParamRef<jobject>& obj) {
855 web_contents_->GetNativeView()->OnBrowserControlsHeightChanged();
856 }
857
858 } // namespace content
859