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 // Implements the Chrome Extensions Media Galleries API. 6 7 #include "chrome/browser/extensions/api/media_galleries/media_galleries_api.h" 8 9 #include <set> 10 #include <string> 11 #include <vector> 12 13 #include "base/callback.h" 14 #include "base/lazy_instance.h" 15 #include "base/numerics/safe_conversions.h" 16 #include "base/stl_util.h" 17 #include "base/strings/string_number_conversions.h" 18 #include "base/strings/utf_string_conversions.h" 19 #include "base/values.h" 20 #include "chrome/browser/browser_process.h" 21 #include "chrome/browser/extensions/api/file_system/file_system_api.h" 22 #include "chrome/browser/extensions/blob_reader.h" 23 #include "chrome/browser/extensions/extension_tab_util.h" 24 #include "chrome/browser/media_galleries/fileapi/safe_media_metadata_parser.h" 25 #include "chrome/browser/media_galleries/gallery_watch_manager.h" 26 #include "chrome/browser/media_galleries/media_file_system_registry.h" 27 #include "chrome/browser/media_galleries/media_galleries_histograms.h" 28 #include "chrome/browser/media_galleries/media_galleries_permission_controller.h" 29 #include "chrome/browser/media_galleries/media_galleries_preferences.h" 30 #include "chrome/browser/media_galleries/media_galleries_scan_result_controller.h" 31 #include "chrome/browser/media_galleries/media_scan_manager.h" 32 #include "chrome/browser/platform_util.h" 33 #include "chrome/browser/profiles/profile.h" 34 #include "chrome/browser/ui/chrome_select_file_policy.h" 35 #include "chrome/common/extensions/api/media_galleries.h" 36 #include "chrome/common/pref_names.h" 37 #include "chrome/grit/generated_resources.h" 38 #include "components/storage_monitor/storage_info.h" 39 #include "components/web_modal/web_contents_modal_dialog_manager.h" 40 #include "content/public/browser/blob_handle.h" 41 #include "content/public/browser/browser_context.h" 42 #include "content/public/browser/browser_thread.h" 43 #include "content/public/browser/child_process_security_policy.h" 44 #include "content/public/browser/render_process_host.h" 45 #include "content/public/browser/render_view_host.h" 46 #include "content/public/browser/web_contents.h" 47 #include "extensions/browser/app_window/app_window.h" 48 #include "extensions/browser/app_window/app_window_registry.h" 49 #include "extensions/browser/blob_holder.h" 50 #include "extensions/browser/extension_prefs.h" 51 #include "extensions/browser/extension_system.h" 52 #include "extensions/common/extension.h" 53 #include "extensions/common/permissions/api_permission.h" 54 #include "extensions/common/permissions/media_galleries_permission.h" 55 #include "extensions/common/permissions/permissions_data.h" 56 #include "net/base/mime_sniffer.h" 57 #include "storage/browser/blob/blob_data_handle.h" 58 #include "ui/base/l10n/l10n_util.h" 59 60 using content::WebContents; 61 using storage_monitor::MediaStorageUtil; 62 using storage_monitor::StorageInfo; 63 using web_modal::WebContentsModalDialogManager; 64 65 namespace extensions { 66 67 namespace MediaGalleries = api::media_galleries; 68 namespace DropPermissionForMediaFileSystem = 69 MediaGalleries::DropPermissionForMediaFileSystem; 70 namespace GetMediaFileSystems = MediaGalleries::GetMediaFileSystems; 71 namespace AddGalleryWatch = MediaGalleries::AddGalleryWatch; 72 namespace RemoveGalleryWatch = MediaGalleries::RemoveGalleryWatch; 73 namespace GetAllGalleryWatch = MediaGalleries::GetAllGalleryWatch; 74 75 namespace { 76 77 const char kDisallowedByPolicy[] = 78 "Media Galleries API is disallowed by policy: "; 79 const char kFailedToSetGalleryPermission[] = 80 "Failed to set gallery permission."; 81 const char kInvalidGalleryIdMsg[] = "Invalid gallery id."; 82 const char kMissingEventListener[] = "Missing event listener registration."; 83 const char kNonExistentGalleryId[] = "Non-existent gallery id."; 84 const char kNoScanPermission[] = "No permission to scan."; 85 86 const char kDeviceIdKey[] = "deviceId"; 87 const char kGalleryIdKey[] = "galleryId"; 88 const char kIsAvailableKey[] = "isAvailable"; 89 const char kIsMediaDeviceKey[] = "isMediaDevice"; 90 const char kIsRemovableKey[] = "isRemovable"; 91 const char kNameKey[] = "name"; 92 93 const char kMetadataKey[] = "metadata"; 94 const char kAttachedImagesBlobInfoKey[] = "attachedImagesBlobInfo"; 95 const char kBlobUUIDKey[] = "blobUUID"; 96 const char kTypeKey[] = "type"; 97 const char kSizeKey[] = "size"; 98 99 const char kInvalidGalleryId[] = "-1"; 100 101 MediaFileSystemRegistry* media_file_system_registry() { 102 return g_browser_process->media_file_system_registry(); 103 } 104 105 GalleryWatchManager* gallery_watch_manager() { 106 return media_file_system_registry()->gallery_watch_manager(); 107 } 108 109 MediaScanManager* media_scan_manager() { 110 return media_file_system_registry()->media_scan_manager(); 111 } 112 113 // Checks whether the MediaGalleries API is currently accessible (it may be 114 // disallowed even if an extension has the requisite permission). Then 115 // initializes the MediaGalleriesPreferences 116 bool Setup(Profile* profile, std::string* error, base::Closure callback) { 117 if (!ChromeSelectFilePolicy::FileSelectDialogsAllowed()) { 118 *error = std::string(kDisallowedByPolicy) + 119 prefs::kAllowFileSelectionDialogs; 120 return false; 121 } 122 123 MediaGalleriesPreferences* preferences = 124 media_file_system_registry()->GetPreferences(profile); 125 preferences->EnsureInitialized(callback); 126 return true; 127 } 128 129 // Returns true and sets |gallery_file_path| and |gallery_pref_id| if the 130 // |gallery_id| is valid and returns false otherwise. 131 bool GetGalleryFilePathAndId(const std::string& gallery_id, 132 Profile* profile, 133 const Extension* extension, 134 base::FilePath* gallery_file_path, 135 MediaGalleryPrefId* gallery_pref_id) { 136 MediaGalleryPrefId pref_id; 137 if (!base::StringToUint64(gallery_id, &pref_id)) 138 return false; 139 MediaGalleriesPreferences* preferences = 140 g_browser_process->media_file_system_registry()->GetPreferences(profile); 141 base::FilePath file_path( 142 preferences->LookUpGalleryPathForExtension(pref_id, extension, false)); 143 if (file_path.empty()) 144 return false; 145 *gallery_pref_id = pref_id; 146 *gallery_file_path = file_path; 147 return true; 148 } 149 150 WebContents* GetWebContents(content::RenderViewHost* rvh, 151 Profile* profile, 152 const std::string& app_id) { 153 WebContents* contents = WebContents::FromRenderViewHost(rvh); 154 WebContentsModalDialogManager* web_contents_modal_dialog_manager = 155 WebContentsModalDialogManager::FromWebContents(contents); 156 if (!web_contents_modal_dialog_manager) { 157 // If there is no WebContentsModalDialogManager, then this contents is 158 // probably the background page for an app. Try to find a app window to 159 // host the dialog. 160 AppWindow* window = AppWindowRegistry::Get(profile) 161 ->GetCurrentAppWindowForApp(app_id); 162 contents = window ? window->web_contents() : NULL; 163 } 164 return contents; 165 } 166 167 base::ListValue* ConstructFileSystemList( 168 content::RenderViewHost* rvh, 169 const Extension* extension, 170 const std::vector<MediaFileSystemInfo>& filesystems) { 171 if (!rvh) 172 return NULL; 173 174 MediaGalleriesPermission::CheckParam read_param( 175 MediaGalleriesPermission::kReadPermission); 176 const PermissionsData* permissions_data = extension->permissions_data(); 177 bool has_read_permission = permissions_data->CheckAPIPermissionWithParam( 178 APIPermission::kMediaGalleries, &read_param); 179 MediaGalleriesPermission::CheckParam copy_to_param( 180 MediaGalleriesPermission::kCopyToPermission); 181 bool has_copy_to_permission = permissions_data->CheckAPIPermissionWithParam( 182 APIPermission::kMediaGalleries, ©_to_param); 183 MediaGalleriesPermission::CheckParam delete_param( 184 MediaGalleriesPermission::kDeletePermission); 185 bool has_delete_permission = permissions_data->CheckAPIPermissionWithParam( 186 APIPermission::kMediaGalleries, &delete_param); 187 188 const int child_id = rvh->GetProcess()->GetID(); 189 scoped_ptr<base::ListValue> list(new base::ListValue()); 190 for (size_t i = 0; i < filesystems.size(); ++i) { 191 scoped_ptr<base::DictionaryValue> file_system_dict_value( 192 new base::DictionaryValue()); 193 194 // Send the file system id so the renderer can create a valid FileSystem 195 // object. 196 file_system_dict_value->SetStringWithoutPathExpansion( 197 "fsid", filesystems[i].fsid); 198 199 file_system_dict_value->SetStringWithoutPathExpansion( 200 kNameKey, filesystems[i].name); 201 file_system_dict_value->SetStringWithoutPathExpansion( 202 kGalleryIdKey, 203 base::Uint64ToString(filesystems[i].pref_id)); 204 if (!filesystems[i].transient_device_id.empty()) { 205 file_system_dict_value->SetStringWithoutPathExpansion( 206 kDeviceIdKey, filesystems[i].transient_device_id); 207 } 208 file_system_dict_value->SetBooleanWithoutPathExpansion( 209 kIsRemovableKey, filesystems[i].removable); 210 file_system_dict_value->SetBooleanWithoutPathExpansion( 211 kIsMediaDeviceKey, filesystems[i].media_device); 212 file_system_dict_value->SetBooleanWithoutPathExpansion( 213 kIsAvailableKey, true); 214 215 list->Append(file_system_dict_value.release()); 216 217 if (filesystems[i].path.empty()) 218 continue; 219 220 if (has_read_permission) { 221 content::ChildProcessSecurityPolicy* policy = 222 content::ChildProcessSecurityPolicy::GetInstance(); 223 policy->GrantReadFile(child_id, filesystems[i].path); 224 if (has_delete_permission) { 225 policy->GrantDeleteFrom(child_id, filesystems[i].path); 226 if (has_copy_to_permission) { 227 policy->GrantCopyInto(child_id, filesystems[i].path); 228 } 229 } 230 } 231 } 232 233 return list.release(); 234 } 235 236 bool CheckScanPermission(const extensions::Extension* extension, 237 std::string* error) { 238 DCHECK(extension); 239 DCHECK(error); 240 MediaGalleriesPermission::CheckParam scan_param( 241 MediaGalleriesPermission::kScanPermission); 242 bool has_scan_permission = 243 extension->permissions_data()->CheckAPIPermissionWithParam( 244 APIPermission::kMediaGalleries, &scan_param); 245 if (!has_scan_permission) 246 *error = kNoScanPermission; 247 return has_scan_permission; 248 } 249 250 class SelectDirectoryDialog : public ui::SelectFileDialog::Listener, 251 public base::RefCounted<SelectDirectoryDialog> { 252 public: 253 // Selected file path, or an empty path if the user canceled. 254 typedef base::Callback<void(const base::FilePath&)> Callback; 255 256 SelectDirectoryDialog(WebContents* web_contents, const Callback& callback) 257 : web_contents_(web_contents), 258 callback_(callback) { 259 select_file_dialog_ = ui::SelectFileDialog::Create( 260 this, new ChromeSelectFilePolicy(web_contents)); 261 } 262 263 void Show(const base::FilePath& default_path) { 264 AddRef(); // Balanced in the two reachable listener outcomes. 265 select_file_dialog_->SelectFile( 266 ui::SelectFileDialog::SELECT_FOLDER, 267 l10n_util::GetStringUTF16(IDS_MEDIA_GALLERIES_DIALOG_ADD_GALLERY_TITLE), 268 default_path, 269 NULL, 270 0, 271 base::FilePath::StringType(), 272 platform_util::GetTopLevel(web_contents_->GetNativeView()), 273 NULL); 274 } 275 276 // ui::SelectFileDialog::Listener implementation. 277 virtual void FileSelected(const base::FilePath& path, 278 int index, 279 void* params) OVERRIDE { 280 callback_.Run(path); 281 Release(); // Balanced in Show(). 282 } 283 284 virtual void MultiFilesSelected(const std::vector<base::FilePath>& files, 285 void* params) OVERRIDE { 286 NOTREACHED() << "Should not be able to select multiple files"; 287 } 288 289 virtual void FileSelectionCanceled(void* params) OVERRIDE { 290 callback_.Run(base::FilePath()); 291 Release(); // Balanced in Show(). 292 } 293 294 private: 295 friend class base::RefCounted<SelectDirectoryDialog>; 296 virtual ~SelectDirectoryDialog() {} 297 298 scoped_refptr<ui::SelectFileDialog> select_file_dialog_; 299 WebContents* web_contents_; 300 Callback callback_; 301 302 DISALLOW_COPY_AND_ASSIGN(SelectDirectoryDialog); 303 }; 304 305 } // namespace 306 307 MediaGalleriesEventRouter::MediaGalleriesEventRouter( 308 content::BrowserContext* context) 309 : profile_(Profile::FromBrowserContext(context)), weak_ptr_factory_(this) { 310 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); 311 DCHECK(profile_); 312 313 EventRouter::Get(profile_)->RegisterObserver( 314 this, MediaGalleries::OnGalleryChanged::kEventName); 315 316 gallery_watch_manager()->AddObserver(profile_, this); 317 media_scan_manager()->AddObserver(profile_, this); 318 } 319 320 MediaGalleriesEventRouter::~MediaGalleriesEventRouter() { 321 } 322 323 void MediaGalleriesEventRouter::Shutdown() { 324 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); 325 weak_ptr_factory_.InvalidateWeakPtrs(); 326 327 EventRouter::Get(profile_)->UnregisterObserver(this); 328 329 gallery_watch_manager()->RemoveObserver(profile_); 330 media_scan_manager()->RemoveObserver(profile_); 331 media_scan_manager()->CancelScansForProfile(profile_); 332 } 333 334 static base::LazyInstance< 335 BrowserContextKeyedAPIFactory<MediaGalleriesEventRouter> > g_factory = 336 LAZY_INSTANCE_INITIALIZER; 337 338 // static 339 BrowserContextKeyedAPIFactory<MediaGalleriesEventRouter>* 340 MediaGalleriesEventRouter::GetFactoryInstance() { 341 return g_factory.Pointer(); 342 } 343 344 // static 345 MediaGalleriesEventRouter* MediaGalleriesEventRouter::Get( 346 content::BrowserContext* context) { 347 DCHECK(media_file_system_registry() 348 ->GetPreferences(Profile::FromBrowserContext(context)) 349 ->IsInitialized()); 350 return BrowserContextKeyedAPIFactory<MediaGalleriesEventRouter>::Get(context); 351 } 352 353 bool MediaGalleriesEventRouter::ExtensionHasGalleryChangeListener( 354 const std::string& extension_id) const { 355 return EventRouter::Get(profile_)->ExtensionHasEventListener( 356 extension_id, MediaGalleries::OnGalleryChanged::kEventName); 357 } 358 359 bool MediaGalleriesEventRouter::ExtensionHasScanProgressListener( 360 const std::string& extension_id) const { 361 return EventRouter::Get(profile_)->ExtensionHasEventListener( 362 extension_id, MediaGalleries::OnScanProgress::kEventName); 363 } 364 365 void MediaGalleriesEventRouter::OnScanStarted(const std::string& extension_id) { 366 MediaGalleries::ScanProgressDetails details; 367 details.type = MediaGalleries::SCAN_PROGRESS_TYPE_START; 368 DispatchEventToExtension( 369 extension_id, 370 MediaGalleries::OnScanProgress::kEventName, 371 MediaGalleries::OnScanProgress::Create(details).Pass()); 372 } 373 374 void MediaGalleriesEventRouter::OnScanCancelled( 375 const std::string& extension_id) { 376 MediaGalleries::ScanProgressDetails details; 377 details.type = MediaGalleries::SCAN_PROGRESS_TYPE_CANCEL; 378 DispatchEventToExtension( 379 extension_id, 380 MediaGalleries::OnScanProgress::kEventName, 381 MediaGalleries::OnScanProgress::Create(details).Pass()); 382 } 383 384 void MediaGalleriesEventRouter::OnScanFinished( 385 const std::string& extension_id, int gallery_count, 386 const MediaGalleryScanResult& file_counts) { 387 media_galleries::UsageCount(media_galleries::SCAN_FINISHED); 388 MediaGalleries::ScanProgressDetails details; 389 details.type = MediaGalleries::SCAN_PROGRESS_TYPE_FINISH; 390 details.gallery_count.reset(new int(gallery_count)); 391 details.audio_count.reset(new int(file_counts.audio_count)); 392 details.image_count.reset(new int(file_counts.image_count)); 393 details.video_count.reset(new int(file_counts.video_count)); 394 DispatchEventToExtension( 395 extension_id, 396 MediaGalleries::OnScanProgress::kEventName, 397 MediaGalleries::OnScanProgress::Create(details).Pass()); 398 } 399 400 void MediaGalleriesEventRouter::OnScanError( 401 const std::string& extension_id) { 402 MediaGalleries::ScanProgressDetails details; 403 details.type = MediaGalleries::SCAN_PROGRESS_TYPE_ERROR; 404 DispatchEventToExtension( 405 extension_id, 406 MediaGalleries::OnScanProgress::kEventName, 407 MediaGalleries::OnScanProgress::Create(details).Pass()); 408 } 409 410 void MediaGalleriesEventRouter::DispatchEventToExtension( 411 const std::string& extension_id, 412 const std::string& event_name, 413 scoped_ptr<base::ListValue> event_args) { 414 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); 415 EventRouter* router = EventRouter::Get(profile_); 416 if (!router->ExtensionHasEventListener(extension_id, event_name)) 417 return; 418 419 scoped_ptr<extensions::Event> event( 420 new extensions::Event(event_name, event_args.Pass())); 421 router->DispatchEventToExtension(extension_id, event.Pass()); 422 } 423 424 void MediaGalleriesEventRouter::OnGalleryChanged( 425 const std::string& extension_id, MediaGalleryPrefId gallery_id) { 426 MediaGalleries::GalleryChangeDetails details; 427 details.type = MediaGalleries::GALLERY_CHANGE_TYPE_CONTENTS_CHANGED; 428 details.gallery_id = base::Uint64ToString(gallery_id); 429 DispatchEventToExtension( 430 extension_id, 431 MediaGalleries::OnGalleryChanged::kEventName, 432 MediaGalleries::OnGalleryChanged::Create(details).Pass()); 433 } 434 435 void MediaGalleriesEventRouter::OnGalleryWatchDropped( 436 const std::string& extension_id, MediaGalleryPrefId gallery_id) { 437 MediaGalleries::GalleryChangeDetails details; 438 details.type = MediaGalleries::GALLERY_CHANGE_TYPE_WATCH_DROPPED; 439 details.gallery_id = gallery_id; 440 DispatchEventToExtension( 441 extension_id, 442 MediaGalleries::OnGalleryChanged::kEventName, 443 MediaGalleries::OnGalleryChanged::Create(details).Pass()); 444 } 445 446 void MediaGalleriesEventRouter::OnListenerRemoved( 447 const EventListenerInfo& details) { 448 if (details.event_name == MediaGalleries::OnGalleryChanged::kEventName && 449 !ExtensionHasGalleryChangeListener(details.extension_id)) { 450 gallery_watch_manager()->RemoveAllWatches(profile_, details.extension_id); 451 } 452 } 453 454 /////////////////////////////////////////////////////////////////////////////// 455 // MediaGalleriesGetMediaFileSystemsFunction // 456 /////////////////////////////////////////////////////////////////////////////// 457 MediaGalleriesGetMediaFileSystemsFunction:: 458 ~MediaGalleriesGetMediaFileSystemsFunction() {} 459 460 bool MediaGalleriesGetMediaFileSystemsFunction::RunAsync() { 461 media_galleries::UsageCount(media_galleries::GET_MEDIA_FILE_SYSTEMS); 462 scoped_ptr<GetMediaFileSystems::Params> params( 463 GetMediaFileSystems::Params::Create(*args_)); 464 EXTENSION_FUNCTION_VALIDATE(params.get()); 465 MediaGalleries::GetMediaFileSystemsInteractivity interactive = 466 MediaGalleries::GET_MEDIA_FILE_SYSTEMS_INTERACTIVITY_NO; 467 if (params->details.get() && params->details->interactive != MediaGalleries:: 468 GET_MEDIA_FILE_SYSTEMS_INTERACTIVITY_NONE) { 469 interactive = params->details->interactive; 470 } 471 472 return Setup(GetProfile(), &error_, base::Bind( 473 &MediaGalleriesGetMediaFileSystemsFunction::OnPreferencesInit, this, 474 interactive)); 475 } 476 477 void MediaGalleriesGetMediaFileSystemsFunction::OnPreferencesInit( 478 MediaGalleries::GetMediaFileSystemsInteractivity interactive) { 479 switch (interactive) { 480 case MediaGalleries::GET_MEDIA_FILE_SYSTEMS_INTERACTIVITY_YES: { 481 // The MediaFileSystemRegistry only updates preferences for extensions 482 // that it knows are in use. Since this may be the first call to 483 // chrome.getMediaFileSystems for this extension, call 484 // GetMediaFileSystemsForExtension() here solely so that 485 // MediaFileSystemRegistry will send preference changes. 486 GetMediaFileSystemsForExtension(base::Bind( 487 &MediaGalleriesGetMediaFileSystemsFunction::AlwaysShowDialog, this)); 488 return; 489 } 490 case MediaGalleries::GET_MEDIA_FILE_SYSTEMS_INTERACTIVITY_IF_NEEDED: { 491 GetMediaFileSystemsForExtension(base::Bind( 492 &MediaGalleriesGetMediaFileSystemsFunction::ShowDialogIfNoGalleries, 493 this)); 494 return; 495 } 496 case MediaGalleries::GET_MEDIA_FILE_SYSTEMS_INTERACTIVITY_NO: 497 GetAndReturnGalleries(); 498 return; 499 case MediaGalleries::GET_MEDIA_FILE_SYSTEMS_INTERACTIVITY_NONE: 500 NOTREACHED(); 501 } 502 SendResponse(false); 503 } 504 505 void MediaGalleriesGetMediaFileSystemsFunction::AlwaysShowDialog( 506 const std::vector<MediaFileSystemInfo>& /*filesystems*/) { 507 ShowDialog(); 508 } 509 510 void MediaGalleriesGetMediaFileSystemsFunction::ShowDialogIfNoGalleries( 511 const std::vector<MediaFileSystemInfo>& filesystems) { 512 if (filesystems.empty()) 513 ShowDialog(); 514 else 515 ReturnGalleries(filesystems); 516 } 517 518 void MediaGalleriesGetMediaFileSystemsFunction::GetAndReturnGalleries() { 519 GetMediaFileSystemsForExtension(base::Bind( 520 &MediaGalleriesGetMediaFileSystemsFunction::ReturnGalleries, this)); 521 } 522 523 void MediaGalleriesGetMediaFileSystemsFunction::ReturnGalleries( 524 const std::vector<MediaFileSystemInfo>& filesystems) { 525 scoped_ptr<base::ListValue> list( 526 ConstructFileSystemList(render_view_host(), extension(), filesystems)); 527 if (!list.get()) { 528 SendResponse(false); 529 return; 530 } 531 532 // The custom JS binding will use this list to create DOMFileSystem objects. 533 SetResult(list.release()); 534 SendResponse(true); 535 } 536 537 void MediaGalleriesGetMediaFileSystemsFunction::ShowDialog() { 538 media_galleries::UsageCount(media_galleries::SHOW_DIALOG); 539 WebContents* contents = 540 GetWebContents(render_view_host(), GetProfile(), extension()->id()); 541 if (!contents) { 542 SendResponse(false); 543 return; 544 } 545 546 // Controller will delete itself. 547 base::Closure cb = base::Bind( 548 &MediaGalleriesGetMediaFileSystemsFunction::GetAndReturnGalleries, this); 549 new MediaGalleriesPermissionController(contents, *extension(), cb); 550 } 551 552 void MediaGalleriesGetMediaFileSystemsFunction::GetMediaFileSystemsForExtension( 553 const MediaFileSystemsCallback& cb) { 554 if (!render_view_host()) { 555 cb.Run(std::vector<MediaFileSystemInfo>()); 556 return; 557 } 558 MediaFileSystemRegistry* registry = media_file_system_registry(); 559 DCHECK(registry->GetPreferences(GetProfile())->IsInitialized()); 560 registry->GetMediaFileSystemsForExtension( 561 render_view_host(), extension(), cb); 562 } 563 564 565 /////////////////////////////////////////////////////////////////////////////// 566 // MediaGalleriesGetAllMediaFileSystemMetadataFunction // 567 /////////////////////////////////////////////////////////////////////////////// 568 MediaGalleriesGetAllMediaFileSystemMetadataFunction:: 569 ~MediaGalleriesGetAllMediaFileSystemMetadataFunction() {} 570 571 bool MediaGalleriesGetAllMediaFileSystemMetadataFunction::RunAsync() { 572 media_galleries::UsageCount( 573 media_galleries::GET_ALL_MEDIA_FILE_SYSTEM_METADATA); 574 return Setup(GetProfile(), &error_, base::Bind( 575 &MediaGalleriesGetAllMediaFileSystemMetadataFunction::OnPreferencesInit, 576 this)); 577 } 578 579 void MediaGalleriesGetAllMediaFileSystemMetadataFunction::OnPreferencesInit() { 580 MediaFileSystemRegistry* registry = media_file_system_registry(); 581 MediaGalleriesPreferences* prefs = registry->GetPreferences(GetProfile()); 582 DCHECK(prefs->IsInitialized()); 583 MediaGalleryPrefIdSet permitted_gallery_ids = 584 prefs->GalleriesForExtension(*extension()); 585 586 MediaStorageUtil::DeviceIdSet* device_ids = new MediaStorageUtil::DeviceIdSet; 587 const MediaGalleriesPrefInfoMap& galleries = prefs->known_galleries(); 588 for (MediaGalleryPrefIdSet::const_iterator it = permitted_gallery_ids.begin(); 589 it != permitted_gallery_ids.end(); ++it) { 590 MediaGalleriesPrefInfoMap::const_iterator gallery_it = galleries.find(*it); 591 DCHECK(gallery_it != galleries.end()); 592 device_ids->insert(gallery_it->second.device_id); 593 } 594 595 MediaStorageUtil::FilterAttachedDevices( 596 device_ids, 597 base::Bind( 598 &MediaGalleriesGetAllMediaFileSystemMetadataFunction::OnGetGalleries, 599 this, 600 permitted_gallery_ids, 601 base::Owned(device_ids))); 602 } 603 604 void MediaGalleriesGetAllMediaFileSystemMetadataFunction::OnGetGalleries( 605 const MediaGalleryPrefIdSet& permitted_gallery_ids, 606 const MediaStorageUtil::DeviceIdSet* available_devices) { 607 MediaFileSystemRegistry* registry = media_file_system_registry(); 608 MediaGalleriesPreferences* prefs = registry->GetPreferences(GetProfile()); 609 610 base::ListValue* list = new base::ListValue(); 611 const MediaGalleriesPrefInfoMap& galleries = prefs->known_galleries(); 612 for (MediaGalleryPrefIdSet::const_iterator it = permitted_gallery_ids.begin(); 613 it != permitted_gallery_ids.end(); ++it) { 614 MediaGalleriesPrefInfoMap::const_iterator gallery_it = galleries.find(*it); 615 DCHECK(gallery_it != galleries.end()); 616 const MediaGalleryPrefInfo& gallery = gallery_it->second; 617 MediaGalleries::MediaFileSystemMetadata metadata; 618 metadata.name = base::UTF16ToUTF8(gallery.GetGalleryDisplayName()); 619 metadata.gallery_id = base::Uint64ToString(gallery.pref_id); 620 metadata.is_removable = StorageInfo::IsRemovableDevice(gallery.device_id); 621 metadata.is_media_device = StorageInfo::IsMediaDevice(gallery.device_id); 622 metadata.is_available = ContainsKey(*available_devices, gallery.device_id); 623 list->Append(metadata.ToValue().release()); 624 } 625 626 SetResult(list); 627 SendResponse(true); 628 } 629 630 /////////////////////////////////////////////////////////////////////////////// 631 // MediaGalleriesAddUserSelectedFolderFunction // 632 /////////////////////////////////////////////////////////////////////////////// 633 MediaGalleriesAddUserSelectedFolderFunction:: 634 ~MediaGalleriesAddUserSelectedFolderFunction() {} 635 636 bool MediaGalleriesAddUserSelectedFolderFunction::RunAsync() { 637 media_galleries::UsageCount(media_galleries::ADD_USER_SELECTED_FOLDER); 638 return Setup(GetProfile(), &error_, base::Bind( 639 &MediaGalleriesAddUserSelectedFolderFunction::OnPreferencesInit, this)); 640 } 641 642 void MediaGalleriesAddUserSelectedFolderFunction::OnPreferencesInit() { 643 Profile* profile = GetProfile(); 644 const std::string& app_id = extension()->id(); 645 WebContents* contents = GetWebContents(render_view_host(), profile, app_id); 646 if (!contents) { 647 // When the request originated from a background page, but there is no app 648 // window open, check to see if it originated from a tab and display the 649 // dialog in that tab. 650 bool found_tab = extensions::ExtensionTabUtil::GetTabById( 651 source_tab_id(), profile, profile->IsOffTheRecord(), 652 NULL, NULL, &contents, NULL); 653 if (!found_tab || !contents) { 654 SendResponse(false); 655 return; 656 } 657 } 658 659 if (!user_gesture()) { 660 OnDirectorySelected(base::FilePath()); 661 return; 662 } 663 664 base::FilePath last_used_path = 665 extensions::file_system_api::GetLastChooseEntryDirectory( 666 extensions::ExtensionPrefs::Get(profile), app_id); 667 SelectDirectoryDialog::Callback callback = base::Bind( 668 &MediaGalleriesAddUserSelectedFolderFunction::OnDirectorySelected, this); 669 scoped_refptr<SelectDirectoryDialog> select_directory_dialog = 670 new SelectDirectoryDialog(contents, callback); 671 select_directory_dialog->Show(last_used_path); 672 } 673 674 void MediaGalleriesAddUserSelectedFolderFunction::OnDirectorySelected( 675 const base::FilePath& selected_directory) { 676 if (selected_directory.empty()) { 677 // User cancelled case. 678 GetMediaFileSystemsForExtension(base::Bind( 679 &MediaGalleriesAddUserSelectedFolderFunction::ReturnGalleriesAndId, 680 this, 681 kInvalidMediaGalleryPrefId)); 682 return; 683 } 684 685 extensions::file_system_api::SetLastChooseEntryDirectory( 686 extensions::ExtensionPrefs::Get(GetProfile()), 687 extension()->id(), 688 selected_directory); 689 690 MediaGalleriesPreferences* preferences = 691 media_file_system_registry()->GetPreferences(GetProfile()); 692 MediaGalleryPrefId pref_id = 693 preferences->AddGalleryByPath(selected_directory, 694 MediaGalleryPrefInfo::kUserAdded); 695 preferences->SetGalleryPermissionForExtension(*extension(), pref_id, true); 696 697 GetMediaFileSystemsForExtension(base::Bind( 698 &MediaGalleriesAddUserSelectedFolderFunction::ReturnGalleriesAndId, 699 this, 700 pref_id)); 701 } 702 703 void MediaGalleriesAddUserSelectedFolderFunction::ReturnGalleriesAndId( 704 MediaGalleryPrefId pref_id, 705 const std::vector<MediaFileSystemInfo>& filesystems) { 706 scoped_ptr<base::ListValue> list( 707 ConstructFileSystemList(render_view_host(), extension(), filesystems)); 708 if (!list.get()) { 709 SendResponse(false); 710 return; 711 } 712 713 int index = -1; 714 if (pref_id != kInvalidMediaGalleryPrefId) { 715 for (size_t i = 0; i < filesystems.size(); ++i) { 716 if (filesystems[i].pref_id == pref_id) { 717 index = i; 718 break; 719 } 720 } 721 } 722 base::DictionaryValue* results = new base::DictionaryValue; 723 results->SetWithoutPathExpansion("mediaFileSystems", list.release()); 724 results->SetIntegerWithoutPathExpansion("selectedFileSystemIndex", index); 725 SetResult(results); 726 SendResponse(true); 727 } 728 729 void 730 MediaGalleriesAddUserSelectedFolderFunction::GetMediaFileSystemsForExtension( 731 const MediaFileSystemsCallback& cb) { 732 if (!render_view_host()) { 733 cb.Run(std::vector<MediaFileSystemInfo>()); 734 return; 735 } 736 MediaFileSystemRegistry* registry = media_file_system_registry(); 737 DCHECK(registry->GetPreferences(GetProfile())->IsInitialized()); 738 registry->GetMediaFileSystemsForExtension( 739 render_view_host(), extension(), cb); 740 } 741 742 /////////////////////////////////////////////////////////////////////////////// 743 // MediaGalleriesDropPermissionForMediaFileSystemFunction // 744 /////////////////////////////////////////////////////////////////////////////// 745 MediaGalleriesDropPermissionForMediaFileSystemFunction:: 746 ~MediaGalleriesDropPermissionForMediaFileSystemFunction() {} 747 748 bool MediaGalleriesDropPermissionForMediaFileSystemFunction::RunAsync() { 749 media_galleries::UsageCount( 750 media_galleries::DROP_PERMISSION_FOR_MEDIA_FILE_SYSTEM); 751 752 scoped_ptr<DropPermissionForMediaFileSystem::Params> params( 753 DropPermissionForMediaFileSystem::Params::Create(*args_)); 754 EXTENSION_FUNCTION_VALIDATE(params.get()); 755 MediaGalleryPrefId pref_id; 756 if (!base::StringToUint64(params->gallery_id, &pref_id)) { 757 error_ = kInvalidGalleryIdMsg; 758 return false; 759 } 760 761 base::Closure callback = base::Bind( 762 &MediaGalleriesDropPermissionForMediaFileSystemFunction:: 763 OnPreferencesInit, 764 this, 765 pref_id); 766 return Setup(GetProfile(), &error_, callback); 767 } 768 769 void MediaGalleriesDropPermissionForMediaFileSystemFunction::OnPreferencesInit( 770 MediaGalleryPrefId pref_id) { 771 MediaGalleriesPreferences* preferences = 772 media_file_system_registry()->GetPreferences(GetProfile()); 773 if (!ContainsKey(preferences->known_galleries(), pref_id)) { 774 error_ = kNonExistentGalleryId; 775 SendResponse(false); 776 return; 777 } 778 779 bool dropped = preferences->SetGalleryPermissionForExtension( 780 *extension(), pref_id, false); 781 if (dropped) 782 SetResult(new base::StringValue(base::Uint64ToString(pref_id))); 783 else 784 error_ = kFailedToSetGalleryPermission; 785 SendResponse(dropped); 786 } 787 788 /////////////////////////////////////////////////////////////////////////////// 789 // MediaGalleriesStartMediaScanFunction // 790 /////////////////////////////////////////////////////////////////////////////// 791 MediaGalleriesStartMediaScanFunction::~MediaGalleriesStartMediaScanFunction() {} 792 793 bool MediaGalleriesStartMediaScanFunction::RunAsync() { 794 media_galleries::UsageCount(media_galleries::START_MEDIA_SCAN); 795 if (!CheckScanPermission(extension(), &error_)) { 796 MediaGalleriesEventRouter::Get(GetProfile()) 797 ->OnScanError(extension()->id()); 798 return false; 799 } 800 return Setup(GetProfile(), &error_, base::Bind( 801 &MediaGalleriesStartMediaScanFunction::OnPreferencesInit, this)); 802 } 803 804 void MediaGalleriesStartMediaScanFunction::OnPreferencesInit() { 805 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); 806 MediaGalleriesEventRouter* api = MediaGalleriesEventRouter::Get(GetProfile()); 807 if (!api->ExtensionHasScanProgressListener(extension()->id())) { 808 error_ = kMissingEventListener; 809 SendResponse(false); 810 return; 811 } 812 813 media_scan_manager()->StartScan(GetProfile(), extension(), user_gesture()); 814 SendResponse(true); 815 } 816 817 /////////////////////////////////////////////////////////////////////////////// 818 // MediaGalleriesCancelMediaScanFunction // 819 /////////////////////////////////////////////////////////////////////////////// 820 MediaGalleriesCancelMediaScanFunction:: 821 ~MediaGalleriesCancelMediaScanFunction() { 822 } 823 824 bool MediaGalleriesCancelMediaScanFunction::RunAsync() { 825 media_galleries::UsageCount(media_galleries::CANCEL_MEDIA_SCAN); 826 if (!CheckScanPermission(extension(), &error_)) { 827 MediaGalleriesEventRouter::Get(GetProfile()) 828 ->OnScanError(extension()->id()); 829 return false; 830 } 831 return Setup(GetProfile(), &error_, base::Bind( 832 &MediaGalleriesCancelMediaScanFunction::OnPreferencesInit, this)); 833 } 834 835 void MediaGalleriesCancelMediaScanFunction::OnPreferencesInit() { 836 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); 837 media_scan_manager()->CancelScan(GetProfile(), extension()); 838 SendResponse(true); 839 } 840 841 /////////////////////////////////////////////////////////////////////////////// 842 // MediaGalleriesAddScanResultsFunction // 843 /////////////////////////////////////////////////////////////////////////////// 844 MediaGalleriesAddScanResultsFunction::~MediaGalleriesAddScanResultsFunction() {} 845 846 bool MediaGalleriesAddScanResultsFunction::RunAsync() { 847 media_galleries::UsageCount(media_galleries::ADD_SCAN_RESULTS); 848 if (!CheckScanPermission(extension(), &error_)) { 849 // We don't fire a scan progress error here, as it would be unintuitive. 850 return false; 851 } 852 if (!user_gesture()) 853 return false; 854 855 return Setup(GetProfile(), &error_, base::Bind( 856 &MediaGalleriesAddScanResultsFunction::OnPreferencesInit, this)); 857 } 858 859 MediaGalleriesScanResultController* 860 MediaGalleriesAddScanResultsFunction::MakeDialog( 861 content::WebContents* web_contents, 862 const extensions::Extension& extension, 863 const base::Closure& on_finish) { 864 // Controller will delete itself. 865 return new MediaGalleriesScanResultController(web_contents, extension, 866 on_finish); 867 } 868 869 void MediaGalleriesAddScanResultsFunction::OnPreferencesInit() { 870 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); 871 MediaGalleriesPreferences* preferences = 872 media_file_system_registry()->GetPreferences(GetProfile()); 873 if (MediaGalleriesScanResultController::ScanResultCountForExtension( 874 preferences, extension()) == 0) { 875 GetAndReturnGalleries(); 876 return; 877 } 878 879 WebContents* contents = 880 GetWebContents(render_view_host(), GetProfile(), extension()->id()); 881 if (!contents) { 882 SendResponse(false); 883 return; 884 } 885 886 base::Closure cb = base::Bind( 887 &MediaGalleriesAddScanResultsFunction::GetAndReturnGalleries, this); 888 MakeDialog(contents, *extension(), cb); 889 } 890 891 void MediaGalleriesAddScanResultsFunction::GetAndReturnGalleries() { 892 if (!render_view_host()) { 893 ReturnGalleries(std::vector<MediaFileSystemInfo>()); 894 return; 895 } 896 MediaFileSystemRegistry* registry = media_file_system_registry(); 897 DCHECK(registry->GetPreferences(GetProfile())->IsInitialized()); 898 registry->GetMediaFileSystemsForExtension( 899 render_view_host(), 900 extension(), 901 base::Bind(&MediaGalleriesAddScanResultsFunction::ReturnGalleries, this)); 902 } 903 904 void MediaGalleriesAddScanResultsFunction::ReturnGalleries( 905 const std::vector<MediaFileSystemInfo>& filesystems) { 906 scoped_ptr<base::ListValue> list( 907 ConstructFileSystemList(render_view_host(), extension(), filesystems)); 908 if (!list.get()) { 909 SendResponse(false); 910 return; 911 } 912 913 // The custom JS binding will use this list to create DOMFileSystem objects. 914 SetResult(list.release()); 915 SendResponse(true); 916 } 917 918 /////////////////////////////////////////////////////////////////////////////// 919 // MediaGalleriesGetMetadataFunction // 920 /////////////////////////////////////////////////////////////////////////////// 921 MediaGalleriesGetMetadataFunction::~MediaGalleriesGetMetadataFunction() {} 922 923 bool MediaGalleriesGetMetadataFunction::RunAsync() { 924 std::string blob_uuid; 925 EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &blob_uuid)); 926 927 const base::Value* options_value = NULL; 928 if (!args_->Get(1, &options_value)) 929 return false; 930 scoped_ptr<MediaGalleries::MediaMetadataOptions> options = 931 MediaGalleries::MediaMetadataOptions::FromValue(*options_value); 932 if (!options) 933 return false; 934 935 return Setup(GetProfile(), &error_, base::Bind( 936 &MediaGalleriesGetMetadataFunction::OnPreferencesInit, this, 937 options->metadata_type, blob_uuid)); 938 } 939 940 void MediaGalleriesGetMetadataFunction::OnPreferencesInit( 941 MediaGalleries::GetMetadataType metadata_type, 942 const std::string& blob_uuid) { 943 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); 944 945 // BlobReader is self-deleting. 946 BlobReader* reader = new BlobReader( 947 GetProfile(), 948 blob_uuid, 949 base::Bind(&MediaGalleriesGetMetadataFunction::GetMetadata, this, 950 metadata_type, blob_uuid)); 951 reader->SetByteRange(0, net::kMaxBytesToSniff); 952 reader->Start(); 953 } 954 955 void MediaGalleriesGetMetadataFunction::GetMetadata( 956 MediaGalleries::GetMetadataType metadata_type, const std::string& blob_uuid, 957 scoped_ptr<std::string> blob_header, int64 total_blob_length) { 958 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); 959 960 std::string mime_type; 961 bool mime_type_sniffed = net::SniffMimeTypeFromLocalData( 962 blob_header->c_str(), blob_header->size(), &mime_type); 963 964 if (!mime_type_sniffed) { 965 SendResponse(false); 966 return; 967 } 968 969 if (metadata_type == MediaGalleries::GET_METADATA_TYPE_MIMETYPEONLY) { 970 MediaGalleries::MediaMetadata metadata; 971 metadata.mime_type = mime_type; 972 973 base::DictionaryValue* result_dictionary = new base::DictionaryValue; 974 result_dictionary->Set(kMetadataKey, metadata.ToValue().release()); 975 SetResult(result_dictionary); 976 SendResponse(true); 977 return; 978 } 979 980 // We get attached images by default. GET_METADATA_TYPE_NONE is the default 981 // value if the caller doesn't specify the metadata type. 982 bool get_attached_images = 983 metadata_type == MediaGalleries::GET_METADATA_TYPE_ALL || 984 metadata_type == MediaGalleries::GET_METADATA_TYPE_NONE; 985 986 scoped_refptr<metadata::SafeMediaMetadataParser> parser( 987 new metadata::SafeMediaMetadataParser(GetProfile(), blob_uuid, 988 total_blob_length, mime_type, 989 get_attached_images)); 990 parser->Start(base::Bind( 991 &MediaGalleriesGetMetadataFunction::OnSafeMediaMetadataParserDone, this)); 992 } 993 994 void MediaGalleriesGetMetadataFunction::OnSafeMediaMetadataParserDone( 995 bool parse_success, scoped_ptr<base::DictionaryValue> metadata_dictionary, 996 scoped_ptr<std::vector<metadata::AttachedImage> > attached_images) { 997 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); 998 999 if (!parse_success) { 1000 SendResponse(false); 1001 return; 1002 } 1003 1004 DCHECK(metadata_dictionary.get()); 1005 DCHECK(attached_images.get()); 1006 1007 scoped_ptr<base::DictionaryValue> result_dictionary( 1008 new base::DictionaryValue); 1009 result_dictionary->Set(kMetadataKey, metadata_dictionary.release()); 1010 1011 if (attached_images->empty()) { 1012 SetResult(result_dictionary.release()); 1013 SendResponse(true); 1014 return; 1015 } 1016 1017 result_dictionary->Set(kAttachedImagesBlobInfoKey, new base::ListValue); 1018 metadata::AttachedImage* first_image = &attached_images->front(); 1019 content::BrowserContext::CreateMemoryBackedBlob( 1020 GetProfile(), 1021 first_image->data.c_str(), 1022 first_image->data.size(), 1023 base::Bind(&MediaGalleriesGetMetadataFunction::ConstructNextBlob, 1024 this, base::Passed(&result_dictionary), 1025 base::Passed(&attached_images), 1026 base::Passed(make_scoped_ptr(new std::vector<std::string>)))); 1027 } 1028 1029 void MediaGalleriesGetMetadataFunction::ConstructNextBlob( 1030 scoped_ptr<base::DictionaryValue> result_dictionary, 1031 scoped_ptr<std::vector<metadata::AttachedImage> > attached_images, 1032 scoped_ptr<std::vector<std::string> > blob_uuids, 1033 scoped_ptr<content::BlobHandle> current_blob) { 1034 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); 1035 1036 DCHECK(result_dictionary.get()); 1037 DCHECK(attached_images.get()); 1038 DCHECK(blob_uuids.get()); 1039 DCHECK(current_blob.get()); 1040 1041 DCHECK(!attached_images->empty()); 1042 DCHECK_LT(blob_uuids->size(), attached_images->size()); 1043 1044 // For the newly constructed Blob, store its image's metadata and Blob UUID. 1045 base::ListValue* attached_images_list = NULL; 1046 result_dictionary->GetList(kAttachedImagesBlobInfoKey, &attached_images_list); 1047 DCHECK(attached_images_list); 1048 DCHECK_LT(attached_images_list->GetSize(), attached_images->size()); 1049 1050 metadata::AttachedImage* current_image = 1051 &(*attached_images)[blob_uuids->size()]; 1052 base::DictionaryValue* attached_image = new base::DictionaryValue; 1053 attached_image->Set(kBlobUUIDKey, new base::StringValue( 1054 current_blob->GetUUID())); 1055 attached_image->Set(kTypeKey, new base::StringValue( 1056 current_image->type)); 1057 attached_image->Set(kSizeKey, new base::FundamentalValue( 1058 base::checked_cast<int>(current_image->data.size()))); 1059 attached_images_list->Append(attached_image); 1060 1061 blob_uuids->push_back(current_blob->GetUUID()); 1062 WebContents* contents = WebContents::FromRenderViewHost(render_view_host()); 1063 extensions::BlobHolder* holder = 1064 extensions::BlobHolder::FromRenderProcessHost( 1065 contents->GetRenderProcessHost()); 1066 holder->HoldBlobReference(current_blob.Pass()); 1067 1068 // Construct the next Blob if necessary. 1069 if (blob_uuids->size() < attached_images->size()) { 1070 metadata::AttachedImage* next_image = 1071 &(*attached_images)[blob_uuids->size()]; 1072 content::BrowserContext::CreateMemoryBackedBlob( 1073 GetProfile(), 1074 next_image->data.c_str(), 1075 next_image->data.size(), 1076 base::Bind(&MediaGalleriesGetMetadataFunction::ConstructNextBlob, 1077 this, base::Passed(&result_dictionary), 1078 base::Passed(&attached_images), base::Passed(&blob_uuids))); 1079 return; 1080 } 1081 1082 // All Blobs have been constructed. The renderer will take ownership. 1083 SetResult(result_dictionary.release()); 1084 SetTransferredBlobUUIDs(*blob_uuids); 1085 SendResponse(true); 1086 } 1087 1088 /////////////////////////////////////////////////////////////////////////////// 1089 // MediaGalleriesAddGalleryWatchFunction // 1090 /////////////////////////////////////////////////////////////////////////////// 1091 MediaGalleriesAddGalleryWatchFunction:: 1092 ~MediaGalleriesAddGalleryWatchFunction() { 1093 } 1094 1095 bool MediaGalleriesAddGalleryWatchFunction::RunAsync() { 1096 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); 1097 DCHECK(GetProfile()); 1098 if (!render_view_host() || !render_view_host()->GetProcess()) 1099 return false; 1100 1101 scoped_ptr<AddGalleryWatch::Params> params( 1102 AddGalleryWatch::Params::Create(*args_)); 1103 EXTENSION_FUNCTION_VALIDATE(params.get()); 1104 1105 MediaGalleriesPreferences* preferences = 1106 g_browser_process->media_file_system_registry()->GetPreferences( 1107 GetProfile()); 1108 preferences->EnsureInitialized( 1109 base::Bind(&MediaGalleriesAddGalleryWatchFunction::OnPreferencesInit, 1110 this, 1111 params->gallery_id)); 1112 1113 return true; 1114 } 1115 1116 void MediaGalleriesAddGalleryWatchFunction::OnPreferencesInit( 1117 const std::string& pref_id) { 1118 base::FilePath gallery_file_path; 1119 MediaGalleryPrefId gallery_pref_id = kInvalidMediaGalleryPrefId; 1120 if (!GetGalleryFilePathAndId(pref_id, 1121 GetProfile(), 1122 extension(), 1123 &gallery_file_path, 1124 &gallery_pref_id)) { 1125 api::media_galleries::AddGalleryWatchResult result; 1126 error_ = kInvalidGalleryIdMsg; 1127 result.gallery_id = kInvalidGalleryId; 1128 result.success = false; 1129 SetResult(result.ToValue().release()); 1130 SendResponse(false); 1131 return; 1132 } 1133 1134 gallery_watch_manager()->AddWatch( 1135 GetProfile(), 1136 extension(), 1137 gallery_pref_id, 1138 base::Bind(&MediaGalleriesAddGalleryWatchFunction::HandleResponse, 1139 this, 1140 gallery_pref_id)); 1141 } 1142 1143 void MediaGalleriesAddGalleryWatchFunction::HandleResponse( 1144 MediaGalleryPrefId gallery_id, 1145 const std::string& error) { 1146 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); 1147 1148 // If an app added a file watch without any event listeners on the 1149 // onGalleryChanged event, that's an error. 1150 MediaGalleriesEventRouter* api = MediaGalleriesEventRouter::Get(GetProfile()); 1151 api::media_galleries::AddGalleryWatchResult result; 1152 result.gallery_id = base::Uint64ToString(gallery_id); 1153 1154 if (!api->ExtensionHasGalleryChangeListener(extension()->id())) { 1155 result.success = false; 1156 SetResult(result.ToValue().release()); 1157 error_ = kMissingEventListener; 1158 SendResponse(false); 1159 return; 1160 } 1161 1162 result.success = error.empty(); 1163 SetResult(result.ToValue().release()); 1164 if (error.empty()) { 1165 SendResponse(true); 1166 } else { 1167 error_ = error.c_str(); 1168 SendResponse(false); 1169 } 1170 } 1171 1172 /////////////////////////////////////////////////////////////////////////////// 1173 // MediaGalleriesRemoveGalleryWatchFunction // 1174 /////////////////////////////////////////////////////////////////////////////// 1175 1176 MediaGalleriesRemoveGalleryWatchFunction:: 1177 ~MediaGalleriesRemoveGalleryWatchFunction() { 1178 } 1179 1180 bool MediaGalleriesRemoveGalleryWatchFunction::RunAsync() { 1181 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); 1182 if (!render_view_host() || !render_view_host()->GetProcess()) 1183 return false; 1184 1185 scoped_ptr<RemoveGalleryWatch::Params> params( 1186 RemoveGalleryWatch::Params::Create(*args_)); 1187 EXTENSION_FUNCTION_VALIDATE(params.get()); 1188 1189 MediaGalleriesPreferences* preferences = 1190 g_browser_process->media_file_system_registry()->GetPreferences( 1191 GetProfile()); 1192 preferences->EnsureInitialized( 1193 base::Bind(&MediaGalleriesRemoveGalleryWatchFunction::OnPreferencesInit, 1194 this, 1195 params->gallery_id)); 1196 return true; 1197 } 1198 1199 void MediaGalleriesRemoveGalleryWatchFunction::OnPreferencesInit( 1200 const std::string& pref_id) { 1201 base::FilePath gallery_file_path; 1202 MediaGalleryPrefId gallery_pref_id = 0; 1203 if (!GetGalleryFilePathAndId(pref_id, 1204 GetProfile(), 1205 extension(), 1206 &gallery_file_path, 1207 &gallery_pref_id)) { 1208 error_ = kInvalidGalleryIdMsg; 1209 SendResponse(false); 1210 return; 1211 } 1212 1213 gallery_watch_manager()->RemoveWatch( 1214 GetProfile(), extension_id(), gallery_pref_id); 1215 SendResponse(true); 1216 } 1217 1218 /////////////////////////////////////////////////////////////////////////////// 1219 // MediaGalleriesGetAllGalleryWatchFunction // 1220 /////////////////////////////////////////////////////////////////////////////// 1221 1222 MediaGalleriesGetAllGalleryWatchFunction:: 1223 ~MediaGalleriesGetAllGalleryWatchFunction() { 1224 } 1225 1226 bool MediaGalleriesGetAllGalleryWatchFunction::RunAsync() { 1227 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); 1228 if (!render_view_host() || !render_view_host()->GetProcess()) 1229 return false; 1230 1231 MediaGalleriesPreferences* preferences = 1232 g_browser_process->media_file_system_registry()->GetPreferences( 1233 GetProfile()); 1234 preferences->EnsureInitialized(base::Bind( 1235 &MediaGalleriesGetAllGalleryWatchFunction::OnPreferencesInit, this)); 1236 return true; 1237 } 1238 1239 void MediaGalleriesGetAllGalleryWatchFunction::OnPreferencesInit() { 1240 std::vector<std::string> result; 1241 MediaGalleryPrefIdSet gallery_ids = 1242 gallery_watch_manager()->GetWatchSet(GetProfile(), extension_id()); 1243 for (MediaGalleryPrefIdSet::const_iterator iter = gallery_ids.begin(); 1244 iter != gallery_ids.end(); 1245 ++iter) { 1246 result.push_back(base::Uint64ToString(*iter)); 1247 } 1248 results_ = GetAllGalleryWatch::Results::Create(result); 1249 SendResponse(true); 1250 } 1251 1252 /////////////////////////////////////////////////////////////////////////////// 1253 // MediaGalleriesRemoveAllGalleryWatchFunction // 1254 /////////////////////////////////////////////////////////////////////////////// 1255 1256 MediaGalleriesRemoveAllGalleryWatchFunction:: 1257 ~MediaGalleriesRemoveAllGalleryWatchFunction() { 1258 } 1259 1260 bool MediaGalleriesRemoveAllGalleryWatchFunction::RunAsync() { 1261 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); 1262 if (!render_view_host() || !render_view_host()->GetProcess()) 1263 return false; 1264 1265 MediaGalleriesPreferences* preferences = 1266 g_browser_process->media_file_system_registry()->GetPreferences( 1267 GetProfile()); 1268 preferences->EnsureInitialized(base::Bind( 1269 &MediaGalleriesRemoveAllGalleryWatchFunction::OnPreferencesInit, this)); 1270 return true; 1271 } 1272 1273 void MediaGalleriesRemoveAllGalleryWatchFunction::OnPreferencesInit() { 1274 gallery_watch_manager()->RemoveAllWatches(GetProfile(), extension_id()); 1275 SendResponse(true); 1276 } 1277 1278 } // namespace extensions 1279