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/frame_messages.h"
19 #include "content/common/input_messages.h"
20 #include "content/common/view_messages.h"
21 #include "content/public/browser/browser_context.h"
22 #include "content/public/browser/browser_thread.h"
23 #include "content/public/browser/web_contents.h"
24 #include "content/public/common/content_switches.h"
25 #include "jni/WebContentsImpl_jni.h"
27 using base::android::AttachCurrentThread
;
28 using base::android::ConvertJavaStringToUTF8
;
29 using base::android::ConvertJavaStringToUTF16
;
30 using base::android::ConvertUTF8ToJavaString
;
31 using base::android::ScopedJavaGlobalRef
;
35 void JavaScriptResultCallback(const ScopedJavaGlobalRef
<jobject
>& callback
,
36 const base::Value
* result
) {
37 JNIEnv
* env
= base::android::AttachCurrentThread();
39 base::JSONWriter::Write(result
, &json
);
40 ScopedJavaLocalRef
<jstring
> j_json
= ConvertUTF8ToJavaString(env
, json
);
41 content::Java_WebContentsImpl_onEvaluateJavaScriptResult(
42 env
, j_json
.obj(), callback
.obj());
50 WebContents
* WebContents::FromJavaWebContents(
51 jobject jweb_contents_android
) {
52 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
53 if (!jweb_contents_android
)
56 WebContentsAndroid
* web_contents_android
=
57 reinterpret_cast<WebContentsAndroid
*>(
58 Java_WebContentsImpl_getNativePointer(AttachCurrentThread(),
59 jweb_contents_android
));
60 if (!web_contents_android
)
62 return web_contents_android
->web_contents();
66 bool WebContentsAndroid::Register(JNIEnv
* env
) {
67 return RegisterNativesImpl(env
);
70 WebContentsAndroid::WebContentsAndroid(WebContents
* web_contents
)
71 : web_contents_(web_contents
),
72 navigation_controller_(&(web_contents
->GetController())) {
73 JNIEnv
* env
= AttachCurrentThread();
75 Java_WebContentsImpl_create(
77 reinterpret_cast<intptr_t>(this),
78 navigation_controller_
.GetJavaObject().obj()).obj());
81 WebContentsAndroid::~WebContentsAndroid() {
82 Java_WebContentsImpl_destroy(AttachCurrentThread(), obj_
.obj());
85 base::android::ScopedJavaLocalRef
<jobject
>
86 WebContentsAndroid::GetJavaObject() {
87 return base::android::ScopedJavaLocalRef
<jobject
>(obj_
);
90 ScopedJavaLocalRef
<jstring
> WebContentsAndroid::GetTitle(
91 JNIEnv
* env
, jobject obj
) const {
92 return base::android::ConvertUTF16ToJavaString(env
,
93 web_contents_
->GetTitle());
96 ScopedJavaLocalRef
<jstring
> WebContentsAndroid::GetVisibleURL(
97 JNIEnv
* env
, jobject obj
) const {
98 return base::android::ConvertUTF8ToJavaString(
99 env
, web_contents_
->GetVisibleURL().spec());
102 bool WebContentsAndroid::IsLoading(JNIEnv
* env
, jobject obj
) const {
103 return web_contents_
->IsLoading();
106 bool WebContentsAndroid::IsLoadingToDifferentDocument(JNIEnv
* env
,
108 return web_contents_
->IsLoadingToDifferentDocument();
111 void WebContentsAndroid::Stop(JNIEnv
* env
, jobject obj
) {
112 web_contents_
->Stop();
115 void WebContentsAndroid::InsertCSS(
116 JNIEnv
* env
, jobject jobj
, jstring jcss
) {
117 web_contents_
->InsertCSS(base::android::ConvertJavaStringToUTF8(env
, jcss
));
120 RenderWidgetHostViewAndroid
*
121 WebContentsAndroid::GetRenderWidgetHostViewAndroid() {
122 RenderWidgetHostView
* rwhv
= NULL
;
123 rwhv
= web_contents_
->GetRenderWidgetHostView();
124 if (web_contents_
->ShowingInterstitialPage()) {
125 rwhv
= static_cast<InterstitialPageImpl
*>(
126 web_contents_
->GetInterstitialPage())->
127 GetRenderViewHost()->GetView();
129 return static_cast<RenderWidgetHostViewAndroid
*>(rwhv
);
132 jint
WebContentsAndroid::GetBackgroundColor(JNIEnv
* env
, jobject obj
) {
133 RenderWidgetHostViewAndroid
* rwhva
= GetRenderWidgetHostViewAndroid();
135 return SK_ColorWHITE
;
136 return rwhva
->GetCachedBackgroundColor();
139 ScopedJavaLocalRef
<jstring
> WebContentsAndroid::GetURL(JNIEnv
* env
,
141 return ConvertUTF8ToJavaString(env
, web_contents_
->GetURL().spec());
144 jboolean
WebContentsAndroid::IsIncognito(JNIEnv
* env
, jobject obj
) {
145 return web_contents_
->GetBrowserContext()->IsOffTheRecord();
148 void WebContentsAndroid::ResumeResponseDeferredAtStart(JNIEnv
* env
,
150 static_cast<WebContentsImpl
*>(web_contents_
)->ResumeResponseDeferredAtStart();
153 void WebContentsAndroid::SetHasPendingNavigationTransitionForTesting(
156 CommandLine::ForCurrentProcess()->AppendSwitch(
157 switches::kEnableExperimentalWebPlatformFeatures
);
158 RenderFrameHost
* frame
=
159 static_cast<WebContentsImpl
*>(web_contents_
)->GetMainFrame();
160 BrowserThread::PostTask(
164 &TransitionRequestManager::AddPendingTransitionRequestDataForTesting
,
165 base::Unretained(TransitionRequestManager::GetInstance()),
166 frame
->GetProcess()->GetID(),
167 frame
->GetRoutingID()));
170 void WebContentsAndroid::SetupTransitionView(JNIEnv
* env
,
173 web_contents_
->GetMainFrame()->Send(new FrameMsg_SetupTransitionView(
174 web_contents_
->GetMainFrame()->GetRoutingID(),
175 ConvertJavaStringToUTF8(env
, markup
)));
178 void WebContentsAndroid::BeginExitTransition(JNIEnv
* env
,
180 jstring css_selector
) {
181 web_contents_
->GetMainFrame()->Send(new FrameMsg_BeginExitTransition(
182 web_contents_
->GetMainFrame()->GetRoutingID(),
183 ConvertJavaStringToUTF8(env
, css_selector
)));
186 void WebContentsAndroid::ClearNavigationTransitionData(JNIEnv
* env
,
188 static_cast<WebContentsImpl
*>(web_contents_
)->ClearNavigationTransitionData();
191 void WebContentsAndroid::OnHide(JNIEnv
* env
, jobject obj
) {
192 web_contents_
->WasHidden();
195 void WebContentsAndroid::OnShow(JNIEnv
* env
, jobject obj
) {
196 web_contents_
->WasShown();
199 void WebContentsAndroid::ReleaseMediaPlayers(JNIEnv
* env
, jobject jobj
) {
200 #if defined(ENABLE_BROWSER_CDMS)
201 RenderViewHostImpl
* rvhi
= static_cast<RenderViewHostImpl
*>(
202 web_contents_
->GetRenderViewHost());
203 if (!rvhi
|| !rvhi
->GetMainFrame())
206 BrowserMediaPlayerManager
* manager
=
207 rvhi
->media_web_contents_observer()->GetMediaPlayerManager(
208 rvhi
->GetMainFrame());
210 manager
->ReleaseAllMediaPlayers();
211 #endif // defined(ENABLE_BROWSER_CDMS)
214 void WebContentsAndroid::AddStyleSheetByURL(
218 web_contents_
->GetMainFrame()->Send(new FrameMsg_AddStyleSheetByURL(
219 web_contents_
->GetMainFrame()->GetRoutingID(),
220 ConvertJavaStringToUTF8(env
, url
)));
223 void WebContentsAndroid::ShowInterstitialPage(
227 jlong delegate_ptr
) {
228 GURL
url(base::android::ConvertJavaStringToUTF8(env
, jurl
));
229 InterstitialPageDelegateAndroid
* delegate
=
230 reinterpret_cast<InterstitialPageDelegateAndroid
*>(delegate_ptr
);
231 InterstitialPage
* interstitial
= InterstitialPage::Create(
232 web_contents_
, false, url
, delegate
);
233 delegate
->set_interstitial_page(interstitial
);
234 interstitial
->Show();
237 jboolean
WebContentsAndroid::IsShowingInterstitialPage(JNIEnv
* env
,
239 return web_contents_
->ShowingInterstitialPage();
242 jboolean
WebContentsAndroid::IsRenderWidgetHostViewReady(
245 RenderWidgetHostViewAndroid
* view
= GetRenderWidgetHostViewAndroid();
246 return view
&& view
->HasValidFrame();
249 void WebContentsAndroid::ExitFullscreen(JNIEnv
* env
, jobject obj
) {
250 RenderViewHost
* host
= web_contents_
->GetRenderViewHost();
253 host
->ExitFullscreen();
256 void WebContentsAndroid::UpdateTopControlsState(
262 RenderViewHost
* host
= web_contents_
->GetRenderViewHost();
265 host
->Send(new ViewMsg_UpdateTopControlsState(host
->GetRoutingID(),
271 void WebContentsAndroid::ShowImeIfNeeded(JNIEnv
* env
, jobject obj
) {
272 RenderViewHost
* host
= web_contents_
->GetRenderViewHost();
275 host
->Send(new ViewMsg_ShowImeIfNeeded(host
->GetRoutingID()));
278 void WebContentsAndroid::ScrollFocusedEditableNodeIntoView(
281 RenderViewHost
* host
= web_contents_
->GetRenderViewHost();
284 host
->Send(new InputMsg_ScrollFocusedEditableNodeIntoRect(
285 host
->GetRoutingID(), gfx::Rect()));
288 void WebContentsAndroid::SelectWordAroundCaret(JNIEnv
* env
, jobject obj
) {
289 RenderViewHost
* host
= web_contents_
->GetRenderViewHost();
292 host
->SelectWordAroundCaret();
295 bool WebContentsAndroid::WillHandleDeferAfterResponseStarted() {
296 JNIEnv
* env
= AttachCurrentThread();
297 return Java_WebContentsImpl_willHandleDeferAfterResponseStarted(env
,
301 void WebContentsAndroid::DidDeferAfterResponseStarted(
302 const TransitionLayerData
& transition_data
) {
303 JNIEnv
* env
= AttachCurrentThread();
304 std::vector
<GURL
> entering_stylesheets
;
305 std::string transition_color
;
306 if (transition_data
.response_headers
.get()) {
307 TransitionRequestManager::ParseTransitionStylesheetsFromHeaders(
308 transition_data
.response_headers
,
309 entering_stylesheets
,
310 transition_data
.request_url
);
312 transition_data
.response_headers
->EnumerateHeader(
313 NULL
, "X-Transition-Entering-Color", &transition_color
);
316 ScopedJavaLocalRef
<jstring
> jstring_markup(
317 ConvertUTF8ToJavaString(env
, transition_data
.markup
));
319 ScopedJavaLocalRef
<jstring
> jstring_css_selector(
320 ConvertUTF8ToJavaString(env
, transition_data
.css_selector
));
322 ScopedJavaLocalRef
<jstring
> jstring_transition_color(
323 ConvertUTF8ToJavaString(env
, transition_color
));
325 Java_WebContentsImpl_didDeferAfterResponseStarted(
328 jstring_markup
.obj(),
329 jstring_css_selector
.obj(),
330 jstring_transition_color
.obj());
332 std::vector
<GURL
>::const_iterator iter
= entering_stylesheets
.begin();
333 for (; iter
!= entering_stylesheets
.end(); ++iter
) {
334 ScopedJavaLocalRef
<jstring
> jstring_url(
335 ConvertUTF8ToJavaString(env
, iter
->spec()));
336 Java_WebContentsImpl_addEnteringStylesheetToTransition(
337 env
, obj_
.obj(), jstring_url
.obj());
341 void WebContentsAndroid::DidStartNavigationTransitionForFrame(int64 frame_id
) {
342 JNIEnv
* env
= AttachCurrentThread();
343 Java_WebContentsImpl_didStartNavigationTransitionForFrame(
344 env
, obj_
.obj(), frame_id
);
347 void WebContentsAndroid::EvaluateJavaScript(JNIEnv
* env
,
351 RenderViewHost
* rvh
= web_contents_
->GetRenderViewHost();
354 if (!rvh
->IsRenderViewLive()) {
355 if (!static_cast<WebContentsImpl
*>(web_contents_
)->
356 CreateRenderViewForInitialEmptyDocument()) {
357 LOG(ERROR
) << "Failed to create RenderView in EvaluateJavaScript";
363 // No callback requested.
364 web_contents_
->GetMainFrame()->ExecuteJavaScript(
365 ConvertJavaStringToUTF16(env
, script
));
369 // Secure the Java callback in a scoped object and give ownership of it to the
371 ScopedJavaGlobalRef
<jobject
> j_callback
;
372 j_callback
.Reset(env
, callback
);
373 content::RenderFrameHost::JavaScriptResultCallback js_callback
=
374 base::Bind(&JavaScriptResultCallback
, j_callback
);
376 web_contents_
->GetMainFrame()->ExecuteJavaScript(
377 ConvertJavaStringToUTF16(env
, script
), js_callback
);
380 // TODO(sgurun) add support for posting a frame whose name is known (only
381 // main frame is supported at this time, see crbug.com/389721)
382 // TODO(sgurun) add support for passing message ports
383 void WebContentsAndroid::PostMessageToFrame(JNIEnv
* env
, jobject obj
,
384 jstring frame_name
, jstring message
, jstring source_origin
,
385 jstring target_origin
) {
387 RenderViewHost
* host
= web_contents_
->GetRenderViewHost();
390 ViewMsg_PostMessage_Params params
;
391 params
.source_origin
= ConvertJavaStringToUTF16(env
, source_origin
);
392 params
.target_origin
= ConvertJavaStringToUTF16(env
, target_origin
);
393 params
.data
= ConvertJavaStringToUTF16(env
, message
);
394 params
.is_data_raw_string
= true;
395 params
.source_routing_id
= MSG_ROUTING_NONE
;
396 host
->Send(new ViewMsg_PostMessageEvent(host
->GetRoutingID(), params
));
399 } // namespace content