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"
28 using base::android::AttachCurrentThread
;
29 using base::android::ConvertJavaStringToUTF8
;
30 using base::android::ConvertJavaStringToUTF16
;
31 using base::android::ConvertUTF8ToJavaString
;
32 using base::android::ScopedJavaGlobalRef
;
36 void JavaScriptResultCallback(const ScopedJavaGlobalRef
<jobject
>& callback
,
37 const base::Value
* result
) {
38 JNIEnv
* env
= base::android::AttachCurrentThread();
40 base::JSONWriter::Write(result
, &json
);
41 ScopedJavaLocalRef
<jstring
> j_json
= ConvertUTF8ToJavaString(env
, json
);
42 content::Java_WebContentsImpl_onEvaluateJavaScriptResult(
43 env
, j_json
.obj(), callback
.obj());
46 void ReleaseAllMediaPlayers(content::WebContents
* web_contents
,
47 content::RenderFrameHost
* render_frame_host
) {
48 content::BrowserMediaPlayerManager
* manager
=
49 static_cast<content::WebContentsImpl
*>(web_contents
)->
50 media_web_contents_observer()->GetMediaPlayerManager(
53 manager
->ReleaseAllMediaPlayers();
61 WebContents
* WebContents::FromJavaWebContents(
62 jobject jweb_contents_android
) {
63 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
64 if (!jweb_contents_android
)
67 WebContentsAndroid
* web_contents_android
=
68 reinterpret_cast<WebContentsAndroid
*>(
69 Java_WebContentsImpl_getNativePointer(AttachCurrentThread(),
70 jweb_contents_android
));
71 if (!web_contents_android
)
73 return web_contents_android
->web_contents();
77 static void DestroyWebContents(JNIEnv
* env
,
79 jlong jweb_contents_android_ptr
) {
80 WebContentsAndroid
* web_contents_android
=
81 reinterpret_cast<WebContentsAndroid
*>(jweb_contents_android_ptr
);
82 if (!web_contents_android
)
85 content::WebContents
* web_contents
= web_contents_android
->web_contents();
93 bool WebContentsAndroid::Register(JNIEnv
* env
) {
94 return RegisterNativesImpl(env
);
97 WebContentsAndroid::WebContentsAndroid(WebContents
* web_contents
)
98 : web_contents_(web_contents
),
99 navigation_controller_(&(web_contents
->GetController())),
100 weak_factory_(this) {
101 JNIEnv
* env
= AttachCurrentThread();
103 Java_WebContentsImpl_create(
105 reinterpret_cast<intptr_t>(this),
106 navigation_controller_
.GetJavaObject().obj()).obj());
109 WebContentsAndroid::~WebContentsAndroid() {
110 Java_WebContentsImpl_clearNativePtr(AttachCurrentThread(), obj_
.obj());
113 base::android::ScopedJavaLocalRef
<jobject
>
114 WebContentsAndroid::GetJavaObject() {
115 return base::android::ScopedJavaLocalRef
<jobject
>(obj_
);
118 ScopedJavaLocalRef
<jstring
> WebContentsAndroid::GetTitle(
119 JNIEnv
* env
, jobject obj
) const {
120 return base::android::ConvertUTF16ToJavaString(env
,
121 web_contents_
->GetTitle());
124 ScopedJavaLocalRef
<jstring
> WebContentsAndroid::GetVisibleURL(
125 JNIEnv
* env
, jobject obj
) const {
126 return base::android::ConvertUTF8ToJavaString(
127 env
, web_contents_
->GetVisibleURL().spec());
130 bool WebContentsAndroid::IsLoading(JNIEnv
* env
, jobject obj
) const {
131 return web_contents_
->IsLoading();
134 bool WebContentsAndroid::IsLoadingToDifferentDocument(JNIEnv
* env
,
136 return web_contents_
->IsLoadingToDifferentDocument();
139 void WebContentsAndroid::Stop(JNIEnv
* env
, jobject obj
) {
140 web_contents_
->Stop();
143 void WebContentsAndroid::InsertCSS(
144 JNIEnv
* env
, jobject jobj
, jstring jcss
) {
145 web_contents_
->InsertCSS(base::android::ConvertJavaStringToUTF8(env
, jcss
));
148 RenderWidgetHostViewAndroid
*
149 WebContentsAndroid::GetRenderWidgetHostViewAndroid() {
150 RenderWidgetHostView
* rwhv
= NULL
;
151 rwhv
= web_contents_
->GetRenderWidgetHostView();
152 if (web_contents_
->ShowingInterstitialPage()) {
153 rwhv
= web_contents_
->GetInterstitialPage()
155 ->GetRenderViewHost()
158 return static_cast<RenderWidgetHostViewAndroid
*>(rwhv
);
161 jint
WebContentsAndroid::GetBackgroundColor(JNIEnv
* env
, jobject obj
) {
162 RenderWidgetHostViewAndroid
* rwhva
= GetRenderWidgetHostViewAndroid();
164 return SK_ColorWHITE
;
165 return rwhva
->GetCachedBackgroundColor();
168 ScopedJavaLocalRef
<jstring
> WebContentsAndroid::GetURL(JNIEnv
* env
,
170 return ConvertUTF8ToJavaString(env
, web_contents_
->GetURL().spec());
173 jboolean
WebContentsAndroid::IsIncognito(JNIEnv
* env
, jobject obj
) {
174 return web_contents_
->GetBrowserContext()->IsOffTheRecord();
177 void WebContentsAndroid::ResumeResponseDeferredAtStart(JNIEnv
* env
,
179 static_cast<WebContentsImpl
*>(web_contents_
)->ResumeResponseDeferredAtStart();
182 void WebContentsAndroid::SetHasPendingNavigationTransitionForTesting(
185 base::CommandLine::ForCurrentProcess()->AppendSwitch(
186 switches::kEnableExperimentalWebPlatformFeatures
);
187 RenderFrameHost
* frame
=
188 static_cast<WebContentsImpl
*>(web_contents_
)->GetMainFrame();
189 BrowserThread::PostTask(
193 &TransitionRequestManager::AddPendingTransitionRequestDataForTesting
,
194 base::Unretained(TransitionRequestManager::GetInstance()),
195 frame
->GetProcess()->GetID(),
196 frame
->GetRoutingID()));
199 void WebContentsAndroid::SetupTransitionView(JNIEnv
* env
,
202 web_contents_
->GetMainFrame()->Send(new FrameMsg_SetupTransitionView(
203 web_contents_
->GetMainFrame()->GetRoutingID(),
204 ConvertJavaStringToUTF8(env
, markup
)));
207 void WebContentsAndroid::BeginExitTransition(JNIEnv
* env
,
209 jstring css_selector
,
210 jboolean exit_to_native_app
) {
211 web_contents_
->GetMainFrame()->Send(new FrameMsg_BeginExitTransition(
212 web_contents_
->GetMainFrame()->GetRoutingID(),
213 ConvertJavaStringToUTF8(env
, css_selector
),
214 exit_to_native_app
));
217 void WebContentsAndroid::RevertExitTransition(JNIEnv
* env
,
219 web_contents_
->GetMainFrame()->Send(new FrameMsg_RevertExitTransition(
220 web_contents_
->GetMainFrame()->GetRoutingID()));
223 void WebContentsAndroid::HideTransitionElements(JNIEnv
* env
,
225 jstring css_selector
) {
226 web_contents_
->GetMainFrame()->Send(
227 new FrameMsg_HideTransitionElements(
228 web_contents_
->GetMainFrame()->GetRoutingID(),
229 ConvertJavaStringToUTF8(env
, css_selector
)));
232 void WebContentsAndroid::ShowTransitionElements(JNIEnv
* env
,
234 jstring css_selector
) {
235 web_contents_
->GetMainFrame()->Send(
236 new FrameMsg_ShowTransitionElements(
237 web_contents_
->GetMainFrame()->GetRoutingID(),
238 ConvertJavaStringToUTF8(env
, css_selector
)));
242 void WebContentsAndroid::ClearNavigationTransitionData(JNIEnv
* env
,
244 static_cast<WebContentsImpl
*>(web_contents_
)->ClearNavigationTransitionData();
247 void WebContentsAndroid::FetchTransitionElements(JNIEnv
* env
,
250 GURL
url(base::android::ConvertJavaStringToUTF8(env
, jurl
));
251 RenderFrameHost
* frame
= web_contents_
->GetMainFrame();
253 scoped_ptr
<TransitionLayerData
> transition_data(new TransitionLayerData());
254 BrowserThread::PostTaskAndReplyWithResult(
257 base::Bind(&TransitionRequestManager::GetPendingTransitionRequest
,
258 base::Unretained(TransitionRequestManager::GetInstance()),
259 frame
->GetProcess()->GetID(),
260 frame
->GetRoutingID(),
262 transition_data
.get()),
263 base::Bind(&WebContentsAndroid::OnTransitionElementsFetched
,
264 weak_factory_
.GetWeakPtr(),
265 base::Passed(&transition_data
)));
268 void WebContentsAndroid::OnTransitionElementsFetched(
269 scoped_ptr
<const TransitionLayerData
> transition_data
,
270 bool has_transition_data
) {
271 // FetchTransitionElements is called after the navigation transition state
272 // machine starts, which means there must be transition data.
273 DCHECK(has_transition_data
);
274 JNIEnv
* env
= AttachCurrentThread();
276 std::vector
<TransitionElement
>::const_iterator it
=
277 transition_data
->elements
.begin();
278 for (; it
!= transition_data
->elements
.end(); ++it
) {
279 ScopedJavaLocalRef
<jstring
> jstring_name(ConvertUTF8ToJavaString(env
,
281 Java_WebContentsImpl_addNavigationTransitionElements(
282 env
, obj_
.obj(), jstring_name
.obj(),
283 it
->rect
.x(), it
->rect
.y(), it
->rect
.width(), it
->rect
.height());
286 ScopedJavaLocalRef
<jstring
> jstring_css_selector(
287 ConvertUTF8ToJavaString(env
, transition_data
->css_selector
));
288 Java_WebContentsImpl_onTransitionElementsFetched(
289 env
, obj_
.obj(), jstring_css_selector
.obj());
292 void WebContentsAndroid::OnHide(JNIEnv
* env
, jobject obj
) {
293 web_contents_
->WasHidden();
296 void WebContentsAndroid::OnShow(JNIEnv
* env
, jobject obj
) {
297 web_contents_
->WasShown();
300 void WebContentsAndroid::ReleaseMediaPlayers(JNIEnv
* env
, jobject jobj
) {
301 #if defined(ENABLE_BROWSER_CDMS)
302 web_contents_
->ForEachFrame(
303 base::Bind(&ReleaseAllMediaPlayers
, base::Unretained(web_contents_
)));
304 #endif // defined(ENABLE_BROWSER_CDMS)
307 void WebContentsAndroid::AddStyleSheetByURL(
311 web_contents_
->GetMainFrame()->Send(new FrameMsg_AddStyleSheetByURL(
312 web_contents_
->GetMainFrame()->GetRoutingID(),
313 ConvertJavaStringToUTF8(env
, url
)));
316 void WebContentsAndroid::ShowInterstitialPage(
320 jlong delegate_ptr
) {
321 GURL
url(base::android::ConvertJavaStringToUTF8(env
, jurl
));
322 InterstitialPageDelegateAndroid
* delegate
=
323 reinterpret_cast<InterstitialPageDelegateAndroid
*>(delegate_ptr
);
324 InterstitialPage
* interstitial
= InterstitialPage::Create(
325 web_contents_
, false, url
, delegate
);
326 delegate
->set_interstitial_page(interstitial
);
327 interstitial
->Show();
330 jboolean
WebContentsAndroid::IsShowingInterstitialPage(JNIEnv
* env
,
332 return web_contents_
->ShowingInterstitialPage();
335 jboolean
WebContentsAndroid::IsRenderWidgetHostViewReady(
338 RenderWidgetHostViewAndroid
* view
= GetRenderWidgetHostViewAndroid();
339 return view
&& view
->HasValidFrame();
342 void WebContentsAndroid::ExitFullscreen(JNIEnv
* env
, jobject obj
) {
343 web_contents_
->ExitFullscreen();
346 void WebContentsAndroid::UpdateTopControlsState(
352 RenderViewHost
* host
= web_contents_
->GetRenderViewHost();
355 host
->Send(new ViewMsg_UpdateTopControlsState(host
->GetRoutingID(),
361 void WebContentsAndroid::ShowImeIfNeeded(JNIEnv
* env
, jobject obj
) {
362 RenderViewHost
* host
= web_contents_
->GetRenderViewHost();
365 host
->Send(new ViewMsg_ShowImeIfNeeded(host
->GetRoutingID()));
368 void WebContentsAndroid::ScrollFocusedEditableNodeIntoView(
371 RenderViewHost
* host
= web_contents_
->GetRenderViewHost();
374 host
->Send(new InputMsg_ScrollFocusedEditableNodeIntoRect(
375 host
->GetRoutingID(), gfx::Rect()));
378 void WebContentsAndroid::SelectWordAroundCaret(JNIEnv
* env
, jobject obj
) {
379 RenderViewHost
* host
= web_contents_
->GetRenderViewHost();
382 host
->SelectWordAroundCaret();
385 bool WebContentsAndroid::WillHandleDeferAfterResponseStarted() {
386 JNIEnv
* env
= AttachCurrentThread();
387 return Java_WebContentsImpl_willHandleDeferAfterResponseStarted(env
,
391 void WebContentsAndroid::DidDeferAfterResponseStarted(
392 const TransitionLayerData
& transition_data
) {
393 JNIEnv
* env
= AttachCurrentThread();
394 std::vector
<GURL
> entering_stylesheets
;
395 std::string transition_color
;
396 if (transition_data
.response_headers
.get()) {
397 TransitionRequestManager::ParseTransitionStylesheetsFromHeaders(
398 transition_data
.response_headers
,
399 entering_stylesheets
,
400 transition_data
.request_url
);
402 transition_data
.response_headers
->EnumerateHeader(
403 NULL
, "X-Transition-Entering-Color", &transition_color
);
406 ScopedJavaLocalRef
<jstring
> jstring_markup(
407 ConvertUTF8ToJavaString(env
, transition_data
.markup
));
409 ScopedJavaLocalRef
<jstring
> jstring_css_selector(
410 ConvertUTF8ToJavaString(env
, transition_data
.css_selector
));
412 ScopedJavaLocalRef
<jstring
> jstring_transition_color(
413 ConvertUTF8ToJavaString(env
, transition_color
));
415 Java_WebContentsImpl_didDeferAfterResponseStarted(
418 jstring_markup
.obj(),
419 jstring_css_selector
.obj(),
420 jstring_transition_color
.obj());
422 std::vector
<GURL
>::const_iterator iter
= entering_stylesheets
.begin();
423 for (; iter
!= entering_stylesheets
.end(); ++iter
) {
424 ScopedJavaLocalRef
<jstring
> jstring_url(
425 ConvertUTF8ToJavaString(env
, iter
->spec()));
426 Java_WebContentsImpl_addEnteringStylesheetToTransition(
427 env
, obj_
.obj(), jstring_url
.obj());
431 void WebContentsAndroid::DidStartNavigationTransitionForFrame(int64 frame_id
) {
432 JNIEnv
* env
= AttachCurrentThread();
433 Java_WebContentsImpl_didStartNavigationTransitionForFrame(
434 env
, obj_
.obj(), frame_id
);
437 void WebContentsAndroid::EvaluateJavaScript(JNIEnv
* env
,
441 RenderViewHost
* rvh
= web_contents_
->GetRenderViewHost();
444 if (!rvh
->IsRenderViewLive()) {
445 if (!static_cast<WebContentsImpl
*>(web_contents_
)->
446 CreateRenderViewForInitialEmptyDocument()) {
447 LOG(ERROR
) << "Failed to create RenderView in EvaluateJavaScript";
453 // No callback requested.
454 web_contents_
->GetMainFrame()->ExecuteJavaScript(
455 ConvertJavaStringToUTF16(env
, script
));
459 // Secure the Java callback in a scoped object and give ownership of it to the
461 ScopedJavaGlobalRef
<jobject
> j_callback
;
462 j_callback
.Reset(env
, callback
);
463 content::RenderFrameHost::JavaScriptResultCallback js_callback
=
464 base::Bind(&JavaScriptResultCallback
, j_callback
);
466 web_contents_
->GetMainFrame()->ExecuteJavaScript(
467 ConvertJavaStringToUTF16(env
, script
), js_callback
);
470 void WebContentsAndroid::AddMessageToDevToolsConsole(JNIEnv
* env
,
475 DCHECK_LE(level
, CONSOLE_MESSAGE_LEVEL_LAST
);
477 web_contents_
->GetMainFrame()->Send(new DevToolsAgentMsg_AddMessageToConsole(
478 web_contents_
->GetMainFrame()->GetRoutingID(),
479 static_cast<ConsoleMessageLevel
>(level
),
480 ConvertJavaStringToUTF8(env
, message
)));
483 } // namespace content