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