Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / content / browser / web_contents / web_contents_android.cc
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 "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/media_web_contents_observer.h"
15 #include "content/browser/renderer_host/render_view_host_impl.h"
16 #include "content/browser/web_contents/web_contents_impl.h"
17 #include "content/common/frame_messages.h"
18 #include "content/common/input_messages.h"
19 #include "content/common/view_messages.h"
20 #include "content/public/browser/browser_context.h"
21 #include "content/public/browser/browser_thread.h"
22 #include "content/public/browser/web_contents.h"
23 #include "content/public/common/content_switches.h"
24 #include "jni/WebContentsImpl_jni.h"
25
26 using base::android::AttachCurrentThread;
27 using base::android::ConvertJavaStringToUTF8;
28 using base::android::ConvertJavaStringToUTF16;
29 using base::android::ConvertUTF8ToJavaString;
30 using base::android::ScopedJavaGlobalRef;
31
32 namespace {
33
34 void JavaScriptResultCallback(const ScopedJavaGlobalRef<jobject>& callback,
35                               const base::Value* result) {
36   JNIEnv* env = base::android::AttachCurrentThread();
37   std::string json;
38   base::JSONWriter::Write(result, &json);
39   ScopedJavaLocalRef<jstring> j_json = ConvertUTF8ToJavaString(env, json);
40   content::Java_WebContentsImpl_onEvaluateJavaScriptResult(
41       env, j_json.obj(), callback.obj());
42 }
43
44 }  // namespace
45
46 namespace content {
47
48 // static
49 WebContents* WebContents::FromJavaWebContents(
50     jobject jweb_contents_android) {
51   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
52   if (!jweb_contents_android)
53     return NULL;
54
55   WebContentsAndroid* web_contents_android =
56       reinterpret_cast<WebContentsAndroid*>(
57           Java_WebContentsImpl_getNativePointer(AttachCurrentThread(),
58                                                 jweb_contents_android));
59   if (!web_contents_android)
60     return NULL;
61   return web_contents_android->web_contents();
62 }
63
64 // static
65 bool WebContentsAndroid::Register(JNIEnv* env) {
66   return RegisterNativesImpl(env);
67 }
68
69 WebContentsAndroid::WebContentsAndroid(WebContents* web_contents)
70     : web_contents_(web_contents),
71       navigation_controller_(&(web_contents->GetController())) {
72   JNIEnv* env = AttachCurrentThread();
73   obj_.Reset(env,
74              Java_WebContentsImpl_create(
75                  env,
76                  reinterpret_cast<intptr_t>(this),
77                  navigation_controller_.GetJavaObject().obj()).obj());
78 }
79
80 WebContentsAndroid::~WebContentsAndroid() {
81   Java_WebContentsImpl_destroy(AttachCurrentThread(), obj_.obj());
82 }
83
84 base::android::ScopedJavaLocalRef<jobject>
85 WebContentsAndroid::GetJavaObject() {
86   return base::android::ScopedJavaLocalRef<jobject>(obj_);
87 }
88
89 ScopedJavaLocalRef<jstring> WebContentsAndroid::GetTitle(
90     JNIEnv* env, jobject obj) const {
91   return base::android::ConvertUTF16ToJavaString(env,
92                                                  web_contents_->GetTitle());
93 }
94
95 ScopedJavaLocalRef<jstring> WebContentsAndroid::GetVisibleURL(
96     JNIEnv* env, jobject obj) const {
97   return base::android::ConvertUTF8ToJavaString(
98       env, web_contents_->GetVisibleURL().spec());
99 }
100
101 void WebContentsAndroid::Stop(JNIEnv* env, jobject obj) {
102   web_contents_->Stop();
103 }
104
105 void WebContentsAndroid::InsertCSS(
106     JNIEnv* env, jobject jobj, jstring jcss) {
107   web_contents_->InsertCSS(base::android::ConvertJavaStringToUTF8(env, jcss));
108 }
109
110 RenderWidgetHostViewAndroid*
111     WebContentsAndroid::GetRenderWidgetHostViewAndroid() {
112   RenderWidgetHostView* rwhv = NULL;
113   rwhv = web_contents_->GetRenderWidgetHostView();
114   if (web_contents_->ShowingInterstitialPage()) {
115     rwhv = static_cast<InterstitialPageImpl*>(
116         web_contents_->GetInterstitialPage())->
117             GetRenderViewHost()->GetView();
118   }
119   return static_cast<RenderWidgetHostViewAndroid*>(rwhv);
120 }
121
122 jint WebContentsAndroid::GetBackgroundColor(JNIEnv* env, jobject obj) {
123   RenderWidgetHostViewAndroid* rwhva = GetRenderWidgetHostViewAndroid();
124   if (!rwhva)
125     return SK_ColorWHITE;
126   return rwhva->GetCachedBackgroundColor();
127 }
128
129 ScopedJavaLocalRef<jstring> WebContentsAndroid::GetURL(JNIEnv* env,
130                                                        jobject obj) const {
131   return ConvertUTF8ToJavaString(env, web_contents_->GetURL().spec());
132 }
133
134 jboolean WebContentsAndroid::IsIncognito(JNIEnv* env, jobject obj) {
135   return web_contents_->GetBrowserContext()->IsOffTheRecord();
136 }
137
138 void WebContentsAndroid::ResumeResponseDeferredAtStart(JNIEnv* env,
139                                                        jobject obj) {
140   static_cast<WebContentsImpl*>(web_contents_)->ResumeResponseDeferredAtStart();
141 }
142
143 void WebContentsAndroid::SetHasPendingNavigationTransitionForTesting(
144     JNIEnv* env,
145     jobject obj) {
146   CommandLine::ForCurrentProcess()->AppendSwitch(
147       switches::kEnableExperimentalWebPlatformFeatures);
148   RenderFrameHost* frame =
149       static_cast<WebContentsImpl*>(web_contents_)->GetMainFrame();
150   BrowserThread::PostTask(
151       BrowserThread::IO,
152       FROM_HERE,
153       base::Bind(&TransitionRequestManager::AddPendingTransitionRequestData,
154                  base::Unretained(TransitionRequestManager::GetInstance()),
155                  frame->GetProcess()->GetID(),
156                  frame->GetRoutingID(),
157                  "*",
158                  "",
159                  ""));
160 }
161
162 void WebContentsAndroid::SetupTransitionView(JNIEnv* env,
163                                              jobject jobj,
164                                              jstring markup) {
165   web_contents_->GetMainFrame()->Send(new FrameMsg_SetupTransitionView(
166       web_contents_->GetMainFrame()->GetRoutingID(),
167       ConvertJavaStringToUTF8(env, markup)));
168 }
169
170 void WebContentsAndroid::BeginExitTransition(JNIEnv* env,
171                                              jobject jobj,
172                                              jstring css_selector) {
173   web_contents_->GetMainFrame()->Send(new FrameMsg_BeginExitTransition(
174       web_contents_->GetMainFrame()->GetRoutingID(),
175       ConvertJavaStringToUTF8(env, css_selector)));
176 }
177
178 void WebContentsAndroid::OnHide(JNIEnv* env, jobject obj) {
179   web_contents_->WasHidden();
180   PauseVideo();
181 }
182
183 void WebContentsAndroid::OnShow(JNIEnv* env, jobject obj) {
184   web_contents_->WasShown();
185 }
186
187 void WebContentsAndroid::PauseVideo() {
188   RenderViewHostImpl* rvhi = static_cast<RenderViewHostImpl*>(
189       web_contents_->GetRenderViewHost());
190   if (rvhi)
191     rvhi->media_web_contents_observer()->PauseVideo();
192 }
193
194 void WebContentsAndroid::AddStyleSheetByURL(
195     JNIEnv* env,
196     jobject obj,
197     jstring url) {
198   web_contents_->GetMainFrame()->Send(new FrameMsg_AddStyleSheetByURL(
199       web_contents_->GetMainFrame()->GetRoutingID(),
200       ConvertJavaStringToUTF8(env, url)));
201 }
202
203 void WebContentsAndroid::ShowInterstitialPage(
204     JNIEnv* env,
205     jobject obj,
206     jstring jurl,
207     jlong delegate_ptr) {
208   GURL url(base::android::ConvertJavaStringToUTF8(env, jurl));
209   InterstitialPageDelegateAndroid* delegate =
210       reinterpret_cast<InterstitialPageDelegateAndroid*>(delegate_ptr);
211   InterstitialPage* interstitial = InterstitialPage::Create(
212       web_contents_, false, url, delegate);
213   delegate->set_interstitial_page(interstitial);
214   interstitial->Show();
215 }
216
217 jboolean WebContentsAndroid::IsShowingInterstitialPage(JNIEnv* env,
218                                                         jobject obj) {
219   return web_contents_->ShowingInterstitialPage();
220 }
221
222 jboolean WebContentsAndroid::IsRenderWidgetHostViewReady(
223     JNIEnv* env,
224     jobject obj) {
225   RenderWidgetHostViewAndroid* view = GetRenderWidgetHostViewAndroid();
226   return view && view->HasValidFrame();
227 }
228
229 void WebContentsAndroid::ExitFullscreen(JNIEnv* env, jobject obj) {
230   RenderViewHost* host = web_contents_->GetRenderViewHost();
231   if (!host)
232     return;
233   host->ExitFullscreen();
234 }
235
236 void WebContentsAndroid::UpdateTopControlsState(
237     JNIEnv* env,
238     jobject obj,
239     bool enable_hiding,
240     bool enable_showing,
241     bool animate) {
242   RenderViewHost* host = web_contents_->GetRenderViewHost();
243   if (!host)
244     return;
245   host->Send(new ViewMsg_UpdateTopControlsState(host->GetRoutingID(),
246                                                 enable_hiding,
247                                                 enable_showing,
248                                                 animate));
249 }
250
251 void WebContentsAndroid::ShowImeIfNeeded(JNIEnv* env, jobject obj) {
252   RenderViewHost* host = web_contents_->GetRenderViewHost();
253   if (!host)
254     return;
255   host->Send(new ViewMsg_ShowImeIfNeeded(host->GetRoutingID()));
256 }
257
258 void WebContentsAndroid::ScrollFocusedEditableNodeIntoView(
259     JNIEnv* env,
260     jobject obj) {
261   RenderViewHost* host = web_contents_->GetRenderViewHost();
262   if (!host)
263     return;
264   host->Send(new InputMsg_ScrollFocusedEditableNodeIntoRect(
265       host->GetRoutingID(), gfx::Rect()));
266 }
267
268 void WebContentsAndroid::SelectWordAroundCaret(JNIEnv* env, jobject obj) {
269   RenderViewHost* host = web_contents_->GetRenderViewHost();
270   if (!host)
271     return;
272   host->SelectWordAroundCaret();
273 }
274
275 bool WebContentsAndroid::WillHandleDeferAfterResponseStarted() {
276   JNIEnv* env = AttachCurrentThread();
277   return Java_WebContentsImpl_willHandleDeferAfterResponseStarted(env,
278                                                                   obj_.obj());
279 }
280
281 void WebContentsAndroid::DidDeferAfterResponseStarted(
282     const TransitionLayerData& transition_data) {
283   JNIEnv* env = AttachCurrentThread();
284   std::vector<GURL> entering_stylesheets;
285   std::string transition_color;
286   if (transition_data.response_headers) {
287     TransitionRequestManager::ParseTransitionStylesheetsFromHeaders(
288         transition_data.response_headers,
289         entering_stylesheets,
290         transition_data.request_url);
291
292     transition_data.response_headers->EnumerateHeader(
293         NULL, "X-Transition-Entering-Color", &transition_color);
294   }
295
296   ScopedJavaLocalRef<jstring> jstring_markup(
297       ConvertUTF8ToJavaString(env, transition_data.markup));
298
299   ScopedJavaLocalRef<jstring> jstring_css_selector(
300       ConvertUTF8ToJavaString(env, transition_data.css_selector));
301
302   ScopedJavaLocalRef<jstring> jstring_transition_color(
303       ConvertUTF8ToJavaString(env, transition_color));
304
305   Java_WebContentsImpl_didDeferAfterResponseStarted(
306       env,
307       obj_.obj(),
308       jstring_markup.obj(),
309       jstring_css_selector.obj(),
310       jstring_transition_color.obj());
311
312   std::vector<GURL>::const_iterator iter = entering_stylesheets.begin();
313   for (; iter != entering_stylesheets.end(); ++iter) {
314     ScopedJavaLocalRef<jstring> jstring_url(
315         ConvertUTF8ToJavaString(env, iter->spec()));
316     Java_WebContentsImpl_addEnteringStylesheetToTransition(
317         env, obj_.obj(), jstring_url.obj());
318   }
319 }
320
321 void WebContentsAndroid::DidStartNavigationTransitionForFrame(int64 frame_id) {
322   JNIEnv* env = AttachCurrentThread();
323   Java_WebContentsImpl_didStartNavigationTransitionForFrame(
324       env, obj_.obj(), frame_id);
325 }
326
327 void WebContentsAndroid::EvaluateJavaScript(JNIEnv* env,
328                                             jobject obj,
329                                             jstring script,
330                                             jobject callback,
331                                             jboolean start_renderer) {
332   RenderViewHost* rvh = web_contents_->GetRenderViewHost();
333   DCHECK(rvh);
334
335   if (start_renderer && !rvh->IsRenderViewLive()) {
336     if (!static_cast<WebContentsImpl*>(web_contents_)->
337         CreateRenderViewForInitialEmptyDocument()) {
338       LOG(ERROR) << "Failed to create RenderView in EvaluateJavaScript";
339       return;
340     }
341   }
342
343   if (!callback) {
344     // No callback requested.
345     web_contents_->GetMainFrame()->ExecuteJavaScript(
346         ConvertJavaStringToUTF16(env, script));
347     return;
348   }
349
350   // Secure the Java callback in a scoped object and give ownership of it to the
351   // base::Callback.
352   ScopedJavaGlobalRef<jobject> j_callback;
353   j_callback.Reset(env, callback);
354   content::RenderFrameHost::JavaScriptResultCallback js_callback =
355       base::Bind(&JavaScriptResultCallback, j_callback);
356
357   web_contents_->GetMainFrame()->ExecuteJavaScript(
358       ConvertJavaStringToUTF16(env, script), js_callback);
359 }
360
361 }  // namespace content