private_api_util.cc revision a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7
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 "chrome/browser/chromeos/extensions/file_manager/private_api_util.h"
6
7#include "base/files/file_path.h"
8#include "chrome/browser/chromeos/drive/drive.pb.h"
9#include "chrome/browser/chromeos/drive/file_errors.h"
10#include "chrome/browser/chromeos/drive/file_system_interface.h"
11#include "chrome/browser/chromeos/drive/file_system_util.h"
12#include "chrome/browser/chromeos/file_manager/app_id.h"
13#include "chrome/browser/chromeos/file_manager/fileapi_util.h"
14#include "chrome/browser/chromeos/file_manager/volume_manager.h"
15#include "chrome/browser/chromeos/fileapi/file_system_backend.h"
16#include "chrome/browser/extensions/extension_function_dispatcher.h"
17#include "chrome/browser/extensions/extension_tab_util.h"
18#include "chrome/browser/profiles/profile.h"
19#include "chrome/common/extensions/api/file_browser_private.h"
20#include "content/public/browser/browser_context.h"
21#include "content/public/browser/browser_thread.h"
22#include "content/public/browser/render_view_host.h"
23#include "content/public/browser/storage_partition.h"
24#include "content/public/browser/web_contents.h"
25#include "ui/shell_dialogs/selected_file_info.h"
26#include "webkit/browser/fileapi/file_system_context.h"
27#include "webkit/browser/fileapi/file_system_url.h"
28
29using content::BrowserThread;
30namespace file_browser_private = extensions::api::file_browser_private;
31
32namespace file_manager {
33namespace util {
34namespace {
35
36// The struct is used for GetSelectedFileInfo().
37struct GetSelectedFileInfoParams {
38  GetSelectedFileInfoLocalPathOption local_path_option;
39  GetSelectedFileInfoCallback callback;
40  std::vector<base::FilePath> file_paths;
41  std::vector<ui::SelectedFileInfo> selected_files;
42};
43
44// Forward declarations of helper functions for GetSelectedFileInfo().
45void ContinueGetSelectedFileInfo(Profile* profile,
46                                 scoped_ptr<GetSelectedFileInfoParams> params,
47                                 drive::FileError error,
48                                 const base::FilePath& local_file_path,
49                                 scoped_ptr<drive::ResourceEntry> entry);
50
51// Part of GetSelectedFileInfo().
52void GetSelectedFileInfoInternal(Profile* profile,
53                                 scoped_ptr<GetSelectedFileInfoParams> params) {
54  DCHECK(profile);
55  drive::FileSystemInterface* file_system =
56      drive::util::GetFileSystemByProfile(profile);
57
58  for (size_t i = params->selected_files.size();
59       i < params->file_paths.size(); ++i) {
60    const base::FilePath& file_path = params->file_paths[i];
61
62    if (!drive::util::IsUnderDriveMountPoint(file_path)) {
63      params->selected_files.push_back(
64          ui::SelectedFileInfo(file_path, base::FilePath()));
65    } else {
66      // |file_system| is NULL if Drive is disabled.
67      if (!file_system) {
68        ContinueGetSelectedFileInfo(profile,
69                                    params.Pass(),
70                                    drive::FILE_ERROR_FAILED,
71                                    base::FilePath(),
72                                    scoped_ptr<drive::ResourceEntry>());
73        return;
74      }
75      // When the caller of the select file dialog wants local file paths,
76      // we should retrieve Drive files onto the local cache.
77      switch (params->local_path_option) {
78        case NO_LOCAL_PATH_RESOLUTION:
79          params->selected_files.push_back(
80              ui::SelectedFileInfo(file_path, base::FilePath()));
81          break;
82        case NEED_LOCAL_PATH_FOR_OPENING:
83          file_system->GetFile(
84              drive::util::ExtractDrivePath(file_path),
85              base::Bind(&ContinueGetSelectedFileInfo,
86                         profile,
87                         base::Passed(&params)));
88          return;  // Remaining work is done in ContinueGetSelectedFileInfo.
89        case NEED_LOCAL_PATH_FOR_SAVING:
90          file_system->GetFileForSaving(
91              drive::util::ExtractDrivePath(file_path),
92              base::Bind(&ContinueGetSelectedFileInfo,
93                         profile,
94                         base::Passed(&params)));
95          return;  // Remaining work is done in ContinueGetSelectedFileInfo.
96      }
97   }
98  }
99  params->callback.Run(params->selected_files);
100}
101
102// Part of GetSelectedFileInfo().
103void ContinueGetSelectedFileInfo(Profile* profile,
104                                 scoped_ptr<GetSelectedFileInfoParams> params,
105                                 drive::FileError error,
106                                 const base::FilePath& local_file_path,
107                                 scoped_ptr<drive::ResourceEntry> entry) {
108  DCHECK(profile);
109
110  const int index = params->selected_files.size();
111  const base::FilePath& file_path = params->file_paths[index];
112  base::FilePath local_path;
113  if (error == drive::FILE_ERROR_OK) {
114    local_path = local_file_path;
115  } else {
116    DLOG(ERROR) << "Failed to get " << file_path.value()
117                << " with error code: " << error;
118  }
119  params->selected_files.push_back(ui::SelectedFileInfo(file_path, local_path));
120  GetSelectedFileInfoInternal(profile, params.Pass());
121}
122
123}  // namespace
124
125void VolumeInfoToVolumeMetadata(
126    Profile* profile,
127    const VolumeInfo& volume_info,
128    file_browser_private::VolumeMetadata* volume_metadata) {
129  DCHECK(volume_metadata);
130  DCHECK(!volume_info.mount_path.empty());
131
132  // Convert mount point path to relative path with the external file system
133  // exposed within File API.
134  base::FilePath relative_mount_path;
135  if (ConvertAbsoluteFilePathToRelativeFileSystemPath(
136          profile, kFileManagerAppId, base::FilePath(volume_info.mount_path),
137          &relative_mount_path)) {
138    volume_metadata->mount_path = "/" + relative_mount_path.AsUTF8Unsafe();
139  }
140
141  volume_metadata->volume_id = volume_info.volume_id;
142
143  // TODO(kinaba): fill appropriate information once multi-profile support is
144  // implemented.
145  volume_metadata->profile.display_name = profile->GetProfileName();
146  volume_metadata->profile.is_current_profile = true;
147
148  if (!volume_info.source_path.empty()) {
149    volume_metadata->source_path.reset(
150        new std::string(volume_info.source_path.AsUTF8Unsafe()));
151  }
152
153  switch (volume_info.type) {
154    case VOLUME_TYPE_GOOGLE_DRIVE:
155      volume_metadata->volume_type =
156          file_browser_private::VolumeMetadata::VOLUME_TYPE_DRIVE;
157      break;
158    case VOLUME_TYPE_DOWNLOADS_DIRECTORY:
159      volume_metadata->volume_type =
160          file_browser_private::VolumeMetadata::VOLUME_TYPE_DOWNLOADS;
161      break;
162    case VOLUME_TYPE_REMOVABLE_DISK_PARTITION:
163      volume_metadata->volume_type =
164          file_browser_private::VolumeMetadata::VOLUME_TYPE_REMOVABLE;
165      break;
166    case VOLUME_TYPE_MOUNTED_ARCHIVE_FILE:
167      volume_metadata->volume_type =
168          file_browser_private::VolumeMetadata::VOLUME_TYPE_ARCHIVE;
169      break;
170  }
171
172  // Fill device_type iff the volume is removable partition.
173  if (volume_info.type == VOLUME_TYPE_REMOVABLE_DISK_PARTITION) {
174    switch (volume_info.device_type) {
175      case chromeos::DEVICE_TYPE_UNKNOWN:
176        volume_metadata->device_type =
177            file_browser_private::VolumeMetadata::DEVICE_TYPE_UNKNOWN;
178        break;
179      case chromeos::DEVICE_TYPE_USB:
180        volume_metadata->device_type =
181            file_browser_private::VolumeMetadata::DEVICE_TYPE_USB;
182        break;
183      case chromeos::DEVICE_TYPE_SD:
184        volume_metadata->device_type =
185            file_browser_private::VolumeMetadata::DEVICE_TYPE_SD;
186        break;
187      case chromeos::DEVICE_TYPE_OPTICAL_DISC:
188      case chromeos::DEVICE_TYPE_DVD:
189        volume_metadata->device_type =
190            file_browser_private::VolumeMetadata::DEVICE_TYPE_OPTICAL;
191        break;
192      case chromeos::DEVICE_TYPE_MOBILE:
193        volume_metadata->device_type =
194            file_browser_private::VolumeMetadata::DEVICE_TYPE_MOBILE;
195        break;
196    }
197  } else {
198    volume_metadata->device_type =
199        file_browser_private::VolumeMetadata::DEVICE_TYPE_NONE;
200  }
201
202  volume_metadata->is_read_only = volume_info.is_read_only;
203
204  switch (volume_info.mount_condition) {
205    case chromeos::disks::MOUNT_CONDITION_NONE:
206      volume_metadata->mount_condition =
207          file_browser_private::VolumeMetadata::MOUNT_CONDITION_NONE;
208      break;
209    case chromeos::disks::MOUNT_CONDITION_UNKNOWN_FILESYSTEM:
210      volume_metadata->mount_condition =
211          file_browser_private::VolumeMetadata::MOUNT_CONDITION_UNKNOWN;
212      break;
213    case chromeos::disks::MOUNT_CONDITION_UNSUPPORTED_FILESYSTEM:
214      volume_metadata->mount_condition =
215          file_browser_private::VolumeMetadata::MOUNT_CONDITION_UNSUPPORTED;
216      break;
217  }
218}
219
220content::WebContents* GetWebContents(ExtensionFunctionDispatcher* dispatcher) {
221  if (!dispatcher) {
222    LOG(WARNING) << "No dispatcher";
223    return NULL;
224  }
225  if (!dispatcher->delegate()) {
226    LOG(WARNING) << "No delegate";
227    return NULL;
228  }
229  content::WebContents* web_contents =
230      dispatcher->delegate()->GetAssociatedWebContents();
231  if (!web_contents) {
232    LOG(WARNING) << "No associated tab contents";
233    return NULL;
234  }
235  return web_contents;
236}
237
238base::FilePath GetLocalPathFromURL(
239    content::RenderViewHost* render_view_host,
240    Profile* profile,
241    const GURL& url) {
242  DCHECK(render_view_host);
243  DCHECK(profile);
244
245  scoped_refptr<fileapi::FileSystemContext> file_system_context =
246      util::GetFileSystemContextForRenderViewHost(
247          profile, render_view_host);
248
249  const fileapi::FileSystemURL filesystem_url(
250      file_system_context->CrackURL(url));
251  base::FilePath path;
252  if (!chromeos::FileSystemBackend::CanHandleURL(filesystem_url))
253    return base::FilePath();
254  return filesystem_url.path();
255}
256
257void GetSelectedFileInfo(content::RenderViewHost* render_view_host,
258                         Profile* profile,
259                         const std::vector<GURL>& file_urls,
260                         GetSelectedFileInfoLocalPathOption local_path_option,
261                         GetSelectedFileInfoCallback callback) {
262  DCHECK(render_view_host);
263  DCHECK(profile);
264
265  scoped_ptr<GetSelectedFileInfoParams> params(new GetSelectedFileInfoParams);
266  params->local_path_option = local_path_option;
267  params->callback = callback;
268
269  for (size_t i = 0; i < file_urls.size(); ++i) {
270    const GURL& file_url = file_urls[i];
271    const base::FilePath path = GetLocalPathFromURL(
272        render_view_host, profile, file_url);
273    if (!path.empty()) {
274      DVLOG(1) << "Selected: file path: " << path.value();
275      params->file_paths.push_back(path);
276    }
277  }
278
279  BrowserThread::PostTask(
280      BrowserThread::UI, FROM_HERE,
281      base::Bind(&GetSelectedFileInfoInternal,
282                 profile,
283                 base::Passed(&params)));
284}
285
286}  // namespace util
287}  // namespace file_manager
288