media_galleries_preferences.cc revision 90dce4d38c5ff5333bea97d859d4e484e27edf0c
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/path_service.h" 8#include "base/prefs/pref_service.h" 9#include "base/stl_util.h" 10#include "base/string16.h" 11#include "base/strings/string_number_conversions.h" 12#include "base/utf_string_conversions.h" 13#include "base/values.h" 14#include "chrome/browser/browser_process.h" 15#include "chrome/browser/extensions/api/media_galleries_private/gallery_watch_state_tracker.h" 16#include "chrome/browser/extensions/api/media_galleries_private/media_galleries_private_api.h" 17#include "chrome/browser/extensions/extension_prefs.h" 18#include "chrome/browser/extensions/extension_service.h" 19#include "chrome/browser/extensions/extension_system.h" 20#include "chrome/browser/media_galleries/fileapi/itunes_finder.h" 21#include "chrome/browser/media_galleries/fileapi/picasa/picasa_finder.h" 22#include "chrome/browser/media_galleries/media_file_system_registry.h" 23#include "chrome/browser/prefs/scoped_user_pref_update.h" 24#include "chrome/browser/profiles/profile.h" 25#include "chrome/browser/storage_monitor/media_storage_util.h" 26#include "chrome/browser/storage_monitor/storage_monitor.h" 27#include "chrome/common/chrome_paths.h" 28#include "chrome/common/extensions/extension.h" 29#include "chrome/common/extensions/permissions/api_permission.h" 30#include "chrome/common/extensions/permissions/media_galleries_permission.h" 31#include "chrome/common/extensions/permissions/permissions_data.h" 32#include "chrome/common/pref_names.h" 33#include "components/user_prefs/pref_registry_syncable.h" 34 35namespace chrome { 36 37namespace { 38 39const char kMediaGalleriesDeviceIdKey[] = "deviceId"; 40const char kMediaGalleriesDisplayNameKey[] = "displayName"; 41const char kMediaGalleriesPathKey[] = "path"; 42const char kMediaGalleriesPrefIdKey[] = "prefId"; 43const char kMediaGalleriesTypeKey[] = "type"; 44const char kMediaGalleriesVolumeLabelKey[] = "volumeLabel"; 45const char kMediaGalleriesVendorNameKey[] = "vendorName"; 46const char kMediaGalleriesModelNameKey[] = "modelName"; 47const char kMediaGalleriesSizeKey[] = "totalSize"; 48const char kMediaGalleriesLastAttachTimeKey[] = "lastAttachTime"; 49const char kMediaGalleriesPrefsVersionKey[] = "preferencesVersion"; 50 51const char kMediaGalleriesTypeAutoDetectedValue[] = "autoDetected"; 52const char kMediaGalleriesTypeUserAddedValue[] = "userAdded"; 53const char kMediaGalleriesTypeBlackListedValue[] = "blackListed"; 54 55const char kITunesGalleryName[] = "iTunes"; 56const char kPicasaGalleryName[] = "Picasa"; 57 58bool GetPrefId(const DictionaryValue& dict, MediaGalleryPrefId* value) { 59 std::string string_id; 60 if (!dict.GetString(kMediaGalleriesPrefIdKey, &string_id) || 61 !base::StringToUint64(string_id, value)) { 62 return false; 63 } 64 65 return true; 66} 67 68bool GetType(const DictionaryValue& dict, MediaGalleryPrefInfo::Type* type) { 69 std::string string_type; 70 if (!dict.GetString(kMediaGalleriesTypeKey, &string_type)) 71 return false; 72 73 if (string_type == kMediaGalleriesTypeAutoDetectedValue) { 74 *type = MediaGalleryPrefInfo::kAutoDetected; 75 return true; 76 } 77 if (string_type == kMediaGalleriesTypeUserAddedValue) { 78 *type = MediaGalleryPrefInfo::kUserAdded; 79 return true; 80 } 81 if (string_type == kMediaGalleriesTypeBlackListedValue) { 82 *type = MediaGalleryPrefInfo::kBlackListed; 83 return true; 84 } 85 86 return false; 87} 88 89bool PopulateGalleryPrefInfoFromDictionary( 90 const DictionaryValue& dict, MediaGalleryPrefInfo* out_gallery_info) { 91 MediaGalleryPrefId pref_id; 92 string16 display_name; 93 std::string device_id; 94 base::FilePath::StringType path; 95 MediaGalleryPrefInfo::Type type = MediaGalleryPrefInfo::kAutoDetected; 96 string16 volume_label; 97 string16 vendor_name; 98 string16 model_name; 99 double total_size_in_bytes = 0.0; 100 double last_attach_time = 0.0; 101 bool volume_metadata_valid = false; 102 int prefs_version = 0; 103 104 if (!GetPrefId(dict, &pref_id) || 105 !dict.GetString(kMediaGalleriesDeviceIdKey, &device_id) || 106 !dict.GetString(kMediaGalleriesPathKey, &path) || 107 !GetType(dict, &type)) { 108 return false; 109 } 110 111 dict.GetString(kMediaGalleriesDisplayNameKey, &display_name); 112 dict.GetInteger(kMediaGalleriesPrefsVersionKey, &prefs_version); 113 114 if (dict.GetString(kMediaGalleriesVolumeLabelKey, &volume_label) && 115 dict.GetString(kMediaGalleriesVendorNameKey, &vendor_name) && 116 dict.GetString(kMediaGalleriesModelNameKey, &model_name) && 117 dict.GetDouble(kMediaGalleriesSizeKey, &total_size_in_bytes) && 118 dict.GetDouble(kMediaGalleriesLastAttachTimeKey, &last_attach_time)) { 119 volume_metadata_valid = true; 120 } 121 122 out_gallery_info->pref_id = pref_id; 123 out_gallery_info->display_name = display_name; 124 out_gallery_info->device_id = device_id; 125 out_gallery_info->path = base::FilePath(path); 126 out_gallery_info->type = type; 127 out_gallery_info->volume_label = volume_label; 128 out_gallery_info->vendor_name = vendor_name; 129 out_gallery_info->model_name = model_name; 130 out_gallery_info->total_size_in_bytes = total_size_in_bytes; 131 out_gallery_info->last_attach_time = 132 base::Time::FromInternalValue(last_attach_time); 133 out_gallery_info->volume_metadata_valid = volume_metadata_valid; 134 out_gallery_info->prefs_version = prefs_version; 135 136 return true; 137} 138 139DictionaryValue* CreateGalleryPrefInfoDictionary( 140 const MediaGalleryPrefInfo& gallery) { 141 DictionaryValue* dict = new DictionaryValue(); 142 dict->SetString(kMediaGalleriesPrefIdKey, 143 base::Uint64ToString(gallery.pref_id)); 144 if (!gallery.volume_metadata_valid) 145 dict->SetString(kMediaGalleriesDisplayNameKey, gallery.display_name); 146 dict->SetString(kMediaGalleriesDeviceIdKey, gallery.device_id); 147 dict->SetString(kMediaGalleriesPathKey, gallery.path.value()); 148 149 const char* type = NULL; 150 switch (gallery.type) { 151 case MediaGalleryPrefInfo::kAutoDetected: 152 type = kMediaGalleriesTypeAutoDetectedValue; 153 break; 154 case MediaGalleryPrefInfo::kUserAdded: 155 type = kMediaGalleriesTypeUserAddedValue; 156 break; 157 case MediaGalleryPrefInfo::kBlackListed: 158 type = kMediaGalleriesTypeBlackListedValue; 159 break; 160 default: 161 NOTREACHED(); 162 break; 163 } 164 dict->SetString(kMediaGalleriesTypeKey, type); 165 166 if (gallery.volume_metadata_valid) { 167 dict->SetString(kMediaGalleriesVolumeLabelKey, gallery.volume_label); 168 dict->SetString(kMediaGalleriesVendorNameKey, gallery.vendor_name); 169 dict->SetString(kMediaGalleriesModelNameKey, gallery.model_name); 170 dict->SetDouble(kMediaGalleriesSizeKey, gallery.total_size_in_bytes); 171 dict->SetDouble(kMediaGalleriesLastAttachTimeKey, 172 gallery.last_attach_time.ToInternalValue()); 173 } 174 175 // Version 0 of the prefs format was that the display_name was always 176 // used to show the user-visible name of the gallery. Version 1 means 177 // that there is an optional display_name, and when it is present, it 178 // overrides the name that would be built from the volume metadata, path, 179 // or whatever other data. So if we see a display_name with version 0, it 180 // means it may be overwritten simply by getting new volume metadata. 181 // A display_name with version 1 should not be overwritten. 182 dict->SetInteger(kMediaGalleriesPrefsVersionKey, gallery.prefs_version); 183 184 return dict; 185} 186 187bool HasAutoDetectedGalleryPermission(const extensions::Extension& extension) { 188 extensions::MediaGalleriesPermission::CheckParam param( 189 extensions::MediaGalleriesPermission::kAllAutoDetectedPermission); 190 return extensions::PermissionsData::CheckAPIPermissionWithParam( 191 &extension, extensions::APIPermission::kMediaGalleries, ¶m); 192} 193 194} // namespace 195 196MediaGalleryPrefInfo::MediaGalleryPrefInfo() 197 : pref_id(kInvalidMediaGalleryPrefId), 198 type(kInvalidType), 199 total_size_in_bytes(0), 200 volume_metadata_valid(false), 201 prefs_version(0) { 202} 203 204MediaGalleryPrefInfo::~MediaGalleryPrefInfo() {} 205 206base::FilePath MediaGalleryPrefInfo::AbsolutePath() const { 207 base::FilePath base_path = MediaStorageUtil::FindDevicePathById(device_id); 208 DCHECK(!path.IsAbsolute()); 209 return base_path.empty() ? base_path : base_path.Append(path); 210} 211 212MediaGalleriesPreferences::GalleryChangeObserver::~GalleryChangeObserver() {} 213 214MediaGalleriesPreferences::MediaGalleriesPreferences(Profile* profile) 215 : weak_factory_(this), 216 profile_(profile) { 217 AddDefaultGalleriesIfFreshProfile(); 218 219 // TODO(vandebo) Turn this back on when the iTunes code is ready. 220 // Temporarily turned off because it adds an extra user-visible entry to the 221 // preferences that does not quite work. 222#if 0 223 // Look for optional default galleries every time. 224 itunes::ITunesFinder::FindITunesLibrary( 225 base::Bind(&MediaGalleriesPreferences::OnITunesDeviceID, 226 weak_factory_.GetWeakPtr())); 227#endif 228 229 // TODO(tommycli): Turn on when Picasa code is ready. 230#if 0 231 picasa::PicasaFinder::FindPicasaDatabaseOnUIThread( 232 base::Bind(&MediaGalleriesPreferences::OnPicasaDeviceID, 233 weak_factory_.GetWeakPtr())); 234#endif 235 236 InitFromPrefs(false /*no notification*/); 237 238 StorageMonitor* monitor = StorageMonitor::GetInstance(); 239 if (monitor) 240 monitor->AddObserver(this); 241} 242 243MediaGalleriesPreferences::~MediaGalleriesPreferences() { 244 StorageMonitor* monitor = StorageMonitor::GetInstance(); 245 if (monitor) 246 monitor->RemoveObserver(this); 247} 248 249void MediaGalleriesPreferences::AddDefaultGalleriesIfFreshProfile() { 250 // Only add defaults the first time. 251 if (APIHasBeenUsed(profile_)) 252 return; 253 254 // Fresh profile case. 255 const int kDirectoryKeys[] = { 256 DIR_USER_MUSIC, 257 DIR_USER_PICTURES, 258 DIR_USER_VIDEOS, 259 }; 260 261 for (size_t i = 0; i < arraysize(kDirectoryKeys); ++i) { 262 base::FilePath path; 263 if (!PathService::Get(kDirectoryKeys[i], &path)) 264 continue; 265 266 base::FilePath relative_path; 267 StorageInfo info; 268 if (MediaStorageUtil::GetDeviceInfoFromPath(path, &info, &relative_path)) { 269 // TODO(gbillock): Add in the volume metadata here when available. 270 AddGalleryWithName(info.device_id(), info.name(), relative_path, 271 false /*user added*/); 272 } 273 } 274} 275 276void MediaGalleriesPreferences::OnITunesDeviceID(const std::string& device_id) { 277 DCHECK(!device_id.empty()); 278 AddGalleryWithName(device_id, ASCIIToUTF16(kITunesGalleryName), 279 base::FilePath(), false /*not user added*/); 280} 281 282void MediaGalleriesPreferences::OnPicasaDeviceID(const std::string& device_id) { 283 // TODO(tommycli): Implement support for location moves. 284 DCHECK(!device_id.empty()); 285 AddGalleryWithName(device_id, ASCIIToUTF16(kPicasaGalleryName), 286 base::FilePath(), false /*not user added*/); 287} 288 289void MediaGalleriesPreferences::InitFromPrefs(bool notify_observers) { 290 known_galleries_.clear(); 291 device_map_.clear(); 292 293 PrefService* prefs = profile_->GetPrefs(); 294 const ListValue* list = prefs->GetList( 295 prefs::kMediaGalleriesRememberedGalleries); 296 if (list) { 297 for (ListValue::const_iterator it = list->begin(); 298 it != list->end(); ++it) { 299 const DictionaryValue* dict = NULL; 300 if (!(*it)->GetAsDictionary(&dict)) 301 continue; 302 303 MediaGalleryPrefInfo gallery_info; 304 if (!PopulateGalleryPrefInfoFromDictionary(*dict, &gallery_info)) 305 continue; 306 307 known_galleries_[gallery_info.pref_id] = gallery_info; 308 device_map_[gallery_info.device_id].insert(gallery_info.pref_id); 309 } 310 } 311 if (notify_observers) 312 NotifyChangeObservers(std::string()); 313} 314 315void MediaGalleriesPreferences::NotifyChangeObservers( 316 const std::string& extension_id) { 317 FOR_EACH_OBSERVER(GalleryChangeObserver, 318 gallery_change_observers_, 319 OnGalleryChanged(this, extension_id)); 320} 321 322void MediaGalleriesPreferences::AddGalleryChangeObserver( 323 GalleryChangeObserver* observer) { 324 gallery_change_observers_.AddObserver(observer); 325} 326 327void MediaGalleriesPreferences::RemoveGalleryChangeObserver( 328 GalleryChangeObserver* observer) { 329 gallery_change_observers_.RemoveObserver(observer); 330} 331 332void MediaGalleriesPreferences::OnRemovableStorageAttached( 333 const StorageInfo& info) { 334 if (!StorageInfo::IsMediaDevice(info.device_id())) 335 return; 336 337 if (info.name().empty()) { 338 AddGallery(info.device_id(), 339 base::FilePath(), 340 false /*not user added*/, 341 info.storage_label(), 342 info.vendor_name(), 343 info.model_name(), 344 info.total_size_in_bytes(), 345 base::Time::Now()); 346 } else { 347 // TODO(gbillock): get rid of this code path. 348 AddGalleryWithName(info.device_id(), info.name(), base::FilePath(), false); 349 } 350} 351 352bool MediaGalleriesPreferences::LookUpGalleryByPath( 353 const base::FilePath& path, 354 MediaGalleryPrefInfo* gallery_info) const { 355 StorageInfo info; 356 base::FilePath relative_path; 357 if (!MediaStorageUtil::GetDeviceInfoFromPath(path, &info, &relative_path)) { 358 if (gallery_info) 359 *gallery_info = MediaGalleryPrefInfo(); 360 return false; 361 } 362 363 relative_path = relative_path.NormalizePathSeparators(); 364 MediaGalleryPrefIdSet galleries_on_device = 365 LookUpGalleriesByDeviceId(info.device_id()); 366 for (MediaGalleryPrefIdSet::const_iterator it = galleries_on_device.begin(); 367 it != galleries_on_device.end(); 368 ++it) { 369 const MediaGalleryPrefInfo& gallery = known_galleries_.find(*it)->second; 370 if (gallery.path != relative_path) 371 continue; 372 373 if (gallery_info) 374 *gallery_info = gallery; 375 return true; 376 } 377 378 // This method is called by controller::FilesSelected when the user 379 // adds a new gallery. Control reaches here when the selected gallery is 380 // on a volume we know about, but have no gallery already for. Returns 381 // hypothetical data to the caller about what the prefs will look like 382 // if the gallery is added. 383 // TODO(gbillock): split this out into another function so it doesn't 384 // conflate LookUp. 385 if (gallery_info) { 386 gallery_info->pref_id = kInvalidMediaGalleryPrefId; 387 gallery_info->display_name = info.name(); 388 gallery_info->device_id = info.device_id(); 389 gallery_info->path = relative_path; 390 gallery_info->type = MediaGalleryPrefInfo::kUserAdded; 391 // TODO(gbillock): Need to add volume metadata here from |info|. 392 } 393 return false; 394} 395 396MediaGalleryPrefIdSet MediaGalleriesPreferences::LookUpGalleriesByDeviceId( 397 const std::string& device_id) const { 398 DeviceIdPrefIdsMap::const_iterator found = device_map_.find(device_id); 399 if (found == device_map_.end()) 400 return MediaGalleryPrefIdSet(); 401 return found->second; 402} 403 404base::FilePath MediaGalleriesPreferences::LookUpGalleryPathForExtension( 405 MediaGalleryPrefId gallery_id, 406 const extensions::Extension* extension, 407 bool include_unpermitted_galleries) { 408 DCHECK(extension); 409 if (!include_unpermitted_galleries && 410 !ContainsKey(GalleriesForExtension(*extension), gallery_id)) 411 return base::FilePath(); 412 413 MediaGalleriesPrefInfoMap::const_iterator it = 414 known_galleries_.find(gallery_id); 415 if (it == known_galleries_.end()) 416 return base::FilePath(); 417 return MediaStorageUtil::FindDevicePathById(it->second.device_id); 418} 419 420MediaGalleryPrefId MediaGalleriesPreferences::AddGallery( 421 const std::string& device_id, 422 const base::FilePath& relative_path, bool user_added, 423 const string16& volume_label, const string16& vendor_name, 424 const string16& model_name, uint64 total_size_in_bytes, 425 base::Time last_attach_time) { 426 return AddGalleryInternal(device_id, string16(), relative_path, user_added, 427 volume_label, vendor_name, model_name, 428 total_size_in_bytes, last_attach_time, true, 1); 429} 430 431MediaGalleryPrefId MediaGalleriesPreferences::AddGalleryWithName( 432 const std::string& device_id, const string16& display_name, 433 const base::FilePath& relative_path, bool user_added) { 434 return AddGalleryInternal(device_id, display_name, relative_path, user_added, 435 string16(), string16(), string16(), 436 0, base::Time(), false, 1); 437} 438 439MediaGalleryPrefId MediaGalleriesPreferences::AddGalleryInternal( 440 const std::string& device_id, const string16& display_name, 441 const base::FilePath& relative_path, bool user_added, 442 const string16& volume_label, const string16& vendor_name, 443 const string16& model_name, uint64 total_size_in_bytes, 444 base::Time last_attach_time, 445 bool volume_metadata_valid, 446 int prefs_version) { 447 base::FilePath normalized_relative_path = 448 relative_path.NormalizePathSeparators(); 449 MediaGalleryPrefIdSet galleries_on_device = 450 LookUpGalleriesByDeviceId(device_id); 451 for (MediaGalleryPrefIdSet::const_iterator it = galleries_on_device.begin(); 452 it != galleries_on_device.end(); 453 ++it) { 454 const MediaGalleryPrefInfo& existing = known_galleries_.find(*it)->second; 455 if (existing.path != normalized_relative_path) 456 continue; 457 458 bool update_gallery_type = 459 user_added && (existing.type == MediaGalleryPrefInfo::kBlackListed); 460 // TODO(gbillock): Once we have all updates adding the device metadata, 461 // we'll change this to always update the gallery name if we have device 462 // metadata. 463 // Status quo: In M27 and M28, galleries added manually use version 0, 464 // and galleries added automatically (including default galleries) use 465 // version 1. The name override is used by default galleries as well 466 // as all device attach events. 467 bool update_gallery_name = existing.display_name != display_name; 468 bool update_gallery_metadata = volume_metadata_valid && 469 ((existing.volume_label != volume_label) || 470 (existing.vendor_name != vendor_name) || 471 (existing.model_name != model_name) || 472 (existing.total_size_in_bytes != total_size_in_bytes) || 473 (existing.last_attach_time != last_attach_time)); 474 475 if (!update_gallery_name && !update_gallery_type && 476 !update_gallery_metadata) 477 return *it; 478 479 PrefService* prefs = profile_->GetPrefs(); 480 scoped_ptr<ListPrefUpdate> update( 481 new ListPrefUpdate(prefs, prefs::kMediaGalleriesRememberedGalleries)); 482 ListValue* list = update->Get(); 483 484 for (ListValue::const_iterator list_iter = list->begin(); 485 list_iter != list->end(); 486 ++list_iter) { 487 DictionaryValue* dict; 488 MediaGalleryPrefId iter_id; 489 if ((*list_iter)->GetAsDictionary(&dict) && 490 GetPrefId(*dict, &iter_id) && 491 *it == iter_id) { 492 if (update_gallery_type) { 493 dict->SetString(kMediaGalleriesTypeKey, 494 kMediaGalleriesTypeAutoDetectedValue); 495 } 496 if (update_gallery_name) 497 dict->SetString(kMediaGalleriesDisplayNameKey, display_name); 498 if (update_gallery_metadata) { 499 dict->SetString(kMediaGalleriesVolumeLabelKey, volume_label); 500 dict->SetString(kMediaGalleriesVendorNameKey, vendor_name); 501 dict->SetString(kMediaGalleriesModelNameKey, model_name); 502 dict->SetDouble(kMediaGalleriesSizeKey, total_size_in_bytes); 503 dict->SetDouble(kMediaGalleriesLastAttachTimeKey, 504 last_attach_time.ToInternalValue()); 505 } 506 dict->SetInteger(kMediaGalleriesPrefsVersionKey, prefs_version); 507 break; 508 } 509 } 510 511 // Commits the prefs update. 512 update.reset(); 513 514 if (update_gallery_name || update_gallery_metadata || update_gallery_type) 515 InitFromPrefs(true /* notify observers */); 516 return *it; 517 } 518 519 PrefService* prefs = profile_->GetPrefs(); 520 521 MediaGalleryPrefInfo gallery_info; 522 gallery_info.pref_id = prefs->GetUint64(prefs::kMediaGalleriesUniqueId); 523 prefs->SetUint64(prefs::kMediaGalleriesUniqueId, gallery_info.pref_id + 1); 524 gallery_info.display_name = display_name; 525 gallery_info.device_id = device_id; 526 gallery_info.path = normalized_relative_path; 527 gallery_info.type = MediaGalleryPrefInfo::kAutoDetected; 528 if (user_added) 529 gallery_info.type = MediaGalleryPrefInfo::kUserAdded; 530 if (volume_metadata_valid) { 531 gallery_info.volume_label = volume_label; 532 gallery_info.vendor_name = vendor_name; 533 gallery_info.model_name = model_name; 534 gallery_info.total_size_in_bytes = total_size_in_bytes; 535 gallery_info.last_attach_time = last_attach_time; 536 } 537 gallery_info.volume_metadata_valid = volume_metadata_valid; 538 gallery_info.prefs_version = prefs_version; 539 540 { 541 ListPrefUpdate update(prefs, prefs::kMediaGalleriesRememberedGalleries); 542 ListValue* list = update.Get(); 543 list->Append(CreateGalleryPrefInfoDictionary(gallery_info)); 544 } 545 InitFromPrefs(true /* notify observers */); 546 547 return gallery_info.pref_id; 548} 549 550MediaGalleryPrefId MediaGalleriesPreferences::AddGalleryByPath( 551 const base::FilePath& path) { 552 MediaGalleryPrefInfo gallery_info; 553 if (LookUpGalleryByPath(path, &gallery_info) && 554 gallery_info.type != MediaGalleryPrefInfo::kBlackListed) { 555 return gallery_info.pref_id; 556 } 557 return AddGalleryInternal(gallery_info.device_id, 558 gallery_info.display_name, 559 gallery_info.path, 560 true /*user added*/, 561 gallery_info.volume_label, 562 gallery_info.vendor_name, 563 gallery_info.model_name, 564 gallery_info.total_size_in_bytes, 565 gallery_info.last_attach_time, 566 gallery_info.volume_metadata_valid, 567 gallery_info.prefs_version); 568} 569 570void MediaGalleriesPreferences::ForgetGalleryById(MediaGalleryPrefId pref_id) { 571 PrefService* prefs = profile_->GetPrefs(); 572 scoped_ptr<ListPrefUpdate> update(new ListPrefUpdate( 573 prefs, prefs::kMediaGalleriesRememberedGalleries)); 574 ListValue* list = update->Get(); 575 576 if (!ContainsKey(known_galleries_, pref_id)) 577 return; 578 579 for (ListValue::iterator iter = list->begin(); iter != list->end(); ++iter) { 580 DictionaryValue* dict; 581 MediaGalleryPrefId iter_id; 582 if ((*iter)->GetAsDictionary(&dict) && GetPrefId(*dict, &iter_id) && 583 pref_id == iter_id) { 584 extensions::MediaGalleriesPrivateAPI::RemoveMediaGalleryPermissions( 585 GetExtensionPrefs(), pref_id); 586 MediaGalleryPrefInfo::Type type; 587 if (GetType(*dict, &type) && 588 type == MediaGalleryPrefInfo::kAutoDetected) { 589 dict->SetString(kMediaGalleriesTypeKey, 590 kMediaGalleriesTypeBlackListedValue); 591 } else { 592 list->Erase(iter, NULL); 593 } 594 update.reset(NULL); // commits the update. 595 596 InitFromPrefs(true /* notify observers */); 597 return; 598 } 599 } 600} 601 602MediaGalleryPrefIdSet MediaGalleriesPreferences::GalleriesForExtension( 603 const extensions::Extension& extension) const { 604 MediaGalleryPrefIdSet result; 605 606 if (HasAutoDetectedGalleryPermission(extension)) { 607 for (MediaGalleriesPrefInfoMap::const_iterator it = 608 known_galleries_.begin(); it != known_galleries_.end(); ++it) { 609 if (it->second.type == MediaGalleryPrefInfo::kAutoDetected) 610 result.insert(it->second.pref_id); 611 } 612 } 613 614 std::vector<MediaGalleryPermission> stored_permissions = 615 extensions::MediaGalleriesPrivateAPI::GetMediaGalleryPermissions( 616 GetExtensionPrefs(), extension.id()); 617 for (std::vector<MediaGalleryPermission>::const_iterator it = 618 stored_permissions.begin(); it != stored_permissions.end(); ++it) { 619 if (!it->has_permission) { 620 result.erase(it->pref_id); 621 } else { 622 MediaGalleriesPrefInfoMap::const_iterator gallery = 623 known_galleries_.find(it->pref_id); 624 DCHECK(gallery != known_galleries_.end()); 625 if (gallery->second.type != MediaGalleryPrefInfo::kBlackListed) { 626 result.insert(it->pref_id); 627 } else { 628 NOTREACHED() << gallery->second.device_id; 629 } 630 } 631 } 632 return result; 633} 634 635void MediaGalleriesPreferences::SetGalleryPermissionForExtension( 636 const extensions::Extension& extension, 637 MediaGalleryPrefId pref_id, 638 bool has_permission) { 639 // The gallery may not exist anymore if the user opened a second config 640 // surface concurrently and removed it. Drop the permission update if so. 641 MediaGalleriesPrefInfoMap::const_iterator gallery_info = 642 known_galleries_.find(pref_id); 643 if (gallery_info == known_galleries_.end()) 644 return; 645 646#if defined(ENABLE_EXTENSIONS) 647 extensions::GalleryWatchStateTracker* state_tracker = 648 extensions::GalleryWatchStateTracker::GetForProfile(profile_); 649#endif 650 bool all_permission = HasAutoDetectedGalleryPermission(extension); 651 if (has_permission && all_permission) { 652 if (gallery_info->second.type == MediaGalleryPrefInfo::kAutoDetected) { 653 extensions::MediaGalleriesPrivateAPI::UnsetMediaGalleryPermission( 654 GetExtensionPrefs(), extension.id(), pref_id); 655 NotifyChangeObservers(extension.id()); 656#if defined(ENABLE_EXTENSIONS) 657 if (state_tracker) { 658 state_tracker->OnGalleryPermissionChanged(extension.id(), pref_id, 659 true); 660 } 661#endif 662 return; 663 } 664 } 665 666 if (!has_permission && !all_permission) { 667 extensions::MediaGalleriesPrivateAPI::UnsetMediaGalleryPermission( 668 GetExtensionPrefs(), extension.id(), pref_id); 669 } else { 670 extensions::MediaGalleriesPrivateAPI::SetMediaGalleryPermission( 671 GetExtensionPrefs(), extension.id(), pref_id, has_permission); 672 } 673 NotifyChangeObservers(extension.id()); 674#if defined(ENABLE_EXTENSIONS) 675 if (state_tracker) { 676 state_tracker->OnGalleryPermissionChanged(extension.id(), pref_id, 677 has_permission); 678 } 679#endif 680} 681 682void MediaGalleriesPreferences::Shutdown() { 683 weak_factory_.InvalidateWeakPtrs(); 684 profile_ = NULL; 685} 686 687// static 688bool MediaGalleriesPreferences::APIHasBeenUsed(Profile* profile) { 689 MediaGalleryPrefId current_id = 690 profile->GetPrefs()->GetUint64(prefs::kMediaGalleriesUniqueId); 691 return current_id != kInvalidMediaGalleryPrefId + 1; 692} 693 694// static 695void MediaGalleriesPreferences::RegisterUserPrefs( 696 user_prefs::PrefRegistrySyncable* registry) { 697 registry->RegisterListPref(prefs::kMediaGalleriesRememberedGalleries, 698 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); 699 registry->RegisterUint64Pref( 700 prefs::kMediaGalleriesUniqueId, 701 kInvalidMediaGalleryPrefId + 1, 702 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); 703} 704 705extensions::ExtensionPrefs* 706MediaGalleriesPreferences::GetExtensionPrefs() const { 707 ExtensionService* extension_service = 708 extensions::ExtensionSystem::Get(profile_)->extension_service(); 709 return extension_service->extension_prefs(); 710} 711 712} // namespace chrome 713