45d107d5f132e7d9b39454703e34fc018b2fa80b
[platform/framework/web/crosswalk.git] / src / chrome / browser / chromeos / file_manager / open_util.cc
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
5 #include "chrome/browser/chromeos/file_manager/open_util.h"
6
7 #include "base/bind.h"
8 #include "base/files/file_path.h"
9 #include "base/logging.h"
10 #include "base/strings/utf_string_conversions.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/file_browser_handlers.h"
14 #include "chrome/browser/chromeos/file_manager/file_tasks.h"
15 #include "chrome/browser/chromeos/file_manager/fileapi_util.h"
16 #include "chrome/browser/chromeos/file_manager/mime_util.h"
17 #include "chrome/browser/chromeos/file_manager/path_util.h"
18 #include "chrome/browser/chromeos/file_manager/url_util.h"
19 #include "chrome/browser/extensions/api/file_handlers/app_file_handler_util.h"
20 #include "chrome/browser/extensions/extension_service.h"
21 #include "chrome/browser/profiles/profile.h"
22 #include "chrome/browser/ui/browser.h"
23 #include "chrome/browser/ui/browser_finder.h"
24 #include "chrome/browser/ui/browser_tabstrip.h"
25 #include "chrome/browser/ui/browser_window.h"
26 #include "chrome/browser/ui/extensions/application_launch.h"
27 #include "chrome/browser/ui/simple_message_box.h"
28 #include "content/public/browser/browser_thread.h"
29 #include "content/public/browser/storage_partition.h"
30 #include "content/public/browser/user_metrics.h"
31 #include "extensions/browser/extension_system.h"
32 #include "google_apis/drive/task_util.h"
33 #include "grit/generated_resources.h"
34 #include "ui/base/l10n/l10n_util.h"
35 #include "webkit/browser/fileapi/file_system_backend.h"
36 #include "webkit/browser/fileapi/file_system_context.h"
37 #include "webkit/browser/fileapi/file_system_operation_runner.h"
38 #include "webkit/browser/fileapi/file_system_url.h"
39
40 using content::BrowserThread;
41 using extensions::Extension;
42 using extensions::app_file_handler_util::FindFileHandlersForFiles;
43 using extensions::app_file_handler_util::PathAndMimeTypeSet;
44 using fileapi::FileSystemURL;
45
46 namespace file_manager {
47 namespace util {
48 namespace {
49
50 // Shows a warning message box saying that the file could not be opened.
51 void ShowWarningMessageBox(Profile* profile, const base::FilePath& file_path) {
52   Browser* browser = chrome::FindTabbedBrowser(
53       profile, false, chrome::HOST_DESKTOP_TYPE_ASH);
54   chrome::ShowMessageBox(
55       browser ? browser->window()->GetNativeWindow() : NULL,
56       l10n_util::GetStringFUTF16(
57           IDS_FILE_BROWSER_ERROR_VIEWING_FILE_TITLE,
58           base::UTF8ToUTF16(file_path.BaseName().AsUTF8Unsafe())),
59       l10n_util::GetStringUTF16(IDS_FILE_BROWSER_ERROR_VIEWING_FILE),
60       chrome::MESSAGE_BOX_TYPE_WARNING);
61 }
62
63 // Grants file system access to the file manager.
64 bool GrantFileSystemAccessToFileBrowser(Profile* profile) {
65   // The file manager always runs in the site for its extension id, so that
66   // is the site for which file access permissions should be granted.
67   fileapi::ExternalFileSystemBackend* backend =
68       GetFileSystemContextForExtensionId(
69           profile, kFileManagerAppId)->external_backend();
70   if (!backend)
71     return false;
72   backend->GrantFullAccessToExtension(kFileManagerAppId);
73   return true;
74 }
75
76 // Executes the |task| for the file specified by |url|.
77 void ExecuteFileTaskForUrl(Profile* profile,
78                            const file_tasks::TaskDescriptor& task,
79                            const GURL& url) {
80   fileapi::FileSystemContext* file_system_context =
81       GetFileSystemContextForExtensionId(profile, kFileManagerAppId);
82
83   file_tasks::ExecuteFileTask(
84       profile,
85       GetFileManagerMainPageUrl(), // Executing the task on behalf of Files.app.
86       task,
87       std::vector<FileSystemURL>(1, file_system_context->CrackURL(url)),
88       file_tasks::FileTaskFinishedCallback());
89 }
90
91 // Opens the file manager for the specified |file_path|. Used to implement
92 // internal handlers of special action IDs:
93 //
94 // "open" - Open the file manager for the given folder.
95 // "auto-open" - Open the file manager for the given removal drive and close
96 //               the file manager when the removal drive is unmounted.
97 // "select" - Open the file manager for the given file. The folder containing
98 //            the file will be opened with the file selected.
99 void OpenFileManagerWithInternalActionId(Profile* profile,
100                                          const base::FilePath& file_path,
101                                          const std::string& action_id) {
102   DCHECK(action_id == "auto-open" ||
103          action_id == "open" ||
104          action_id == "select");
105
106   content::RecordAction(base::UserMetricsAction("ShowFileBrowserFullTab"));
107
108   GURL url;
109   if (!ConvertAbsoluteFilePathToFileSystemUrl(
110           profile, file_path, kFileManagerAppId, &url))
111     return;
112
113   file_tasks::TaskDescriptor task(kFileManagerAppId,
114                                   file_tasks::TASK_TYPE_FILE_BROWSER_HANDLER,
115                                   action_id);
116   ExecuteFileTaskForUrl(profile, task, url);
117 }
118
119 // Opens the file specified by |file_path| by finding and executing a file
120 // task for the file. Returns false if failed to open the file (i.e. no file
121 // task is found).
122 bool OpenFile(Profile* profile, const base::FilePath& file_path) {
123   GURL url;
124   if (!ConvertAbsoluteFilePathToFileSystemUrl(
125           profile, file_path, kFileManagerAppId, &url))
126     return false;
127
128   // The file is opened per the file extension, hence extension-less files
129   // cannot be opened properly.
130   std::string mime_type = GetMimeTypeForPath(file_path);
131   extensions::app_file_handler_util::PathAndMimeTypeSet path_mime_set;
132   path_mime_set.insert(std::make_pair(file_path, mime_type));
133
134   std::vector<GURL> file_urls;
135   file_urls.push_back(url);
136
137   std::vector<file_tasks::FullTaskDescriptor> tasks;
138   file_tasks::FindAllTypesOfTasks(
139       profile,
140       drive::util::GetDriveAppRegistryByProfile(profile),
141       path_mime_set,
142       file_urls,
143       &tasks);
144   if (tasks.empty())
145     return false;
146
147   const file_tasks::FullTaskDescriptor* chosen_task = &tasks[0];
148   for (size_t i = 0; i < tasks.size(); ++i) {
149     if (tasks[i].is_default()) {
150       chosen_task = &tasks[i];
151       break;
152     }
153   }
154
155   ExecuteFileTaskForUrl(profile, chosen_task->task_descriptor(), url);
156   return true;
157 }
158
159 // Used to implement OpenItem().
160 void ContinueOpenItem(Profile* profile,
161                       const base::FilePath& file_path,
162                       base::File::Error error) {
163   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
164
165   if (error == base::File::FILE_OK) {
166     // A directory exists at |file_path|. Open it with the file manager.
167     OpenFileManagerWithInternalActionId(profile, file_path, "open");
168   } else {
169     // |file_path| should be a file. Open it.
170     if (!OpenFile(profile, file_path))
171       ShowWarningMessageBox(profile, file_path);
172   }
173 }
174
175 // Used to implement CheckIfDirectoryExists().
176 void CheckIfDirectoryExistsOnIOThread(
177     scoped_refptr<fileapi::FileSystemContext> file_system_context,
178     const GURL& url,
179     const fileapi::FileSystemOperationRunner::StatusCallback& callback) {
180   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
181
182   fileapi::FileSystemURL file_system_url = file_system_context->CrackURL(url);
183   file_system_context->operation_runner()->DirectoryExists(
184       file_system_url, callback);
185 }
186
187 // Checks if a directory exists at |url|.
188 void CheckIfDirectoryExists(
189     scoped_refptr<fileapi::FileSystemContext> file_system_context,
190     const GURL& url,
191     const fileapi::FileSystemOperationRunner::StatusCallback& callback) {
192   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
193
194   BrowserThread::PostTask(
195       BrowserThread::IO, FROM_HERE,
196       base::Bind(&CheckIfDirectoryExistsOnIOThread,
197                  file_system_context,
198                  url,
199                  google_apis::CreateRelayCallback(callback)));
200 }
201
202 }  // namespace
203
204 void OpenRemovableDrive(Profile* profile, const base::FilePath& file_path) {
205   OpenFileManagerWithInternalActionId(profile, file_path, "auto-open");
206 }
207
208 void OpenItem(Profile* profile, const base::FilePath& file_path) {
209   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
210
211   // The path may have been stored in preferences in old versions.
212   // We need migration here.
213   // TODO(kinaba): crbug.com/313539 remove it in the future.
214   base::FilePath path;
215   if (!util::MigratePathFromOldFormat(profile, file_path, &path))
216     path = file_path;
217
218   GURL url;
219   if (!ConvertAbsoluteFilePathToFileSystemUrl(
220           profile, path, kFileManagerAppId, &url) ||
221       !GrantFileSystemAccessToFileBrowser(profile)) {
222     ShowWarningMessageBox(profile, path);
223     return;
224   }
225
226   scoped_refptr<fileapi::FileSystemContext> file_system_context =
227       GetFileSystemContextForExtensionId(
228           profile, kFileManagerAppId);
229
230   CheckIfDirectoryExists(file_system_context, url,
231                          base::Bind(&ContinueOpenItem, profile, path));
232 }
233
234 void ShowItemInFolder(Profile* profile, const base::FilePath& file_path) {
235   // The path may have been stored in preferences in old versions.
236   // We need migration here.
237   // TODO(kinaba): crbug.com/313539 remove it in the future.
238   base::FilePath path;
239   if (!util::MigratePathFromOldFormat(profile, file_path, &path))
240     path = file_path;
241
242   // This action changes the selection so we do not reuse existing tabs.
243   OpenFileManagerWithInternalActionId(profile, path, "select");
244 }
245
246 }  // namespace util
247 }  // namespace file_manager