Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(196)

Side by Side Diff: chrome/browser/chromeos/extensions/file_browser_event_router.cc

Issue 14020002: chromeos: Move chrome/browser/chromeos/extensions/file_browser* to chrome/browser/chromeos/file_man… (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Sort Created 7 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
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/extensions/file_browser_event_router.h"
6
7 #include "base/bind.h"
8 #include "base/file_util.h"
9 #include "base/json/json_writer.h"
10 #include "base/message_loop.h"
11 #include "base/prefs/pref_change_registrar.h"
12 #include "base/prefs/pref_service.h"
13 #include "base/stl_util.h"
14 #include "base/values.h"
15 #include "chrome/browser/chromeos/drive/drive_cache.h"
16 #include "chrome/browser/chromeos/drive/drive_file_system_interface.h"
17 #include "chrome/browser/chromeos/drive/drive_file_system_util.h"
18 #include "chrome/browser/chromeos/drive/drive_system_service.h"
19 #include "chrome/browser/chromeos/extensions/file_browser_notifications.h"
20 #include "chrome/browser/chromeos/extensions/file_manager/file_manager_util.h"
21 #include "chrome/browser/chromeos/login/base_login_display_host.h"
22 #include "chrome/browser/chromeos/login/screen_locker.h"
23 #include "chrome/browser/chromeos/login/user_manager.h"
24 #include "chrome/browser/chromeos/net/connectivity_state_helper.h"
25 #include "chrome/browser/extensions/event_names.h"
26 #include "chrome/browser/extensions/event_router.h"
27 #include "chrome/browser/extensions/extension_service.h"
28 #include "chrome/browser/extensions/extension_system.h"
29 #include "chrome/browser/google_apis/drive_service_interface.h"
30 #include "chrome/browser/profiles/profile.h"
31 #include "chrome/common/chrome_notification_types.h"
32 #include "chrome/common/pref_names.h"
33 #include "chromeos/dbus/cros_disks_client.h"
34 #include "chromeos/dbus/dbus_thread_manager.h"
35 #include "chromeos/dbus/power_manager_client.h"
36 #include "chromeos/dbus/session_manager_client.h"
37 #include "content/public/browser/browser_thread.h"
38 #include "content/public/browser/notification_source.h"
39 #include "grit/generated_resources.h"
40 #include "ui/base/l10n/l10n_util.h"
41 #include "webkit/fileapi/file_system_types.h"
42 #include "webkit/fileapi/file_system_util.h"
43
44 using chromeos::DBusThreadManager;
45 using chromeos::disks::DiskMountManager;
46 using content::BrowserThread;
47 using drive::DriveSystemService;
48 using drive::DriveSystemServiceFactory;
49
50 namespace {
51
52 const char kPathChanged[] = "changed";
53 const char kPathWatchError[] = "error";
54
55 DictionaryValue* DiskToDictionaryValue(
56 const DiskMountManager::Disk* disk) {
57 DictionaryValue* result = new DictionaryValue();
58 result->SetString("mountPath", disk->mount_path());
59 result->SetString("devicePath", disk->device_path());
60 result->SetString("label", disk->device_label());
61 result->SetString("deviceType",
62 DiskMountManager::DeviceTypeToString(disk->device_type()));
63 result->SetInteger("totalSizeKB", disk->total_size_in_bytes() / 1024);
64 result->SetBoolean("readOnly", disk->is_read_only());
65 return result;
66 }
67
68 // Used as a callback for DriveCache::MarkAsUnmounted().
69 void OnMarkAsUnmounted(drive::DriveFileError error) {
70 LOG_IF(ERROR, error != drive::DRIVE_FILE_OK)
71 << "Failed to unmount: " << error;
72 }
73
74 const char* MountErrorToString(chromeos::MountError error) {
75 switch (error) {
76 case chromeos::MOUNT_ERROR_NONE:
77 return "success";
78 case chromeos::MOUNT_ERROR_UNKNOWN:
79 return "error_unknown";
80 case chromeos::MOUNT_ERROR_INTERNAL:
81 return "error_internal";
82 case chromeos::MOUNT_ERROR_INVALID_ARGUMENT:
83 return "error_invalid_argument";
84 case chromeos::MOUNT_ERROR_INVALID_PATH:
85 return "error_invalid_path";
86 case chromeos::MOUNT_ERROR_PATH_ALREADY_MOUNTED:
87 return "error_path_already_mounted";
88 case chromeos::MOUNT_ERROR_PATH_NOT_MOUNTED:
89 return "error_path_not_mounted";
90 case chromeos::MOUNT_ERROR_DIRECTORY_CREATION_FAILED:
91 return "error_directory_creation_failed";
92 case chromeos::MOUNT_ERROR_INVALID_MOUNT_OPTIONS:
93 return "error_invalid_mount_options";
94 case chromeos::MOUNT_ERROR_INVALID_UNMOUNT_OPTIONS:
95 return "error_invalid_unmount_options";
96 case chromeos::MOUNT_ERROR_INSUFFICIENT_PERMISSIONS:
97 return "error_insufficient_permissions";
98 case chromeos::MOUNT_ERROR_MOUNT_PROGRAM_NOT_FOUND:
99 return "error_mount_program_not_found";
100 case chromeos::MOUNT_ERROR_MOUNT_PROGRAM_FAILED:
101 return "error_mount_program_failed";
102 case chromeos::MOUNT_ERROR_INVALID_DEVICE_PATH:
103 return "error_invalid_device_path";
104 case chromeos::MOUNT_ERROR_UNKNOWN_FILESYSTEM:
105 return "error_unknown_filesystem";
106 case chromeos::MOUNT_ERROR_UNSUPPORTED_FILESYSTEM:
107 return "error_unsuported_filesystem";
108 case chromeos::MOUNT_ERROR_INVALID_ARCHIVE:
109 return "error_invalid_archive";
110 case chromeos::MOUNT_ERROR_NOT_AUTHENTICATED:
111 return "error_authentication";
112 case chromeos::MOUNT_ERROR_PATH_UNMOUNTED:
113 return "error_path_unmounted";
114 }
115 NOTREACHED();
116 return "";
117 }
118
119 void RelayFileWatcherCallbackToUIThread(
120 const base::FilePathWatcher::Callback& callback,
121 const base::FilePath& local_path,
122 bool got_error) {
123 BrowserThread::PostTask(
124 BrowserThread::UI, FROM_HERE,
125 base::Bind(callback, local_path, got_error));
126 }
127
128 // Observes PowerManager and updates its state when the system suspends and
129 // resumes. After the system resumes it will stay in "is_resuming" state for 5
130 // seconds. This is to give DiskManager time to process device removed/added
131 // events (events for the devices that were present before suspend should not
132 // trigger any new notifications or file manager windows).
133 // The delegate will go into the same state after screen is unlocked. Cros-disks
134 // will not send events while the screen is locked. The events will be postponed
135 // until the screen is unlocked. These have to be handled too.
136 class SuspendStateDelegateImpl
137 : public chromeos::PowerManagerClient::Observer,
138 public chromeos::SessionManagerClient::Observer,
139 public FileBrowserEventRouter::SuspendStateDelegate {
140 public:
141 SuspendStateDelegateImpl()
142 : is_resuming_(false),
143 weak_factory_(this) {
144 DBusThreadManager::Get()->GetPowerManagerClient()->AddObserver(this);
145 DBusThreadManager::Get()->GetSessionManagerClient()->AddObserver(this);
146 }
147
148 virtual ~SuspendStateDelegateImpl() {
149 DBusThreadManager::Get()->GetPowerManagerClient()->RemoveObserver(this);
150 DBusThreadManager::Get()->GetSessionManagerClient()->RemoveObserver(this);
151 }
152
153 // chromeos::PowerManagerClient::Observer implementation.
154 virtual void SuspendImminent() OVERRIDE {
155 is_resuming_ = false;
156 weak_factory_.InvalidateWeakPtrs();
157 }
158
159 // chromeos::PowerManagerClient::Observer implementation.
160 virtual void SystemResumed(const base::TimeDelta& sleep_duration) OVERRIDE {
161 is_resuming_ = true;
162 // Undo any previous resets.
163 weak_factory_.InvalidateWeakPtrs();
164 base::MessageLoopProxy::current()->PostDelayedTask(
165 FROM_HERE,
166 base::Bind(&SuspendStateDelegateImpl::Reset,
167 weak_factory_.GetWeakPtr()),
168 base::TimeDelta::FromSeconds(5));
169 }
170
171 // chromeos::SessionManagerClient::Observer implementation.
172 virtual void ScreenIsUnlocked() OVERRIDE {
173 is_resuming_ = true;
174 // Undo any previous resets.
175 weak_factory_.InvalidateWeakPtrs();
176 base::MessageLoopProxy::current()->PostDelayedTask(
177 FROM_HERE,
178 base::Bind(&SuspendStateDelegateImpl::Reset,
179 weak_factory_.GetWeakPtr()),
180 base::TimeDelta::FromSeconds(5));
181 }
182
183 // FileBrowserEventRouter::SuspendStateDelegate implementation.
184 virtual bool SystemIsResuming() const OVERRIDE {
185 return is_resuming_;
186 }
187
188 // FileBrowserEventRouter::SuspendStateDelegate implementation.
189 virtual bool DiskWasPresentBeforeSuspend(
190 const DiskMountManager::Disk& disk) const OVERRIDE {
191 // TODO(tbarzic): Implement this. Blocked on http://crbug.com/153338.
192 return false;
193 }
194
195 private:
196 void Reset() {
197 is_resuming_ = false;
198 }
199
200 bool is_resuming_;
201
202 base::WeakPtrFactory<SuspendStateDelegateImpl> weak_factory_;
203
204 DISALLOW_COPY_AND_ASSIGN(SuspendStateDelegateImpl);
205 };
206
207 void DirectoryExistsOnBlockingPool(const base::FilePath& directory_path,
208 const base::Closure& success_callback,
209 const base::Closure& failure_callback) {
210 DCHECK(BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread());
211
212 if (file_util::DirectoryExists(directory_path))
213 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, success_callback);
214 else
215 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, failure_callback);
216 };
217
218 void DirectoryExistsOnUIThread(const base::FilePath& directory_path,
219 const base::Closure& success_callback,
220 const base::Closure& failure_callback) {
221 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
222
223 content::BrowserThread::PostBlockingPoolTask(
224 FROM_HERE,
225 base::Bind(&DirectoryExistsOnBlockingPool,
226 directory_path,
227 success_callback,
228 failure_callback));
229 };
230
231 // Creates a base::FilePathWatcher and starts watching at |watch_path| with
232 // |callback|. Returns NULL on failure.
233 base::FilePathWatcher* CreateAndStartFilePathWatcher(
234 const base::FilePath& watch_path,
235 const base::FilePathWatcher::Callback& callback) {
236 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
237 DCHECK(!callback.is_null());
238
239 base::FilePathWatcher* watcher(new base::FilePathWatcher);
240 if (!watcher->Watch(watch_path, false /* recursive */, callback)) {
241 delete watcher;
242 return NULL;
243 }
244
245 return watcher;
246 }
247
248 } // namespace
249
250 FileBrowserEventRouter::FileBrowserEventRouter(
251 Profile* profile)
252 : weak_factory_(this),
253 notifications_(new FileBrowserNotifications(profile)),
254 pref_change_registrar_(new PrefChangeRegistrar),
255 profile_(profile),
256 num_remote_update_requests_(0),
257 shift_pressed_(false) {
258 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
259
260 file_watcher_callback_ =
261 base::Bind(&FileBrowserEventRouter::HandleFileWatchNotification,
262 weak_factory_.GetWeakPtr());
263
264 // Listen for the Shift modifier's state changes.
265 chromeos::SystemKeyEventListener* key_event_listener =
266 chromeos::SystemKeyEventListener::GetInstance();
267 if (key_event_listener)
268 key_event_listener->AddModifiersObserver(this);
269 }
270
271 FileBrowserEventRouter::~FileBrowserEventRouter() {
272 }
273
274 void FileBrowserEventRouter::Shutdown() {
275 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
276
277 DLOG_IF(WARNING, !file_watchers_.empty()) << "Not all file watchers are "
278 << "removed. This can happen when Files.app is open during shutdown.";
279 STLDeleteValues(&file_watchers_);
280 if (!profile_) {
281 NOTREACHED();
282 return;
283 }
284
285 chromeos::SystemKeyEventListener* key_event_listener =
286 chromeos::SystemKeyEventListener::GetInstance();
287 if (key_event_listener)
288 key_event_listener->RemoveModifiersObserver(this);
289
290 DiskMountManager* disk_mount_manager = DiskMountManager::GetInstance();
291 if (disk_mount_manager)
292 disk_mount_manager->RemoveObserver(this);
293
294 DriveSystemService* system_service =
295 DriveSystemServiceFactory::FindForProfileRegardlessOfStates(profile_);
296 if (system_service) {
297 system_service->file_system()->RemoveObserver(this);
298 system_service->drive_service()->RemoveObserver(this);
299 }
300
301 if (chromeos::ConnectivityStateHelper::IsInitialized()) {
302 chromeos::ConnectivityStateHelper::Get()->
303 RemoveNetworkManagerObserver(this);
304 }
305 profile_ = NULL;
306 }
307
308 void FileBrowserEventRouter::ObserveFileSystemEvents() {
309 if (!profile_) {
310 NOTREACHED();
311 return;
312 }
313 if (!chromeos::UserManager::Get()->IsUserLoggedIn())
314 return;
315
316 DiskMountManager* disk_mount_manager = DiskMountManager::GetInstance();
317 if (disk_mount_manager) {
318 disk_mount_manager->RemoveObserver(this);
319 disk_mount_manager->AddObserver(this);
320 disk_mount_manager->RequestMountInfoRefresh();
321 }
322
323 DriveSystemService* system_service =
324 DriveSystemServiceFactory::GetForProfileRegardlessOfStates(profile_);
325 if (system_service) {
326 system_service->drive_service()->AddObserver(this);
327 system_service->file_system()->AddObserver(this);
328 }
329
330 if (chromeos::ConnectivityStateHelper::IsInitialized()) {
331 chromeos::ConnectivityStateHelper::Get()->
332 AddNetworkManagerObserver(this);
333 }
334 suspend_state_delegate_.reset(new SuspendStateDelegateImpl());
335
336 pref_change_registrar_->Init(profile_->GetPrefs());
337
338 pref_change_registrar_->Add(
339 prefs::kExternalStorageDisabled,
340 base::Bind(&FileBrowserEventRouter::OnExternalStorageDisabledChanged,
341 weak_factory_.GetWeakPtr()));
342
343 base::Closure callback =
344 base::Bind(&FileBrowserEventRouter::OnFileBrowserPrefsChanged,
345 weak_factory_.GetWeakPtr());
346 pref_change_registrar_->Add(prefs::kDisableDriveOverCellular, callback);
347 pref_change_registrar_->Add(prefs::kDisableDriveHostedFiles, callback);
348 pref_change_registrar_->Add(prefs::kDisableDrive, callback);
349 pref_change_registrar_->Add(prefs::kUse24HourClock, callback);
350 }
351
352 // File watch setup routines.
353 void FileBrowserEventRouter::AddFileWatch(
354 const base::FilePath& local_path,
355 const base::FilePath& virtual_path,
356 const std::string& extension_id,
357 const BoolCallback& callback) {
358 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
359 DCHECK(!callback.is_null());
360
361 base::FilePath watch_path = local_path;
362 bool is_remote_watch = false;
363 // Tweak watch path for remote sources - we need to drop leading /special
364 // directory from there in order to be able to pair these events with
365 // their change notifications.
366 if (drive::util::GetSpecialRemoteRootPath().IsParent(watch_path)) {
367 watch_path = drive::util::ExtractDrivePath(watch_path);
368 is_remote_watch = true;
369 HandleRemoteUpdateRequestOnUIThread(true /* start */);
370 }
371
372 WatcherMap::iterator iter = file_watchers_.find(watch_path);
373 if (iter == file_watchers_.end()) {
374 scoped_ptr<FileWatcherExtensions>
375 watch(new FileWatcherExtensions(virtual_path,
376 extension_id,
377 is_remote_watch));
378 watch->Watch(watch_path,
379 file_watcher_callback_,
380 callback);
381 file_watchers_[watch_path] = watch.release();
382 } else {
383 iter->second->AddExtension(extension_id);
384 base::MessageLoopProxy::current()->PostTask(FROM_HERE,
385 base::Bind(callback, true));
386 }
387 }
388
389 void FileBrowserEventRouter::RemoveFileWatch(
390 const base::FilePath& local_path,
391 const std::string& extension_id) {
392 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
393
394 base::FilePath watch_path = local_path;
395 // Tweak watch path for remote sources - we need to drop leading /special
396 // directory from there in order to be able to pair these events with
397 // their change notifications.
398 if (drive::util::GetSpecialRemoteRootPath().IsParent(watch_path)) {
399 watch_path = drive::util::ExtractDrivePath(watch_path);
400 HandleRemoteUpdateRequestOnUIThread(false /* start */);
401 }
402 WatcherMap::iterator iter = file_watchers_.find(watch_path);
403 if (iter == file_watchers_.end())
404 return;
405 // Remove the renderer process for this watch.
406 iter->second->RemoveExtension(extension_id);
407 if (iter->second->GetRefCount() == 0) {
408 delete iter->second;
409 file_watchers_.erase(iter);
410 }
411 }
412
413 void FileBrowserEventRouter::MountDrive(
414 const base::Closure& callback) {
415 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
416
417 // Pass back the gdata mount point path as source path.
418 const std::string& gdata_path = drive::util::GetDriveMountPointPathAsString();
419 DiskMountManager::MountPointInfo mount_info(
420 gdata_path,
421 gdata_path,
422 chromeos::MOUNT_TYPE_GOOGLE_DRIVE,
423 chromeos::disks::MOUNT_CONDITION_NONE);
424
425 // Raise mount event.
426 // We can pass chromeos::MOUNT_ERROR_NONE even when authentication is failed
427 // or network is unreachable. These two errors will be handled later.
428 OnMountEvent(DiskMountManager::MOUNTING,
429 chromeos::MOUNT_ERROR_NONE,
430 mount_info);
431
432 if (!callback.is_null())
433 callback.Run();
434 }
435
436 void FileBrowserEventRouter::HandleRemoteUpdateRequestOnUIThread(bool start) {
437 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
438
439 drive::DriveFileSystemInterface* file_system = GetRemoteFileSystem();
440 // |file_system| is NULL if Drive is disabled.
441 if (!file_system)
442 return;
443
444 if (start) {
445 file_system->CheckForUpdates();
446 if (num_remote_update_requests_ == 0)
447 file_system->StartPolling();
448 ++num_remote_update_requests_;
449 } else {
450 DCHECK_LE(1, num_remote_update_requests_);
451 --num_remote_update_requests_;
452 if (num_remote_update_requests_ == 0)
453 file_system->StopPolling();
454 }
455 }
456
457 void FileBrowserEventRouter::OnDiskEvent(
458 DiskMountManager::DiskEvent event,
459 const DiskMountManager::Disk* disk) {
460 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
461
462 // Disregard hidden devices.
463 if (disk->is_hidden())
464 return;
465 if (event == DiskMountManager::DISK_ADDED) {
466 OnDiskAdded(disk);
467 } else if (event == DiskMountManager::DISK_REMOVED) {
468 OnDiskRemoved(disk);
469 }
470 }
471
472 void FileBrowserEventRouter::OnDeviceEvent(
473 DiskMountManager::DeviceEvent event,
474 const std::string& device_path) {
475 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
476
477 if (event == DiskMountManager::DEVICE_ADDED) {
478 OnDeviceAdded(device_path);
479 } else if (event == DiskMountManager::DEVICE_REMOVED) {
480 OnDeviceRemoved(device_path);
481 } else if (event == DiskMountManager::DEVICE_SCANNED) {
482 OnDeviceScanned(device_path);
483 }
484 }
485
486 void FileBrowserEventRouter::OnMountEvent(
487 DiskMountManager::MountEvent event,
488 chromeos::MountError error_code,
489 const DiskMountManager::MountPointInfo& mount_info) {
490 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
491 // profile_ is NULL if ShutdownOnUIThread() is called earlier. This can
492 // happen at shutdown.
493 if (!profile_)
494 return;
495
496 DCHECK(mount_info.mount_type != chromeos::MOUNT_TYPE_INVALID);
497
498 DispatchMountEvent(event, error_code, mount_info);
499
500 if (mount_info.mount_type == chromeos::MOUNT_TYPE_DEVICE &&
501 event == DiskMountManager::MOUNTING) {
502 DiskMountManager* disk_mount_manager = DiskMountManager::GetInstance();
503 const DiskMountManager::Disk* disk =
504 disk_mount_manager->FindDiskBySourcePath(mount_info.source_path);
505 // TODO(tbarzic): DiskWasPresentBeforeSuspend is not yet functional. It
506 // always returns false.
507 if (!disk || suspend_state_delegate_->DiskWasPresentBeforeSuspend(*disk))
508 return;
509
510 notifications_->ManageNotificationsOnMountCompleted(
511 disk->system_path_prefix(), disk->drive_label(), disk->is_parent(),
512 error_code == chromeos::MOUNT_ERROR_NONE,
513 error_code == chromeos::MOUNT_ERROR_UNSUPPORTED_FILESYSTEM);
514
515 // If a new device was mounted, a new File manager window may need to be
516 // opened.
517 if (error_code == chromeos::MOUNT_ERROR_NONE)
518 ShowRemovableDeviceInFileManager(
519 *disk,
520 base::FilePath::FromUTF8Unsafe(mount_info.mount_path));
521 } else if (mount_info.mount_type == chromeos::MOUNT_TYPE_ARCHIVE) {
522 // Clear the "mounted" state for archive files in gdata cache
523 // when mounting failed or unmounting succeeded.
524 if ((event == DiskMountManager::MOUNTING) !=
525 (error_code == chromeos::MOUNT_ERROR_NONE)) {
526 base::FilePath source_path(mount_info.source_path);
527 DriveSystemService* system_service =
528 DriveSystemServiceFactory::GetForProfile(profile_);
529 drive::DriveCache* cache =
530 system_service ? system_service->cache() : NULL;
531 if (cache && cache->IsUnderDriveCacheDirectory(source_path))
532 cache->MarkAsUnmounted(source_path, base::Bind(&OnMarkAsUnmounted));
533 }
534 }
535 }
536
537 void FileBrowserEventRouter::OnFormatEvent(
538 DiskMountManager::FormatEvent event,
539 chromeos::FormatError error_code,
540 const std::string& device_path) {
541 if (event == DiskMountManager::FORMAT_STARTED) {
542 OnFormatStarted(device_path, error_code == chromeos::FORMAT_ERROR_NONE);
543 } else if (event == DiskMountManager::FORMAT_COMPLETED) {
544 OnFormatCompleted(device_path, error_code == chromeos::FORMAT_ERROR_NONE);
545 }
546 }
547
548 void FileBrowserEventRouter::NetworkManagerChanged() {
549 if (!profile_ ||
550 !extensions::ExtensionSystem::Get(profile_)->event_router()) {
551 NOTREACHED();
552 return;
553 }
554 scoped_ptr<extensions::Event> event(new extensions::Event(
555 extensions::event_names::kOnFileBrowserDriveConnectionStatusChanged,
556 scoped_ptr<ListValue>(new ListValue())));
557 extensions::ExtensionSystem::Get(profile_)->event_router()->
558 BroadcastEvent(event.Pass());
559 }
560
561 void FileBrowserEventRouter::OnExternalStorageDisabledChanged() {
562 // If the policy just got disabled we have to unmount every device currently
563 // mounted. The opposite is fine - we can let the user re-plug her device to
564 // make it available.
565 if (profile_->GetPrefs()->GetBoolean(prefs::kExternalStorageDisabled)) {
566 DiskMountManager* manager = DiskMountManager::GetInstance();
567 DiskMountManager::MountPointMap mounts(manager->mount_points());
568 for (DiskMountManager::MountPointMap::const_iterator it = mounts.begin();
569 it != mounts.end(); ++it) {
570 LOG(INFO) << "Unmounting " << it->second.mount_path
571 << " because of policy.";
572 manager->UnmountPath(it->second.mount_path,
573 chromeos::UNMOUNT_OPTIONS_NONE,
574 DiskMountManager::UnmountPathCallback());
575 }
576 }
577 }
578
579 void FileBrowserEventRouter::OnFileBrowserPrefsChanged() {
580 if (!profile_ ||
581 !extensions::ExtensionSystem::Get(profile_)->event_router()) {
582 NOTREACHED();
583 return;
584 }
585
586 scoped_ptr<extensions::Event> event(new extensions::Event(
587 extensions::event_names::kOnFileBrowserPreferencesChanged,
588 scoped_ptr<ListValue>(new ListValue())));
589 extensions::ExtensionSystem::Get(profile_)->event_router()->
590 BroadcastEvent(event.Pass());
591 }
592
593 void FileBrowserEventRouter::OnProgressUpdate(
594 const google_apis::OperationProgressStatusList& list) {
595 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
596
597 scoped_ptr<ListValue> event_list(
598 file_manager_util::ProgressStatusVectorToListValue(
599 profile_, kFileBrowserDomain, list));
600
601 scoped_ptr<ListValue> args(new ListValue());
602 args->Append(event_list.release());
603 scoped_ptr<extensions::Event> event(new extensions::Event(
604 extensions::event_names::kOnFileTransfersUpdated, args.Pass()));
605 extensions::ExtensionSystem::Get(profile_)->event_router()->
606 DispatchEventToExtension(kFileBrowserDomain, event.Pass());
607 }
608
609 void FileBrowserEventRouter::OnDirectoryChanged(
610 const base::FilePath& directory_path) {
611 HandleFileWatchNotification(directory_path, false);
612 }
613
614 void FileBrowserEventRouter::OnFileSystemMounted() {
615 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
616
617 MountDrive(base::Bind(&base::DoNothing)); // Callback does nothing.
618 }
619
620 void FileBrowserEventRouter::OnModifiersChange(int pressed_modifiers) {
621 shift_pressed_ = (pressed_modifiers & SHIFT_PRESSED);
622 }
623
624 void FileBrowserEventRouter::OnFileSystemBeingUnmounted() {
625 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
626
627 // Raise a mount event to notify the File Manager.
628 const std::string& gdata_path = drive::util::GetDriveMountPointPathAsString();
629 DiskMountManager::MountPointInfo mount_info(
630 gdata_path,
631 gdata_path,
632 chromeos::MOUNT_TYPE_GOOGLE_DRIVE,
633 chromeos::disks::MOUNT_CONDITION_NONE);
634 OnMountEvent(DiskMountManager::UNMOUNTING, chromeos::MOUNT_ERROR_NONE,
635 mount_info);
636 }
637
638 void FileBrowserEventRouter::OnRefreshTokenInvalid() {
639 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
640
641 // Raise a DriveConnectionStatusChanged event to notify the status offline.
642 scoped_ptr<extensions::Event> event(new extensions::Event(
643 extensions::event_names::kOnFileBrowserDriveConnectionStatusChanged,
644 scoped_ptr<ListValue>(new ListValue())));
645 extensions::ExtensionSystem::Get(profile_)->event_router()->
646 BroadcastEvent(event.Pass());
647 }
648
649 void FileBrowserEventRouter::HandleFileWatchNotification(
650 const base::FilePath& local_path, bool got_error) {
651 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
652
653 WatcherMap::const_iterator iter = file_watchers_.find(local_path);
654 if (iter == file_watchers_.end()) {
655 return;
656 }
657 DispatchDirectoryChangeEvent(iter->second->GetVirtualPath(), got_error,
658 iter->second->GetExtensions());
659 }
660
661 void FileBrowserEventRouter::DispatchDirectoryChangeEvent(
662 const base::FilePath& virtual_path,
663 bool got_error,
664 const FileBrowserEventRouter::ExtensionUsageRegistry& extensions) {
665 if (!profile_) {
666 NOTREACHED();
667 return;
668 }
669
670 for (ExtensionUsageRegistry::const_iterator iter = extensions.begin();
671 iter != extensions.end(); ++iter) {
672 GURL target_origin_url(extensions::Extension::GetBaseURLFromExtensionId(
673 iter->first));
674 GURL base_url = fileapi::GetFileSystemRootURI(target_origin_url,
675 fileapi::kFileSystemTypeExternal);
676 GURL target_directory_url = GURL(base_url.spec() + virtual_path.value());
677 scoped_ptr<ListValue> args(new ListValue());
678 DictionaryValue* watch_info = new DictionaryValue();
679 args->Append(watch_info);
680 watch_info->SetString("directoryUrl", target_directory_url.spec());
681 watch_info->SetString("eventType",
682 got_error ? kPathWatchError : kPathChanged);
683
684 // TODO(mtomasz): Pass set of entries. http://crbug.com/157834
685 ListValue* watch_info_entries = new ListValue();
686 watch_info->Set("changedEntries", watch_info_entries);
687
688 scoped_ptr<extensions::Event> event(new extensions::Event(
689 extensions::event_names::kOnDirectoryChanged, args.Pass()));
690 extensions::ExtensionSystem::Get(profile_)->event_router()->
691 DispatchEventToExtension(iter->first, event.Pass());
692 }
693 }
694
695 void FileBrowserEventRouter::DispatchMountEvent(
696 DiskMountManager::MountEvent event,
697 chromeos::MountError error_code,
698 const DiskMountManager::MountPointInfo& mount_info) {
699 scoped_ptr<ListValue> args(new ListValue());
700 DictionaryValue* mount_info_value = new DictionaryValue();
701 args->Append(mount_info_value);
702 mount_info_value->SetString("eventType",
703 event == DiskMountManager::MOUNTING ? "mount" : "unmount");
704 mount_info_value->SetString("status", MountErrorToString(error_code));
705 mount_info_value->SetString(
706 "mountType",
707 DiskMountManager::MountTypeToString(mount_info.mount_type));
708
709 // Add sourcePath to the event.
710 mount_info_value->SetString("sourcePath", mount_info.source_path);
711
712 base::FilePath relative_mount_path;
713
714 // If there were no error or some special conditions occurred, add mountPath
715 // to the event.
716 if (event == DiskMountManager::UNMOUNTING ||
717 error_code == chromeos::MOUNT_ERROR_NONE ||
718 mount_info.mount_condition) {
719 // Convert mount point path to relative path with the external file system
720 // exposed within File API.
721 if (file_manager_util::ConvertFileToRelativeFileSystemPath(
722 profile_,
723 kFileBrowserDomain,
724 base::FilePath(mount_info.mount_path),
725 &relative_mount_path)) {
726 mount_info_value->SetString("mountPath",
727 "/" + relative_mount_path.value());
728 } else {
729 mount_info_value->SetString("status",
730 MountErrorToString(chromeos::MOUNT_ERROR_PATH_UNMOUNTED));
731 }
732 }
733
734 scoped_ptr<extensions::Event> extension_event(new extensions::Event(
735 extensions::event_names::kOnFileBrowserMountCompleted, args.Pass()));
736 extensions::ExtensionSystem::Get(profile_)->event_router()->
737 BroadcastEvent(extension_event.Pass());
738 }
739
740 void FileBrowserEventRouter::ShowRemovableDeviceInFileManager(
741 const DiskMountManager::Disk& disk, const base::FilePath& mount_path) {
742 // Do not attempt to open File Manager while the login is in progress or
743 // the screen is locked.
744 if (chromeos::BaseLoginDisplayHost::default_host() ||
745 chromeos::ScreenLocker::default_screen_locker())
746 return;
747
748 // According to DCF (Design rule of Camera File system) by JEITA / CP-3461
749 // cameras should have pictures located in the DCIM root directory.
750 const base::FilePath dcim_path = mount_path.Append(
751 FILE_PATH_LITERAL("DCIM"));
752
753 // TODO(mtomasz): Temporarily for M26. Remove it on M27.
754 // If an external photo importer is installed, then do not show the action
755 // choice dialog.
756 ExtensionService* service =
757 extensions::ExtensionSystem::Get(profile_)->extension_service();
758 if (!service)
759 return;
760 const std::string kExternalPhotoImporterExtensionId =
761 "efjnaogkjbogokcnohkmnjdojkikgobo";
762 const bool external_photo_importer_available =
763 service->GetExtensionById(kExternalPhotoImporterExtensionId,
764 false /* include_disable */) != NULL;
765
766 // If there is no DCIM folder or an external photo importer is not available,
767 // then launch Files.app.
768 DirectoryExistsOnUIThread(
769 dcim_path,
770 external_photo_importer_available ?
771 base::Bind(&base::DoNothing) :
772 base::Bind(&file_manager_util::ViewRemovableDrive, mount_path),
773 base::Bind(&file_manager_util::ViewRemovableDrive, mount_path));
774 }
775
776 void FileBrowserEventRouter::OnDiskAdded(
777 const DiskMountManager::Disk* disk) {
778 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
779
780 VLOG(1) << "Disk added: " << disk->device_path();
781 if (disk->device_path().empty()) {
782 VLOG(1) << "Empty system path for " << disk->device_path();
783 return;
784 }
785
786 // If disk is not mounted yet and it has media and there is no policy
787 // forbidding external storage, give it a try.
788 if (disk->mount_path().empty() && disk->has_media() &&
789 !profile_->GetPrefs()->GetBoolean(prefs::kExternalStorageDisabled)) {
790 // Initiate disk mount operation. MountPath auto-detects the filesystem
791 // format if the second argument is empty. The third argument (mount label)
792 // is not used in a disk mount operation.
793 DiskMountManager::GetInstance()->MountPath(
794 disk->device_path(), std::string(), std::string(),
795 chromeos::MOUNT_TYPE_DEVICE);
796 } else {
797 // Either the disk was mounted or it has no media. In both cases we don't
798 // want the Scanning notification to persist.
799 notifications_->HideNotification(FileBrowserNotifications::DEVICE,
800 disk->system_path_prefix());
801 }
802 }
803
804 void FileBrowserEventRouter::OnDiskRemoved(
805 const DiskMountManager::Disk* disk) {
806 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
807
808 VLOG(1) << "Disk removed: " << disk->device_path();
809
810 if (!disk->mount_path().empty()) {
811 DiskMountManager::GetInstance()->UnmountPath(
812 disk->mount_path(),
813 chromeos::UNMOUNT_OPTIONS_LAZY,
814 DiskMountManager::UnmountPathCallback());
815 }
816 }
817
818 void FileBrowserEventRouter::OnDeviceAdded(
819 const std::string& device_path) {
820 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
821
822 VLOG(1) << "Device added : " << device_path;
823
824 // If the policy is set instead of showing the new device notification we show
825 // a notification that the operation is not permitted.
826 if (profile_->GetPrefs()->GetBoolean(prefs::kExternalStorageDisabled)) {
827 notifications_->ShowNotification(
828 FileBrowserNotifications::DEVICE_EXTERNAL_STORAGE_DISABLED,
829 device_path);
830 return;
831 }
832
833 notifications_->RegisterDevice(device_path);
834 notifications_->ShowNotificationDelayed(FileBrowserNotifications::DEVICE,
835 device_path,
836 base::TimeDelta::FromSeconds(5));
837 }
838
839 void FileBrowserEventRouter::OnDeviceRemoved(
840 const std::string& device_path) {
841 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
842
843 VLOG(1) << "Device removed : " << device_path;
844 notifications_->HideNotification(FileBrowserNotifications::DEVICE,
845 device_path);
846 notifications_->HideNotification(FileBrowserNotifications::DEVICE_FAIL,
847 device_path);
848 notifications_->UnregisterDevice(device_path);
849 }
850
851 void FileBrowserEventRouter::OnDeviceScanned(
852 const std::string& device_path) {
853 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
854 VLOG(1) << "Device scanned : " << device_path;
855 }
856
857 void FileBrowserEventRouter::OnFormatStarted(
858 const std::string& device_path, bool success) {
859 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
860
861 if (success) {
862 notifications_->ShowNotification(FileBrowserNotifications::FORMAT_START,
863 device_path);
864 } else {
865 notifications_->ShowNotification(
866 FileBrowserNotifications::FORMAT_START_FAIL, device_path);
867 }
868 }
869
870 void FileBrowserEventRouter::OnFormatCompleted(
871 const std::string& device_path, bool success) {
872 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
873
874 if (success) {
875 notifications_->HideNotification(FileBrowserNotifications::FORMAT_START,
876 device_path);
877 notifications_->ShowNotification(FileBrowserNotifications::FORMAT_SUCCESS,
878 device_path);
879 // Hide it after a couple of seconds.
880 notifications_->HideNotificationDelayed(
881 FileBrowserNotifications::FORMAT_SUCCESS,
882 device_path,
883 base::TimeDelta::FromSeconds(4));
884 // MountPath auto-detects filesystem format if second argument is empty.
885 // The third argument (mount label) is not used in a disk mount operation.
886 DiskMountManager::GetInstance()->MountPath(device_path, std::string(),
887 std::string(),
888 chromeos::MOUNT_TYPE_DEVICE);
889 } else {
890 notifications_->HideNotification(FileBrowserNotifications::FORMAT_START,
891 device_path);
892 notifications_->ShowNotification(FileBrowserNotifications::FORMAT_FAIL,
893 device_path);
894 }
895 }
896
897 FileBrowserEventRouter::FileWatcherExtensions::FileWatcherExtensions(
898 const base::FilePath& virtual_path,
899 const std::string& extension_id,
900 bool is_remote_file_system)
901 : file_watcher_(NULL),
902 virtual_path_(virtual_path),
903 ref_count_(0),
904 is_remote_file_system_(is_remote_file_system),
905 ALLOW_THIS_IN_INITIALIZER_LIST(weak_ptr_factory_(this)) {
906 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
907
908 AddExtension(extension_id);
909 }
910
911 FileBrowserEventRouter::FileWatcherExtensions::~FileWatcherExtensions() {
912 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
913
914 BrowserThread::DeleteSoon(BrowserThread::FILE, FROM_HERE, file_watcher_);
915 }
916
917 void FileBrowserEventRouter::FileWatcherExtensions::AddExtension(
918 const std::string& extension_id) {
919 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
920
921 ExtensionUsageRegistry::iterator it = extensions_.find(extension_id);
922 if (it != extensions_.end()) {
923 it->second++;
924 } else {
925 extensions_.insert(ExtensionUsageRegistry::value_type(extension_id, 1));
926 }
927
928 ref_count_++;
929 }
930
931 void FileBrowserEventRouter::FileWatcherExtensions::RemoveExtension(
932 const std::string& extension_id) {
933 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
934
935 ExtensionUsageRegistry::iterator it = extensions_.find(extension_id);
936
937 if (it != extensions_.end()) {
938 // If entry found - decrease it's count and remove if necessary
939 if (0 == it->second--) {
940 extensions_.erase(it);
941 }
942
943 ref_count_--;
944 } else {
945 // Might be reference counting problem - e.g. if some component of
946 // extension subscribes/unsubscribes correctly, but other component
947 // only unsubscribes, developer of first one might receive this message
948 LOG(FATAL) << " Extension [" << extension_id
949 << "] tries to unsubscribe from folder [" << local_path_.value()
950 << "] it isn't subscribed";
951 }
952 }
953
954 const FileBrowserEventRouter::ExtensionUsageRegistry&
955 FileBrowserEventRouter::FileWatcherExtensions::GetExtensions() const {
956 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
957 return extensions_;
958 }
959
960 unsigned int
961 FileBrowserEventRouter::FileWatcherExtensions::GetRefCount() const {
962 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
963 return ref_count_;
964 }
965
966 const base::FilePath&
967 FileBrowserEventRouter::FileWatcherExtensions::GetVirtualPath() const {
968 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
969 return virtual_path_;
970 }
971
972 drive::DriveFileSystemInterface*
973 FileBrowserEventRouter::GetRemoteFileSystem() const {
974 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
975 DriveSystemService* system_service =
976 DriveSystemServiceFactory::GetForProfile(profile_);
977 return (system_service ? system_service->file_system() : NULL);
978 }
979
980 void FileBrowserEventRouter::FileWatcherExtensions::Watch(
981 const base::FilePath& local_path,
982 const base::FilePathWatcher::Callback& file_watcher_callback,
983 const BoolCallback& callback) {
984 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
985 DCHECK(!callback.is_null());
986 DCHECK(!file_watcher_);
987
988 local_path_ = local_path; // For error message in RemoveExtension().
989
990 if (is_remote_file_system_) {
991 base::MessageLoopProxy::current()->PostTask(FROM_HERE,
992 base::Bind(callback, true));
993 return;
994 }
995
996 BrowserThread::PostTaskAndReplyWithResult(
997 BrowserThread::FILE,
998 FROM_HERE,
999 base::Bind(&CreateAndStartFilePathWatcher,
1000 local_path,
1001 base::Bind(&RelayFileWatcherCallbackToUIThread,
1002 file_watcher_callback)),
1003 base::Bind(
1004 &FileBrowserEventRouter::FileWatcherExtensions::OnWatcherStarted,
1005 weak_ptr_factory_.GetWeakPtr(),
1006 callback));
1007 }
1008
1009 void FileBrowserEventRouter::FileWatcherExtensions::OnWatcherStarted(
1010 const BoolCallback& callback,
1011 base::FilePathWatcher* file_watcher) {
1012 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1013
1014 if (file_watcher) {
1015 file_watcher_ = file_watcher;
1016 callback.Run(true);
1017 } else {
1018 callback.Run(false);
1019 }
1020 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698