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