Upstream version 6.35.131.0
[platform/framework/web/crosswalk.git] / src / xwalk / runtime / browser / android / xwalk_contents_client_bridge.cc
1 // Copyright (c) 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 "xwalk/runtime/browser/android/xwalk_contents_client_bridge.h"
6
7 #include <string>
8
9 #include "base/android/jni_android.h"
10 #include "base/android/jni_array.h"
11 #include "base/android/jni_string.h"
12 #include "base/callback.h"
13 #include "content/public/browser/browser_thread.h"
14 #include "content/public/browser/render_view_host.h"
15 #include "content/public/browser/web_contents.h"
16 #include "content/public/common/file_chooser_params.h"
17 #include "content/public/common/show_desktop_notification_params.h"
18 #include "jni/XWalkContentsClientBridge_jni.h"
19 #include "net/cert/x509_certificate.h"
20 #include "third_party/skia/include/core/SkBitmap.h"
21 #include "url/gurl.h"
22 #include "ui/gfx/android/java_bitmap.h"
23 #include "ui/shell_dialogs/selected_file_info.h"
24
25 using base::android::AttachCurrentThread;
26 using base::android::ConvertJavaStringToUTF16;
27 using base::android::ConvertUTF8ToJavaString;
28 using base::android::ConvertUTF16ToJavaString;
29 using base::android::JavaRef;
30 using base::android::ScopedJavaLocalRef;
31 using content::BrowserThread;
32 using content::FileChooserParams;
33 using content::RenderViewHost;
34 using content::WebContents;
35
36 namespace xwalk {
37
38 namespace {
39
40 void RunUpdateNotificationIconOnUIThread(
41     int notification_id,
42     int process_id,
43     int route_id,
44     const SkBitmap& icon) {
45   XWalkContentsClientBridgeBase* bridge =
46       XWalkContentsClientBridgeBase::FromRenderViewID(process_id, route_id);
47   if (bridge)
48     bridge->UpdateNotificationIcon(notification_id, icon);
49 }
50
51 }  // namespace
52
53 XWalkContentsClientBridge::XWalkContentsClientBridge(JNIEnv* env, jobject obj)
54     : java_ref_(env, obj) {
55   DCHECK(obj);
56   Java_XWalkContentsClientBridge_setNativeContentsClientBridge(
57       env, obj, reinterpret_cast<intptr_t>(this));
58 }
59
60 XWalkContentsClientBridge::~XWalkContentsClientBridge() {
61   JNIEnv* env = AttachCurrentThread();
62
63   ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
64   if (obj.is_null())
65     return;
66   // Clear the weak reference from the java peer to the native object since
67   // it is possible that java object lifetime can exceed the XWalkViewContents.
68   Java_XWalkContentsClientBridge_setNativeContentsClientBridge(
69       env, obj.obj(), 0);
70 }
71
72 void XWalkContentsClientBridge::AllowCertificateError(
73     int cert_error,
74     net::X509Certificate* cert,
75     const GURL& request_url,
76     const base::Callback<void(bool)>& callback, // NOLINT
77     bool* cancel_request) {
78
79   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
80   JNIEnv* env = AttachCurrentThread();
81
82   ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
83   if (obj.is_null())
84     return;
85
86   std::string der_string;
87   net::X509Certificate::GetDEREncoded(cert->os_cert_handle(), &der_string);
88   ScopedJavaLocalRef<jbyteArray> jcert = base::android::ToJavaByteArray(
89       env,
90       reinterpret_cast<const uint8*>(der_string.data()),
91       der_string.length());
92   ScopedJavaLocalRef<jstring> jurl(ConvertUTF8ToJavaString(
93       env, request_url.spec()));
94   // We need to add the callback before making the call to java side,
95   // as it may do a synchronous callback prior to returning.
96   int request_id = pending_cert_error_callbacks_.Add(
97       new CertErrorCallback(callback));
98   *cancel_request = !Java_XWalkContentsClientBridge_allowCertificateError(
99       env, obj.obj(), cert_error, jcert.obj(), jurl.obj(), request_id);
100   // if the request is cancelled, then cancel the stored callback
101   if (*cancel_request) {
102     pending_cert_error_callbacks_.Remove(request_id);
103   }
104 }
105
106 void XWalkContentsClientBridge::ProceedSslError(JNIEnv* env, jobject obj,
107                                                 jboolean proceed, jint id) {
108   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
109   CertErrorCallback* callback = pending_cert_error_callbacks_.Lookup(id);
110   if (!callback || callback->is_null()) {
111     LOG(WARNING) << "Ignoring unexpected ssl error proceed callback";
112     return;
113   }
114   callback->Run(proceed);
115   pending_cert_error_callbacks_.Remove(id);
116 }
117
118 void XWalkContentsClientBridge::RunJavaScriptDialog(
119     content::JavaScriptMessageType message_type,
120     const GURL& origin_url,
121     const base::string16& message_text,
122     const base::string16& default_prompt_text,
123     const content::JavaScriptDialogManager::DialogClosedCallback& callback) {
124   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
125   JNIEnv* env = AttachCurrentThread();
126
127   ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
128   if (obj.is_null())
129     return;
130
131   int callback_id = pending_js_dialog_callbacks_.Add(
132       new content::JavaScriptDialogManager::DialogClosedCallback(callback));
133   ScopedJavaLocalRef<jstring> jurl(
134       ConvertUTF8ToJavaString(env, origin_url.spec()));
135   ScopedJavaLocalRef<jstring> jmessage(
136       ConvertUTF16ToJavaString(env, message_text));
137
138   switch (message_type) {
139     case content::JAVASCRIPT_MESSAGE_TYPE_ALERT:
140       Java_XWalkContentsClientBridge_handleJsAlert(
141           env, obj.obj(), jurl.obj(), jmessage.obj(), callback_id);
142       break;
143     case content::JAVASCRIPT_MESSAGE_TYPE_CONFIRM:
144       Java_XWalkContentsClientBridge_handleJsConfirm(
145           env, obj.obj(), jurl.obj(), jmessage.obj(), callback_id);
146       break;
147     case content::JAVASCRIPT_MESSAGE_TYPE_PROMPT: {
148       ScopedJavaLocalRef<jstring> jdefault_value(
149           ConvertUTF16ToJavaString(env, default_prompt_text));
150       Java_XWalkContentsClientBridge_handleJsPrompt(env,
151                                                     obj.obj(),
152                                                     jurl.obj(),
153                                                     jmessage.obj(),
154                                                     jdefault_value.obj(),
155                                                     callback_id);
156       break;
157     }
158     default:
159        NOTREACHED();
160   }
161 }
162
163 void XWalkContentsClientBridge::RunBeforeUnloadDialog(
164     const GURL& origin_url,
165     const base::string16& message_text,
166     const content::JavaScriptDialogManager::DialogClosedCallback& callback) {
167   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
168   JNIEnv* env = AttachCurrentThread();
169
170   ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
171   if (obj.is_null())
172     return;
173
174   int callback_id = pending_js_dialog_callbacks_.Add(
175       new content::JavaScriptDialogManager::DialogClosedCallback(callback));
176   ScopedJavaLocalRef<jstring> jurl(
177       ConvertUTF8ToJavaString(env, origin_url.spec()));
178   ScopedJavaLocalRef<jstring> jmessage(
179       ConvertUTF16ToJavaString(env, message_text));
180
181   Java_XWalkContentsClientBridge_handleJsBeforeUnload(
182       env, obj.obj(), jurl.obj(), jmessage.obj(), callback_id);
183 }
184
185 bool XWalkContentsClientBridge::OnReceivedHttpAuthRequest(
186     const JavaRef<jobject>& handler,
187     const std::string& host,
188     const std::string& realm) {
189   JNIEnv* env = AttachCurrentThread();
190   ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
191   if (obj.is_null())
192     return false;
193
194   ScopedJavaLocalRef<jstring> jhost = ConvertUTF8ToJavaString(env, host);
195   ScopedJavaLocalRef<jstring> jrealm = ConvertUTF8ToJavaString(env, realm);
196   Java_XWalkContentsClientBridge_onReceivedHttpAuthRequest(
197       env, obj.obj(), handler.obj(), jhost.obj(), jrealm.obj());
198   return true;
199 }
200
201 void XWalkContentsClientBridge::OnNotificationIconDownloaded(
202     int id,
203     int http_status_code,
204     const GURL& icon_url,
205     const std::vector<SkBitmap>& bitmaps,
206     const std::vector<gfx::Size>& original_bitmap_sizes) {
207   if (bitmaps.empty() && http_status_code == 404) {
208     LOG(WARNING) << "Failed to download notification icon from "
209                  << icon_url.spec();
210   } else {
211     NotificationDownloadRequestIdMap::iterator iter =
212         downloading_icon_notifications_.find(id);
213     if (iter == downloading_icon_notifications_.end() ||
214         iter->second.size() != 3) {
215       return;
216     }
217     int notification_id = iter->second[0];
218     int process_id = iter->second[1];
219     int route_id = iter->second[2];
220     // This will lead to a second call of ShowNotification for the
221     // same notification id to update the icon. On Android, when
222     // the notification which is already shown is fired again, it will
223     // silently update the content only.
224     BrowserThread::PostTask(
225         BrowserThread::UI,
226         FROM_HERE,
227         base::Bind(&RunUpdateNotificationIconOnUIThread,
228                    notification_id,
229                    process_id,
230                    route_id,
231                    bitmaps[0]));
232   }
233   downloading_icon_notifications_.erase(id);
234 }
235
236 void XWalkContentsClientBridge::UpdateNotificationIcon(
237     int notification_id, const SkBitmap& icon) {
238   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
239   JNIEnv* env = AttachCurrentThread();
240
241   ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
242   if (obj.is_null())
243     return;
244
245   ScopedJavaLocalRef<jobject> jicon = gfx::ConvertToJavaBitmap(&icon);
246   Java_XWalkContentsClientBridge_updateNotificationIcon(
247       env, obj.obj(), notification_id, jicon.obj());
248 }
249
250 void XWalkContentsClientBridge::ShowNotification(
251     const content::ShowDesktopNotificationHostMsgParams& params,
252     bool worker,
253     int process_id,
254     int route_id) {
255   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
256   JNIEnv* env = AttachCurrentThread();
257
258   ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
259   if (obj.is_null())
260     return;
261
262   ScopedJavaLocalRef<jstring> jtitle(
263     ConvertUTF16ToJavaString(env, params.title));
264   ScopedJavaLocalRef<jstring> jbody(
265     ConvertUTF16ToJavaString(env, params.body));
266   ScopedJavaLocalRef<jstring> jreplace_id(
267     ConvertUTF16ToJavaString(env, params.replace_id));
268
269   Java_XWalkContentsClientBridge_showNotification(
270       env, obj.obj(), jtitle.obj(), jbody.obj(),
271       jreplace_id.obj(), params.notification_id,
272       process_id, route_id);
273
274   if (params.icon_url.is_valid()) {
275     RenderViewHost* rvh = RenderViewHost::FromID(process_id, route_id);
276     if (rvh) {
277       WebContents* web_contents = WebContents::FromRenderViewHost(rvh);
278       if (web_contents) {
279         int download_request_id = web_contents->DownloadImage(
280             params.icon_url,
281             false,
282             0,
283             base::Bind(
284                 &XWalkContentsClientBridge::OnNotificationIconDownloaded,
285                 base::Unretained(this)));
286         std::vector<int> ids;
287         ids.push_back(params.notification_id);
288         ids.push_back(process_id);
289         ids.push_back(route_id);
290         downloading_icon_notifications_[download_request_id] = ids;
291       }
292     }
293   }
294 }
295
296 void XWalkContentsClientBridge::CancelNotification(
297     int notification_id,
298     int process_id,
299     int route_id) {
300   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
301   JNIEnv* env = AttachCurrentThread();
302
303   ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
304   if (obj.is_null())
305     return;
306
307   Java_XWalkContentsClientBridge_cancelNotification(
308       env, obj.obj(), notification_id,
309       process_id, route_id);
310 }
311
312 void XWalkContentsClientBridge::ConfirmJsResult(JNIEnv* env,
313                                                 jobject,
314                                                 int id,
315                                                 jstring prompt) {
316   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
317   content::JavaScriptDialogManager::DialogClosedCallback* callback =
318       pending_js_dialog_callbacks_.Lookup(id);
319   base::string16 prompt_text;
320   if (prompt) {
321     prompt_text = ConvertJavaStringToUTF16(env, prompt);
322   }
323   if (callback)
324     callback->Run(true, prompt_text);
325   pending_js_dialog_callbacks_.Remove(id);
326 }
327
328 void XWalkContentsClientBridge::CancelJsResult(JNIEnv*, jobject, int id) {
329   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
330   content::JavaScriptDialogManager::DialogClosedCallback* callback =
331       pending_js_dialog_callbacks_.Lookup(id);
332   if (callback)
333     callback->Run(false, base::string16());
334   pending_js_dialog_callbacks_.Remove(id);
335 }
336
337 void XWalkContentsClientBridge::ExitFullscreen(
338     JNIEnv*, jobject, jlong j_web_contents) {
339   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
340   WebContents* web_contents = reinterpret_cast<WebContents*>(j_web_contents);
341   if (web_contents) {
342     RenderViewHost* rvh = web_contents->GetRenderViewHost();
343     if (rvh)
344       rvh->ExitFullscreen();
345   }
346 }
347
348 void XWalkContentsClientBridge::NotificationDisplayed(
349     JNIEnv*, jobject, int id, int process_id, int route_id) {
350   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
351   RenderViewHost* rvh = RenderViewHost::FromID(
352       process_id, route_id);
353   if (!rvh)
354     return;
355   rvh->DesktopNotificationPostDisplay(id);
356 }
357
358 void XWalkContentsClientBridge::NotificationError(
359     JNIEnv* env, jobject, int id, jstring error,
360     int process_id, int route_id) {
361   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
362   RenderViewHost* rvh = RenderViewHost::FromID(
363       process_id, route_id);
364   if (!rvh)
365     return;
366   base::string16 error_text;
367   if (error)
368     error_text = ConvertJavaStringToUTF16(env, error);
369   rvh->DesktopNotificationPostError(id, error_text);
370 }
371
372 void XWalkContentsClientBridge::NotificationClicked(
373     JNIEnv*, jobject, int id, int process_id, int route_id) {
374   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
375   RenderViewHost* rvh = RenderViewHost::FromID(
376       process_id, route_id);
377   if (!rvh)
378     return;
379   rvh->DesktopNotificationPostClick(id);
380 }
381
382 void XWalkContentsClientBridge::NotificationClosed(
383     JNIEnv*, jobject, int id, bool by_user,
384     int process_id, int route_id) {
385   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
386   RenderViewHost* rvh = RenderViewHost::FromID(
387       process_id, route_id);
388   if (!rvh)
389     return;
390   rvh->DesktopNotificationPostClose(id, by_user);
391 }
392
393 void XWalkContentsClientBridge::OnFilesSelected(
394     JNIEnv* env, jobject, int process_id, int render_id,
395     int mode, jstring filepath, jstring display_name) {
396   content::RenderViewHost* rvh =
397       content::RenderViewHost::FromID(process_id, render_id);
398   if (!rvh)
399     return;
400
401   std::string path = base::android::ConvertJavaStringToUTF8(env, filepath);
402   std::string file_name =
403       base::android::ConvertJavaStringToUTF8(env, display_name);
404   base::FilePath file_path = base::FilePath(path);
405   ui::SelectedFileInfo file_info;
406   file_info.file_path = file_path;
407   file_info.local_path = file_path;
408   if (!file_name.empty())
409     file_info.display_name = file_name;
410   std::vector<ui::SelectedFileInfo> files;
411   files.push_back(file_info);
412
413   rvh->FilesSelectedInChooser(
414       files, static_cast<content::FileChooserParams::Mode>(mode));
415 }
416
417 void XWalkContentsClientBridge::OnFilesNotSelected(
418     JNIEnv* env, jobject, int process_id, int render_id, int mode) {
419   content::RenderViewHost* rvh =
420       content::RenderViewHost::FromID(process_id, render_id);
421   if (!rvh)
422     return;
423
424   std::vector<ui::SelectedFileInfo> files;
425
426   rvh->FilesSelectedInChooser(
427       files, static_cast<content::FileChooserParams::Mode>(mode));
428 }
429
430 bool RegisterXWalkContentsClientBridge(JNIEnv* env) {
431   return RegisterNativesImpl(env) >= 0;
432 }
433
434 }  // namespace xwalk