Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / content / browser / web_contents / web_contents_android.cc
blob8fd5c506a2dfb263920e9538108c22af5985d837
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.
5 #include "content/browser/web_contents/web_contents_android.h"
7 #include "base/android/jni_android.h"
8 #include "base/android/jni_array.h"
9 #include "base/android/jni_string.h"
10 #include "base/command_line.h"
11 #include "base/containers/hash_tables.h"
12 #include "base/json/json_writer.h"
13 #include "base/lazy_instance.h"
14 #include "base/logging.h"
15 #include "content/browser/accessibility/browser_accessibility_android.h"
16 #include "content/browser/accessibility/browser_accessibility_manager_android.h"
17 #include "content/browser/android/content_view_core_impl.h"
18 #include "content/browser/android/interstitial_page_delegate_android.h"
19 #include "content/browser/frame_host/interstitial_page_impl.h"
20 #include "content/browser/media/android/browser_media_player_manager.h"
21 #include "content/browser/media/media_web_contents_observer.h"
22 #include "content/browser/renderer_host/render_view_host_impl.h"
23 #include "content/browser/web_contents/web_contents_impl.h"
24 #include "content/common/devtools_messages.h"
25 #include "content/common/frame_messages.h"
26 #include "content/common/input_messages.h"
27 #include "content/common/view_messages.h"
28 #include "content/public/browser/browser_context.h"
29 #include "content/public/browser/browser_thread.h"
30 #include "content/public/browser/web_contents.h"
31 #include "content/public/common/content_switches.h"
32 #include "jni/WebContentsImpl_jni.h"
33 #include "net/android/network_library.h"
34 #include "ui/accessibility/ax_node_data.h"
35 #include "ui/gfx/android/device_display_info.h"
37 using base::android::AttachCurrentThread;
38 using base::android::ConvertJavaStringToUTF8;
39 using base::android::ConvertJavaStringToUTF16;
40 using base::android::ConvertUTF8ToJavaString;
41 using base::android::ConvertUTF16ToJavaString;
42 using base::android::ScopedJavaGlobalRef;
43 using base::android::ToJavaIntArray;
45 namespace content {
47 namespace {
49 // Track all WebContentsAndroid objects here so that we don't deserialize a
50 // destroyed WebContents object.
51 base::LazyInstance<base::hash_set<WebContentsAndroid*> >::Leaky
52 g_allocated_web_contents_androids = LAZY_INSTANCE_INITIALIZER;
54 void JavaScriptResultCallback(const ScopedJavaGlobalRef<jobject>& callback,
55 const base::Value* result) {
56 JNIEnv* env = base::android::AttachCurrentThread();
57 std::string json;
58 base::JSONWriter::Write(*result, &json);
59 ScopedJavaLocalRef<jstring> j_json = ConvertUTF8ToJavaString(env, json);
60 Java_WebContentsImpl_onEvaluateJavaScriptResult(
61 env, j_json.obj(), callback.obj());
64 ScopedJavaLocalRef<jobject> WalkAXTreeDepthFirst(JNIEnv* env,
65 BrowserAccessibilityAndroid* node, float scale_factor,
66 float y_offset, float x_scroll) {
67 ScopedJavaLocalRef<jstring> j_text =
68 ConvertUTF16ToJavaString(env, node->GetText());
69 ScopedJavaLocalRef<jstring> j_class =
70 ConvertUTF8ToJavaString(env, node->GetClassName());
71 const gfx::Rect& location = node->GetLocalBoundsRect();
72 // The style attributes exists and valid if size attribute exists. Otherwise,
73 // they are not. Use a negative size information to indicate the existence
74 // of style information.
75 float size = -1.0;
76 int color = 0;
77 int bgcolor = 0;
78 int text_style = 0;
79 if (node->HasFloatAttribute(ui::AX_ATTR_FONT_SIZE)) {
80 color = node->GetIntAttribute(ui::AX_ATTR_COLOR);
81 bgcolor = node->GetIntAttribute(ui::AX_ATTR_BACKGROUND_COLOR);
82 size = node->GetFloatAttribute(ui::AX_ATTR_FONT_SIZE);
83 text_style = node->GetIntAttribute(ui::AX_ATTR_TEXT_STYLE);
85 ScopedJavaLocalRef<jobject> j_node =
86 Java_WebContentsImpl_createAccessibilitySnapshotNode(env,
87 scale_factor * location.x() - x_scroll,
88 scale_factor * location.y() + y_offset,
89 scale_factor * node->GetScrollX(), scale_factor * node->GetScrollY(),
90 scale_factor * location.width(), scale_factor * location.height(),
91 j_text.obj(), color, bgcolor, scale_factor * size, text_style,
92 j_class.obj());
94 for(uint32 i = 0; i < node->PlatformChildCount(); i++) {
95 BrowserAccessibilityAndroid* child =
96 static_cast<BrowserAccessibilityAndroid*>(
97 node->PlatformGetChild(i));
98 Java_WebContentsImpl_addAccessibilityNodeAsChild(env,
99 j_node.obj(), WalkAXTreeDepthFirst(env, child, scale_factor, y_offset,
100 x_scroll).obj());
102 return j_node;
105 // Walks over the AXTreeUpdate and creates a light weight snapshot.
106 void AXTreeSnapshotCallback(const ScopedJavaGlobalRef<jobject>& callback,
107 float scale_factor,
108 float y_offset,
109 float x_scroll,
110 const ui::AXTreeUpdate& result) {
111 JNIEnv* env = base::android::AttachCurrentThread();
112 if (result.nodes.empty()) {
113 Java_WebContentsImpl_onAccessibilitySnapshot(env, nullptr, callback.obj());
114 return;
116 scoped_ptr<BrowserAccessibilityManagerAndroid> manager(
117 static_cast<BrowserAccessibilityManagerAndroid*>(
118 BrowserAccessibilityManager::Create(result, nullptr)));
119 manager->set_prune_tree_for_screen_reader(false);
120 BrowserAccessibilityAndroid* root =
121 static_cast<BrowserAccessibilityAndroid*>(manager->GetRoot());
122 ScopedJavaLocalRef<jobject> j_root =
123 WalkAXTreeDepthFirst(env, root, scale_factor, y_offset, x_scroll);
124 Java_WebContentsImpl_onAccessibilitySnapshot(
125 env, j_root.obj(), callback.obj());
128 void ReleaseAllMediaPlayers(WebContents* web_contents,
129 RenderFrameHost* render_frame_host) {
130 BrowserMediaPlayerManager* manager =
131 static_cast<WebContentsImpl*>(web_contents)->
132 media_web_contents_observer()->GetMediaPlayerManager(
133 render_frame_host);
134 if (manager)
135 manager->ReleaseAllMediaPlayers();
138 } // namespace
140 // static
141 WebContents* WebContents::FromJavaWebContents(
142 jobject jweb_contents_android) {
143 DCHECK_CURRENTLY_ON(BrowserThread::UI);
144 if (!jweb_contents_android)
145 return NULL;
147 WebContentsAndroid* web_contents_android =
148 reinterpret_cast<WebContentsAndroid*>(
149 Java_WebContentsImpl_getNativePointer(AttachCurrentThread(),
150 jweb_contents_android));
151 if (!web_contents_android)
152 return NULL;
153 return web_contents_android->web_contents();
156 // static
157 static void DestroyWebContents(JNIEnv* env,
158 jclass clazz,
159 jlong jweb_contents_android_ptr) {
160 WebContentsAndroid* web_contents_android =
161 reinterpret_cast<WebContentsAndroid*>(jweb_contents_android_ptr);
162 if (!web_contents_android)
163 return;
165 WebContents* web_contents = web_contents_android->web_contents();
166 if (!web_contents)
167 return;
169 delete web_contents;
172 // static
173 jobject FromNativePtr(JNIEnv* env,
174 jclass clazz,
175 jlong web_contents_ptr) {
176 WebContentsAndroid* web_contents_android =
177 reinterpret_cast<WebContentsAndroid*>(web_contents_ptr);
179 if (!web_contents_android)
180 return 0;
182 // Check to make sure this object hasn't been destroyed.
183 if (g_allocated_web_contents_androids.Get().find(web_contents_android) ==
184 g_allocated_web_contents_androids.Get().end()) {
185 return 0;
188 return web_contents_android->GetJavaObject().Release();
191 // static
192 bool WebContentsAndroid::Register(JNIEnv* env) {
193 return RegisterNativesImpl(env);
196 WebContentsAndroid::WebContentsAndroid(WebContents* web_contents)
197 : web_contents_(web_contents),
198 navigation_controller_(&(web_contents->GetController())),
199 weak_factory_(this) {
200 g_allocated_web_contents_androids.Get().insert(this);
201 JNIEnv* env = AttachCurrentThread();
202 obj_.Reset(env,
203 Java_WebContentsImpl_create(
204 env,
205 reinterpret_cast<intptr_t>(this),
206 navigation_controller_.GetJavaObject().obj()).obj());
207 RendererPreferences* prefs = web_contents_->GetMutableRendererPrefs();
208 base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
209 prefs->network_contry_iso =
210 command_line->HasSwitch(switches::kNetworkCountryIso) ?
211 command_line->GetSwitchValueASCII(switches::kNetworkCountryIso)
212 : net::android::GetTelephonyNetworkCountryIso();
215 WebContentsAndroid::~WebContentsAndroid() {
216 DCHECK(g_allocated_web_contents_androids.Get().find(this) !=
217 g_allocated_web_contents_androids.Get().end());
218 g_allocated_web_contents_androids.Get().erase(this);
219 Java_WebContentsImpl_clearNativePtr(AttachCurrentThread(), obj_.obj());
222 base::android::ScopedJavaLocalRef<jobject>
223 WebContentsAndroid::GetJavaObject() {
224 return base::android::ScopedJavaLocalRef<jobject>(obj_);
227 ScopedJavaLocalRef<jstring> WebContentsAndroid::GetTitle(
228 JNIEnv* env, jobject obj) const {
229 return base::android::ConvertUTF16ToJavaString(env,
230 web_contents_->GetTitle());
233 ScopedJavaLocalRef<jstring> WebContentsAndroid::GetVisibleURL(
234 JNIEnv* env, jobject obj) const {
235 return base::android::ConvertUTF8ToJavaString(
236 env, web_contents_->GetVisibleURL().spec());
239 bool WebContentsAndroid::IsLoading(JNIEnv* env, jobject obj) const {
240 return web_contents_->IsLoading();
243 bool WebContentsAndroid::IsLoadingToDifferentDocument(JNIEnv* env,
244 jobject obj) const {
245 return web_contents_->IsLoadingToDifferentDocument();
248 void WebContentsAndroid::Stop(JNIEnv* env, jobject obj) {
249 web_contents_->Stop();
252 void WebContentsAndroid::Cut(JNIEnv* env, jobject obj) {
253 web_contents_->Cut();
256 void WebContentsAndroid::Copy(JNIEnv* env, jobject obj) {
257 web_contents_->Copy();
260 void WebContentsAndroid::Paste(JNIEnv* env, jobject obj) {
261 web_contents_->Paste();
264 void WebContentsAndroid::SelectAll(JNIEnv* env, jobject obj) {
265 web_contents_->SelectAll();
268 void WebContentsAndroid::Unselect(JNIEnv* env, jobject obj) {
269 web_contents_->Unselect();
272 void WebContentsAndroid::InsertCSS(
273 JNIEnv* env, jobject jobj, jstring jcss) {
274 web_contents_->InsertCSS(base::android::ConvertJavaStringToUTF8(env, jcss));
277 RenderWidgetHostViewAndroid*
278 WebContentsAndroid::GetRenderWidgetHostViewAndroid() {
279 RenderWidgetHostView* rwhv = NULL;
280 rwhv = web_contents_->GetRenderWidgetHostView();
281 if (web_contents_->ShowingInterstitialPage()) {
282 rwhv = web_contents_->GetInterstitialPage()
283 ->GetMainFrame()
284 ->GetRenderViewHost()
285 ->GetView();
287 return static_cast<RenderWidgetHostViewAndroid*>(rwhv);
290 jint WebContentsAndroid::GetBackgroundColor(JNIEnv* env, jobject obj) {
291 RenderWidgetHostViewAndroid* rwhva = GetRenderWidgetHostViewAndroid();
292 if (!rwhva)
293 return SK_ColorWHITE;
294 return rwhva->GetCachedBackgroundColor();
297 ScopedJavaLocalRef<jstring> WebContentsAndroid::GetURL(JNIEnv* env,
298 jobject obj) const {
299 return ConvertUTF8ToJavaString(env, web_contents_->GetURL().spec());
302 ScopedJavaLocalRef<jstring> WebContentsAndroid::GetLastCommittedURL(
303 JNIEnv* env,
304 jobject) const {
305 return ConvertUTF8ToJavaString(env,
306 web_contents_->GetLastCommittedURL().spec());
310 jboolean WebContentsAndroid::IsIncognito(JNIEnv* env, jobject obj) {
311 return web_contents_->GetBrowserContext()->IsOffTheRecord();
314 void WebContentsAndroid::ResumeLoadingCreatedWebContents(JNIEnv* env,
315 jobject obj) {
316 web_contents_->ResumeLoadingCreatedWebContents();
319 void WebContentsAndroid::OnHide(JNIEnv* env, jobject obj) {
320 web_contents_->WasHidden();
323 void WebContentsAndroid::OnShow(JNIEnv* env, jobject obj) {
324 web_contents_->WasShown();
327 void WebContentsAndroid::ReleaseMediaPlayers(JNIEnv* env, jobject jobj) {
328 #if defined(ENABLE_BROWSER_CDMS)
329 web_contents_->ForEachFrame(
330 base::Bind(&ReleaseAllMediaPlayers, base::Unretained(web_contents_)));
331 #endif // defined(ENABLE_BROWSER_CDMS)
334 void WebContentsAndroid::ShowInterstitialPage(
335 JNIEnv* env,
336 jobject obj,
337 jstring jurl,
338 jlong delegate_ptr) {
339 GURL url(base::android::ConvertJavaStringToUTF8(env, jurl));
340 InterstitialPageDelegateAndroid* delegate =
341 reinterpret_cast<InterstitialPageDelegateAndroid*>(delegate_ptr);
342 InterstitialPage* interstitial = InterstitialPage::Create(
343 web_contents_, false, url, delegate);
344 delegate->set_interstitial_page(interstitial);
345 interstitial->Show();
348 jboolean WebContentsAndroid::IsShowingInterstitialPage(JNIEnv* env,
349 jobject obj) {
350 return web_contents_->ShowingInterstitialPage();
353 jboolean WebContentsAndroid::IsRenderWidgetHostViewReady(
354 JNIEnv* env,
355 jobject obj) {
356 RenderWidgetHostViewAndroid* view = GetRenderWidgetHostViewAndroid();
357 return view && view->HasValidFrame();
360 void WebContentsAndroid::ExitFullscreen(JNIEnv* env, jobject obj) {
361 web_contents_->ExitFullscreen();
364 void WebContentsAndroid::UpdateTopControlsState(
365 JNIEnv* env,
366 jobject obj,
367 bool enable_hiding,
368 bool enable_showing,
369 bool animate) {
370 RenderViewHost* host = web_contents_->GetRenderViewHost();
371 if (!host)
372 return;
373 host->Send(new ViewMsg_UpdateTopControlsState(host->GetRoutingID(),
374 enable_hiding,
375 enable_showing,
376 animate));
379 void WebContentsAndroid::ShowImeIfNeeded(JNIEnv* env, jobject obj) {
380 RenderViewHost* host = web_contents_->GetRenderViewHost();
381 if (!host)
382 return;
383 host->Send(new ViewMsg_ShowImeIfNeeded(host->GetRoutingID()));
386 void WebContentsAndroid::ScrollFocusedEditableNodeIntoView(
387 JNIEnv* env,
388 jobject obj) {
389 RenderViewHost* host = web_contents_->GetRenderViewHost();
390 if (!host)
391 return;
392 host->Send(new InputMsg_ScrollFocusedEditableNodeIntoRect(
393 host->GetRoutingID(), gfx::Rect()));
396 void WebContentsAndroid::SelectWordAroundCaret(JNIEnv* env, jobject obj) {
397 RenderViewHost* host = web_contents_->GetRenderViewHost();
398 if (!host)
399 return;
400 host->SelectWordAroundCaret();
403 void WebContentsAndroid::AdjustSelectionByCharacterOffset(JNIEnv* env,
404 jobject obj,
405 jint start_adjust,
406 jint end_adjust) {
407 web_contents_->AdjustSelectionByCharacterOffset(start_adjust, end_adjust);
410 void WebContentsAndroid::EvaluateJavaScript(JNIEnv* env,
411 jobject obj,
412 jstring script,
413 jobject callback) {
414 RenderViewHost* rvh = web_contents_->GetRenderViewHost();
415 DCHECK(rvh);
417 if (!rvh->IsRenderViewLive()) {
418 if (!static_cast<WebContentsImpl*>(web_contents_)->
419 CreateRenderViewForInitialEmptyDocument()) {
420 LOG(ERROR) << "Failed to create RenderView in EvaluateJavaScript";
421 return;
425 if (!callback) {
426 // No callback requested.
427 web_contents_->GetMainFrame()->ExecuteJavaScript(
428 ConvertJavaStringToUTF16(env, script));
429 return;
432 // Secure the Java callback in a scoped object and give ownership of it to the
433 // base::Callback.
434 ScopedJavaGlobalRef<jobject> j_callback;
435 j_callback.Reset(env, callback);
436 RenderFrameHost::JavaScriptResultCallback js_callback =
437 base::Bind(&JavaScriptResultCallback, j_callback);
439 web_contents_->GetMainFrame()->ExecuteJavaScript(
440 ConvertJavaStringToUTF16(env, script), js_callback);
443 void WebContentsAndroid::EvaluateJavaScriptForTests(JNIEnv* env,
444 jobject obj,
445 jstring script,
446 jobject callback) {
447 RenderViewHost* rvh = web_contents_->GetRenderViewHost();
448 DCHECK(rvh);
450 if (!rvh->IsRenderViewLive()) {
451 if (!static_cast<WebContentsImpl*>(web_contents_)->
452 CreateRenderViewForInitialEmptyDocument()) {
453 LOG(ERROR) << "Failed to create RenderView in EvaluateJavaScriptForTests";
454 return;
458 if (!callback) {
459 // No callback requested.
460 web_contents_->GetMainFrame()->ExecuteJavaScriptForTests(
461 ConvertJavaStringToUTF16(env, script));
462 return;
465 // Secure the Java callback in a scoped object and give ownership of it to the
466 // base::Callback.
467 ScopedJavaGlobalRef<jobject> j_callback;
468 j_callback.Reset(env, callback);
469 RenderFrameHost::JavaScriptResultCallback js_callback =
470 base::Bind(&JavaScriptResultCallback, j_callback);
472 web_contents_->GetMainFrame()->ExecuteJavaScriptForTests(
473 ConvertJavaStringToUTF16(env, script), js_callback);
476 void WebContentsAndroid::AddMessageToDevToolsConsole(JNIEnv* env,
477 jobject jobj,
478 jint level,
479 jstring message) {
480 DCHECK_GE(level, 0);
481 DCHECK_LE(level, CONSOLE_MESSAGE_LEVEL_LAST);
483 web_contents_->GetMainFrame()->AddMessageToConsole(
484 static_cast<ConsoleMessageLevel>(level),
485 ConvertJavaStringToUTF8(env, message));
488 jboolean WebContentsAndroid::HasAccessedInitialDocument(
489 JNIEnv* env,
490 jobject jobj) {
491 return static_cast<WebContentsImpl*>(web_contents_)->
492 HasAccessedInitialDocument();
495 jint WebContentsAndroid::GetThemeColor(JNIEnv* env, jobject obj) {
496 return web_contents_->GetThemeColor();
499 void WebContentsAndroid::RequestAccessibilitySnapshot(JNIEnv* env,
500 jobject obj,
501 jobject callback,
502 jfloat y_offset,
503 jfloat x_scroll) {
504 // Secure the Java callback in a scoped object and give ownership of it to the
505 // base::Callback.
506 ScopedJavaGlobalRef<jobject> j_callback;
507 j_callback.Reset(env, callback);
508 gfx::DeviceDisplayInfo device_info;
509 ContentViewCoreImpl* contentViewCore =
510 ContentViewCoreImpl::FromWebContents(web_contents_);
511 WebContentsImpl::AXTreeSnapshotCallback snapshot_callback =
512 base::Bind(&AXTreeSnapshotCallback, j_callback,
513 contentViewCore->GetScaleFactor(), y_offset, x_scroll);
514 static_cast<WebContentsImpl*>(web_contents_)->RequestAXTreeSnapshot(
515 snapshot_callback);
518 void WebContentsAndroid::ResumeMediaSession(JNIEnv* env, jobject obj) {
519 web_contents_->ResumeMediaSession();
522 void WebContentsAndroid::SuspendMediaSession(JNIEnv* env, jobject obj) {
523 web_contents_->SuspendMediaSession();
526 } // namespace content