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