OLD | NEW |
| (Empty) |
1 // Copyright (c) 2011 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 "chrome/browser/chromeos/extensions/file_manager_util.h" | |
5 | |
6 #include "base/bind.h" | |
7 #include "base/json/json_writer.h" | |
8 #include "base/logging.h" | |
9 #include "base/metrics/histogram.h" | |
10 #include "base/path_service.h" | |
11 #include "base/string_util.h" | |
12 #include "base/utf_string_conversions.h" | |
13 #include "base/values.h" | |
14 #include "chrome/browser/plugin_prefs.h" | |
15 #include "chrome/browser/profiles/profile.h" | |
16 #include "chrome/browser/simple_message_box.h" | |
17 #include "chrome/browser/ui/browser.h" | |
18 #include "chrome/browser/ui/browser_list.h" | |
19 #include "chrome/browser/ui/browser_window.h" | |
20 #include "chrome/common/chrome_paths.h" | |
21 #include "chrome/common/url_constants.h" | |
22 #include "content/browser/plugin_service.h" | |
23 #include "content/browser/user_metrics.h" | |
24 #include "content/public/browser/browser_thread.h" | |
25 #include "grit/generated_resources.h" | |
26 #include "net/base/escape.h" | |
27 #include "ui/base/l10n/l10n_util.h" | |
28 #include "webkit/fileapi/file_system_context.h" | |
29 #include "webkit/fileapi/file_system_mount_point_provider.h" | |
30 #include "webkit/fileapi/file_system_util.h" | |
31 | |
32 #if defined(OS_CHROMEOS) | |
33 #include "chrome/browser/chromeos/media/media_player.h" | |
34 #endif | |
35 | |
36 using content::BrowserThread; | |
37 | |
38 #define FILEBROWSER_DOMAIN "hhaomjibdihmijegdhdafkllkbggdgoj" | |
39 const char kFileBrowserDomain[] = FILEBROWSER_DOMAIN; | |
40 | |
41 namespace file_manager_util { | |
42 namespace { | |
43 | |
44 #define FILEBROWSER_URL(PATH) \ | |
45 ("chrome-extension://" FILEBROWSER_DOMAIN "/" PATH) | |
46 // This is the "well known" url for the file manager extension from | |
47 // browser/resources/file_manager. In the future we may provide a way to swap | |
48 // out this file manager for an aftermarket part, but not yet. | |
49 const char kFileBrowserExtensionUrl[] = FILEBROWSER_URL(""); | |
50 const char kBaseFileBrowserUrl[] = FILEBROWSER_URL("main.html"); | |
51 const char kMediaPlayerUrl[] = FILEBROWSER_URL("mediaplayer.html"); | |
52 const char kMediaPlayerPlaylistUrl[] = FILEBROWSER_URL("playlist.html"); | |
53 #undef FILEBROWSER_URL | |
54 #undef FILEBROWSER_DOMAIN | |
55 | |
56 const char kPdfExtension[] = ".pdf"; | |
57 // List of file extension we can open in tab. | |
58 const char* kBrowserSupportedExtensions[] = { | |
59 #if defined(GOOGLE_CHROME_BUILD) | |
60 ".pdf", | |
61 #endif | |
62 ".bmp", ".jpg", ".jpeg", ".png", ".webp", ".gif", ".txt", ".html", ".htm" | |
63 }; | |
64 // List of file extension that can be handled with the media player. | |
65 const char* kAVExtensions[] = { | |
66 #if defined(GOOGLE_CHROME_BUILD) || defined(USE_PROPRIETARY_CODECS) | |
67 ".3gp", ".avi", ".mp3", ".mp4", ".m4v", ".mov", ".m4a", | |
68 #endif | |
69 ".flac", ".ogm", ".ogv", ".ogx", ".ogg", ".oga", ".wav", ".webm", | |
70 /* TODO(zelidrag): Add unsupported ones as we enable them: | |
71 ".mkv", ".divx", ".xvid", ".wmv", ".asf", ".mpeg", ".mpg", | |
72 ".wma", ".aiff", | |
73 */ | |
74 }; | |
75 | |
76 // List of all extensions we want to be shown in histogram that keep track of | |
77 // files that were unsuccessfully tried to be opened. | |
78 // The list has to be synced with histogram values. | |
79 const char* kUMATrackingExtensions[] = { | |
80 "other", ".doc", ".docx", ".odt", ".rtf", ".pdf", ".ppt", ".pptx", ".odp", | |
81 ".xls", ".xlsx", ".ods", ".csv", ".odf", ".rar", ".asf", ".wma", ".wmv", | |
82 ".mov", ".mpg", ".log" | |
83 }; | |
84 | |
85 bool IsSupportedBrowserExtension(const char* ext) { | |
86 for (size_t i = 0; i < arraysize(kBrowserSupportedExtensions); i++) { | |
87 if (base::strcasecmp(ext, kBrowserSupportedExtensions[i]) == 0) { | |
88 return true; | |
89 } | |
90 } | |
91 return false; | |
92 } | |
93 | |
94 bool IsSupportedAVExtension(const char* ext) { | |
95 for (size_t i = 0; i < arraysize(kAVExtensions); i++) { | |
96 if (base::strcasecmp(ext, kAVExtensions[i]) == 0) { | |
97 return true; | |
98 } | |
99 } | |
100 return false; | |
101 } | |
102 | |
103 // If pdf plugin is enabled, we should open pdf files in a tab. | |
104 bool ShouldBeOpenedWithPdfPlugin(const char* ext) { | |
105 if (base::strcasecmp(ext, kPdfExtension) != 0) | |
106 return false; | |
107 | |
108 Browser* browser = BrowserList::GetLastActive(); | |
109 if (!browser) | |
110 return false; | |
111 | |
112 FilePath pdf_path; | |
113 PathService::Get(chrome::FILE_PDF_PLUGIN, &pdf_path); | |
114 | |
115 webkit::WebPluginInfo plugin; | |
116 if (!PluginService::GetInstance()->GetPluginInfoByPath(pdf_path, &plugin)) | |
117 return false; | |
118 | |
119 PluginPrefs* plugin_prefs = PluginPrefs::GetForProfile(browser->profile()); | |
120 if (!plugin_prefs) | |
121 return false; | |
122 | |
123 return plugin_prefs->IsPluginEnabled(plugin); | |
124 } | |
125 | |
126 // Returns index |ext| has in the |array|. If there is no |ext| in |array|, last | |
127 // element's index is return (last element should have irrelevant value). | |
128 int UMAExtensionIndex(const char *ext, | |
129 const char** array, | |
130 size_t array_size) { | |
131 for (size_t i = 0; i < array_size; i++) { | |
132 if (base::strcasecmp(ext, array[i]) == 0) { | |
133 return i; | |
134 } | |
135 } | |
136 return 0; | |
137 } | |
138 | |
139 // Convert numeric dialog type to a string. | |
140 std::string GetDialogTypeAsString( | |
141 SelectFileDialog::Type dialog_type) { | |
142 std::string type_str; | |
143 switch (dialog_type) { | |
144 case SelectFileDialog::SELECT_NONE: | |
145 type_str = "full-page"; | |
146 break; | |
147 | |
148 case SelectFileDialog::SELECT_FOLDER: | |
149 type_str = "folder"; | |
150 break; | |
151 | |
152 case SelectFileDialog::SELECT_SAVEAS_FILE: | |
153 type_str = "saveas-file"; | |
154 break; | |
155 | |
156 case SelectFileDialog::SELECT_OPEN_FILE: | |
157 type_str = "open-file"; | |
158 break; | |
159 | |
160 case SelectFileDialog::SELECT_OPEN_MULTI_FILE: | |
161 type_str = "open-multi-file"; | |
162 break; | |
163 | |
164 default: | |
165 NOTREACHED(); | |
166 } | |
167 | |
168 return type_str; | |
169 } | |
170 | |
171 } // namespace | |
172 | |
173 GURL GetFileBrowserExtensionUrl() { | |
174 return GURL(kFileBrowserExtensionUrl); | |
175 } | |
176 | |
177 GURL GetFileBrowserUrl() { | |
178 return GURL(kBaseFileBrowserUrl); | |
179 } | |
180 | |
181 GURL GetMediaPlayerUrl() { | |
182 return GURL(kMediaPlayerUrl); | |
183 } | |
184 | |
185 GURL GetMediaPlayerPlaylistUrl() { | |
186 return GURL(kMediaPlayerPlaylistUrl); | |
187 } | |
188 | |
189 bool ConvertFileToFileSystemUrl( | |
190 Profile* profile, const FilePath& full_file_path, const GURL& origin_url, | |
191 GURL* url) { | |
192 FilePath virtual_path; | |
193 if (!ConvertFileToRelativeFileSystemPath(profile, full_file_path, | |
194 &virtual_path)) { | |
195 return false; | |
196 } | |
197 | |
198 GURL base_url = fileapi::GetFileSystemRootURI(origin_url, | |
199 fileapi::kFileSystemTypeExternal); | |
200 *url = GURL(base_url.spec() + virtual_path.value()); | |
201 return true; | |
202 } | |
203 | |
204 bool ConvertFileToRelativeFileSystemPath( | |
205 Profile* profile, const FilePath& full_file_path, FilePath* virtual_path) { | |
206 fileapi::FileSystemPathManager* path_manager = | |
207 profile->GetFileSystemContext()->path_manager(); | |
208 fileapi::ExternalFileSystemMountPointProvider* provider = | |
209 path_manager->external_provider(); | |
210 if (!provider) | |
211 return false; | |
212 | |
213 // Find if this file path is managed by the external provider. | |
214 if (!provider->GetVirtualPath(full_file_path, virtual_path)) | |
215 return false; | |
216 | |
217 return true; | |
218 } | |
219 | |
220 GURL GetFileBrowserUrlWithParams( | |
221 SelectFileDialog::Type type, | |
222 const string16& title, | |
223 const FilePath& default_virtual_path, | |
224 const SelectFileDialog::FileTypeInfo* file_types, | |
225 int file_type_index, | |
226 const FilePath::StringType& default_extension) { | |
227 DictionaryValue arg_value; | |
228 arg_value.SetString("type", GetDialogTypeAsString(type)); | |
229 arg_value.SetString("title", title); | |
230 arg_value.SetString("defaultPath", default_virtual_path.value()); | |
231 arg_value.SetString("defaultExtension", default_extension); | |
232 | |
233 if (file_types) { | |
234 ListValue* types_list = new ListValue(); | |
235 for (size_t i = 0; i < file_types->extensions.size(); ++i) { | |
236 ListValue* extensions_list = new ListValue(); | |
237 for (size_t j = 0; j < file_types->extensions[i].size(); ++j) { | |
238 extensions_list->Set( | |
239 i, Value::CreateStringValue(file_types->extensions[i][j])); | |
240 } | |
241 | |
242 DictionaryValue* dict = new DictionaryValue(); | |
243 dict->Set("extensions", extensions_list); | |
244 | |
245 if (i < file_types->extension_description_overrides.size()) { | |
246 string16 desc = file_types->extension_description_overrides[i]; | |
247 dict->SetString("description", desc); | |
248 } | |
249 | |
250 dict->SetBoolean("selected", | |
251 (static_cast<size_t>(file_type_index) == i)); | |
252 | |
253 types_list->Set(i, dict); | |
254 } | |
255 arg_value.Set("typeList", types_list); | |
256 } | |
257 | |
258 std::string json_args; | |
259 base::JSONWriter::Write(&arg_value, false, &json_args); | |
260 | |
261 // kChromeUIFileManagerURL could not be used since query parameters are not | |
262 // supported for it. | |
263 std::string url = GetFileBrowserUrl().spec() + | |
264 '?' + net::EscapeUrlEncodedData(json_args, false); | |
265 return GURL(url); | |
266 } | |
267 | |
268 void ViewFolder(const FilePath& dir) { | |
269 Browser* browser = BrowserList::GetLastActive(); | |
270 if (!browser) | |
271 return; | |
272 | |
273 FilePath virtual_path; | |
274 if (!ConvertFileToRelativeFileSystemPath(browser->profile(), dir, | |
275 &virtual_path)) { | |
276 return; | |
277 } | |
278 | |
279 std::string url = chrome::kChromeUIFileManagerURL; | |
280 url += "#/" + net::EscapeUrlEncodedData(virtual_path.value(), false); | |
281 | |
282 UserMetrics::RecordAction(UserMetricsAction("ShowFileBrowserFullTab")); | |
283 browser->ShowSingletonTabRespectRef(GURL(url)); | |
284 } | |
285 | |
286 void ViewItem(const FilePath& full_path, bool enqueue) { | |
287 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { | |
288 bool result = BrowserThread::PostTask( | |
289 BrowserThread::UI, FROM_HERE, | |
290 base::Bind(&ViewItem, full_path, enqueue)); | |
291 DCHECK(result); | |
292 return; | |
293 } | |
294 | |
295 // There is nothing we can do if the browser is not present. | |
296 Browser* browser = BrowserList::GetLastActive(); | |
297 if (!browser) | |
298 return; | |
299 | |
300 std::string ext = full_path.Extension(); | |
301 // For things supported natively by the browser, we should open it | |
302 // in a tab. | |
303 if (IsSupportedBrowserExtension(ext.data()) || | |
304 ShouldBeOpenedWithPdfPlugin(ext.data())) { | |
305 std::string path; | |
306 path = "file://"; | |
307 path.append(net::EscapeUrlEncodedData(full_path.value(), false)); | |
308 browser->AddSelectedTabWithURL(GURL(path), content::PAGE_TRANSITION_LINK); | |
309 return; | |
310 } | |
311 #if defined(OS_CHROMEOS) | |
312 if (IsSupportedAVExtension(ext.data())) { | |
313 MediaPlayer* mediaplayer = MediaPlayer::GetInstance(); | |
314 | |
315 if (mediaplayer->GetPlaylist().empty()) | |
316 enqueue = false; // Force to start playback if current playlist is | |
317 // empty. | |
318 | |
319 if (enqueue) { | |
320 mediaplayer->PopupPlaylist(browser); | |
321 mediaplayer->EnqueueMediaFile(browser->profile(), full_path); | |
322 } else { | |
323 mediaplayer->PopupMediaPlayer(browser); | |
324 mediaplayer->ForcePlayMediaFile(browser->profile(), full_path); | |
325 } | |
326 return; | |
327 } | |
328 #endif // OS_CHROMEOS | |
329 | |
330 // Unknown file type. Record UMA and show an error message. | |
331 size_t extension_index = UMAExtensionIndex(ext.data(), | |
332 kUMATrackingExtensions, | |
333 arraysize(kUMATrackingExtensions)); | |
334 UMA_HISTOGRAM_ENUMERATION("FileBrowser.OpeningFileType", | |
335 extension_index, | |
336 arraysize(kUMATrackingExtensions) - 1); | |
337 | |
338 browser::ShowErrorBox( | |
339 browser->window()->GetNativeHandle(), | |
340 l10n_util::GetStringFUTF16( | |
341 IDS_FILEBROWSER_ERROR_VIEWING_FILE_TITLE, | |
342 UTF8ToUTF16(full_path.BaseName().value())), | |
343 l10n_util::GetStringUTF16( | |
344 IDS_FILEBROWSER_ERROR_VIEWING_FILE)); | |
345 } | |
346 | |
347 } // namespace file_manager_util | |
OLD | NEW |