aw_web_contents_delegate.cc 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374
  1. // Copyright (c) 2012 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. #include "android_webview/browser/aw_web_contents_delegate.h"
  5. #include <utility>
  6. #include "android_webview/browser/aw_contents.h"
  7. #include "android_webview/browser/aw_contents_io_thread_client.h"
  8. #include "android_webview/browser/aw_javascript_dialog_manager.h"
  9. #include "android_webview/browser/find_helper.h"
  10. #include "android_webview/browser/permission/media_access_permission_request.h"
  11. #include "android_webview/browser/permission/permission_request_handler.h"
  12. #include "android_webview/browser_jni_headers/AwWebContentsDelegate_jni.h"
  13. #include "base/android/jni_array.h"
  14. #include "base/android/jni_string.h"
  15. #include "base/android/scoped_java_ref.h"
  16. #include "base/location.h"
  17. #include "base/logging.h"
  18. #include "base/memory/ptr_util.h"
  19. #include "base/no_destructor.h"
  20. #include "base/strings/string_util.h"
  21. #include "base/strings/utf_string_conversions.h"
  22. #include "base/task/single_thread_task_runner.h"
  23. #include "base/threading/thread_task_runner_handle.h"
  24. #include "components/navigation_interception/intercept_navigation_delegate.h"
  25. #include "content/public/browser/file_select_listener.h"
  26. #include "content/public/browser/render_frame_host.h"
  27. #include "content/public/browser/render_process_host.h"
  28. #include "content/public/browser/render_view_host.h"
  29. #include "content/public/browser/render_widget_host.h"
  30. #include "content/public/browser/web_contents.h"
  31. #include "net/base/filename_util.h"
  32. #include "third_party/blink/public/common/mediastream/media_stream_request.h"
  33. #include "third_party/blink/public/mojom/mediastream/media_stream.mojom.h"
  34. using base::android::AttachCurrentThread;
  35. using base::android::ConvertUTF16ToJavaString;
  36. using base::android::ConvertUTF8ToJavaString;
  37. using base::android::JavaParamRef;
  38. using base::android::ScopedJavaLocalRef;
  39. using blink::mojom::FileChooserFileInfo;
  40. using blink::mojom::FileChooserFileInfoPtr;
  41. using blink::mojom::FileChooserParams;
  42. using content::WebContents;
  43. namespace android_webview {
  44. AwWebContentsDelegate::AwWebContentsDelegate(JNIEnv* env, jobject obj)
  45. : WebContentsDelegateAndroid(env, obj), is_fullscreen_(false) {}
  46. AwWebContentsDelegate::~AwWebContentsDelegate() = default;
  47. void AwWebContentsDelegate::RendererUnresponsive(
  48. content::WebContents* source,
  49. content::RenderWidgetHost* render_widget_host,
  50. base::RepeatingClosure hang_monitor_restarter) {
  51. AwContents* aw_contents = AwContents::FromWebContents(source);
  52. if (!aw_contents)
  53. return;
  54. content::RenderProcessHost* render_process_host =
  55. render_widget_host->GetProcess();
  56. if (render_process_host->IsInitializedAndNotDead()) {
  57. aw_contents->RendererUnresponsive(render_widget_host->GetProcess());
  58. hang_monitor_restarter.Run();
  59. }
  60. }
  61. void AwWebContentsDelegate::RendererResponsive(
  62. content::WebContents* source,
  63. content::RenderWidgetHost* render_widget_host) {
  64. AwContents* aw_contents = AwContents::FromWebContents(source);
  65. if (!aw_contents)
  66. return;
  67. content::RenderProcessHost* render_process_host =
  68. render_widget_host->GetProcess();
  69. if (render_process_host->IsInitializedAndNotDead()) {
  70. aw_contents->RendererResponsive(render_widget_host->GetProcess());
  71. }
  72. }
  73. content::JavaScriptDialogManager*
  74. AwWebContentsDelegate::GetJavaScriptDialogManager(WebContents* source) {
  75. static base::NoDestructor<AwJavaScriptDialogManager>
  76. javascript_dialog_manager;
  77. return javascript_dialog_manager.get();
  78. }
  79. void AwWebContentsDelegate::FindReply(WebContents* web_contents,
  80. int request_id,
  81. int number_of_matches,
  82. const gfx::Rect& selection_rect,
  83. int active_match_ordinal,
  84. bool final_update) {
  85. AwContents* aw_contents = AwContents::FromWebContents(web_contents);
  86. if (!aw_contents)
  87. return;
  88. aw_contents->GetFindHelper()->HandleFindReply(
  89. request_id, number_of_matches, active_match_ordinal, final_update);
  90. }
  91. void AwWebContentsDelegate::RunFileChooser(
  92. content::RenderFrameHost* render_frame_host,
  93. scoped_refptr<content::FileSelectListener> listener,
  94. const FileChooserParams& params) {
  95. JNIEnv* env = AttachCurrentThread();
  96. ScopedJavaLocalRef<jobject> java_delegate = GetJavaDelegate(env);
  97. if (!java_delegate.obj()) {
  98. listener->FileSelectionCanceled();
  99. return;
  100. }
  101. int mode_flags = 0;
  102. if (params.mode == FileChooserParams::Mode::kUploadFolder ||
  103. params.mode == FileChooserParams::Mode::kOpenMultiple) {
  104. // Folder implies multiple in Chrome.
  105. mode_flags = static_cast<int>(FileChooserParams::Mode::kOpenMultiple);
  106. } else if (params.mode == FileChooserParams::Mode::kSave) {
  107. // Save not supported, so cancel it.
  108. listener->FileSelectionCanceled();
  109. return;
  110. } else {
  111. DCHECK_EQ(FileChooserParams::Mode::kOpen, params.mode);
  112. }
  113. DCHECK(!file_select_listener_)
  114. << "Multiple concurrent FileChooser requests are not supported.";
  115. file_select_listener_ = std::move(listener);
  116. Java_AwWebContentsDelegate_runFileChooser(
  117. env, java_delegate, render_frame_host->GetProcess()->GetID(),
  118. render_frame_host->GetRoutingID(), mode_flags,
  119. ConvertUTF16ToJavaString(env,
  120. base::JoinString(params.accept_types, u",")),
  121. params.title.empty() ? nullptr
  122. : ConvertUTF16ToJavaString(env, params.title),
  123. params.default_file_name.empty()
  124. ? nullptr
  125. : ConvertUTF8ToJavaString(env, params.default_file_name.value()),
  126. params.use_media_capture);
  127. }
  128. void AwWebContentsDelegate::AddNewContents(
  129. WebContents* source,
  130. std::unique_ptr<WebContents> new_contents,
  131. const GURL& target_url,
  132. WindowOpenDisposition disposition,
  133. const gfx::Rect& initial_rect,
  134. bool user_gesture,
  135. bool* was_blocked) {
  136. JNIEnv* env = AttachCurrentThread();
  137. bool is_dialog = disposition == WindowOpenDisposition::NEW_POPUP;
  138. ScopedJavaLocalRef<jobject> java_delegate = GetJavaDelegate(env);
  139. bool create_popup = false;
  140. if (java_delegate.obj()) {
  141. create_popup = Java_AwWebContentsDelegate_addNewContents(
  142. env, java_delegate, is_dialog, user_gesture);
  143. }
  144. if (create_popup) {
  145. // The embedder would like to display the popup and we will receive
  146. // a callback from them later with an AwContents to use to display
  147. // it. The source AwContents takes ownership of the new WebContents
  148. // until then, and when the callback is made we will swap the WebContents
  149. // out into the new AwContents.
  150. WebContents* raw_new_contents = new_contents.get();
  151. AwContents::FromWebContents(source)->SetPendingWebContentsForPopup(
  152. std::move(new_contents));
  153. // It's possible that SetPendingWebContentsForPopup deletes |new_contents|,
  154. // but it only does so asynchronously, so it's safe to use a raw pointer
  155. // here.
  156. // Hide the WebContents for the pop up now, we will show it again
  157. // when the user calls us back with an AwContents to use to show it.
  158. raw_new_contents->WasHidden();
  159. } else {
  160. // The embedder has forgone their chance to display this popup
  161. // window, so we're done with the WebContents now. We use
  162. // DeleteSoon as WebContentsImpl may call methods on |new_contents|
  163. // after this method returns.
  164. base::ThreadTaskRunnerHandle::Get()->DeleteSoon(FROM_HERE,
  165. std::move(new_contents));
  166. }
  167. if (was_blocked) {
  168. *was_blocked = !create_popup;
  169. }
  170. }
  171. void AwWebContentsDelegate::NavigationStateChanged(
  172. content::WebContents* source,
  173. content::InvalidateTypes changed_flags) {
  174. JNIEnv* env = AttachCurrentThread();
  175. ScopedJavaLocalRef<jobject> java_delegate = GetJavaDelegate(env);
  176. if (java_delegate.obj()) {
  177. Java_AwWebContentsDelegate_navigationStateChanged(env, java_delegate,
  178. changed_flags);
  179. }
  180. }
  181. // Notifies the delegate about the creation of a new WebContents. This
  182. // typically happens when popups are created.
  183. void AwWebContentsDelegate::WebContentsCreated(
  184. WebContents* source_contents,
  185. int opener_render_process_id,
  186. int opener_render_frame_id,
  187. const std::string& frame_name,
  188. const GURL& target_url,
  189. content::WebContents* new_contents) {
  190. // Intentionally left empty to override implementation in superclasses.
  191. }
  192. void AwWebContentsDelegate::CloseContents(WebContents* source) {
  193. JNIEnv* env = AttachCurrentThread();
  194. ScopedJavaLocalRef<jobject> java_delegate = GetJavaDelegate(env);
  195. if (java_delegate.obj()) {
  196. Java_AwWebContentsDelegate_closeContents(env, java_delegate);
  197. }
  198. }
  199. void AwWebContentsDelegate::ActivateContents(WebContents* contents) {
  200. JNIEnv* env = AttachCurrentThread();
  201. ScopedJavaLocalRef<jobject> java_delegate = GetJavaDelegate(env);
  202. if (java_delegate.obj()) {
  203. Java_AwWebContentsDelegate_activateContents(env, java_delegate);
  204. }
  205. }
  206. void AwWebContentsDelegate::LoadingStateChanged(WebContents* source,
  207. bool to_different_document) {
  208. // Page title may have changed, need to inform the embedder.
  209. // |source| may be null if loading has started.
  210. JNIEnv* env = AttachCurrentThread();
  211. ScopedJavaLocalRef<jobject> java_delegate = GetJavaDelegate(env);
  212. if (java_delegate.obj()) {
  213. Java_AwWebContentsDelegate_loadingStateChanged(env, java_delegate);
  214. }
  215. }
  216. bool AwWebContentsDelegate::ShouldResumeRequestsForCreatedWindow() {
  217. // Always return false here since we need to defer loading the created window
  218. // until after we have attached a new delegate to the new webcontents (which
  219. // happens asynchronously).
  220. return false;
  221. }
  222. void AwWebContentsDelegate::RequestMediaAccessPermission(
  223. WebContents* web_contents,
  224. const content::MediaStreamRequest& request,
  225. content::MediaResponseCallback callback) {
  226. AwContents* aw_contents = AwContents::FromWebContents(web_contents);
  227. if (!aw_contents) {
  228. std::move(callback).Run(
  229. blink::mojom::StreamDevicesSet(),
  230. blink::mojom::MediaStreamRequestResult::FAILED_DUE_TO_SHUTDOWN,
  231. nullptr);
  232. return;
  233. }
  234. aw_contents->GetPermissionRequestHandler()->SendRequest(
  235. std::make_unique<MediaAccessPermissionRequest>(request,
  236. std::move(callback)));
  237. }
  238. void AwWebContentsDelegate::EnterFullscreenModeForTab(
  239. content::RenderFrameHost* requesting_frame,
  240. const blink::mojom::FullscreenOptions& options) {
  241. WebContentsDelegateAndroid::EnterFullscreenModeForTab(requesting_frame,
  242. options);
  243. is_fullscreen_ = true;
  244. requesting_frame->GetRenderViewHost()
  245. ->GetWidget()
  246. ->SynchronizeVisualProperties();
  247. }
  248. void AwWebContentsDelegate::ExitFullscreenModeForTab(
  249. content::WebContents* web_contents) {
  250. WebContentsDelegateAndroid::ExitFullscreenModeForTab(web_contents);
  251. is_fullscreen_ = false;
  252. web_contents->GetRenderViewHost()->GetWidget()->SynchronizeVisualProperties();
  253. }
  254. bool AwWebContentsDelegate::IsFullscreenForTabOrPending(
  255. const content::WebContents* web_contents) {
  256. return is_fullscreen_;
  257. }
  258. void AwWebContentsDelegate::UpdateUserGestureCarryoverInfo(
  259. content::WebContents* web_contents) {
  260. auto* intercept_navigation_delegate =
  261. navigation_interception::InterceptNavigationDelegate::Get(web_contents);
  262. if (intercept_navigation_delegate)
  263. intercept_navigation_delegate->OnResourceRequestWithGesture();
  264. }
  265. scoped_refptr<content::FileSelectListener>
  266. AwWebContentsDelegate::TakeFileSelectListener() {
  267. return std::move(file_select_listener_);
  268. }
  269. static void JNI_AwWebContentsDelegate_FilesSelectedInChooser(
  270. JNIEnv* env,
  271. jint process_id,
  272. jint render_id,
  273. jint mode_flags,
  274. const JavaParamRef<jobjectArray>& file_paths,
  275. const JavaParamRef<jobjectArray>& display_names) {
  276. content::RenderFrameHost* rfh =
  277. content::RenderFrameHost::FromID(process_id, render_id);
  278. auto* web_contents = WebContents::FromRenderFrameHost(rfh);
  279. if (!web_contents)
  280. return;
  281. auto* delegate =
  282. static_cast<AwWebContentsDelegate*>(web_contents->GetDelegate());
  283. if (!delegate)
  284. return;
  285. scoped_refptr<content::FileSelectListener> listener =
  286. delegate->TakeFileSelectListener();
  287. if (!file_paths.obj()) {
  288. listener->FileSelectionCanceled();
  289. return;
  290. }
  291. std::vector<std::string> file_path_str;
  292. std::vector<std::u16string> display_name_str;
  293. // Note file_paths maybe NULL, but this will just yield a zero-length vector.
  294. base::android::AppendJavaStringArrayToStringVector(env, file_paths,
  295. &file_path_str);
  296. base::android::AppendJavaStringArrayToStringVector(env, display_names,
  297. &display_name_str);
  298. std::vector<FileChooserFileInfoPtr> files;
  299. files.reserve(file_path_str.size());
  300. for (size_t i = 0; i < file_path_str.size(); ++i) {
  301. GURL url(file_path_str[i]);
  302. if (!url.is_valid()) {
  303. LOG(ERROR) << "The file choice request has an invalid Uri: "
  304. << file_path_str[i];
  305. continue;
  306. }
  307. base::FilePath path;
  308. if (url.SchemeIsFile()) {
  309. if (!net::FileURLToFilePath(url, &path))
  310. continue;
  311. } else {
  312. path = base::FilePath(file_path_str[i]);
  313. }
  314. auto file_info = blink::mojom::NativeFileInfo::New();
  315. file_info->file_path = path;
  316. if (!display_name_str[i].empty())
  317. file_info->display_name = display_name_str[i];
  318. files.push_back(FileChooserFileInfo::NewNativeFile(std::move(file_info)));
  319. }
  320. base::FilePath base_dir;
  321. FileChooserParams::Mode mode;
  322. // We'd like to set |base_dir| to a folder which a user selected. But it's
  323. // impossible with WebChromeClient API in the current Android.
  324. if (mode_flags == static_cast<int>(FileChooserParams::Mode::kOpenMultiple)) {
  325. mode = FileChooserParams::Mode::kOpenMultiple;
  326. } else {
  327. mode = FileChooserParams::Mode::kOpen;
  328. }
  329. DVLOG(0) << "File Chooser result: mode = " << mode
  330. << ", file paths = " << base::JoinString(file_path_str, ":");
  331. listener->FileSelected(std::move(files), base_dir, mode);
  332. }
  333. } // namespace android_webview