FileChooser: Mojoify FileChooser IPC, part 4

Introduce content::FileSelectListener, which receives the result of FileSelectHelper.
An implementation class of FileSelectListener will implement blink.mojom.FileChooser
mojo interface in a following CL.

a) Add content::FileSelectListener
 - content/public/browser/BUILD.gn
 - content/public/browser/file_select_listener.h

b) Receive FileSelectHelper arguments, and call its methods to notify results
  instead of RFH::FilesSelectedInChooser() and RVH::
  DirectoryEnumerationFinished().
 - chrome/browser/file_select_helper.cc
 - chrome/browser/file_select_helper.h

c) Add FileChooserImpl class implementing content::FileSelectListener. A
  FileChooserImpl instance is passed to RenderFrameHostDelgate::
  RunFileChooser().  RFH::FilesSelectedInChooser() is removed because
  FileChooserImpl receives a file list, and it sends the list via IPC.
 - content/public/browser/render_frame_host.h
 - content/browser/frame_host/render_frame_host_impl.cc
 - content/browser/frame_host/render_frame_host_impl.h

d) Add ViewFileChooser class implementing content::FileSelectListener. A
  ViewFileChooser instance is passed to WebContentsDelegate::
  EnumerateDirectory(). RVH::DirectoryEnumerationFinished() is called by
  ViewFileChooser instead of FileSelectHelper.
 - content/browser/web_contents/web_contents_impl.cc
 - content/browser/web_contents/web_contents_impl.h

e) Add FileSelectListener argument, and call FileSelectListener::FileSelected()
  instead of RFH::FilesSelectedInChooser().  Maintain a FileSelectListener instance
  in AwWebContentsDelegate class.
 - android_webview/browser/aw_web_contents_delegate.cc
 - android_webview/browser/aw_web_contents_delegate.h


f) Add FileSelectListener argument, and forward it to another function or call
  FileSelectListener::FileSelectionCanceled()
 - chrome/browser/android/tab_web_contents_delegate_android.cc
 - chrome/browser/android/tab_web_contents_delegate_android.h
 - chrome/browser/devtools/devtools_window.cc
 - chrome/browser/devtools/devtools_window.h
 - chrome/browser/extensions/extension_view_host.cc
 - chrome/browser/extensions/extension_view_host.h
 - chrome/browser/ui/apps/chrome_app_delegate.cc
 - chrome/browser/ui/apps/chrome_app_delegate.h
 - chrome/browser/ui/browser.cc
 - chrome/browser/ui/browser.h
 - components/guest_view/browser/guest_view_base.cc
 - components/guest_view/browser/guest_view_base.h
 - content/browser/frame_host/render_frame_host_delegate.cc
 - content/browser/frame_host/render_frame_host_delegate.h
 - content/public/browser/web_contents_delegate.cc
 - content/public/browser/web_contents_delegate.h
 - extensions/browser/app_window/app_delegate.h
 - extensions/browser/app_window/app_window.cc
 - extensions/browser/app_window/app_window.h
 - extensions/shell/browser/shell_app_delegate.cc
 - extensions/shell/browser/shell_app_delegate.h

g) Add FileSelectListener argument, and call FileSelectListener::FileSelected()
  instead of RFH::FilesSelectedInChooser()
 - chrome/browser/ssl/security_state_tab_helper_browsertest.cc
 - content/test/content_browser_test_utils_internal.cc
 - content/test/content_browser_test_utils_internal.h

h) Add MockFileLister and pass it to RunFileChooser() to avoid null dereference.
 - content/browser/web_contents/web_contents_impl_browsertest.cc


FYI: All-in-one CL: https://chromium-review.googlesource.com/1170454

Bug: 869257
Change-Id: I190159bd5819d228c703028584b9929aa2ad80c2
Reviewed-on: https://chromium-review.googlesource.com/c/1251182
Reviewed-by: Istiaque Ahmed <[email protected]>
Reviewed-by: Richard Coles <[email protected]>
Reviewed-by: Avi Drissman <[email protected]>
Commit-Queue: Kent Tamura <[email protected]>
Cr-Commit-Position: refs/heads/master@{#596451}
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
index 169b1d8..9cb87f79 100644
--- a/content/browser/web_contents/web_contents_impl.cc
+++ b/content/browser/web_contents/web_contents_impl.cc
@@ -106,6 +106,7 @@
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/content_browser_client.h"
 #include "content/public/browser/download_manager.h"
+#include "content/public/browser/file_select_listener.h"
 #include "content/public/browser/focused_node_details.h"
 #include "content/public/browser/guest_mode.h"
 #include "content/public/browser/invalidate_type.h"
@@ -298,6 +299,46 @@
   return a->frame_tree_node()->depth() < b->frame_tree_node()->depth();
 }
 
+// TODO(tkent): This will be merged into FileChooserImpl in
+// render_frame_host_impl.cc.
+class ViewFileSelectListener : public FileSelectListener,
+                               private WebContentsObserver {
+ public:
+  ViewFileSelectListener(WebContents* web_contents, int request_id)
+      : web_contents_(web_contents), request_id_(request_id) {
+    Observe(web_contents);
+  }
+  ~ViewFileSelectListener() override = default;
+
+ private:
+  // content::FileSelectListener overrides:
+
+  void FileSelected(std::vector<blink::mojom::FileChooserFileInfoPtr> files,
+                    blink::mojom::FileChooserParams::Mode mode) override {
+    if (!web_contents_)
+      return;
+    std::vector<base::FilePath> file_path_list;
+    for (const auto& file_info : files) {
+      file_path_list.push_back(file_info->get_native_file()->file_path);
+    }
+    web_contents_->GetRenderViewHost()->DirectoryEnumerationFinished(
+        request_id_, file_path_list);
+  }
+
+  void FileSelectionCanceled() override {
+    if (!web_contents_)
+      return;
+    web_contents_->GetRenderViewHost()->DirectoryEnumerationFinished(
+        request_id_, std::vector<base::FilePath>());
+  }
+
+  // content::WebContentsObserver override:
+  void WebContentsDestroyed() override { web_contents_ = nullptr; }
+
+  WebContents* web_contents_;
+  int request_id_;
+};
+
 }  // namespace
 
 std::unique_ptr<WebContents> WebContents::Create(
@@ -4589,10 +4630,11 @@
 
   ChildProcessSecurityPolicyImpl* policy =
       ChildProcessSecurityPolicyImpl::GetInstance();
-  if (policy->CanReadFile(source->GetProcess()->GetID(), path)) {
-    // TODO(nick): |this| param in the call below ought to be a RenderFrameHost.
-    delegate_->EnumerateDirectory(this, request_id, path);
-  }
+  if (!policy->CanReadFile(source->GetProcess()->GetID(), path))
+    return;
+  auto listener = std::make_unique<ViewFileSelectListener>(this, request_id);
+  // TODO(nick): |this| param in the call below ought to be a RenderFrameHost.
+  delegate_->EnumerateDirectory(this, std::move(listener), path);
 }
 
 void WebContentsImpl::OnRegisterProtocolHandler(RenderFrameHostImpl* source,
@@ -5254,13 +5296,16 @@
 
 void WebContentsImpl::RunFileChooser(
     RenderFrameHost* render_frame_host,
+    std::unique_ptr<content::FileSelectListener> listener,
     const blink::mojom::FileChooserParams& params) {
   // Any explicit focusing of another window while this WebContents is in
   // fullscreen can be used to confuse the user, so drop fullscreen.
   ForSecurityDropFullscreen();
 
   if (delegate_)
-    delegate_->RunFileChooser(render_frame_host, params);
+    delegate_->RunFileChooser(render_frame_host, std::move(listener), params);
+  else
+    listener->FileSelectionCanceled();
 }
 
 WebContents* WebContentsImpl::GetAsWebContents() {