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/media_galleries/media_galleries_preferences.h" 6 7 #include "base/base_paths_posix.h" 8 #include "base/callback.h" 9 #include "base/i18n/time_formatting.h" 10 #include "base/path_service.h" 11 #include "base/prefs/pref_service.h" 12 #include "base/prefs/scoped_user_pref_update.h" 13 #include "base/stl_util.h" 14 #include "base/strings/string16.h" 15 #include "base/strings/string_number_conversions.h" 16 #include "base/strings/utf_string_conversions.h" 17 #include "base/values.h" 18 #include "chrome/browser/browser_process.h" 19 #include "chrome/browser/extensions/api/media_galleries_private/media_galleries_private_api.h" 20 #include "chrome/browser/extensions/extension_service.h" 21 #include "chrome/browser/media_galleries/fileapi/iapps_finder.h" 22 #include "chrome/browser/media_galleries/fileapi/picasa_finder.h" 23 #include "chrome/browser/media_galleries/imported_media_gallery_registry.h" 24 #include "chrome/browser/media_galleries/media_file_system_registry.h" 25 #include "chrome/browser/media_galleries/media_galleries_histograms.h" 26 #include "chrome/browser/profiles/profile.h" 27 #include "chrome/common/chrome_paths.h" 28 #include "chrome/common/pref_names.h" 29 #include "components/pref_registry/pref_registry_syncable.h" 30 #include "components/storage_monitor/media_storage_util.h" 31 #include "components/storage_monitor/storage_monitor.h" 32 #include "content/public/browser/browser_thread.h" 33 #include "extensions/browser/extension_prefs.h" 34 #include "extensions/browser/extension_system.h" 35 #include "extensions/browser/pref_names.h" 36 #include "extensions/common/extension.h" 37 #include "extensions/common/extension_set.h" 38 #include "extensions/common/permissions/api_permission.h" 39 #include "extensions/common/permissions/media_galleries_permission.h" 40 #include "extensions/common/permissions/permissions_data.h" 41 #include "grit/generated_resources.h" 42 #include "ui/base/l10n/l10n_util.h" 43 44 using base::DictionaryValue; 45 using base::ListValue; 46 using extensions::ExtensionPrefs; 47 using storage_monitor::MediaStorageUtil; 48 using storage_monitor::StorageInfo; 49 using storage_monitor::StorageMonitor; 50 51 namespace { 52 53 // Pref key for the list of media gallery permissions. 54 const char kMediaGalleriesPermissions[] = "media_galleries_permissions"; 55 // Pref key for Media Gallery ID. 56 const char kMediaGalleryIdKey[] = "id"; 57 // Pref key for Media Gallery Permission Value. 58 const char kMediaGalleryHasPermissionKey[] = "has_permission"; 59 60 const char kMediaGalleriesDeviceIdKey[] = "deviceId"; 61 const char kMediaGalleriesDisplayNameKey[] = "displayName"; 62 const char kMediaGalleriesPathKey[] = "path"; 63 const char kMediaGalleriesPrefIdKey[] = "prefId"; 64 const char kMediaGalleriesTypeKey[] = "type"; 65 const char kMediaGalleriesVolumeLabelKey[] = "volumeLabel"; 66 const char kMediaGalleriesVendorNameKey[] = "vendorName"; 67 const char kMediaGalleriesModelNameKey[] = "modelName"; 68 const char kMediaGalleriesSizeKey[] = "totalSize"; 69 const char kMediaGalleriesLastAttachTimeKey[] = "lastAttachTime"; 70 const char kMediaGalleriesScanAudioCountKey[] = "audioCount"; 71 const char kMediaGalleriesScanImageCountKey[] = "imageCount"; 72 const char kMediaGalleriesScanVideoCountKey[] = "videoCount"; 73 const char kMediaGalleriesPrefsVersionKey[] = "preferencesVersion"; 74 75 const char kMediaGalleriesTypeAutoDetectedValue[] = "autoDetected"; 76 const char kMediaGalleriesTypeBlackListedValue[] = "blackListed"; 77 const char kMediaGalleriesTypeRemovedScanValue[] = "removedScan"; 78 const char kMediaGalleriesTypeScanResultValue[] = "scanResult"; 79 const char kMediaGalleriesTypeUserAddedValue[] = "userAdded"; 80 81 const char kIPhotoGalleryName[] = "iPhoto"; 82 const char kITunesGalleryName[] = "iTunes"; 83 const char kPicasaGalleryName[] = "Picasa"; 84 85 const int kCurrentPrefsVersion = 2; 86 87 int NumberExtensionsUsingMediaGalleries(Profile* profile) { 88 int count = 0; 89 if (!profile) 90 return count; 91 ExtensionService* extension_service = 92 extensions::ExtensionSystem::Get(profile)->extension_service(); 93 if (!extension_service) 94 return count; 95 96 const extensions::ExtensionSet* extensions = extension_service->extensions(); 97 for (extensions::ExtensionSet::const_iterator i = extensions->begin(); 98 i != extensions->end(); ++i) { 99 const extensions::PermissionsData* permissions_data = 100 (*i)->permissions_data(); 101 if (permissions_data->HasAPIPermission( 102 extensions::APIPermission::kMediaGalleries) || 103 permissions_data->HasAPIPermission( 104 extensions::APIPermission::kMediaGalleriesPrivate)) { 105 count++; 106 } 107 } 108 return count; 109 } 110 111 bool GetPrefId(const base::DictionaryValue& dict, MediaGalleryPrefId* value) { 112 std::string string_id; 113 if (!dict.GetString(kMediaGalleriesPrefIdKey, &string_id) || 114 !base::StringToUint64(string_id, value)) { 115 return false; 116 } 117 118 return true; 119 } 120 121 bool GetType(const base::DictionaryValue& dict, 122 MediaGalleryPrefInfo::Type* type) { 123 std::string string_type; 124 if (!dict.GetString(kMediaGalleriesTypeKey, &string_type)) 125 return false; 126 127 if (string_type == kMediaGalleriesTypeUserAddedValue) { 128 *type = MediaGalleryPrefInfo::kUserAdded; 129 return true; 130 } 131 if (string_type == kMediaGalleriesTypeAutoDetectedValue) { 132 *type = MediaGalleryPrefInfo::kAutoDetected; 133 return true; 134 } 135 if (string_type == kMediaGalleriesTypeBlackListedValue) { 136 *type = MediaGalleryPrefInfo::kBlackListed; 137 return true; 138 } 139 if (string_type == kMediaGalleriesTypeScanResultValue) { 140 *type = MediaGalleryPrefInfo::kScanResult; 141 return true; 142 } 143 if (string_type == kMediaGalleriesTypeRemovedScanValue) { 144 *type = MediaGalleryPrefInfo::kRemovedScan; 145 return true; 146 } 147 148 return false; 149 } 150 151 const char* TypeToStringValue(MediaGalleryPrefInfo::Type type) { 152 const char* result = NULL; 153 switch (type) { 154 case MediaGalleryPrefInfo::kUserAdded: 155 result = kMediaGalleriesTypeUserAddedValue; 156 break; 157 case MediaGalleryPrefInfo::kAutoDetected: 158 result = kMediaGalleriesTypeAutoDetectedValue; 159 break; 160 case MediaGalleryPrefInfo::kBlackListed: 161 result = kMediaGalleriesTypeBlackListedValue; 162 break; 163 case MediaGalleryPrefInfo::kScanResult: 164 result = kMediaGalleriesTypeScanResultValue; 165 break; 166 case MediaGalleryPrefInfo::kRemovedScan: 167 result = kMediaGalleriesTypeRemovedScanValue; 168 break; 169 default: 170 NOTREACHED(); 171 break; 172 } 173 return result; 174 } 175 176 bool PopulateGalleryPrefInfoFromDictionary( 177 const base::DictionaryValue& dict, MediaGalleryPrefInfo* out_gallery_info) { 178 MediaGalleryPrefId pref_id; 179 base::string16 display_name; 180 std::string device_id; 181 base::FilePath::StringType path; 182 MediaGalleryPrefInfo::Type type = MediaGalleryPrefInfo::kInvalidType; 183 base::string16 volume_label; 184 base::string16 vendor_name; 185 base::string16 model_name; 186 double total_size_in_bytes = 0.0; 187 double last_attach_time = 0.0; 188 bool volume_metadata_valid = false; 189 int audio_count = 0; 190 int image_count = 0; 191 int video_count = 0; 192 int prefs_version = 0; 193 194 if (!GetPrefId(dict, &pref_id) || 195 !dict.GetString(kMediaGalleriesDeviceIdKey, &device_id) || 196 !dict.GetString(kMediaGalleriesPathKey, &path) || 197 !GetType(dict, &type)) { 198 return false; 199 } 200 201 dict.GetString(kMediaGalleriesDisplayNameKey, &display_name); 202 dict.GetInteger(kMediaGalleriesPrefsVersionKey, &prefs_version); 203 204 if (dict.GetString(kMediaGalleriesVolumeLabelKey, &volume_label) && 205 dict.GetString(kMediaGalleriesVendorNameKey, &vendor_name) && 206 dict.GetString(kMediaGalleriesModelNameKey, &model_name) && 207 dict.GetDouble(kMediaGalleriesSizeKey, &total_size_in_bytes) && 208 dict.GetDouble(kMediaGalleriesLastAttachTimeKey, &last_attach_time)) { 209 volume_metadata_valid = true; 210 } 211 212 if (dict.GetInteger(kMediaGalleriesScanAudioCountKey, &audio_count) && 213 dict.GetInteger(kMediaGalleriesScanImageCountKey, &image_count) && 214 dict.GetInteger(kMediaGalleriesScanVideoCountKey, &video_count)) { 215 out_gallery_info->audio_count = audio_count; 216 out_gallery_info->image_count = image_count; 217 out_gallery_info->video_count = video_count; 218 } else { 219 out_gallery_info->audio_count = 0; 220 out_gallery_info->image_count = 0; 221 out_gallery_info->video_count = 0; 222 } 223 224 out_gallery_info->pref_id = pref_id; 225 out_gallery_info->display_name = display_name; 226 out_gallery_info->device_id = device_id; 227 out_gallery_info->path = base::FilePath(path); 228 out_gallery_info->type = type; 229 out_gallery_info->volume_label = volume_label; 230 out_gallery_info->vendor_name = vendor_name; 231 out_gallery_info->model_name = model_name; 232 out_gallery_info->total_size_in_bytes = total_size_in_bytes; 233 out_gallery_info->last_attach_time = 234 base::Time::FromInternalValue(last_attach_time); 235 out_gallery_info->volume_metadata_valid = volume_metadata_valid; 236 out_gallery_info->prefs_version = prefs_version; 237 238 return true; 239 } 240 241 base::DictionaryValue* CreateGalleryPrefInfoDictionary( 242 const MediaGalleryPrefInfo& gallery) { 243 base::DictionaryValue* dict = new base::DictionaryValue(); 244 dict->SetString(kMediaGalleriesPrefIdKey, 245 base::Uint64ToString(gallery.pref_id)); 246 dict->SetString(kMediaGalleriesDeviceIdKey, gallery.device_id); 247 dict->SetString(kMediaGalleriesPathKey, gallery.path.value()); 248 dict->SetString(kMediaGalleriesTypeKey, TypeToStringValue(gallery.type)); 249 250 if (gallery.volume_metadata_valid) { 251 dict->SetString(kMediaGalleriesVolumeLabelKey, gallery.volume_label); 252 dict->SetString(kMediaGalleriesVendorNameKey, gallery.vendor_name); 253 dict->SetString(kMediaGalleriesModelNameKey, gallery.model_name); 254 dict->SetDouble(kMediaGalleriesSizeKey, gallery.total_size_in_bytes); 255 dict->SetDouble(kMediaGalleriesLastAttachTimeKey, 256 gallery.last_attach_time.ToInternalValue()); 257 } else { 258 dict->SetString(kMediaGalleriesDisplayNameKey, gallery.display_name); 259 } 260 261 if (gallery.audio_count || gallery.image_count || gallery.video_count) { 262 dict->SetInteger(kMediaGalleriesScanAudioCountKey, gallery.audio_count); 263 dict->SetInteger(kMediaGalleriesScanImageCountKey, gallery.image_count); 264 dict->SetInteger(kMediaGalleriesScanVideoCountKey, gallery.video_count); 265 } 266 267 // Version 0 of the prefs format was that the display_name was always 268 // used to show the user-visible name of the gallery. Version 1 means 269 // that there is an optional display_name, and when it is present, it 270 // overrides the name that would be built from the volume metadata, path, 271 // or whatever other data. So if we see a display_name with version 0, it 272 // means it may be overwritten simply by getting new volume metadata. 273 // A display_name with version 1 should not be overwritten. 274 dict->SetInteger(kMediaGalleriesPrefsVersionKey, gallery.prefs_version); 275 276 return dict; 277 } 278 279 bool HasAutoDetectedGalleryPermission(const extensions::Extension& extension) { 280 extensions::MediaGalleriesPermission::CheckParam param( 281 extensions::MediaGalleriesPermission::kAllAutoDetectedPermission); 282 return extension.permissions_data()->CheckAPIPermissionWithParam( 283 extensions::APIPermission::kMediaGalleries, ¶m); 284 } 285 286 // Retrieves the MediaGalleryPermission from the given dictionary; DCHECKs on 287 // failure. 288 bool GetMediaGalleryPermissionFromDictionary( 289 const base::DictionaryValue* dict, 290 MediaGalleryPermission* out_permission) { 291 std::string string_id; 292 if (dict->GetString(kMediaGalleryIdKey, &string_id) && 293 base::StringToUint64(string_id, &out_permission->pref_id) && 294 dict->GetBoolean(kMediaGalleryHasPermissionKey, 295 &out_permission->has_permission)) { 296 return true; 297 } 298 NOTREACHED(); 299 return false; 300 } 301 302 // For a device with |device_name| and a relative path |sub_folder|, construct 303 // a display name. If |sub_folder| is empty, then just return |device_name|. 304 base::string16 GetDisplayNameForSubFolder(const base::string16& device_name, 305 const base::FilePath& sub_folder) { 306 if (sub_folder.empty()) 307 return device_name; 308 return (sub_folder.BaseName().LossyDisplayName() + 309 base::ASCIIToUTF16(" - ") + 310 device_name); 311 } 312 313 void InitializeImportedMediaGalleryRegistryOnFileThread() { 314 DCHECK_CURRENTLY_ON(content::BrowserThread::FILE); 315 ImportedMediaGalleryRegistry::GetInstance()->Initialize(); 316 } 317 318 } // namespace 319 320 MediaGalleryPrefInfo::MediaGalleryPrefInfo() 321 : pref_id(kInvalidMediaGalleryPrefId), 322 type(kInvalidType), 323 total_size_in_bytes(0), 324 volume_metadata_valid(false), 325 audio_count(0), 326 image_count(0), 327 video_count(0), 328 prefs_version(0) { 329 } 330 331 MediaGalleryPrefInfo::~MediaGalleryPrefInfo() {} 332 333 base::FilePath MediaGalleryPrefInfo::AbsolutePath() const { 334 base::FilePath base_path = MediaStorageUtil::FindDevicePathById(device_id); 335 DCHECK(!path.IsAbsolute()); 336 return base_path.empty() ? base_path : base_path.Append(path); 337 } 338 339 bool MediaGalleryPrefInfo::IsBlackListedType() const { 340 return type == kBlackListed || type == kRemovedScan; 341 } 342 343 base::string16 MediaGalleryPrefInfo::GetGalleryDisplayName() const { 344 if (!StorageInfo::IsRemovableDevice(device_id)) { 345 // For fixed storage, the default name is the fully qualified directory 346 // name, or in the case of a root directory, the root directory name. 347 // Exception: ChromeOS -- the full pathname isn't visible there, so only 348 // the directory name is used. 349 base::FilePath path = AbsolutePath(); 350 if (!display_name.empty()) 351 return display_name; 352 353 #if defined(OS_CHROMEOS) 354 // See chrome/browser/chromeos/fileapi/file_system_backend.cc 355 base::FilePath download_path; 356 if (PathService::Get(chrome::DIR_DEFAULT_DOWNLOADS_SAFE, &download_path)) { 357 base::FilePath relative; 358 if (download_path.AppendRelativePath(path, &relative)) 359 return relative.LossyDisplayName(); 360 } 361 return path.BaseName().LossyDisplayName(); 362 #else 363 return path.LossyDisplayName(); 364 #endif 365 } 366 367 StorageInfo info(device_id, 368 MediaStorageUtil::FindDevicePathById(device_id).value(), 369 volume_label, vendor_name, model_name, total_size_in_bytes); 370 base::string16 name = info.GetDisplayNameWithOverride(display_name, true); 371 if (!path.empty()) 372 name = GetDisplayNameForSubFolder(name, path); 373 return name; 374 } 375 376 base::string16 MediaGalleryPrefInfo::GetGalleryTooltip() const { 377 return AbsolutePath().LossyDisplayName(); 378 } 379 380 base::string16 MediaGalleryPrefInfo::GetGalleryAdditionalDetails() const { 381 base::string16 attached; 382 if (StorageInfo::IsRemovableDevice(device_id)) { 383 if (MediaStorageUtil::IsRemovableStorageAttached(device_id)) { 384 attached = l10n_util::GetStringUTF16( 385 IDS_MEDIA_GALLERIES_DIALOG_DEVICE_ATTACHED); 386 } else if (!last_attach_time.is_null()) { 387 attached = l10n_util::GetStringFUTF16( 388 IDS_MEDIA_GALLERIES_LAST_ATTACHED, 389 base::TimeFormatShortDateNumeric(last_attach_time)); 390 } else { 391 attached = l10n_util::GetStringUTF16( 392 IDS_MEDIA_GALLERIES_DIALOG_DEVICE_NOT_ATTACHED); 393 } 394 } 395 396 return attached; 397 } 398 399 bool MediaGalleryPrefInfo::IsGalleryAvailable() const { 400 return !StorageInfo::IsRemovableDevice(device_id) || 401 MediaStorageUtil::IsRemovableStorageAttached(device_id); 402 } 403 404 MediaGalleriesPreferences::GalleryChangeObserver::~GalleryChangeObserver() {} 405 406 MediaGalleriesPreferences::MediaGalleriesPreferences(Profile* profile) 407 : initialized_(false), 408 pre_initialization_callbacks_waiting_(0), 409 profile_(profile), 410 extension_prefs_for_testing_(NULL), 411 weak_factory_(this) { 412 } 413 414 MediaGalleriesPreferences::~MediaGalleriesPreferences() { 415 if (StorageMonitor::GetInstance()) 416 StorageMonitor::GetInstance()->RemoveObserver(this); 417 } 418 419 void MediaGalleriesPreferences::EnsureInitialized(base::Closure callback) { 420 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); 421 422 if (IsInitialized()) { 423 if (!callback.is_null()) 424 callback.Run(); 425 return; 426 } 427 428 on_initialize_callbacks_.push_back(callback); 429 if (on_initialize_callbacks_.size() > 1) 430 return; 431 432 // This counter must match the number of async methods dispatched below. 433 // It cannot be incremented inline with each callback, as some may return 434 // synchronously, decrement the counter to 0, and prematurely trigger 435 // FinishInitialization. 436 pre_initialization_callbacks_waiting_ = 4; 437 438 // Check whether we should be initializing -- are there any extensions that 439 // are using media galleries? 440 media_galleries::UsageCount(media_galleries::PREFS_INITIALIZED); 441 if (NumberExtensionsUsingMediaGalleries(profile_) == 0) { 442 media_galleries::UsageCount(media_galleries::PREFS_INITIALIZED_ERROR); 443 } 444 445 // We determine the freshness of the profile here, before any of the finders 446 // return and add media galleries to it. 447 StorageMonitor::GetInstance()->EnsureInitialized( 448 base::Bind(&MediaGalleriesPreferences::OnStorageMonitorInit, 449 weak_factory_.GetWeakPtr(), 450 !APIHasBeenUsed(profile_) /* add_default_galleries */)); 451 452 // Look for optional default galleries every time. 453 iapps::FindITunesLibrary( 454 base::Bind(&MediaGalleriesPreferences::OnFinderDeviceID, 455 weak_factory_.GetWeakPtr())); 456 457 picasa::FindPicasaDatabase( 458 base::Bind(&MediaGalleriesPreferences::OnFinderDeviceID, 459 weak_factory_.GetWeakPtr())); 460 461 iapps::FindIPhotoLibrary( 462 base::Bind(&MediaGalleriesPreferences::OnFinderDeviceID, 463 weak_factory_.GetWeakPtr())); 464 } 465 466 bool MediaGalleriesPreferences::IsInitialized() const { return initialized_; } 467 468 Profile* MediaGalleriesPreferences::profile() { return profile_; } 469 470 void MediaGalleriesPreferences::OnInitializationCallbackReturned() { 471 DCHECK(!IsInitialized()); 472 DCHECK_GT(pre_initialization_callbacks_waiting_, 0); 473 if (--pre_initialization_callbacks_waiting_ == 0) 474 FinishInitialization(); 475 } 476 477 void MediaGalleriesPreferences::FinishInitialization() { 478 DCHECK(!IsInitialized()); 479 480 initialized_ = true; 481 482 StorageMonitor* monitor = StorageMonitor::GetInstance(); 483 DCHECK(monitor->IsInitialized()); 484 485 InitFromPrefs(); 486 487 StorageMonitor::GetInstance()->AddObserver(this); 488 489 std::vector<StorageInfo> existing_devices = 490 monitor->GetAllAvailableStorages(); 491 for (size_t i = 0; i < existing_devices.size(); i++) { 492 if (!(StorageInfo::IsMediaDevice(existing_devices[i].device_id()) && 493 StorageInfo::IsRemovableDevice(existing_devices[i].device_id()))) 494 continue; 495 AddGallery(existing_devices[i].device_id(), 496 base::FilePath(), 497 MediaGalleryPrefInfo::kAutoDetected, 498 existing_devices[i].storage_label(), 499 existing_devices[i].vendor_name(), 500 existing_devices[i].model_name(), 501 existing_devices[i].total_size_in_bytes(), 502 base::Time::Now(), 0, 0, 0); 503 } 504 505 for (std::vector<base::Closure>::iterator iter = 506 on_initialize_callbacks_.begin(); 507 iter != on_initialize_callbacks_.end(); 508 ++iter) { 509 iter->Run(); 510 } 511 on_initialize_callbacks_.clear(); 512 } 513 514 void MediaGalleriesPreferences::AddDefaultGalleries() { 515 const int kDirectoryKeys[] = { 516 chrome::DIR_USER_MUSIC, 517 chrome::DIR_USER_PICTURES, 518 chrome::DIR_USER_VIDEOS, 519 }; 520 521 for (size_t i = 0; i < arraysize(kDirectoryKeys); ++i) { 522 base::FilePath path; 523 if (!PathService::Get(kDirectoryKeys[i], &path)) 524 continue; 525 526 base::FilePath relative_path; 527 StorageInfo info; 528 if (MediaStorageUtil::GetDeviceInfoFromPath(path, &info, &relative_path)) { 529 AddGalleryInternal(info.device_id(), base::string16(), relative_path, 530 MediaGalleryPrefInfo::kAutoDetected, 531 info.storage_label(), info.vendor_name(), 532 info.model_name(), info.total_size_in_bytes(), 533 base::Time(), true, 0, 0, 0, kCurrentPrefsVersion); 534 } 535 } 536 } 537 538 bool MediaGalleriesPreferences::UpdateDeviceIDForSingletonType( 539 const std::string& device_id) { 540 StorageInfo::Type singleton_type; 541 if (!StorageInfo::CrackDeviceId(device_id, &singleton_type, NULL)) 542 return false; 543 544 PrefService* prefs = profile_->GetPrefs(); 545 scoped_ptr<ListPrefUpdate> update(new ListPrefUpdate( 546 prefs, prefs::kMediaGalleriesRememberedGalleries)); 547 base::ListValue* list = update->Get(); 548 for (base::ListValue::iterator iter = list->begin(); 549 iter != list->end(); ++iter) { 550 // All of these calls should succeed, but preferences file can be corrupt. 551 base::DictionaryValue* dict; 552 if (!(*iter)->GetAsDictionary(&dict)) 553 continue; 554 std::string this_device_id; 555 if (!dict->GetString(kMediaGalleriesDeviceIdKey, &this_device_id)) 556 continue; 557 if (this_device_id == device_id) 558 return true; // No update is necessary. 559 StorageInfo::Type device_type; 560 if (!StorageInfo::CrackDeviceId(this_device_id, &device_type, NULL)) 561 continue; 562 563 if (device_type == singleton_type) { 564 dict->SetString(kMediaGalleriesDeviceIdKey, device_id); 565 update.reset(); // commits the update. 566 InitFromPrefs(); 567 MediaGalleryPrefId pref_id; 568 if (GetPrefId(*dict, &pref_id)) { 569 FOR_EACH_OBSERVER(GalleryChangeObserver, 570 gallery_change_observers_, 571 OnGalleryInfoUpdated(this, pref_id)); 572 } 573 return true; 574 } 575 } 576 return false; 577 } 578 579 void MediaGalleriesPreferences::OnStorageMonitorInit( 580 bool add_default_galleries) { 581 if (add_default_galleries) 582 AddDefaultGalleries(); 583 OnInitializationCallbackReturned(); 584 } 585 586 void MediaGalleriesPreferences::OnFinderDeviceID(const std::string& device_id) { 587 if (!device_id.empty()) { 588 std::string gallery_name; 589 if (StorageInfo::IsIPhotoDevice(device_id)) 590 gallery_name = kIPhotoGalleryName; 591 else if (StorageInfo::IsITunesDevice(device_id)) 592 gallery_name = kITunesGalleryName; 593 else if (StorageInfo::IsPicasaDevice(device_id)) 594 gallery_name = kPicasaGalleryName; 595 596 if (!gallery_name.empty()) { 597 pre_initialization_callbacks_waiting_++; 598 content::BrowserThread::PostTaskAndReply( 599 content::BrowserThread::FILE, 600 FROM_HERE, 601 base::Bind(&InitializeImportedMediaGalleryRegistryOnFileThread), 602 base::Bind( 603 &MediaGalleriesPreferences::OnInitializationCallbackReturned, 604 weak_factory_.GetWeakPtr())); 605 } 606 607 if (!UpdateDeviceIDForSingletonType(device_id)) { 608 DCHECK(!gallery_name.empty()); 609 AddGalleryInternal(device_id, base::ASCIIToUTF16(gallery_name), 610 base::FilePath(), MediaGalleryPrefInfo::kAutoDetected, 611 base::string16(), base::string16(), base::string16(), 612 0, base::Time(), false, 0, 0, 0, kCurrentPrefsVersion); 613 } 614 } 615 616 OnInitializationCallbackReturned(); 617 } 618 619 void MediaGalleriesPreferences::InitFromPrefs() { 620 known_galleries_.clear(); 621 device_map_.clear(); 622 623 PrefService* prefs = profile_->GetPrefs(); 624 const base::ListValue* list = prefs->GetList( 625 prefs::kMediaGalleriesRememberedGalleries); 626 if (list) { 627 for (base::ListValue::const_iterator it = list->begin(); 628 it != list->end(); ++it) { 629 const base::DictionaryValue* dict = NULL; 630 if (!(*it)->GetAsDictionary(&dict)) 631 continue; 632 633 MediaGalleryPrefInfo gallery_info; 634 if (!PopulateGalleryPrefInfoFromDictionary(*dict, &gallery_info)) 635 continue; 636 637 known_galleries_[gallery_info.pref_id] = gallery_info; 638 device_map_[gallery_info.device_id].insert(gallery_info.pref_id); 639 } 640 } 641 } 642 643 void MediaGalleriesPreferences::AddGalleryChangeObserver( 644 GalleryChangeObserver* observer) { 645 DCHECK(IsInitialized()); 646 gallery_change_observers_.AddObserver(observer); 647 } 648 649 void MediaGalleriesPreferences::RemoveGalleryChangeObserver( 650 GalleryChangeObserver* observer) { 651 DCHECK(IsInitialized()); 652 gallery_change_observers_.RemoveObserver(observer); 653 } 654 655 void MediaGalleriesPreferences::OnRemovableStorageAttached( 656 const StorageInfo& info) { 657 DCHECK(IsInitialized()); 658 if (!StorageInfo::IsMediaDevice(info.device_id())) 659 return; 660 661 AddGallery(info.device_id(), base::FilePath(), 662 MediaGalleryPrefInfo::kAutoDetected, info.storage_label(), 663 info.vendor_name(), info.model_name(), info.total_size_in_bytes(), 664 base::Time::Now(), 0, 0, 0); 665 } 666 667 bool MediaGalleriesPreferences::LookUpGalleryByPath( 668 const base::FilePath& path, 669 MediaGalleryPrefInfo* gallery_info) const { 670 DCHECK(IsInitialized()); 671 672 // First check if the path matches an imported gallery. 673 for (MediaGalleriesPrefInfoMap::const_iterator it = 674 known_galleries_.begin(); it != known_galleries_.end(); ++it) { 675 const std::string& device_id = it->second.device_id; 676 if (iapps::PathIndicatesIPhotoLibrary(device_id, path) || 677 iapps::PathIndicatesITunesLibrary(device_id, path)) { 678 *gallery_info = it->second; 679 return true; 680 } 681 } 682 683 StorageInfo info; 684 base::FilePath relative_path; 685 if (!MediaStorageUtil::GetDeviceInfoFromPath(path, &info, &relative_path)) { 686 if (gallery_info) 687 *gallery_info = MediaGalleryPrefInfo(); 688 return false; 689 } 690 691 relative_path = relative_path.NormalizePathSeparators(); 692 MediaGalleryPrefIdSet galleries_on_device = 693 LookUpGalleriesByDeviceId(info.device_id()); 694 for (MediaGalleryPrefIdSet::const_iterator it = galleries_on_device.begin(); 695 it != galleries_on_device.end(); 696 ++it) { 697 const MediaGalleryPrefInfo& gallery = known_galleries_.find(*it)->second; 698 if (gallery.path != relative_path) 699 continue; 700 701 if (gallery_info) 702 *gallery_info = gallery; 703 return true; 704 } 705 706 // This method is called by controller::FilesSelected when the user 707 // adds a new gallery. Control reaches here when the selected gallery is 708 // on a volume we know about, but have no gallery already for. Returns 709 // hypothetical data to the caller about what the prefs will look like 710 // if the gallery is added. 711 // TODO(gbillock): split this out into another function so it doesn't 712 // conflate LookUp. 713 if (gallery_info) { 714 gallery_info->pref_id = kInvalidMediaGalleryPrefId; 715 gallery_info->device_id = info.device_id(); 716 gallery_info->path = relative_path; 717 gallery_info->type = MediaGalleryPrefInfo::kInvalidType; 718 gallery_info->volume_label = info.storage_label(); 719 gallery_info->vendor_name = info.vendor_name(); 720 gallery_info->model_name = info.model_name(); 721 gallery_info->total_size_in_bytes = info.total_size_in_bytes(); 722 gallery_info->last_attach_time = base::Time::Now(); 723 gallery_info->volume_metadata_valid = true; 724 gallery_info->prefs_version = kCurrentPrefsVersion; 725 } 726 return false; 727 } 728 729 MediaGalleryPrefIdSet MediaGalleriesPreferences::LookUpGalleriesByDeviceId( 730 const std::string& device_id) const { 731 DeviceIdPrefIdsMap::const_iterator found = device_map_.find(device_id); 732 if (found == device_map_.end()) 733 return MediaGalleryPrefIdSet(); 734 return found->second; 735 } 736 737 base::FilePath MediaGalleriesPreferences::LookUpGalleryPathForExtension( 738 MediaGalleryPrefId gallery_id, 739 const extensions::Extension* extension, 740 bool include_unpermitted_galleries) { 741 DCHECK(IsInitialized()); 742 DCHECK(extension); 743 if (!include_unpermitted_galleries && 744 !ContainsKey(GalleriesForExtension(*extension), gallery_id)) 745 return base::FilePath(); 746 747 MediaGalleriesPrefInfoMap::const_iterator it = 748 known_galleries_.find(gallery_id); 749 if (it == known_galleries_.end()) 750 return base::FilePath(); 751 return MediaStorageUtil::FindDevicePathById(it->second.device_id); 752 } 753 754 MediaGalleryPrefId MediaGalleriesPreferences::AddGallery( 755 const std::string& device_id, 756 const base::FilePath& relative_path, 757 MediaGalleryPrefInfo::Type type, 758 const base::string16& volume_label, 759 const base::string16& vendor_name, 760 const base::string16& model_name, 761 uint64 total_size_in_bytes, 762 base::Time last_attach_time, 763 int audio_count, 764 int image_count, 765 int video_count) { 766 DCHECK(IsInitialized()); 767 return AddGalleryInternal(device_id, base::string16(), relative_path, 768 type, volume_label, vendor_name, model_name, 769 total_size_in_bytes, last_attach_time, true, 770 audio_count, image_count, video_count, 771 kCurrentPrefsVersion); 772 } 773 774 MediaGalleryPrefId MediaGalleriesPreferences::AddGalleryInternal( 775 const std::string& device_id, const base::string16& display_name, 776 const base::FilePath& relative_path, MediaGalleryPrefInfo::Type type, 777 const base::string16& volume_label, const base::string16& vendor_name, 778 const base::string16& model_name, uint64 total_size_in_bytes, 779 base::Time last_attach_time, bool volume_metadata_valid, 780 int audio_count, int image_count, int video_count, int prefs_version) { 781 DCHECK(type == MediaGalleryPrefInfo::kUserAdded || 782 type == MediaGalleryPrefInfo::kAutoDetected || 783 type == MediaGalleryPrefInfo::kScanResult); 784 base::FilePath normalized_relative_path = 785 relative_path.NormalizePathSeparators(); 786 MediaGalleryPrefIdSet galleries_on_device = 787 LookUpGalleriesByDeviceId(device_id); 788 for (MediaGalleryPrefIdSet::const_iterator pref_id_it = 789 galleries_on_device.begin(); 790 pref_id_it != galleries_on_device.end(); 791 ++pref_id_it) { 792 const MediaGalleryPrefInfo& existing = 793 known_galleries_.find(*pref_id_it)->second; 794 if (existing.path != normalized_relative_path) 795 continue; 796 797 bool update_gallery_type = false; 798 MediaGalleryPrefInfo::Type new_type = existing.type; 799 if (type == MediaGalleryPrefInfo::kUserAdded) { 800 if (existing.type == MediaGalleryPrefInfo::kBlackListed) { 801 new_type = MediaGalleryPrefInfo::kAutoDetected; 802 update_gallery_type = true; 803 } 804 if (existing.type == MediaGalleryPrefInfo::kRemovedScan) { 805 new_type = MediaGalleryPrefInfo::kUserAdded; 806 update_gallery_type = true; 807 } 808 } 809 810 // Status quo: In M27 and M28, galleries added manually use version 0, 811 // and galleries added automatically (including default galleries) use 812 // version 1. The name override is used by default galleries as well 813 // as all device attach events. 814 // We want to upgrade the name if the existing version is < 2. Leave it 815 // alone if the existing display name is set with version == 2 and the 816 // proposed new name is empty. 817 bool update_gallery_name = existing.display_name != display_name; 818 if (existing.prefs_version == 2 && !existing.display_name.empty() && 819 display_name.empty()) { 820 update_gallery_name = false; 821 } 822 bool update_gallery_metadata = volume_metadata_valid && 823 ((existing.volume_label != volume_label) || 824 (existing.vendor_name != vendor_name) || 825 (existing.model_name != model_name) || 826 (existing.total_size_in_bytes != total_size_in_bytes) || 827 (existing.last_attach_time != last_attach_time)); 828 829 bool update_scan_counts = 830 new_type != MediaGalleryPrefInfo::kRemovedScan && 831 new_type != MediaGalleryPrefInfo::kBlackListed && 832 (audio_count > 0 || image_count > 0 || video_count > 0 || 833 existing.audio_count || existing.image_count || existing.video_count); 834 835 if (!update_gallery_name && !update_gallery_type && 836 !update_gallery_metadata && !update_scan_counts) 837 return *pref_id_it; 838 839 PrefService* prefs = profile_->GetPrefs(); 840 scoped_ptr<ListPrefUpdate> update( 841 new ListPrefUpdate(prefs, prefs::kMediaGalleriesRememberedGalleries)); 842 base::ListValue* list = update->Get(); 843 844 for (base::ListValue::const_iterator list_iter = list->begin(); 845 list_iter != list->end(); 846 ++list_iter) { 847 base::DictionaryValue* dict; 848 MediaGalleryPrefId iter_id; 849 if ((*list_iter)->GetAsDictionary(&dict) && 850 GetPrefId(*dict, &iter_id) && 851 *pref_id_it == iter_id) { 852 if (update_gallery_type) 853 dict->SetString(kMediaGalleriesTypeKey, TypeToStringValue(new_type)); 854 if (update_gallery_name) 855 dict->SetString(kMediaGalleriesDisplayNameKey, display_name); 856 if (update_gallery_metadata) { 857 dict->SetString(kMediaGalleriesVolumeLabelKey, volume_label); 858 dict->SetString(kMediaGalleriesVendorNameKey, vendor_name); 859 dict->SetString(kMediaGalleriesModelNameKey, model_name); 860 dict->SetDouble(kMediaGalleriesSizeKey, total_size_in_bytes); 861 dict->SetDouble(kMediaGalleriesLastAttachTimeKey, 862 last_attach_time.ToInternalValue()); 863 } 864 if (update_scan_counts) { 865 dict->SetInteger(kMediaGalleriesScanAudioCountKey, audio_count); 866 dict->SetInteger(kMediaGalleriesScanImageCountKey, image_count); 867 dict->SetInteger(kMediaGalleriesScanVideoCountKey, video_count); 868 } 869 dict->SetInteger(kMediaGalleriesPrefsVersionKey, prefs_version); 870 break; 871 } 872 } 873 874 // Commits the prefs update. 875 update.reset(); 876 877 InitFromPrefs(); 878 FOR_EACH_OBSERVER(GalleryChangeObserver, gallery_change_observers_, 879 OnGalleryInfoUpdated(this, *pref_id_it)); 880 return *pref_id_it; 881 } 882 883 PrefService* prefs = profile_->GetPrefs(); 884 885 MediaGalleryPrefInfo gallery_info; 886 gallery_info.pref_id = prefs->GetUint64(prefs::kMediaGalleriesUniqueId); 887 prefs->SetUint64(prefs::kMediaGalleriesUniqueId, gallery_info.pref_id + 1); 888 gallery_info.display_name = display_name; 889 gallery_info.device_id = device_id; 890 gallery_info.path = normalized_relative_path; 891 gallery_info.type = type; 892 gallery_info.volume_label = volume_label; 893 gallery_info.vendor_name = vendor_name; 894 gallery_info.model_name = model_name; 895 gallery_info.total_size_in_bytes = total_size_in_bytes; 896 gallery_info.last_attach_time = last_attach_time; 897 gallery_info.volume_metadata_valid = volume_metadata_valid; 898 gallery_info.audio_count = audio_count; 899 gallery_info.image_count = image_count; 900 gallery_info.video_count = video_count; 901 gallery_info.prefs_version = prefs_version; 902 903 { 904 ListPrefUpdate update(prefs, prefs::kMediaGalleriesRememberedGalleries); 905 base::ListValue* list = update.Get(); 906 list->Append(CreateGalleryPrefInfoDictionary(gallery_info)); 907 } 908 InitFromPrefs(); 909 FOR_EACH_OBSERVER(GalleryChangeObserver, 910 gallery_change_observers_, 911 OnGalleryAdded(this, gallery_info.pref_id)); 912 913 return gallery_info.pref_id; 914 } 915 916 MediaGalleryPrefId MediaGalleriesPreferences::AddGalleryByPath( 917 const base::FilePath& path, MediaGalleryPrefInfo::Type type) { 918 DCHECK(IsInitialized()); 919 MediaGalleryPrefInfo gallery_info; 920 if (LookUpGalleryByPath(path, &gallery_info) && 921 !gallery_info.IsBlackListedType()) { 922 return gallery_info.pref_id; 923 } 924 return AddGalleryInternal(gallery_info.device_id, 925 gallery_info.display_name, 926 gallery_info.path, 927 type, 928 gallery_info.volume_label, 929 gallery_info.vendor_name, 930 gallery_info.model_name, 931 gallery_info.total_size_in_bytes, 932 gallery_info.last_attach_time, 933 gallery_info.volume_metadata_valid, 934 0, 0, 0, 935 kCurrentPrefsVersion); 936 } 937 938 void MediaGalleriesPreferences::ForgetGalleryById(MediaGalleryPrefId id) { 939 EraseOrBlacklistGalleryById(id, false); 940 } 941 942 void MediaGalleriesPreferences::EraseGalleryById(MediaGalleryPrefId id) { 943 EraseOrBlacklistGalleryById(id, true); 944 } 945 946 void MediaGalleriesPreferences::EraseOrBlacklistGalleryById( 947 MediaGalleryPrefId id, bool erase) { 948 DCHECK(IsInitialized()); 949 PrefService* prefs = profile_->GetPrefs(); 950 scoped_ptr<ListPrefUpdate> update(new ListPrefUpdate( 951 prefs, prefs::kMediaGalleriesRememberedGalleries)); 952 base::ListValue* list = update->Get(); 953 954 if (!ContainsKey(known_galleries_, id)) 955 return; 956 957 for (base::ListValue::iterator iter = list->begin(); 958 iter != list->end(); ++iter) { 959 base::DictionaryValue* dict; 960 MediaGalleryPrefId iter_id; 961 if ((*iter)->GetAsDictionary(&dict) && GetPrefId(*dict, &iter_id) && 962 id == iter_id) { 963 RemoveGalleryPermissionsFromPrefs(id); 964 MediaGalleryPrefInfo::Type type; 965 if (!erase && GetType(*dict, &type) && 966 (type == MediaGalleryPrefInfo::kAutoDetected || 967 type == MediaGalleryPrefInfo::kScanResult)) { 968 if (type == MediaGalleryPrefInfo::kAutoDetected) { 969 dict->SetString(kMediaGalleriesTypeKey, 970 kMediaGalleriesTypeBlackListedValue); 971 } else { 972 dict->SetString(kMediaGalleriesTypeKey, 973 kMediaGalleriesTypeRemovedScanValue); 974 dict->SetInteger(kMediaGalleriesScanAudioCountKey, 0); 975 dict->SetInteger(kMediaGalleriesScanImageCountKey, 0); 976 dict->SetInteger(kMediaGalleriesScanVideoCountKey, 0); 977 } 978 } else { 979 list->Erase(iter, NULL); 980 } 981 update.reset(NULL); // commits the update. 982 983 InitFromPrefs(); 984 FOR_EACH_OBSERVER(GalleryChangeObserver, 985 gallery_change_observers_, 986 OnGalleryRemoved(this, id)); 987 return; 988 } 989 } 990 } 991 992 bool MediaGalleriesPreferences::NonAutoGalleryHasPermission( 993 MediaGalleryPrefId id) const { 994 DCHECK(IsInitialized()); 995 DCHECK(!ContainsKey(known_galleries_, id) || 996 known_galleries_.find(id)->second.type != 997 MediaGalleryPrefInfo::kAutoDetected); 998 ExtensionPrefs* prefs = GetExtensionPrefs(); 999 const base::DictionaryValue* extensions = 1000 prefs->pref_service()->GetDictionary(extensions::pref_names::kExtensions); 1001 if (!extensions) 1002 return true; 1003 1004 for (base::DictionaryValue::Iterator iter(*extensions); !iter.IsAtEnd(); 1005 iter.Advance()) { 1006 if (!extensions::Extension::IdIsValid(iter.key())) { 1007 NOTREACHED(); 1008 continue; 1009 } 1010 std::vector<MediaGalleryPermission> permissions = 1011 GetGalleryPermissionsFromPrefs(iter.key()); 1012 for (std::vector<MediaGalleryPermission>::const_iterator it = 1013 permissions.begin(); it != permissions.end(); ++it) { 1014 if (it->pref_id == id) { 1015 if (it->has_permission) 1016 return true; 1017 break; 1018 } 1019 } 1020 } 1021 return false; 1022 } 1023 1024 MediaGalleryPrefIdSet MediaGalleriesPreferences::GalleriesForExtension( 1025 const extensions::Extension& extension) const { 1026 DCHECK(IsInitialized()); 1027 MediaGalleryPrefIdSet result; 1028 1029 if (HasAutoDetectedGalleryPermission(extension)) { 1030 for (MediaGalleriesPrefInfoMap::const_iterator it = 1031 known_galleries_.begin(); it != known_galleries_.end(); ++it) { 1032 if (it->second.type == MediaGalleryPrefInfo::kAutoDetected) 1033 result.insert(it->second.pref_id); 1034 } 1035 } 1036 1037 std::vector<MediaGalleryPermission> stored_permissions = 1038 GetGalleryPermissionsFromPrefs(extension.id()); 1039 for (std::vector<MediaGalleryPermission>::const_iterator it = 1040 stored_permissions.begin(); it != stored_permissions.end(); ++it) { 1041 if (!it->has_permission) { 1042 result.erase(it->pref_id); 1043 } else { 1044 MediaGalleriesPrefInfoMap::const_iterator gallery = 1045 known_galleries_.find(it->pref_id); 1046 DCHECK(gallery != known_galleries_.end()); 1047 if (!gallery->second.IsBlackListedType()) { 1048 result.insert(it->pref_id); 1049 } else { 1050 NOTREACHED() << gallery->second.device_id; 1051 } 1052 } 1053 } 1054 return result; 1055 } 1056 1057 bool MediaGalleriesPreferences::SetGalleryPermissionForExtension( 1058 const extensions::Extension& extension, 1059 MediaGalleryPrefId pref_id, 1060 bool has_permission) { 1061 DCHECK(IsInitialized()); 1062 // The gallery may not exist anymore if the user opened a second config 1063 // surface concurrently and removed it. Drop the permission update if so. 1064 MediaGalleriesPrefInfoMap::const_iterator gallery_info = 1065 known_galleries_.find(pref_id); 1066 if (gallery_info == known_galleries_.end()) 1067 return false; 1068 1069 bool default_permission = false; 1070 if (gallery_info->second.type == MediaGalleryPrefInfo::kAutoDetected) 1071 default_permission = HasAutoDetectedGalleryPermission(extension); 1072 // When the permission matches the default, we don't need to remember it. 1073 if (has_permission == default_permission) { 1074 if (!UnsetGalleryPermissionInPrefs(extension.id(), pref_id)) 1075 // If permission wasn't set, assume nothing has changed. 1076 return false; 1077 } else { 1078 if (!SetGalleryPermissionInPrefs(extension.id(), pref_id, has_permission)) 1079 return false; 1080 } 1081 if (has_permission) 1082 FOR_EACH_OBSERVER(GalleryChangeObserver, 1083 gallery_change_observers_, 1084 OnPermissionAdded(this, extension.id(), pref_id)); 1085 else 1086 FOR_EACH_OBSERVER(GalleryChangeObserver, 1087 gallery_change_observers_, 1088 OnPermissionRemoved(this, extension.id(), pref_id)); 1089 return true; 1090 } 1091 1092 const MediaGalleriesPrefInfoMap& MediaGalleriesPreferences::known_galleries() 1093 const { 1094 DCHECK(IsInitialized()); 1095 return known_galleries_; 1096 } 1097 1098 base::Time MediaGalleriesPreferences::GetLastScanCompletionTime() const { 1099 int64 last_scan_time_internal = 1100 profile_->GetPrefs()->GetInt64(prefs::kMediaGalleriesLastScanTime); 1101 return base::Time::FromInternalValue(last_scan_time_internal); 1102 } 1103 1104 void MediaGalleriesPreferences::SetLastScanCompletionTime( 1105 const base::Time& time) { 1106 profile_->GetPrefs()->SetInt64(prefs::kMediaGalleriesLastScanTime, 1107 time.ToInternalValue()); 1108 } 1109 1110 void MediaGalleriesPreferences::Shutdown() { 1111 weak_factory_.InvalidateWeakPtrs(); 1112 profile_ = NULL; 1113 } 1114 1115 // static 1116 bool MediaGalleriesPreferences::APIHasBeenUsed(Profile* profile) { 1117 MediaGalleryPrefId current_id = 1118 profile->GetPrefs()->GetUint64(prefs::kMediaGalleriesUniqueId); 1119 return current_id != kInvalidMediaGalleryPrefId + 1; 1120 } 1121 1122 // static 1123 void MediaGalleriesPreferences::RegisterProfilePrefs( 1124 user_prefs::PrefRegistrySyncable* registry) { 1125 registry->RegisterListPref(prefs::kMediaGalleriesRememberedGalleries, 1126 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); 1127 registry->RegisterUint64Pref( 1128 prefs::kMediaGalleriesUniqueId, 1129 kInvalidMediaGalleryPrefId + 1, 1130 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); 1131 registry->RegisterInt64Pref( 1132 prefs::kMediaGalleriesLastScanTime, 1133 base::Time().ToInternalValue(), 1134 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); 1135 } 1136 1137 bool MediaGalleriesPreferences::SetGalleryPermissionInPrefs( 1138 const std::string& extension_id, 1139 MediaGalleryPrefId gallery_id, 1140 bool has_access) { 1141 DCHECK(IsInitialized()); 1142 ExtensionPrefs::ScopedListUpdate update(GetExtensionPrefs(), 1143 extension_id, 1144 kMediaGalleriesPermissions); 1145 base::ListValue* permissions = update.Get(); 1146 if (!permissions) { 1147 permissions = update.Create(); 1148 } else { 1149 // If the gallery is already in the list, update the permission... 1150 for (base::ListValue::iterator iter = permissions->begin(); 1151 iter != permissions->end(); ++iter) { 1152 base::DictionaryValue* dict = NULL; 1153 if (!(*iter)->GetAsDictionary(&dict)) 1154 continue; 1155 MediaGalleryPermission perm; 1156 if (!GetMediaGalleryPermissionFromDictionary(dict, &perm)) 1157 continue; 1158 if (perm.pref_id == gallery_id) { 1159 if (has_access != perm.has_permission) { 1160 dict->SetBoolean(kMediaGalleryHasPermissionKey, has_access); 1161 return true; 1162 } else { 1163 return false; 1164 } 1165 } 1166 } 1167 } 1168 // ...Otherwise, add a new entry for the gallery. 1169 base::DictionaryValue* dict = new base::DictionaryValue; 1170 dict->SetString(kMediaGalleryIdKey, base::Uint64ToString(gallery_id)); 1171 dict->SetBoolean(kMediaGalleryHasPermissionKey, has_access); 1172 permissions->Append(dict); 1173 return true; 1174 } 1175 1176 bool MediaGalleriesPreferences::UnsetGalleryPermissionInPrefs( 1177 const std::string& extension_id, 1178 MediaGalleryPrefId gallery_id) { 1179 DCHECK(IsInitialized()); 1180 ExtensionPrefs::ScopedListUpdate update(GetExtensionPrefs(), 1181 extension_id, 1182 kMediaGalleriesPermissions); 1183 base::ListValue* permissions = update.Get(); 1184 if (!permissions) 1185 return false; 1186 1187 for (base::ListValue::iterator iter = permissions->begin(); 1188 iter != permissions->end(); ++iter) { 1189 const base::DictionaryValue* dict = NULL; 1190 if (!(*iter)->GetAsDictionary(&dict)) 1191 continue; 1192 MediaGalleryPermission perm; 1193 if (!GetMediaGalleryPermissionFromDictionary(dict, &perm)) 1194 continue; 1195 if (perm.pref_id == gallery_id) { 1196 permissions->Erase(iter, NULL); 1197 return true; 1198 } 1199 } 1200 return false; 1201 } 1202 1203 std::vector<MediaGalleryPermission> 1204 MediaGalleriesPreferences::GetGalleryPermissionsFromPrefs( 1205 const std::string& extension_id) const { 1206 DCHECK(IsInitialized()); 1207 std::vector<MediaGalleryPermission> result; 1208 const base::ListValue* permissions; 1209 if (!GetExtensionPrefs()->ReadPrefAsList(extension_id, 1210 kMediaGalleriesPermissions, 1211 &permissions)) { 1212 return result; 1213 } 1214 1215 for (base::ListValue::const_iterator iter = permissions->begin(); 1216 iter != permissions->end(); ++iter) { 1217 base::DictionaryValue* dict = NULL; 1218 if (!(*iter)->GetAsDictionary(&dict)) 1219 continue; 1220 MediaGalleryPermission perm; 1221 if (!GetMediaGalleryPermissionFromDictionary(dict, &perm)) 1222 continue; 1223 result.push_back(perm); 1224 } 1225 1226 return result; 1227 } 1228 1229 void MediaGalleriesPreferences::RemoveGalleryPermissionsFromPrefs( 1230 MediaGalleryPrefId gallery_id) { 1231 DCHECK(IsInitialized()); 1232 ExtensionPrefs* prefs = GetExtensionPrefs(); 1233 const base::DictionaryValue* extensions = 1234 prefs->pref_service()->GetDictionary(extensions::pref_names::kExtensions); 1235 if (!extensions) 1236 return; 1237 1238 for (base::DictionaryValue::Iterator iter(*extensions); !iter.IsAtEnd(); 1239 iter.Advance()) { 1240 if (!extensions::Extension::IdIsValid(iter.key())) { 1241 NOTREACHED(); 1242 continue; 1243 } 1244 UnsetGalleryPermissionInPrefs(iter.key(), gallery_id); 1245 } 1246 } 1247 1248 ExtensionPrefs* MediaGalleriesPreferences::GetExtensionPrefs() const { 1249 DCHECK(IsInitialized()); 1250 if (extension_prefs_for_testing_) 1251 return extension_prefs_for_testing_; 1252 return extensions::ExtensionPrefs::Get(profile_); 1253 } 1254 1255 void MediaGalleriesPreferences::SetExtensionPrefsForTesting( 1256 extensions::ExtensionPrefs* extension_prefs) { 1257 DCHECK(IsInitialized()); 1258 extension_prefs_for_testing_ = extension_prefs; 1259 } 1260