media_galleries_preferences.cc revision 46d4c2bc3267f3f028f39e7e311b0f89aba2e4fd
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 44using base::DictionaryValue; 45using base::ListValue; 46using extensions::ExtensionPrefs; 47using storage_monitor::MediaStorageUtil; 48using storage_monitor::StorageInfo; 49using storage_monitor::StorageMonitor; 50 51namespace { 52 53// Pref key for the list of media gallery permissions. 54const char kMediaGalleriesPermissions[] = "media_galleries_permissions"; 55// Pref key for Media Gallery ID. 56const char kMediaGalleryIdKey[] = "id"; 57// Pref key for Media Gallery Permission Value. 58const char kMediaGalleryHasPermissionKey[] = "has_permission"; 59 60const char kMediaGalleriesDeviceIdKey[] = "deviceId"; 61const char kMediaGalleriesDisplayNameKey[] = "displayName"; 62const char kMediaGalleriesPathKey[] = "path"; 63const char kMediaGalleriesPrefIdKey[] = "prefId"; 64const char kMediaGalleriesTypeKey[] = "type"; 65const char kMediaGalleriesVolumeLabelKey[] = "volumeLabel"; 66const char kMediaGalleriesVendorNameKey[] = "vendorName"; 67const char kMediaGalleriesModelNameKey[] = "modelName"; 68const char kMediaGalleriesSizeKey[] = "totalSize"; 69const char kMediaGalleriesLastAttachTimeKey[] = "lastAttachTime"; 70const char kMediaGalleriesScanAudioCountKey[] = "audioCount"; 71const char kMediaGalleriesScanImageCountKey[] = "imageCount"; 72const char kMediaGalleriesScanVideoCountKey[] = "videoCount"; 73const char kMediaGalleriesPrefsVersionKey[] = "preferencesVersion"; 74 75const char kMediaGalleriesTypeAutoDetectedValue[] = "autoDetected"; 76const char kMediaGalleriesTypeBlackListedValue[] = "blackListed"; 77const char kMediaGalleriesTypeRemovedScanValue[] = "removedScan"; 78const char kMediaGalleriesTypeScanResultValue[] = "scanResult"; 79const char kMediaGalleriesTypeUserAddedValue[] = "userAdded"; 80 81const char kIPhotoGalleryName[] = "iPhoto"; 82const char kITunesGalleryName[] = "iTunes"; 83const char kPicasaGalleryName[] = "Picasa"; 84 85const int kCurrentPrefsVersion = 2; 86 87int 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 111bool 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 121bool 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 151const 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 176bool 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 241base::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 279bool 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. 288bool 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|. 304base::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 313void InitializeImportedMediaGalleryRegistryOnFileThread() { 314 DCHECK_CURRENTLY_ON(content::BrowserThread::FILE); 315 ImportedMediaGalleryRegistry::GetInstance()->Initialize(); 316} 317 318} // namespace 319 320MediaGalleryPrefInfo::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 331MediaGalleryPrefInfo::~MediaGalleryPrefInfo() {} 332 333base::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 339bool MediaGalleryPrefInfo::IsBlackListedType() const { 340 return type == kBlackListed || type == kRemovedScan; 341} 342 343base::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 376base::string16 MediaGalleryPrefInfo::GetGalleryTooltip() const { 377 return AbsolutePath().LossyDisplayName(); 378} 379 380base::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 399bool MediaGalleryPrefInfo::IsGalleryAvailable() const { 400 return !StorageInfo::IsRemovableDevice(device_id) || 401 MediaStorageUtil::IsRemovableStorageAttached(device_id); 402} 403 404MediaGalleriesPreferences::GalleryChangeObserver::~GalleryChangeObserver() {} 405 406MediaGalleriesPreferences::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 414MediaGalleriesPreferences::~MediaGalleriesPreferences() { 415 if (StorageMonitor::GetInstance()) 416 StorageMonitor::GetInstance()->RemoveObserver(this); 417} 418 419void 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 466bool MediaGalleriesPreferences::IsInitialized() const { return initialized_; } 467 468Profile* MediaGalleriesPreferences::profile() { return profile_; } 469 470void MediaGalleriesPreferences::OnInitializationCallbackReturned() { 471 DCHECK(!IsInitialized()); 472 DCHECK_GT(pre_initialization_callbacks_waiting_, 0); 473 if (--pre_initialization_callbacks_waiting_ == 0) 474 FinishInitialization(); 475} 476 477void 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 514void 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 538bool 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 579void MediaGalleriesPreferences::OnStorageMonitorInit( 580 bool add_default_galleries) { 581 if (add_default_galleries) 582 AddDefaultGalleries(); 583 OnInitializationCallbackReturned(); 584} 585 586void 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 619void 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 643void MediaGalleriesPreferences::AddGalleryChangeObserver( 644 GalleryChangeObserver* observer) { 645 DCHECK(IsInitialized()); 646 gallery_change_observers_.AddObserver(observer); 647} 648 649void MediaGalleriesPreferences::RemoveGalleryChangeObserver( 650 GalleryChangeObserver* observer) { 651 DCHECK(IsInitialized()); 652 gallery_change_observers_.RemoveObserver(observer); 653} 654 655void 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 667bool MediaGalleriesPreferences::LookUpGalleryByPath( 668 const base::FilePath& path, 669 MediaGalleryPrefInfo* gallery_info) const { 670 DCHECK(IsInitialized()); 671 StorageInfo info; 672 base::FilePath relative_path; 673 if (!MediaStorageUtil::GetDeviceInfoFromPath(path, &info, &relative_path)) { 674 if (gallery_info) 675 *gallery_info = MediaGalleryPrefInfo(); 676 return false; 677 } 678 679 relative_path = relative_path.NormalizePathSeparators(); 680 MediaGalleryPrefIdSet galleries_on_device = 681 LookUpGalleriesByDeviceId(info.device_id()); 682 for (MediaGalleryPrefIdSet::const_iterator it = galleries_on_device.begin(); 683 it != galleries_on_device.end(); 684 ++it) { 685 const MediaGalleryPrefInfo& gallery = known_galleries_.find(*it)->second; 686 if (gallery.path != relative_path) 687 continue; 688 689 if (gallery_info) 690 *gallery_info = gallery; 691 return true; 692 } 693 694 // This method is called by controller::FilesSelected when the user 695 // adds a new gallery. Control reaches here when the selected gallery is 696 // on a volume we know about, but have no gallery already for. Returns 697 // hypothetical data to the caller about what the prefs will look like 698 // if the gallery is added. 699 // TODO(gbillock): split this out into another function so it doesn't 700 // conflate LookUp. 701 if (gallery_info) { 702 gallery_info->pref_id = kInvalidMediaGalleryPrefId; 703 gallery_info->device_id = info.device_id(); 704 gallery_info->path = relative_path; 705 gallery_info->type = MediaGalleryPrefInfo::kInvalidType; 706 gallery_info->volume_label = info.storage_label(); 707 gallery_info->vendor_name = info.vendor_name(); 708 gallery_info->model_name = info.model_name(); 709 gallery_info->total_size_in_bytes = info.total_size_in_bytes(); 710 gallery_info->last_attach_time = base::Time::Now(); 711 gallery_info->volume_metadata_valid = true; 712 gallery_info->prefs_version = kCurrentPrefsVersion; 713 } 714 return false; 715} 716 717MediaGalleryPrefIdSet MediaGalleriesPreferences::LookUpGalleriesByDeviceId( 718 const std::string& device_id) const { 719 DeviceIdPrefIdsMap::const_iterator found = device_map_.find(device_id); 720 if (found == device_map_.end()) 721 return MediaGalleryPrefIdSet(); 722 return found->second; 723} 724 725base::FilePath MediaGalleriesPreferences::LookUpGalleryPathForExtension( 726 MediaGalleryPrefId gallery_id, 727 const extensions::Extension* extension, 728 bool include_unpermitted_galleries) { 729 DCHECK(IsInitialized()); 730 DCHECK(extension); 731 if (!include_unpermitted_galleries && 732 !ContainsKey(GalleriesForExtension(*extension), gallery_id)) 733 return base::FilePath(); 734 735 MediaGalleriesPrefInfoMap::const_iterator it = 736 known_galleries_.find(gallery_id); 737 if (it == known_galleries_.end()) 738 return base::FilePath(); 739 return MediaStorageUtil::FindDevicePathById(it->second.device_id); 740} 741 742MediaGalleryPrefId MediaGalleriesPreferences::AddGallery( 743 const std::string& device_id, 744 const base::FilePath& relative_path, 745 MediaGalleryPrefInfo::Type type, 746 const base::string16& volume_label, 747 const base::string16& vendor_name, 748 const base::string16& model_name, 749 uint64 total_size_in_bytes, 750 base::Time last_attach_time, 751 int audio_count, 752 int image_count, 753 int video_count) { 754 DCHECK(IsInitialized()); 755 return AddGalleryInternal(device_id, base::string16(), relative_path, 756 type, volume_label, vendor_name, model_name, 757 total_size_in_bytes, last_attach_time, true, 758 audio_count, image_count, video_count, 759 kCurrentPrefsVersion); 760} 761 762MediaGalleryPrefId MediaGalleriesPreferences::AddGalleryInternal( 763 const std::string& device_id, const base::string16& display_name, 764 const base::FilePath& relative_path, MediaGalleryPrefInfo::Type type, 765 const base::string16& volume_label, const base::string16& vendor_name, 766 const base::string16& model_name, uint64 total_size_in_bytes, 767 base::Time last_attach_time, bool volume_metadata_valid, 768 int audio_count, int image_count, int video_count, int prefs_version) { 769 DCHECK(type == MediaGalleryPrefInfo::kUserAdded || 770 type == MediaGalleryPrefInfo::kAutoDetected || 771 type == MediaGalleryPrefInfo::kScanResult); 772 base::FilePath normalized_relative_path = 773 relative_path.NormalizePathSeparators(); 774 MediaGalleryPrefIdSet galleries_on_device = 775 LookUpGalleriesByDeviceId(device_id); 776 for (MediaGalleryPrefIdSet::const_iterator pref_id_it = 777 galleries_on_device.begin(); 778 pref_id_it != galleries_on_device.end(); 779 ++pref_id_it) { 780 const MediaGalleryPrefInfo& existing = 781 known_galleries_.find(*pref_id_it)->second; 782 if (existing.path != normalized_relative_path) 783 continue; 784 785 bool update_gallery_type = false; 786 MediaGalleryPrefInfo::Type new_type = existing.type; 787 if (type == MediaGalleryPrefInfo::kUserAdded) { 788 if (existing.type == MediaGalleryPrefInfo::kBlackListed) { 789 new_type = MediaGalleryPrefInfo::kAutoDetected; 790 update_gallery_type = true; 791 } 792 if (existing.type == MediaGalleryPrefInfo::kRemovedScan) { 793 new_type = MediaGalleryPrefInfo::kUserAdded; 794 update_gallery_type = true; 795 } 796 } 797 798 // Status quo: In M27 and M28, galleries added manually use version 0, 799 // and galleries added automatically (including default galleries) use 800 // version 1. The name override is used by default galleries as well 801 // as all device attach events. 802 // We want to upgrade the name if the existing version is < 2. Leave it 803 // alone if the existing display name is set with version == 2 and the 804 // proposed new name is empty. 805 bool update_gallery_name = existing.display_name != display_name; 806 if (existing.prefs_version == 2 && !existing.display_name.empty() && 807 display_name.empty()) { 808 update_gallery_name = false; 809 } 810 bool update_gallery_metadata = volume_metadata_valid && 811 ((existing.volume_label != volume_label) || 812 (existing.vendor_name != vendor_name) || 813 (existing.model_name != model_name) || 814 (existing.total_size_in_bytes != total_size_in_bytes) || 815 (existing.last_attach_time != last_attach_time)); 816 817 bool update_scan_counts = 818 new_type != MediaGalleryPrefInfo::kRemovedScan && 819 new_type != MediaGalleryPrefInfo::kBlackListed && 820 (audio_count > 0 || image_count > 0 || video_count > 0 || 821 existing.audio_count || existing.image_count || existing.video_count); 822 823 if (!update_gallery_name && !update_gallery_type && 824 !update_gallery_metadata && !update_scan_counts) 825 return *pref_id_it; 826 827 PrefService* prefs = profile_->GetPrefs(); 828 scoped_ptr<ListPrefUpdate> update( 829 new ListPrefUpdate(prefs, prefs::kMediaGalleriesRememberedGalleries)); 830 base::ListValue* list = update->Get(); 831 832 for (base::ListValue::const_iterator list_iter = list->begin(); 833 list_iter != list->end(); 834 ++list_iter) { 835 base::DictionaryValue* dict; 836 MediaGalleryPrefId iter_id; 837 if ((*list_iter)->GetAsDictionary(&dict) && 838 GetPrefId(*dict, &iter_id) && 839 *pref_id_it == iter_id) { 840 if (update_gallery_type) 841 dict->SetString(kMediaGalleriesTypeKey, TypeToStringValue(new_type)); 842 if (update_gallery_name) 843 dict->SetString(kMediaGalleriesDisplayNameKey, display_name); 844 if (update_gallery_metadata) { 845 dict->SetString(kMediaGalleriesVolumeLabelKey, volume_label); 846 dict->SetString(kMediaGalleriesVendorNameKey, vendor_name); 847 dict->SetString(kMediaGalleriesModelNameKey, model_name); 848 dict->SetDouble(kMediaGalleriesSizeKey, total_size_in_bytes); 849 dict->SetDouble(kMediaGalleriesLastAttachTimeKey, 850 last_attach_time.ToInternalValue()); 851 } 852 if (update_scan_counts) { 853 dict->SetInteger(kMediaGalleriesScanAudioCountKey, audio_count); 854 dict->SetInteger(kMediaGalleriesScanImageCountKey, image_count); 855 dict->SetInteger(kMediaGalleriesScanVideoCountKey, video_count); 856 } 857 dict->SetInteger(kMediaGalleriesPrefsVersionKey, prefs_version); 858 break; 859 } 860 } 861 862 // Commits the prefs update. 863 update.reset(); 864 865 InitFromPrefs(); 866 FOR_EACH_OBSERVER(GalleryChangeObserver, gallery_change_observers_, 867 OnGalleryInfoUpdated(this, *pref_id_it)); 868 return *pref_id_it; 869 } 870 871 PrefService* prefs = profile_->GetPrefs(); 872 873 MediaGalleryPrefInfo gallery_info; 874 gallery_info.pref_id = prefs->GetUint64(prefs::kMediaGalleriesUniqueId); 875 prefs->SetUint64(prefs::kMediaGalleriesUniqueId, gallery_info.pref_id + 1); 876 gallery_info.display_name = display_name; 877 gallery_info.device_id = device_id; 878 gallery_info.path = normalized_relative_path; 879 gallery_info.type = type; 880 gallery_info.volume_label = volume_label; 881 gallery_info.vendor_name = vendor_name; 882 gallery_info.model_name = model_name; 883 gallery_info.total_size_in_bytes = total_size_in_bytes; 884 gallery_info.last_attach_time = last_attach_time; 885 gallery_info.volume_metadata_valid = volume_metadata_valid; 886 gallery_info.audio_count = audio_count; 887 gallery_info.image_count = image_count; 888 gallery_info.video_count = video_count; 889 gallery_info.prefs_version = prefs_version; 890 891 { 892 ListPrefUpdate update(prefs, prefs::kMediaGalleriesRememberedGalleries); 893 base::ListValue* list = update.Get(); 894 list->Append(CreateGalleryPrefInfoDictionary(gallery_info)); 895 } 896 InitFromPrefs(); 897 FOR_EACH_OBSERVER(GalleryChangeObserver, 898 gallery_change_observers_, 899 OnGalleryAdded(this, gallery_info.pref_id)); 900 901 return gallery_info.pref_id; 902} 903 904MediaGalleryPrefId MediaGalleriesPreferences::AddGalleryByPath( 905 const base::FilePath& path, MediaGalleryPrefInfo::Type type) { 906 DCHECK(IsInitialized()); 907 MediaGalleryPrefInfo gallery_info; 908 if (LookUpGalleryByPath(path, &gallery_info) && 909 !gallery_info.IsBlackListedType()) { 910 return gallery_info.pref_id; 911 } 912 return AddGalleryInternal(gallery_info.device_id, 913 gallery_info.display_name, 914 gallery_info.path, 915 type, 916 gallery_info.volume_label, 917 gallery_info.vendor_name, 918 gallery_info.model_name, 919 gallery_info.total_size_in_bytes, 920 gallery_info.last_attach_time, 921 gallery_info.volume_metadata_valid, 922 0, 0, 0, 923 kCurrentPrefsVersion); 924} 925 926void MediaGalleriesPreferences::ForgetGalleryById(MediaGalleryPrefId id) { 927 EraseOrBlacklistGalleryById(id, false); 928} 929 930void MediaGalleriesPreferences::EraseGalleryById(MediaGalleryPrefId id) { 931 EraseOrBlacklistGalleryById(id, true); 932} 933 934void MediaGalleriesPreferences::EraseOrBlacklistGalleryById( 935 MediaGalleryPrefId id, bool erase) { 936 DCHECK(IsInitialized()); 937 PrefService* prefs = profile_->GetPrefs(); 938 scoped_ptr<ListPrefUpdate> update(new ListPrefUpdate( 939 prefs, prefs::kMediaGalleriesRememberedGalleries)); 940 base::ListValue* list = update->Get(); 941 942 if (!ContainsKey(known_galleries_, id)) 943 return; 944 945 for (base::ListValue::iterator iter = list->begin(); 946 iter != list->end(); ++iter) { 947 base::DictionaryValue* dict; 948 MediaGalleryPrefId iter_id; 949 if ((*iter)->GetAsDictionary(&dict) && GetPrefId(*dict, &iter_id) && 950 id == iter_id) { 951 RemoveGalleryPermissionsFromPrefs(id); 952 MediaGalleryPrefInfo::Type type; 953 if (!erase && GetType(*dict, &type) && 954 (type == MediaGalleryPrefInfo::kAutoDetected || 955 type == MediaGalleryPrefInfo::kScanResult)) { 956 if (type == MediaGalleryPrefInfo::kAutoDetected) { 957 dict->SetString(kMediaGalleriesTypeKey, 958 kMediaGalleriesTypeBlackListedValue); 959 } else { 960 dict->SetString(kMediaGalleriesTypeKey, 961 kMediaGalleriesTypeRemovedScanValue); 962 dict->SetInteger(kMediaGalleriesScanAudioCountKey, 0); 963 dict->SetInteger(kMediaGalleriesScanImageCountKey, 0); 964 dict->SetInteger(kMediaGalleriesScanVideoCountKey, 0); 965 } 966 } else { 967 list->Erase(iter, NULL); 968 } 969 update.reset(NULL); // commits the update. 970 971 InitFromPrefs(); 972 FOR_EACH_OBSERVER(GalleryChangeObserver, 973 gallery_change_observers_, 974 OnGalleryRemoved(this, id)); 975 return; 976 } 977 } 978} 979 980bool MediaGalleriesPreferences::NonAutoGalleryHasPermission( 981 MediaGalleryPrefId id) const { 982 DCHECK(IsInitialized()); 983 DCHECK(!ContainsKey(known_galleries_, id) || 984 known_galleries_.find(id)->second.type != 985 MediaGalleryPrefInfo::kAutoDetected); 986 ExtensionPrefs* prefs = GetExtensionPrefs(); 987 const base::DictionaryValue* extensions = 988 prefs->pref_service()->GetDictionary(extensions::pref_names::kExtensions); 989 if (!extensions) 990 return true; 991 992 for (base::DictionaryValue::Iterator iter(*extensions); !iter.IsAtEnd(); 993 iter.Advance()) { 994 if (!extensions::Extension::IdIsValid(iter.key())) { 995 NOTREACHED(); 996 continue; 997 } 998 std::vector<MediaGalleryPermission> permissions = 999 GetGalleryPermissionsFromPrefs(iter.key()); 1000 for (std::vector<MediaGalleryPermission>::const_iterator it = 1001 permissions.begin(); it != permissions.end(); ++it) { 1002 if (it->pref_id == id) { 1003 if (it->has_permission) 1004 return true; 1005 break; 1006 } 1007 } 1008 } 1009 return false; 1010} 1011 1012MediaGalleryPrefIdSet MediaGalleriesPreferences::GalleriesForExtension( 1013 const extensions::Extension& extension) const { 1014 DCHECK(IsInitialized()); 1015 MediaGalleryPrefIdSet result; 1016 1017 if (HasAutoDetectedGalleryPermission(extension)) { 1018 for (MediaGalleriesPrefInfoMap::const_iterator it = 1019 known_galleries_.begin(); it != known_galleries_.end(); ++it) { 1020 if (it->second.type == MediaGalleryPrefInfo::kAutoDetected) 1021 result.insert(it->second.pref_id); 1022 } 1023 } 1024 1025 std::vector<MediaGalleryPermission> stored_permissions = 1026 GetGalleryPermissionsFromPrefs(extension.id()); 1027 for (std::vector<MediaGalleryPermission>::const_iterator it = 1028 stored_permissions.begin(); it != stored_permissions.end(); ++it) { 1029 if (!it->has_permission) { 1030 result.erase(it->pref_id); 1031 } else { 1032 MediaGalleriesPrefInfoMap::const_iterator gallery = 1033 known_galleries_.find(it->pref_id); 1034 DCHECK(gallery != known_galleries_.end()); 1035 if (!gallery->second.IsBlackListedType()) { 1036 result.insert(it->pref_id); 1037 } else { 1038 NOTREACHED() << gallery->second.device_id; 1039 } 1040 } 1041 } 1042 return result; 1043} 1044 1045bool MediaGalleriesPreferences::SetGalleryPermissionForExtension( 1046 const extensions::Extension& extension, 1047 MediaGalleryPrefId pref_id, 1048 bool has_permission) { 1049 DCHECK(IsInitialized()); 1050 // The gallery may not exist anymore if the user opened a second config 1051 // surface concurrently and removed it. Drop the permission update if so. 1052 MediaGalleriesPrefInfoMap::const_iterator gallery_info = 1053 known_galleries_.find(pref_id); 1054 if (gallery_info == known_galleries_.end()) 1055 return false; 1056 1057 bool default_permission = false; 1058 if (gallery_info->second.type == MediaGalleryPrefInfo::kAutoDetected) 1059 default_permission = HasAutoDetectedGalleryPermission(extension); 1060 // When the permission matches the default, we don't need to remember it. 1061 if (has_permission == default_permission) { 1062 if (!UnsetGalleryPermissionInPrefs(extension.id(), pref_id)) 1063 // If permission wasn't set, assume nothing has changed. 1064 return false; 1065 } else { 1066 if (!SetGalleryPermissionInPrefs(extension.id(), pref_id, has_permission)) 1067 return false; 1068 } 1069 if (has_permission) 1070 FOR_EACH_OBSERVER(GalleryChangeObserver, 1071 gallery_change_observers_, 1072 OnPermissionAdded(this, extension.id(), pref_id)); 1073 else 1074 FOR_EACH_OBSERVER(GalleryChangeObserver, 1075 gallery_change_observers_, 1076 OnPermissionRemoved(this, extension.id(), pref_id)); 1077 return true; 1078} 1079 1080const MediaGalleriesPrefInfoMap& MediaGalleriesPreferences::known_galleries() 1081 const { 1082 DCHECK(IsInitialized()); 1083 return known_galleries_; 1084} 1085 1086base::Time MediaGalleriesPreferences::GetLastScanCompletionTime() const { 1087 int64 last_scan_time_internal = 1088 profile_->GetPrefs()->GetInt64(prefs::kMediaGalleriesLastScanTime); 1089 return base::Time::FromInternalValue(last_scan_time_internal); 1090} 1091 1092void MediaGalleriesPreferences::SetLastScanCompletionTime( 1093 const base::Time& time) { 1094 profile_->GetPrefs()->SetInt64(prefs::kMediaGalleriesLastScanTime, 1095 time.ToInternalValue()); 1096} 1097 1098void MediaGalleriesPreferences::Shutdown() { 1099 weak_factory_.InvalidateWeakPtrs(); 1100 profile_ = NULL; 1101} 1102 1103// static 1104bool MediaGalleriesPreferences::APIHasBeenUsed(Profile* profile) { 1105 MediaGalleryPrefId current_id = 1106 profile->GetPrefs()->GetUint64(prefs::kMediaGalleriesUniqueId); 1107 return current_id != kInvalidMediaGalleryPrefId + 1; 1108} 1109 1110// static 1111void MediaGalleriesPreferences::RegisterProfilePrefs( 1112 user_prefs::PrefRegistrySyncable* registry) { 1113 registry->RegisterListPref(prefs::kMediaGalleriesRememberedGalleries, 1114 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); 1115 registry->RegisterUint64Pref( 1116 prefs::kMediaGalleriesUniqueId, 1117 kInvalidMediaGalleryPrefId + 1, 1118 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); 1119 registry->RegisterInt64Pref( 1120 prefs::kMediaGalleriesLastScanTime, 1121 base::Time().ToInternalValue(), 1122 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); 1123} 1124 1125bool MediaGalleriesPreferences::SetGalleryPermissionInPrefs( 1126 const std::string& extension_id, 1127 MediaGalleryPrefId gallery_id, 1128 bool has_access) { 1129 DCHECK(IsInitialized()); 1130 ExtensionPrefs::ScopedListUpdate update(GetExtensionPrefs(), 1131 extension_id, 1132 kMediaGalleriesPermissions); 1133 base::ListValue* permissions = update.Get(); 1134 if (!permissions) { 1135 permissions = update.Create(); 1136 } else { 1137 // If the gallery is already in the list, update the permission... 1138 for (base::ListValue::iterator iter = permissions->begin(); 1139 iter != permissions->end(); ++iter) { 1140 base::DictionaryValue* dict = NULL; 1141 if (!(*iter)->GetAsDictionary(&dict)) 1142 continue; 1143 MediaGalleryPermission perm; 1144 if (!GetMediaGalleryPermissionFromDictionary(dict, &perm)) 1145 continue; 1146 if (perm.pref_id == gallery_id) { 1147 if (has_access != perm.has_permission) { 1148 dict->SetBoolean(kMediaGalleryHasPermissionKey, has_access); 1149 return true; 1150 } else { 1151 return false; 1152 } 1153 } 1154 } 1155 } 1156 // ...Otherwise, add a new entry for the gallery. 1157 base::DictionaryValue* dict = new base::DictionaryValue; 1158 dict->SetString(kMediaGalleryIdKey, base::Uint64ToString(gallery_id)); 1159 dict->SetBoolean(kMediaGalleryHasPermissionKey, has_access); 1160 permissions->Append(dict); 1161 return true; 1162} 1163 1164bool MediaGalleriesPreferences::UnsetGalleryPermissionInPrefs( 1165 const std::string& extension_id, 1166 MediaGalleryPrefId gallery_id) { 1167 DCHECK(IsInitialized()); 1168 ExtensionPrefs::ScopedListUpdate update(GetExtensionPrefs(), 1169 extension_id, 1170 kMediaGalleriesPermissions); 1171 base::ListValue* permissions = update.Get(); 1172 if (!permissions) 1173 return false; 1174 1175 for (base::ListValue::iterator iter = permissions->begin(); 1176 iter != permissions->end(); ++iter) { 1177 const base::DictionaryValue* dict = NULL; 1178 if (!(*iter)->GetAsDictionary(&dict)) 1179 continue; 1180 MediaGalleryPermission perm; 1181 if (!GetMediaGalleryPermissionFromDictionary(dict, &perm)) 1182 continue; 1183 if (perm.pref_id == gallery_id) { 1184 permissions->Erase(iter, NULL); 1185 return true; 1186 } 1187 } 1188 return false; 1189} 1190 1191std::vector<MediaGalleryPermission> 1192MediaGalleriesPreferences::GetGalleryPermissionsFromPrefs( 1193 const std::string& extension_id) const { 1194 DCHECK(IsInitialized()); 1195 std::vector<MediaGalleryPermission> result; 1196 const base::ListValue* permissions; 1197 if (!GetExtensionPrefs()->ReadPrefAsList(extension_id, 1198 kMediaGalleriesPermissions, 1199 &permissions)) { 1200 return result; 1201 } 1202 1203 for (base::ListValue::const_iterator iter = permissions->begin(); 1204 iter != permissions->end(); ++iter) { 1205 base::DictionaryValue* dict = NULL; 1206 if (!(*iter)->GetAsDictionary(&dict)) 1207 continue; 1208 MediaGalleryPermission perm; 1209 if (!GetMediaGalleryPermissionFromDictionary(dict, &perm)) 1210 continue; 1211 result.push_back(perm); 1212 } 1213 1214 return result; 1215} 1216 1217void MediaGalleriesPreferences::RemoveGalleryPermissionsFromPrefs( 1218 MediaGalleryPrefId gallery_id) { 1219 DCHECK(IsInitialized()); 1220 ExtensionPrefs* prefs = GetExtensionPrefs(); 1221 const base::DictionaryValue* extensions = 1222 prefs->pref_service()->GetDictionary(extensions::pref_names::kExtensions); 1223 if (!extensions) 1224 return; 1225 1226 for (base::DictionaryValue::Iterator iter(*extensions); !iter.IsAtEnd(); 1227 iter.Advance()) { 1228 if (!extensions::Extension::IdIsValid(iter.key())) { 1229 NOTREACHED(); 1230 continue; 1231 } 1232 UnsetGalleryPermissionInPrefs(iter.key(), gallery_id); 1233 } 1234} 1235 1236ExtensionPrefs* MediaGalleriesPreferences::GetExtensionPrefs() const { 1237 DCHECK(IsInitialized()); 1238 if (extension_prefs_for_testing_) 1239 return extension_prefs_for_testing_; 1240 return extensions::ExtensionPrefs::Get(profile_); 1241} 1242 1243void MediaGalleriesPreferences::SetExtensionPrefsForTesting( 1244 extensions::ExtensionPrefs* extension_prefs) { 1245 DCHECK(IsInitialized()); 1246 extension_prefs_for_testing_ = extension_prefs; 1247} 1248