15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/file_select_helper.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <string>
87dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include <utility>
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h"
11868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/files/file_enumerator.h"
121320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "base/files/file_util.h"
132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/strings/string_split.h"
14868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/string_util.h"
15868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/utf_string_conversions.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/platform_util.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/profiles/profile.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/browser.h"
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/browser_list.h"
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/chrome_select_file_policy.h"
2103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#include "chrome/grit/generated_resources.h"
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/browser_thread.h"
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/notification_details.h"
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/notification_source.h"
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/notification_types.h"
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/render_view_host.h"
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/render_widget_host_view.h"
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/web_contents.h"
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/common/file_chooser_params.h"
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/mime_util.h"
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/l10n/l10n_util.h"
322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/shell_dialogs/selected_file_info.h"
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using content::BrowserThread;
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using content::FileChooserParams;
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using content::RenderViewHost;
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using content::RenderWidgetHost;
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using content::WebContents;
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// There is only one file-selection happening at any given time,
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// so we allocate an enumeration ID for that purpose.  All IDs from
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// the renderer must start at 0 and increase.
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kFileSelectEnumerationId = -1;
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void NotifyRenderViewHost(RenderViewHost* render_view_host,
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          const std::vector<ui::SelectedFileInfo>& files,
497dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                          FileChooserParams::Mode dialog_mode) {
507dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  render_view_host->FilesSelectedInChooser(files, dialog_mode);
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Converts a list of FilePaths to a list of ui::SelectedFileInfo.
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::vector<ui::SelectedFileInfo> FilePathListToSelectedFileInfoList(
552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::vector<base::FilePath>& paths) {
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<ui::SelectedFileInfo> selected_files;
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < paths.size(); ++i) {
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    selected_files.push_back(
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ui::SelectedFileInfo(paths[i], paths[i]));
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return selected_files;
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)struct FileSelectHelper::ActiveDirectoryEnumeration {
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ActiveDirectoryEnumeration() : rvh_(NULL) {}
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<DirectoryListerDispatchDelegate> delegate_;
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<net::DirectoryLister> lister_;
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  RenderViewHost* rvh_;
722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::vector<base::FilePath> results_;
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)FileSelectHelper::FileSelectHelper(Profile* profile)
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : profile_(profile),
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      render_view_host_(NULL),
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      web_contents_(NULL),
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      select_file_dialog_(),
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      select_file_types_(),
817dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      dialog_type_(ui::SelectFileDialog::SELECT_OPEN_FILE),
827dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      dialog_mode_(FileChooserParams::Open) {
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)FileSelectHelper::~FileSelectHelper() {
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // There may be pending file dialogs, we need to tell them that we've gone
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // away so they don't try and call back to us.
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (select_file_dialog_.get())
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    select_file_dialog_->ListenerDestroyed();
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Stop any pending directory enumeration, prevent a callback, and free
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // allocated memory.
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::map<int, ActiveDirectoryEnumeration*>::iterator iter;
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (iter = directory_enumerations_.begin();
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       iter != directory_enumerations_.end();
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       ++iter) {
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    iter->second->lister_.reset();
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    delete iter->second;
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void FileSelectHelper::DirectoryListerDispatchDelegate::OnListFile(
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const net::DirectoryLister::DirectoryListerData& data) {
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  parent_->OnListFile(id_, data);
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void FileSelectHelper::DirectoryListerDispatchDelegate::OnListDone(int error) {
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  parent_->OnListDone(id_, error);
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void FileSelectHelper::FileSelected(const base::FilePath& path,
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                    int index, void* params) {
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  FileSelectedWithExtraInfo(ui::SelectedFileInfo(path, path), index, params);
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void FileSelectHelper::FileSelectedWithExtraInfo(
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const ui::SelectedFileInfo& file,
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int index,
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    void* params) {
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!render_view_host_)
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  profile_->set_last_selected_directory(file.file_path.DirName());
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const base::FilePath& path = file.local_path;
126a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  if (dialog_type_ == ui::SelectFileDialog::SELECT_UPLOAD_FOLDER) {
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    StartNewEnumeration(path, kFileSelectEnumerationId, render_view_host_);
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<ui::SelectedFileInfo> files;
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  files.push_back(file);
1337dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  NotifyRenderViewHost(render_view_host_, files, dialog_mode_);
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // No members should be accessed from here on.
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  RunFileChooserEnd();
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void FileSelectHelper::MultiFilesSelected(
1402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::vector<base::FilePath>& files,
1412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    void* params) {
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<ui::SelectedFileInfo> selected_files =
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      FilePathListToSelectedFileInfoList(files);
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  MultiFilesSelectedWithExtraInfo(selected_files, params);
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void FileSelectHelper::MultiFilesSelectedWithExtraInfo(
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::vector<ui::SelectedFileInfo>& files,
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    void* params) {
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!files.empty())
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    profile_->set_last_selected_directory(files[0].file_path.DirName());
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!render_view_host_)
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1567dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  NotifyRenderViewHost(render_view_host_, files, dialog_mode_);
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // No members should be accessed from here on.
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  RunFileChooserEnd();
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void FileSelectHelper::FileSelectionCanceled(void* params) {
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!render_view_host_)
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If the user cancels choosing a file to upload we pass back an
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // empty vector.
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  NotifyRenderViewHost(
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      render_view_host_, std::vector<ui::SelectedFileInfo>(),
1707dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      dialog_mode_);
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // No members should be accessed from here on.
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  RunFileChooserEnd();
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void FileSelectHelper::StartNewEnumeration(const base::FilePath& path,
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                           int request_id,
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                           RenderViewHost* render_view_host) {
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<ActiveDirectoryEnumeration> entry(new ActiveDirectoryEnumeration);
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  entry->rvh_ = render_view_host;
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  entry->delegate_.reset(new DirectoryListerDispatchDelegate(this, request_id));
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  entry->lister_.reset(new net::DirectoryLister(path,
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                true,
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                net::DirectoryLister::NO_SORT,
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                entry->delegate_.get()));
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!entry->lister_->Start()) {
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (request_id == kFileSelectEnumerationId)
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      FileSelectionCanceled(NULL);
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      render_view_host->DirectoryEnumerationFinished(request_id,
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                     entry->results_);
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    directory_enumerations_[request_id] = entry.release();
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void FileSelectHelper::OnListFile(
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int id,
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const net::DirectoryLister::DirectoryListerData& data) {
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ActiveDirectoryEnumeration* entry = directory_enumerations_[id];
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
202effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  // Directory upload only cares about files.
203868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (data.info.IsDirectory())
204effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    return;
205effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
206effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  entry->results_.push_back(data.path);
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void FileSelectHelper::OnListDone(int id, int error) {
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // This entry needs to be cleaned up when this function is done.
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<ActiveDirectoryEnumeration> entry(directory_enumerations_[id]);
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  directory_enumerations_.erase(id);
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!entry->rvh_)
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (error) {
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    FileSelectionCanceled(NULL);
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<ui::SelectedFileInfo> selected_files =
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      FilePathListToSelectedFileInfoList(entry->results_);
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (id == kFileSelectEnumerationId)
2247dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    NotifyRenderViewHost(entry->rvh_, selected_files, dialog_mode_);
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  else
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    entry->rvh_->DirectoryEnumerationFinished(id, entry->results_);
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EnumerateDirectoryEnd();
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)scoped_ptr<ui::SelectFileDialog::FileTypeInfo>
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)FileSelectHelper::GetFileTypesFromAcceptType(
2335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const std::vector<base::string16>& accept_types) {
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<ui::SelectFileDialog::FileTypeInfo> base_file_type(
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      new ui::SelectFileDialog::FileTypeInfo());
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (accept_types.empty())
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return base_file_type.Pass();
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Create FileTypeInfo and pre-allocate for the first extension list.
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<ui::SelectFileDialog::FileTypeInfo> file_type(
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      new ui::SelectFileDialog::FileTypeInfo(*base_file_type));
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  file_type->include_all_files = true;
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  file_type->extensions.resize(1);
2442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::vector<base::FilePath::StringType>* extensions =
2452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      &file_type->extensions.back();
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Find the corresponding extensions.
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int valid_type_count = 0;
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int description_id = 0;
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < accept_types.size(); ++i) {
251a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    std::string ascii_type = base::UTF16ToASCII(accept_types[i]);
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!IsAcceptTypeValid(ascii_type))
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    size_t old_extension_size = extensions->size();
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (ascii_type[0] == '.') {
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // If the type starts with a period it is assumed to be a file extension
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // so we just have to add it to the list.
2592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::FilePath::StringType ext(ascii_type.begin(), ascii_type.end());
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      extensions->push_back(ext.substr(1));
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (ascii_type == "image/*")
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        description_id = IDS_IMAGE_FILES;
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      else if (ascii_type == "audio/*")
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        description_id = IDS_AUDIO_FILES;
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      else if (ascii_type == "video/*")
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        description_id = IDS_VIDEO_FILES;
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      net::GetExtensionsForMimeType(ascii_type, extensions);
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (extensions->size() > old_extension_size)
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      valid_type_count++;
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If no valid extension is added, bail out.
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (valid_type_count == 0)
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return base_file_type.Pass();
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Use a generic description "Custom Files" if either of the following is
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // true:
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // 1) There're multiple types specified, like "audio/*,video/*"
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // 2) There're multiple extensions for a MIME type without parameter, like
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //    "ehtml,shtml,htm,html" for "text/html". On Windows, the select file
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //    dialog uses the first extension in the list to form the description,
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //    like "EHTML Files". This is not what we want.
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (valid_type_count > 1 ||
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      (valid_type_count == 1 && description_id == 0 && extensions->size() > 1))
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    description_id = IDS_CUSTOM_FILES;
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (description_id) {
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    file_type->extension_description_overrides.push_back(
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        l10n_util::GetStringUTF16(description_id));
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return file_type.Pass();
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void FileSelectHelper::RunFileChooser(content::WebContents* tab,
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      const FileChooserParams& params) {
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Profile* profile = Profile::FromBrowserContext(tab->GetBrowserContext());
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // FileSelectHelper will keep itself alive until it sends the result message.
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_refptr<FileSelectHelper> file_select_helper(
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      new FileSelectHelper(profile));
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  file_select_helper->RunFileChooser(tab->GetRenderViewHost(), tab, params);
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void FileSelectHelper::EnumerateDirectory(content::WebContents* tab,
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                          int request_id,
3122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                          const base::FilePath& path) {
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Profile* profile = Profile::FromBrowserContext(tab->GetBrowserContext());
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // FileSelectHelper will keep itself alive until it sends the result message.
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_refptr<FileSelectHelper> file_select_helper(
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      new FileSelectHelper(profile));
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  file_select_helper->EnumerateDirectory(
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      request_id, tab->GetRenderViewHost(), path);
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void FileSelectHelper::RunFileChooser(RenderViewHost* render_view_host,
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      content::WebContents* web_contents,
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      const FileChooserParams& params) {
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!render_view_host_);
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!web_contents_);
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  render_view_host_ = render_view_host;
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  web_contents_ = web_contents;
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  notification_registrar_.RemoveAll();
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  notification_registrar_.Add(
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      this, content::NOTIFICATION_RENDER_WIDGET_HOST_DESTROYED,
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      content::Source<RenderWidgetHost>(render_view_host_));
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  notification_registrar_.Add(
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      this, content::NOTIFICATION_WEB_CONTENTS_DESTROYED,
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      content::Source<WebContents>(web_contents_));
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BrowserThread::PostTask(
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      BrowserThread::FILE, FROM_HERE,
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&FileSelectHelper::RunFileChooserOnFileThread, this, params));
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Because this class returns notifications to the RenderViewHost, it is
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // difficult for callers to know how long to keep a reference to this
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // instance. We AddRef() here to keep the instance alive after we return
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // to the caller, until the last callback is received from the file dialog.
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // At that point, we must call RunFileChooserEnd().
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AddRef();
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void FileSelectHelper::RunFileChooserOnFileThread(
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const FileChooserParams& params) {
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  select_file_types_ = GetFileTypesFromAcceptType(params.accept_types);
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BrowserThread::PostTask(
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      BrowserThread::UI, FROM_HERE,
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&FileSelectHelper::RunFileChooserOnUIThread, this, params));
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void FileSelectHelper::RunFileChooserOnUIThread(
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const FileChooserParams& params) {
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!render_view_host_ || !web_contents_) {
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // If the renderer was destroyed before we started, just cancel the
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // operation.
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    RunFileChooserEnd();
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  select_file_dialog_ = ui::SelectFileDialog::Create(
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      this, new ChromeSelectFilePolicy(web_contents_));
3681320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (!select_file_dialog_.get())
36923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    return;
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3717dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  dialog_mode_ = params.mode;
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (params.mode) {
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case FileChooserParams::Open:
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      dialog_type_ = ui::SelectFileDialog::SELECT_OPEN_FILE;
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case FileChooserParams::OpenMultiple:
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      dialog_type_ = ui::SelectFileDialog::SELECT_OPEN_MULTI_FILE;
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
379a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    case FileChooserParams::UploadFolder:
380a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      dialog_type_ = ui::SelectFileDialog::SELECT_UPLOAD_FOLDER;
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case FileChooserParams::Save:
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      dialog_type_ = ui::SelectFileDialog::SELECT_SAVEAS_FILE;
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    default:
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Prevent warning.
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      dialog_type_ = ui::SelectFileDialog::SELECT_OPEN_FILE;
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NOTREACHED();
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath default_file_name = params.default_file_name.IsAbsolute() ?
3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      params.default_file_name :
3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      profile_->last_selected_directory().Append(params.default_file_name);
3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gfx::NativeWindow owning_window =
3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      platform_util::GetTopLevel(render_view_host_->GetView()->GetNativeView());
3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_ANDROID)
3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Android needs the original MIME types and an additional capture value.
4005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::pair<std::vector<base::string16>, bool> accept_types =
4017dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      std::make_pair(params.accept_types, params.capture);
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  select_file_dialog_->SelectFile(
4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      dialog_type_,
4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      params.title,
4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      default_file_name,
4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      select_file_types_.get(),
409c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      select_file_types_.get() && !select_file_types_->extensions.empty()
410c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          ? 1
411c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          : 0,  // 1-based index of default extension to show.
412c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      base::FilePath::StringType(),
4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      owning_window,
4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_ANDROID)
4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      &accept_types);
4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else
4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NULL);
4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  select_file_types_.reset();
4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This method is called when we receive the last callback from the file
4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// chooser dialog. Perform any cleanup and release the reference we added
4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// in RunFileChooser().
4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void FileSelectHelper::RunFileChooserEnd() {
4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  render_view_host_ = NULL;
4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  web_contents_ = NULL;
4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Release();
4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void FileSelectHelper::EnumerateDirectory(int request_id,
4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                          RenderViewHost* render_view_host,
4342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                          const base::FilePath& path) {
4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Because this class returns notifications to the RenderViewHost, it is
4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // difficult for callers to know how long to keep a reference to this
4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // instance. We AddRef() here to keep the instance alive after we return
4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // to the caller, until the last callback is received from the enumeration
4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // code. At that point, we must call EnumerateDirectoryEnd().
4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AddRef();
4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  StartNewEnumeration(path, request_id, render_view_host);
4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This method is called when we receive the last callback from the enumeration
4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// code. Perform any cleanup and release the reference we added in
4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// EnumerateDirectory().
4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void FileSelectHelper::EnumerateDirectoryEnd() {
4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Release();
4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void FileSelectHelper::Observe(int type,
4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               const content::NotificationSource& source,
4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               const content::NotificationDetails& details) {
4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (type) {
4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case content::NOTIFICATION_RENDER_WIDGET_HOST_DESTROYED: {
4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      DCHECK(content::Source<RenderWidgetHost>(source).ptr() ==
4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             render_view_host_);
4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      render_view_host_ = NULL;
4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case content::NOTIFICATION_WEB_CONTENTS_DESTROYED: {
4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      DCHECK(content::Source<WebContents>(source).ptr() == web_contents_);
4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      web_contents_ = NULL;
4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    default:
4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NOTREACHED();
4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool FileSelectHelper::IsAcceptTypeValid(const std::string& accept_type) {
4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(raymes): This only does some basic checks, extend to test more cases.
4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // A 1 character accept type will always be invalid (either a "." in the case
4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // of an extension or a "/" in the case of a MIME type).
4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string unused;
4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (accept_type.length() <= 1 ||
4816e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      base::StringToLowerASCII(accept_type) != accept_type ||
482a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      base::TrimWhitespaceASCII(accept_type, base::TRIM_ALL, &unused) !=
483a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)          base::TRIM_NONE) {
4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
488