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