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_string.h"
9 #include "base/command_line.h"
10 #include "base/json/json_writer.h"
11 #include "base/logging.h"
12 #include "content/browser/android/interstitial_page_delegate_android.h"
13 #include "content/browser/frame_host/interstitial_page_impl.h"
14 #include "content/browser/media/android/browser_media_player_manager.h"
15 #include "content/browser/media/media_web_contents_observer.h"
16 #include "content/browser/renderer_host/render_view_host_impl.h"
17 #include "content/browser/web_contents/web_contents_impl.h"
18 #include "content/common/devtools_messages.h"
19 #include "content/common/frame_messages.h"
20 #include "content/common/input_messages.h"
21 #include "content/common/view_messages.h"
22 #include "content/public/browser/browser_context.h"
23 #include "content/public/browser/browser_thread.h"
24 #include "content/public/browser/web_contents.h"
25 #include "content/public/common/content_switches.h"
26 #include "jni/WebContentsImpl_jni.h"
27 #include "net/android/network_library.h"
29 using base::android::AttachCurrentThread
;
30 using base::android::ConvertJavaStringToUTF8
;
31 using base::android::ConvertJavaStringToUTF16
;
32 using base::android::ConvertUTF8ToJavaString
;
33 using base::android::ScopedJavaGlobalRef
;
37 void JavaScriptResultCallback(const ScopedJavaGlobalRef
<jobject
>& callback
,
38 const base::Value
* result
) {
39 JNIEnv
* env
= base::android::AttachCurrentThread();
41 base::JSONWriter::Write(result
, &json
);
42 ScopedJavaLocalRef
<jstring
> j_json
= ConvertUTF8ToJavaString(env
, json
);
43 content::Java_WebContentsImpl_onEvaluateJavaScriptResult(
44 env
, j_json
.obj(), callback
.obj());
47 void ReleaseAllMediaPlayers(content::WebContents
* web_contents
,
48 content::RenderFrameHost
* render_frame_host
) {
49 content::BrowserMediaPlayerManager
* manager
=
50 static_cast<content::WebContentsImpl
*>(web_contents
)->
51 media_web_contents_observer()->GetMediaPlayerManager(
54 manager
->ReleaseAllMediaPlayers();
62 WebContents
* WebContents::FromJavaWebContents(
63 jobject jweb_contents_android
) {
64 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
65 if (!jweb_contents_android
)
68 WebContentsAndroid
* web_contents_android
=
69 reinterpret_cast<WebContentsAndroid
*>(
70 Java_WebContentsImpl_getNativePointer(AttachCurrentThread(),
71 jweb_contents_android
));
72 if (!web_contents_android
)
74 return web_contents_android
->web_contents();
78 static void DestroyWebContents(JNIEnv
* env
,
80 jlong jweb_contents_android_ptr
) {
81 WebContentsAndroid
* web_contents_android
=
82 reinterpret_cast<WebContentsAndroid
*>(jweb_contents_android_ptr
);
83 if (!web_contents_android
)
86 content::WebContents
* web_contents
= web_contents_android
->web_contents();
94 bool WebContentsAndroid::Register(JNIEnv
* env
) {
95 return RegisterNativesImpl(env
);
98 WebContentsAndroid::WebContentsAndroid(WebContents
* web_contents
)
99 : web_contents_(web_contents
),
100 navigation_controller_(&(web_contents
->GetController())),
101 weak_factory_(this) {
102 JNIEnv
* env
= AttachCurrentThread();
104 Java_WebContentsImpl_create(
106 reinterpret_cast<intptr_t>(this),
107 navigation_controller_
.GetJavaObject().obj()).obj());
108 RendererPreferences
* prefs
= web_contents_
->GetMutableRendererPrefs();
109 base::CommandLine
* command_line
= base::CommandLine::ForCurrentProcess();
110 prefs
->network_contry_iso
=
111 command_line
->HasSwitch(switches::kNetworkCountryIso
) ?
112 command_line
->GetSwitchValueASCII(switches::kNetworkCountryIso
)
113 : net::android::GetTelephonyNetworkCountryIso();
116 WebContentsAndroid::~WebContentsAndroid() {
117 Java_WebContentsImpl_clearNativePtr(AttachCurrentThread(), obj_
.obj());
120 base::android::ScopedJavaLocalRef
<jobject
>
121 WebContentsAndroid::GetJavaObject() {
122 return base::android::ScopedJavaLocalRef
<jobject
>(obj_
);
125 ScopedJavaLocalRef
<jstring
> WebContentsAndroid::GetTitle(
126 JNIEnv
* env
, jobject obj
) const {
127 return base::android::ConvertUTF16ToJavaString(env
,
128 web_contents_
->GetTitle());
131 ScopedJavaLocalRef
<jstring
> WebContentsAndroid::GetVisibleURL(
132 JNIEnv
* env
, jobject obj
) const {
133 return base::android::ConvertUTF8ToJavaString(
134 env
, web_contents_
->GetVisibleURL().spec());
137 bool WebContentsAndroid::IsLoading(JNIEnv
* env
, jobject obj
) const {
138 return web_contents_
->IsLoading();
141 bool WebContentsAndroid::IsLoadingToDifferentDocument(JNIEnv
* env
,
143 return web_contents_
->IsLoadingToDifferentDocument();
146 void WebContentsAndroid::Stop(JNIEnv
* env
, jobject obj
) {
147 web_contents_
->Stop();
150 void WebContentsAndroid::InsertCSS(
151 JNIEnv
* env
, jobject jobj
, jstring jcss
) {
152 web_contents_
->InsertCSS(base::android::ConvertJavaStringToUTF8(env
, jcss
));
155 RenderWidgetHostViewAndroid
*
156 WebContentsAndroid::GetRenderWidgetHostViewAndroid() {
157 RenderWidgetHostView
* rwhv
= NULL
;
158 rwhv
= web_contents_
->GetRenderWidgetHostView();
159 if (web_contents_
->ShowingInterstitialPage()) {
160 rwhv
= web_contents_
->GetInterstitialPage()
162 ->GetRenderViewHost()
165 return static_cast<RenderWidgetHostViewAndroid
*>(rwhv
);
168 jint
WebContentsAndroid::GetBackgroundColor(JNIEnv
* env
, jobject obj
) {
169 RenderWidgetHostViewAndroid
* rwhva
= GetRenderWidgetHostViewAndroid();
171 return SK_ColorWHITE
;
172 return rwhva
->GetCachedBackgroundColor();
175 ScopedJavaLocalRef
<jstring
> WebContentsAndroid::GetURL(JNIEnv
* env
,
177 return ConvertUTF8ToJavaString(env
, web_contents_
->GetURL().spec());
180 ScopedJavaLocalRef
<jstring
> WebContentsAndroid::GetLastCommittedURL(
183 return ConvertUTF8ToJavaString(env
,
184 web_contents_
->GetLastCommittedURL().spec());
188 jboolean
WebContentsAndroid::IsIncognito(JNIEnv
* env
, jobject obj
) {
189 return web_contents_
->GetBrowserContext()->IsOffTheRecord();
192 void WebContentsAndroid::ResumeResponseDeferredAtStart(JNIEnv
* env
,
194 static_cast<WebContentsImpl
*>(web_contents_
)->ResumeResponseDeferredAtStart();
197 void WebContentsAndroid::SetHasPendingNavigationTransitionForTesting(
200 base::CommandLine::ForCurrentProcess()->AppendSwitch(
201 switches::kEnableExperimentalWebPlatformFeatures
);
202 RenderFrameHost
* frame
=
203 static_cast<WebContentsImpl
*>(web_contents_
)->GetMainFrame();
204 BrowserThread::PostTask(
208 &TransitionRequestManager::AddPendingTransitionRequestDataForTesting
,
209 base::Unretained(TransitionRequestManager::GetInstance()),
210 frame
->GetProcess()->GetID(),
211 frame
->GetRoutingID()));
214 void WebContentsAndroid::SetupTransitionView(JNIEnv
* env
,
217 web_contents_
->GetMainFrame()->Send(new FrameMsg_SetupTransitionView(
218 web_contents_
->GetMainFrame()->GetRoutingID(),
219 ConvertJavaStringToUTF8(env
, markup
)));
222 void WebContentsAndroid::BeginExitTransition(JNIEnv
* env
,
224 jstring css_selector
,
225 jboolean exit_to_native_app
) {
226 web_contents_
->GetMainFrame()->Send(new FrameMsg_BeginExitTransition(
227 web_contents_
->GetMainFrame()->GetRoutingID(),
228 ConvertJavaStringToUTF8(env
, css_selector
),
229 exit_to_native_app
));
232 void WebContentsAndroid::RevertExitTransition(JNIEnv
* env
,
234 web_contents_
->GetMainFrame()->Send(new FrameMsg_RevertExitTransition(
235 web_contents_
->GetMainFrame()->GetRoutingID()));
238 void WebContentsAndroid::HideTransitionElements(JNIEnv
* env
,
240 jstring css_selector
) {
241 web_contents_
->GetMainFrame()->Send(
242 new FrameMsg_HideTransitionElements(
243 web_contents_
->GetMainFrame()->GetRoutingID(),
244 ConvertJavaStringToUTF8(env
, css_selector
)));
247 void WebContentsAndroid::ShowTransitionElements(JNIEnv
* env
,
249 jstring css_selector
) {
250 web_contents_
->GetMainFrame()->Send(
251 new FrameMsg_ShowTransitionElements(
252 web_contents_
->GetMainFrame()->GetRoutingID(),
253 ConvertJavaStringToUTF8(env
, css_selector
)));
257 void WebContentsAndroid::ClearNavigationTransitionData(JNIEnv
* env
,
259 static_cast<WebContentsImpl
*>(web_contents_
)->ClearNavigationTransitionData();
262 void WebContentsAndroid::FetchTransitionElements(JNIEnv
* env
,
265 GURL
url(base::android::ConvertJavaStringToUTF8(env
, jurl
));
266 RenderFrameHost
* frame
= web_contents_
->GetMainFrame();
268 scoped_ptr
<TransitionLayerData
> transition_data(new TransitionLayerData());
269 BrowserThread::PostTaskAndReplyWithResult(
272 base::Bind(&TransitionRequestManager::GetPendingTransitionRequest
,
273 base::Unretained(TransitionRequestManager::GetInstance()),
274 frame
->GetProcess()->GetID(),
275 frame
->GetRoutingID(),
277 transition_data
.get()),
278 base::Bind(&WebContentsAndroid::OnTransitionElementsFetched
,
279 weak_factory_
.GetWeakPtr(),
280 base::Passed(&transition_data
)));
283 void WebContentsAndroid::OnTransitionElementsFetched(
284 scoped_ptr
<const TransitionLayerData
> transition_data
,
285 bool has_transition_data
) {
286 // FetchTransitionElements is called after the navigation transition state
287 // machine starts, which means there must be transition data.
288 DCHECK(has_transition_data
);
289 JNIEnv
* env
= AttachCurrentThread();
291 std::vector
<TransitionElement
>::const_iterator it
=
292 transition_data
->elements
.begin();
293 for (; it
!= transition_data
->elements
.end(); ++it
) {
294 ScopedJavaLocalRef
<jstring
> jstring_name(ConvertUTF8ToJavaString(env
,
296 Java_WebContentsImpl_addNavigationTransitionElements(
297 env
, obj_
.obj(), jstring_name
.obj(),
298 it
->rect
.x(), it
->rect
.y(), it
->rect
.width(), it
->rect
.height());
301 ScopedJavaLocalRef
<jstring
> jstring_css_selector(
302 ConvertUTF8ToJavaString(env
, transition_data
->css_selector
));
303 Java_WebContentsImpl_onTransitionElementsFetched(
304 env
, obj_
.obj(), jstring_css_selector
.obj());
307 void WebContentsAndroid::OnHide(JNIEnv
* env
, jobject obj
) {
308 web_contents_
->WasHidden();
311 void WebContentsAndroid::OnShow(JNIEnv
* env
, jobject obj
) {
312 web_contents_
->WasShown();
315 void WebContentsAndroid::ReleaseMediaPlayers(JNIEnv
* env
, jobject jobj
) {
316 #if defined(ENABLE_BROWSER_CDMS)
317 web_contents_
->ForEachFrame(
318 base::Bind(&ReleaseAllMediaPlayers
, base::Unretained(web_contents_
)));
319 #endif // defined(ENABLE_BROWSER_CDMS)
322 void WebContentsAndroid::AddStyleSheetByURL(
326 web_contents_
->GetMainFrame()->Send(new FrameMsg_AddStyleSheetByURL(
327 web_contents_
->GetMainFrame()->GetRoutingID(),
328 ConvertJavaStringToUTF8(env
, url
)));
331 void WebContentsAndroid::ShowInterstitialPage(
335 jlong delegate_ptr
) {
336 GURL
url(base::android::ConvertJavaStringToUTF8(env
, jurl
));
337 InterstitialPageDelegateAndroid
* delegate
=
338 reinterpret_cast<InterstitialPageDelegateAndroid
*>(delegate_ptr
);
339 InterstitialPage
* interstitial
= InterstitialPage::Create(
340 web_contents_
, false, url
, delegate
);
341 delegate
->set_interstitial_page(interstitial
);
342 interstitial
->Show();
345 jboolean
WebContentsAndroid::IsShowingInterstitialPage(JNIEnv
* env
,
347 return web_contents_
->ShowingInterstitialPage();
350 jboolean
WebContentsAndroid::IsRenderWidgetHostViewReady(
353 RenderWidgetHostViewAndroid
* view
= GetRenderWidgetHostViewAndroid();
354 return view
&& view
->HasValidFrame();
357 void WebContentsAndroid::ExitFullscreen(JNIEnv
* env
, jobject obj
) {
358 web_contents_
->ExitFullscreen();
361 void WebContentsAndroid::UpdateTopControlsState(
367 RenderViewHost
* host
= web_contents_
->GetRenderViewHost();
370 host
->Send(new ViewMsg_UpdateTopControlsState(host
->GetRoutingID(),
376 void WebContentsAndroid::ShowImeIfNeeded(JNIEnv
* env
, jobject obj
) {
377 RenderViewHost
* host
= web_contents_
->GetRenderViewHost();
380 host
->Send(new ViewMsg_ShowImeIfNeeded(host
->GetRoutingID()));
383 void WebContentsAndroid::ScrollFocusedEditableNodeIntoView(
386 RenderViewHost
* host
= web_contents_
->GetRenderViewHost();
389 host
->Send(new InputMsg_ScrollFocusedEditableNodeIntoRect(
390 host
->GetRoutingID(), gfx::Rect()));
393 void WebContentsAndroid::SelectWordAroundCaret(JNIEnv
* env
, jobject obj
) {
394 RenderViewHost
* host
= web_contents_
->GetRenderViewHost();
397 host
->SelectWordAroundCaret();
400 bool WebContentsAndroid::WillHandleDeferAfterResponseStarted() {
401 JNIEnv
* env
= AttachCurrentThread();
402 return Java_WebContentsImpl_willHandleDeferAfterResponseStarted(env
,
406 void WebContentsAndroid::DidDeferAfterResponseStarted(
407 const TransitionLayerData
& transition_data
) {
408 JNIEnv
* env
= AttachCurrentThread();
409 std::vector
<GURL
> entering_stylesheets
;
410 std::string transition_color
;
411 if (transition_data
.response_headers
.get()) {
412 TransitionRequestManager::ParseTransitionStylesheetsFromHeaders(
413 transition_data
.response_headers
,
414 entering_stylesheets
,
415 transition_data
.request_url
);
417 transition_data
.response_headers
->EnumerateHeader(
418 NULL
, "X-Transition-Entering-Color", &transition_color
);
421 ScopedJavaLocalRef
<jstring
> jstring_markup(
422 ConvertUTF8ToJavaString(env
, transition_data
.markup
));
424 ScopedJavaLocalRef
<jstring
> jstring_css_selector(
425 ConvertUTF8ToJavaString(env
, transition_data
.css_selector
));
427 ScopedJavaLocalRef
<jstring
> jstring_transition_color(
428 ConvertUTF8ToJavaString(env
, transition_color
));
430 Java_WebContentsImpl_didDeferAfterResponseStarted(
433 jstring_markup
.obj(),
434 jstring_css_selector
.obj(),
435 jstring_transition_color
.obj());
437 std::vector
<GURL
>::const_iterator iter
= entering_stylesheets
.begin();
438 for (; iter
!= entering_stylesheets
.end(); ++iter
) {
439 ScopedJavaLocalRef
<jstring
> jstring_url(
440 ConvertUTF8ToJavaString(env
, iter
->spec()));
441 Java_WebContentsImpl_addEnteringStylesheetToTransition(
442 env
, obj_
.obj(), jstring_url
.obj());
446 void WebContentsAndroid::DidStartNavigationTransitionForFrame(int64 frame_id
) {
447 JNIEnv
* env
= AttachCurrentThread();
448 Java_WebContentsImpl_didStartNavigationTransitionForFrame(
449 env
, obj_
.obj(), frame_id
);
452 void WebContentsAndroid::EvaluateJavaScript(JNIEnv
* env
,
456 RenderViewHost
* rvh
= web_contents_
->GetRenderViewHost();
459 if (!rvh
->IsRenderViewLive()) {
460 if (!static_cast<WebContentsImpl
*>(web_contents_
)->
461 CreateRenderViewForInitialEmptyDocument()) {
462 LOG(ERROR
) << "Failed to create RenderView in EvaluateJavaScript";
468 // No callback requested.
469 web_contents_
->GetMainFrame()->ExecuteJavaScript(
470 ConvertJavaStringToUTF16(env
, script
));
474 // Secure the Java callback in a scoped object and give ownership of it to the
476 ScopedJavaGlobalRef
<jobject
> j_callback
;
477 j_callback
.Reset(env
, callback
);
478 content::RenderFrameHost::JavaScriptResultCallback js_callback
=
479 base::Bind(&JavaScriptResultCallback
, j_callback
);
481 web_contents_
->GetMainFrame()->ExecuteJavaScript(
482 ConvertJavaStringToUTF16(env
, script
), js_callback
);
485 void WebContentsAndroid::AddMessageToDevToolsConsole(JNIEnv
* env
,
490 DCHECK_LE(level
, CONSOLE_MESSAGE_LEVEL_LAST
);
492 web_contents_
->GetMainFrame()->Send(new DevToolsAgentMsg_AddMessageToConsole(
493 web_contents_
->GetMainFrame()->GetRoutingID(),
494 static_cast<ConsoleMessageLevel
>(level
),
495 ConvertJavaStringToUTF8(env
, message
)));
498 jboolean
WebContentsAndroid::HasAccessedInitialDocument(
501 return static_cast<content::WebContentsImpl
*>(web_contents_
)->
502 HasAccessedInitialDocument();
505 jint
WebContentsAndroid::GetThemeColor(JNIEnv
* env
, jobject obj
) {
506 return web_contents_
->GetThemeColor();
509 } // namespace content