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