| OLD | NEW |
| (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 } | |
| OLD | NEW |