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/media_galleries/fileapi/iapps_finder.h"
20 #include "chrome/browser/media_galleries/fileapi/picasa_finder.h"
21 #include "chrome/browser/media_galleries/imported_media_gallery_registry.h"
22 #include "chrome/browser/media_galleries/media_file_system_registry.h"
23 #include "chrome/browser/media_galleries/media_galleries_histograms.h"
24 #include "chrome/browser/profiles/profile.h"
25 #include "chrome/common/chrome_paths.h"
26 #include "chrome/common/pref_names.h"
27 #include "chrome/grit/generated_resources.h"
28 #include "components/crx_file/id_util.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_registry.h"
35 #include "extensions/browser/pref_names.h"
36 #include "extensions/common/extension_set.h"
37 #include "extensions/common/permissions/api_permission.h"
38 #include "extensions/common/permissions/media_galleries_permission.h"
39 #include "extensions/common/permissions/permissions_data.h"
40 #include "ui/base/l10n/l10n_util.h"
42 using base::DictionaryValue
;
43 using base::ListValue
;
44 using extensions::ExtensionPrefs
;
45 using storage_monitor::MediaStorageUtil
;
46 using storage_monitor::StorageInfo
;
47 using storage_monitor::StorageMonitor
;
51 // Pref key for the list of media gallery permissions.
52 const char kMediaGalleriesPermissions
[] = "media_galleries_permissions";
53 // Pref key for Media Gallery ID.
54 const char kMediaGalleryIdKey
[] = "id";
55 // Pref key for Media Gallery Permission Value.
56 const char kMediaGalleryHasPermissionKey
[] = "has_permission";
58 const char kMediaGalleriesDeviceIdKey
[] = "deviceId";
59 const char kMediaGalleriesDisplayNameKey
[] = "displayName";
60 const char kMediaGalleriesPathKey
[] = "path";
61 const char kMediaGalleriesPrefIdKey
[] = "prefId";
62 const char kMediaGalleriesTypeKey
[] = "type";
63 const char kMediaGalleriesVolumeLabelKey
[] = "volumeLabel";
64 const char kMediaGalleriesVendorNameKey
[] = "vendorName";
65 const char kMediaGalleriesModelNameKey
[] = "modelName";
66 const char kMediaGalleriesSizeKey
[] = "totalSize";
67 const char kMediaGalleriesLastAttachTimeKey
[] = "lastAttachTime";
68 const char kMediaGalleriesScanAudioCountKey
[] = "audioCount";
69 const char kMediaGalleriesScanImageCountKey
[] = "imageCount";
70 const char kMediaGalleriesScanVideoCountKey
[] = "videoCount";
72 const char kMediaGalleriesTypeAutoDetectedValue
[] = "autoDetected";
73 const char kMediaGalleriesTypeBlackListedValue
[] = "blackListed";
74 const char kMediaGalleriesTypeRemovedScanValue
[] = "removedScan";
75 const char kMediaGalleriesTypeScanResultValue
[] = "scanResult";
76 const char kMediaGalleriesTypeUserAddedValue
[] = "userAdded";
78 const char kMediaGalleriesDefaultGalleryTypeNotDefaultValue
[] = "notDefault";
79 const char kMediaGalleriesDefaultGalleryTypeMusicDefaultValue
[] = "music";
80 const char kMediaGalleriesDefaultGalleryTypePicturesDefaultValue
[] = "pictures";
81 const char kMediaGalleriesDefaultGalleryTypeVideosDefaultValue
[] = "videos";
83 const char kIPhotoGalleryName
[] = "iPhoto";
84 const char kITunesGalleryName
[] = "iTunes";
85 const char kPicasaGalleryName
[] = "Picasa";
87 const int kCurrentPrefsVersion
= 3;
89 int NumberExtensionsUsingMediaGalleries(Profile
* profile
) {
94 for (const scoped_refptr
<const extensions::Extension
>& extension
:
95 extensions::ExtensionRegistry::Get(profile
)->enabled_extensions()) {
96 const extensions::PermissionsData
* permissions_data
=
97 extension
->permissions_data();
98 if (permissions_data
->HasAPIPermission(
99 extensions::APIPermission::kMediaGalleries
)) {
106 bool GetPrefId(const base::DictionaryValue
& dict
, MediaGalleryPrefId
* value
) {
107 std::string string_id
;
108 if (!dict
.GetString(kMediaGalleriesPrefIdKey
, &string_id
) ||
109 !base::StringToUint64(string_id
, value
)) {
116 bool GetType(const base::DictionaryValue
& dict
,
117 MediaGalleryPrefInfo::Type
* type
) {
118 std::string string_type
;
119 if (!dict
.GetString(kMediaGalleriesTypeKey
, &string_type
))
122 if (string_type
== kMediaGalleriesTypeUserAddedValue
) {
123 *type
= MediaGalleryPrefInfo::kUserAdded
;
126 if (string_type
== kMediaGalleriesTypeAutoDetectedValue
) {
127 *type
= MediaGalleryPrefInfo::kAutoDetected
;
130 if (string_type
== kMediaGalleriesTypeBlackListedValue
) {
131 *type
= MediaGalleryPrefInfo::kBlackListed
;
134 if (string_type
== kMediaGalleriesTypeScanResultValue
) {
135 *type
= MediaGalleryPrefInfo::kScanResult
;
138 if (string_type
== kMediaGalleriesTypeRemovedScanValue
) {
139 *type
= MediaGalleryPrefInfo::kRemovedScan
;
146 const char* TypeToStringValue(MediaGalleryPrefInfo::Type type
) {
147 const char* result
= NULL
;
149 case MediaGalleryPrefInfo::kUserAdded
:
150 result
= kMediaGalleriesTypeUserAddedValue
;
152 case MediaGalleryPrefInfo::kAutoDetected
:
153 result
= kMediaGalleriesTypeAutoDetectedValue
;
155 case MediaGalleryPrefInfo::kBlackListed
:
156 result
= kMediaGalleriesTypeBlackListedValue
;
158 case MediaGalleryPrefInfo::kScanResult
:
159 result
= kMediaGalleriesTypeScanResultValue
;
161 case MediaGalleryPrefInfo::kRemovedScan
:
162 result
= kMediaGalleriesTypeRemovedScanValue
;
171 MediaGalleryPrefInfo::DefaultGalleryType
GetDefaultGalleryType(
172 const base::DictionaryValue
& dict
) {
173 std::string default_gallery_type_string
;
175 kMediaGalleriesDefaultGalleryTypeKey
, &default_gallery_type_string
))
176 return MediaGalleryPrefInfo::kNotDefault
;
178 if (default_gallery_type_string
==
179 kMediaGalleriesDefaultGalleryTypeMusicDefaultValue
) {
180 return MediaGalleryPrefInfo::kMusicDefault
;
182 if (default_gallery_type_string
==
183 kMediaGalleriesDefaultGalleryTypePicturesDefaultValue
) {
184 return MediaGalleryPrefInfo::kPicturesDefault
;
186 if (default_gallery_type_string
==
187 kMediaGalleriesDefaultGalleryTypeVideosDefaultValue
) {
188 return MediaGalleryPrefInfo::kVideosDefault
;
190 return MediaGalleryPrefInfo::kNotDefault
;
193 const char* DefaultGalleryTypeToStringValue(
194 MediaGalleryPrefInfo::DefaultGalleryType default_gallery_type
) {
195 const char* result
= NULL
;
196 switch (default_gallery_type
) {
197 case MediaGalleryPrefInfo::kNotDefault
:
198 result
= kMediaGalleriesDefaultGalleryTypeNotDefaultValue
;
200 case MediaGalleryPrefInfo::kMusicDefault
:
201 result
= kMediaGalleriesDefaultGalleryTypeMusicDefaultValue
;
203 case MediaGalleryPrefInfo::kPicturesDefault
:
204 result
= kMediaGalleriesDefaultGalleryTypePicturesDefaultValue
;
206 case MediaGalleryPrefInfo::kVideosDefault
:
207 result
= kMediaGalleriesDefaultGalleryTypeVideosDefaultValue
;
216 bool PopulateGalleryPrefInfoFromDictionary(
217 const base::DictionaryValue
& dict
, MediaGalleryPrefInfo
* out_gallery_info
) {
218 MediaGalleryPrefId pref_id
;
219 base::string16 display_name
;
220 std::string device_id
;
221 base::FilePath::StringType path
;
222 MediaGalleryPrefInfo::Type type
= MediaGalleryPrefInfo::kInvalidType
;
223 base::string16 volume_label
;
224 base::string16 vendor_name
;
225 base::string16 model_name
;
226 double total_size_in_bytes
= 0.0;
227 double last_attach_time
= 0.0;
228 bool volume_metadata_valid
= false;
232 int prefs_version
= 0;
234 if (!GetPrefId(dict
, &pref_id
) ||
235 !dict
.GetString(kMediaGalleriesDeviceIdKey
, &device_id
) ||
236 !dict
.GetString(kMediaGalleriesPathKey
, &path
) ||
237 !GetType(dict
, &type
)) {
241 dict
.GetString(kMediaGalleriesDisplayNameKey
, &display_name
);
242 dict
.GetInteger(kMediaGalleriesPrefsVersionKey
, &prefs_version
);
244 if (dict
.GetString(kMediaGalleriesVolumeLabelKey
, &volume_label
) &&
245 dict
.GetString(kMediaGalleriesVendorNameKey
, &vendor_name
) &&
246 dict
.GetString(kMediaGalleriesModelNameKey
, &model_name
) &&
247 dict
.GetDouble(kMediaGalleriesSizeKey
, &total_size_in_bytes
) &&
248 dict
.GetDouble(kMediaGalleriesLastAttachTimeKey
, &last_attach_time
)) {
249 volume_metadata_valid
= true;
252 if (dict
.GetInteger(kMediaGalleriesScanAudioCountKey
, &audio_count
) &&
253 dict
.GetInteger(kMediaGalleriesScanImageCountKey
, &image_count
) &&
254 dict
.GetInteger(kMediaGalleriesScanVideoCountKey
, &video_count
)) {
255 out_gallery_info
->audio_count
= audio_count
;
256 out_gallery_info
->image_count
= image_count
;
257 out_gallery_info
->video_count
= video_count
;
259 out_gallery_info
->audio_count
= 0;
260 out_gallery_info
->image_count
= 0;
261 out_gallery_info
->video_count
= 0;
264 out_gallery_info
->pref_id
= pref_id
;
265 out_gallery_info
->display_name
= display_name
;
266 out_gallery_info
->device_id
= device_id
;
267 out_gallery_info
->path
= base::FilePath(path
);
268 out_gallery_info
->type
= type
;
269 out_gallery_info
->volume_label
= volume_label
;
270 out_gallery_info
->vendor_name
= vendor_name
;
271 out_gallery_info
->model_name
= model_name
;
272 out_gallery_info
->total_size_in_bytes
= total_size_in_bytes
;
273 out_gallery_info
->last_attach_time
=
274 base::Time::FromInternalValue(last_attach_time
);
275 out_gallery_info
->volume_metadata_valid
= volume_metadata_valid
;
276 out_gallery_info
->prefs_version
= prefs_version
;
277 out_gallery_info
->default_gallery_type
= GetDefaultGalleryType(dict
);
281 base::DictionaryValue
* CreateGalleryPrefInfoDictionary(
282 const MediaGalleryPrefInfo
& gallery
) {
283 base::DictionaryValue
* dict
= new base::DictionaryValue();
284 dict
->SetString(kMediaGalleriesPrefIdKey
,
285 base::Uint64ToString(gallery
.pref_id
));
286 dict
->SetString(kMediaGalleriesDeviceIdKey
, gallery
.device_id
);
287 dict
->SetString(kMediaGalleriesPathKey
, gallery
.path
.value());
288 dict
->SetString(kMediaGalleriesTypeKey
, TypeToStringValue(gallery
.type
));
290 if (gallery
.default_gallery_type
!= MediaGalleryPrefInfo::kNotDefault
) {
291 dict
->SetString(kMediaGalleriesDefaultGalleryTypeKey
,
292 DefaultGalleryTypeToStringValue(
293 gallery
.default_gallery_type
));
296 if (gallery
.volume_metadata_valid
) {
297 dict
->SetString(kMediaGalleriesVolumeLabelKey
, gallery
.volume_label
);
298 dict
->SetString(kMediaGalleriesVendorNameKey
, gallery
.vendor_name
);
299 dict
->SetString(kMediaGalleriesModelNameKey
, gallery
.model_name
);
300 dict
->SetDouble(kMediaGalleriesSizeKey
, gallery
.total_size_in_bytes
);
301 dict
->SetDouble(kMediaGalleriesLastAttachTimeKey
,
302 gallery
.last_attach_time
.ToInternalValue());
304 dict
->SetString(kMediaGalleriesDisplayNameKey
, gallery
.display_name
);
307 if (gallery
.audio_count
|| gallery
.image_count
|| gallery
.video_count
) {
308 dict
->SetInteger(kMediaGalleriesScanAudioCountKey
, gallery
.audio_count
);
309 dict
->SetInteger(kMediaGalleriesScanImageCountKey
, gallery
.image_count
);
310 dict
->SetInteger(kMediaGalleriesScanVideoCountKey
, gallery
.video_count
);
313 // Version 0 of the prefs format was that the display_name was always
314 // used to show the user-visible name of the gallery. Version 1 means
315 // that there is an optional display_name, and when it is present, it
316 // overrides the name that would be built from the volume metadata, path,
317 // or whatever other data. So if we see a display_name with version 0, it
318 // means it may be overwritten simply by getting new volume metadata.
319 // A display_name with version 1 should not be overwritten.
320 dict
->SetInteger(kMediaGalleriesPrefsVersionKey
, gallery
.prefs_version
);
325 bool HasAutoDetectedGalleryPermission(const extensions::Extension
& extension
) {
326 extensions::MediaGalleriesPermission::CheckParam
param(
327 extensions::MediaGalleriesPermission::kAllAutoDetectedPermission
);
328 return extension
.permissions_data()->CheckAPIPermissionWithParam(
329 extensions::APIPermission::kMediaGalleries
, ¶m
);
332 // Retrieves the MediaGalleryPermission from the given dictionary; DCHECKs on
334 bool GetMediaGalleryPermissionFromDictionary(
335 const base::DictionaryValue
* dict
,
336 MediaGalleryPermission
* out_permission
) {
337 std::string string_id
;
338 if (dict
->GetString(kMediaGalleryIdKey
, &string_id
) &&
339 base::StringToUint64(string_id
, &out_permission
->pref_id
) &&
340 dict
->GetBoolean(kMediaGalleryHasPermissionKey
,
341 &out_permission
->has_permission
)) {
348 // For a device with |device_name| and a relative path |sub_folder|, construct
349 // a display name. If |sub_folder| is empty, then just return |device_name|.
350 base::string16
GetDisplayNameForSubFolder(const base::string16
& device_name
,
351 const base::FilePath
& sub_folder
) {
352 if (sub_folder
.empty())
354 return (sub_folder
.BaseName().LossyDisplayName() +
355 base::ASCIIToUTF16(" - ") +
359 void InitializeImportedMediaGalleryRegistryOnFileThread() {
360 DCHECK_CURRENTLY_ON(content::BrowserThread::FILE);
361 ImportedMediaGalleryRegistry::GetInstance()->Initialize();
366 MediaGalleryPrefInfo::MediaGalleryPrefInfo()
367 : pref_id(kInvalidMediaGalleryPrefId
),
369 total_size_in_bytes(0),
370 volume_metadata_valid(false),
374 default_gallery_type(kNotDefault
),
378 MediaGalleryPrefInfo::~MediaGalleryPrefInfo() {}
380 base::FilePath
MediaGalleryPrefInfo::AbsolutePath() const {
381 base::FilePath base_path
= MediaStorageUtil::FindDevicePathById(device_id
);
382 DCHECK(!path
.IsAbsolute());
383 return base_path
.empty() ? base_path
: base_path
.Append(path
);
386 bool MediaGalleryPrefInfo::IsBlackListedType() const {
387 return type
== kBlackListed
|| type
== kRemovedScan
;
390 base::string16
MediaGalleryPrefInfo::GetGalleryDisplayName() const {
391 if (!StorageInfo::IsRemovableDevice(device_id
)) {
392 // For fixed storage, the default name is the fully qualified directory
393 // name, or in the case of a root directory, the root directory name.
394 // Exception: ChromeOS -- the full pathname isn't visible there, so only
395 // the directory name is used.
396 base::FilePath path
= AbsolutePath();
397 if (!display_name
.empty())
400 #if defined(OS_CHROMEOS)
401 // See chrome/browser/chromeos/fileapi/file_system_backend.cc
402 base::FilePath download_path
;
403 if (PathService::Get(chrome::DIR_DEFAULT_DOWNLOADS_SAFE
, &download_path
)) {
404 base::FilePath relative
;
405 if (download_path
.AppendRelativePath(path
, &relative
))
406 return relative
.LossyDisplayName();
408 return path
.BaseName().LossyDisplayName();
410 return path
.LossyDisplayName();
414 StorageInfo
info(device_id
,
415 MediaStorageUtil::FindDevicePathById(device_id
).value(),
416 volume_label
, vendor_name
, model_name
, total_size_in_bytes
);
417 base::string16 name
= info
.GetDisplayNameWithOverride(display_name
, true);
419 name
= GetDisplayNameForSubFolder(name
, path
);
423 base::string16
MediaGalleryPrefInfo::GetGalleryTooltip() const {
424 return AbsolutePath().LossyDisplayName();
427 base::string16
MediaGalleryPrefInfo::GetGalleryAdditionalDetails() const {
428 base::string16 attached
;
429 if (StorageInfo::IsRemovableDevice(device_id
)) {
430 if (MediaStorageUtil::IsRemovableStorageAttached(device_id
)) {
431 attached
= l10n_util::GetStringUTF16(
432 IDS_MEDIA_GALLERIES_DIALOG_DEVICE_ATTACHED
);
433 } else if (!last_attach_time
.is_null()) {
434 attached
= l10n_util::GetStringFUTF16(
435 IDS_MEDIA_GALLERIES_LAST_ATTACHED
,
436 base::TimeFormatShortDateNumeric(last_attach_time
));
438 attached
= l10n_util::GetStringUTF16(
439 IDS_MEDIA_GALLERIES_DIALOG_DEVICE_NOT_ATTACHED
);
446 bool MediaGalleryPrefInfo::IsGalleryAvailable() const {
447 return !StorageInfo::IsRemovableDevice(device_id
) ||
448 MediaStorageUtil::IsRemovableStorageAttached(device_id
);
451 MediaGalleriesPreferences::GalleryChangeObserver::~GalleryChangeObserver() {}
453 MediaGalleriesPreferences::MediaGalleriesPreferences(Profile
* profile
)
454 : initialized_(false),
455 pre_initialization_callbacks_waiting_(0),
457 extension_prefs_for_testing_(NULL
),
458 weak_factory_(this) {
461 MediaGalleriesPreferences::~MediaGalleriesPreferences() {
462 if (StorageMonitor::GetInstance())
463 StorageMonitor::GetInstance()->RemoveObserver(this);
466 void MediaGalleriesPreferences::EnsureInitialized(base::Closure callback
) {
467 DCHECK_CURRENTLY_ON(content::BrowserThread::UI
);
469 if (IsInitialized()) {
470 if (!callback
.is_null())
475 on_initialize_callbacks_
.push_back(callback
);
476 if (on_initialize_callbacks_
.size() > 1)
479 // This counter must match the number of async methods dispatched below.
480 // It cannot be incremented inline with each callback, as some may return
481 // synchronously, decrement the counter to 0, and prematurely trigger
482 // FinishInitialization.
483 pre_initialization_callbacks_waiting_
= 4;
485 // Check whether we should be initializing -- are there any extensions that
486 // are using media galleries?
487 media_galleries::UsageCount(media_galleries::PREFS_INITIALIZED
);
488 if (NumberExtensionsUsingMediaGalleries(profile_
) == 0) {
489 media_galleries::UsageCount(media_galleries::PREFS_INITIALIZED_ERROR
);
492 // We determine the freshness of the profile here, before any of the finders
493 // return and add media galleries to it (hence why the APIHasBeenUsed check
494 // needs to happen here rather than inside OnStorageMonitorInit itself).
495 StorageMonitor::GetInstance()->EnsureInitialized(
496 base::Bind(&MediaGalleriesPreferences::OnStorageMonitorInit
,
497 weak_factory_
.GetWeakPtr(),
498 APIHasBeenUsed(profile_
)));
500 // Look for optional default galleries every time.
501 iapps::FindITunesLibrary(
502 base::Bind(&MediaGalleriesPreferences::OnFinderDeviceID
,
503 weak_factory_
.GetWeakPtr()));
505 picasa::FindPicasaDatabase(
506 base::Bind(&MediaGalleriesPreferences::OnFinderDeviceID
,
507 weak_factory_
.GetWeakPtr()));
509 iapps::FindIPhotoLibrary(
510 base::Bind(&MediaGalleriesPreferences::OnFinderDeviceID
,
511 weak_factory_
.GetWeakPtr()));
514 bool MediaGalleriesPreferences::IsInitialized() const { return initialized_
; }
516 Profile
* MediaGalleriesPreferences::profile() { return profile_
; }
518 void MediaGalleriesPreferences::OnInitializationCallbackReturned() {
519 DCHECK(!IsInitialized());
520 DCHECK_GT(pre_initialization_callbacks_waiting_
, 0);
521 if (--pre_initialization_callbacks_waiting_
== 0)
522 FinishInitialization();
525 void MediaGalleriesPreferences::FinishInitialization() {
526 DCHECK(!IsInitialized());
530 StorageMonitor
* monitor
= StorageMonitor::GetInstance();
531 DCHECK(monitor
->IsInitialized());
535 StorageMonitor::GetInstance()->AddObserver(this);
537 std::vector
<StorageInfo
> existing_devices
=
538 monitor
->GetAllAvailableStorages();
539 for (size_t i
= 0; i
< existing_devices
.size(); i
++) {
540 if (!(StorageInfo::IsMediaDevice(existing_devices
[i
].device_id()) &&
541 StorageInfo::IsRemovableDevice(existing_devices
[i
].device_id())))
543 AddGallery(existing_devices
[i
].device_id(),
545 MediaGalleryPrefInfo::kAutoDetected
,
546 existing_devices
[i
].storage_label(),
547 existing_devices
[i
].vendor_name(),
548 existing_devices
[i
].model_name(),
549 existing_devices
[i
].total_size_in_bytes(),
550 base::Time::Now(), 0, 0, 0);
553 for (std::vector
<base::Closure
>::iterator iter
=
554 on_initialize_callbacks_
.begin();
555 iter
!= on_initialize_callbacks_
.end();
559 on_initialize_callbacks_
.clear();
562 void MediaGalleriesPreferences::AddDefaultGalleries() {
563 const struct DefaultTypes
{
565 MediaGalleryPrefInfo::DefaultGalleryType default_gallery_type
;
567 {chrome::DIR_USER_MUSIC
, MediaGalleryPrefInfo::kMusicDefault
},
568 {chrome::DIR_USER_PICTURES
, MediaGalleryPrefInfo::kPicturesDefault
},
569 {chrome::DIR_USER_VIDEOS
, MediaGalleryPrefInfo::kVideosDefault
},
572 for (size_t i
= 0; i
< arraysize(kDirectories
); ++i
) {
574 if (!PathService::Get(kDirectories
[i
].directory_key
, &path
))
577 base::FilePath relative_path
;
579 if (MediaStorageUtil::GetDeviceInfoFromPath(path
, &info
, &relative_path
)) {
580 MediaGalleryPrefInfo::DefaultGalleryType default_gallery_type
=
581 kDirectories
[i
].default_gallery_type
;
582 DCHECK_NE(default_gallery_type
, MediaGalleryPrefInfo::kNotDefault
);
584 AddOrUpdateGalleryInternal(
588 MediaGalleryPrefInfo::kAutoDetected
,
589 info
.storage_label(),
592 info
.total_size_in_bytes(),
598 kCurrentPrefsVersion
,
599 default_gallery_type
);
604 bool MediaGalleriesPreferences::UpdateDeviceIDForSingletonType(
605 const std::string
& device_id
) {
606 StorageInfo::Type singleton_type
;
607 if (!StorageInfo::CrackDeviceId(device_id
, &singleton_type
, NULL
))
610 PrefService
* prefs
= profile_
->GetPrefs();
611 scoped_ptr
<ListPrefUpdate
> update(new ListPrefUpdate(
612 prefs
, prefs::kMediaGalleriesRememberedGalleries
));
613 base::ListValue
* list
= update
->Get();
614 for (base::ListValue::iterator iter
= list
->begin();
615 iter
!= list
->end(); ++iter
) {
616 // All of these calls should succeed, but preferences file can be corrupt.
617 base::DictionaryValue
* dict
;
618 if (!(*iter
)->GetAsDictionary(&dict
))
620 std::string this_device_id
;
621 if (!dict
->GetString(kMediaGalleriesDeviceIdKey
, &this_device_id
))
623 if (this_device_id
== device_id
)
624 return true; // No update is necessary.
625 StorageInfo::Type device_type
;
626 if (!StorageInfo::CrackDeviceId(this_device_id
, &device_type
, NULL
))
629 if (device_type
== singleton_type
) {
630 dict
->SetString(kMediaGalleriesDeviceIdKey
, device_id
);
631 update
.reset(); // commits the update.
633 MediaGalleryPrefId pref_id
;
634 if (GetPrefId(*dict
, &pref_id
)) {
635 FOR_EACH_OBSERVER(GalleryChangeObserver
,
636 gallery_change_observers_
,
637 OnGalleryInfoUpdated(this, pref_id
));
645 void MediaGalleriesPreferences::OnStorageMonitorInit(
646 bool api_has_been_used
) {
647 if (api_has_been_used
)
648 UpdateDefaultGalleriesPaths();
650 // Invoke this method even if the API has been used before, in order to ensure
651 // we upgrade (migrate) prefs for galleries with prefs version prior to 3.
652 AddDefaultGalleries();
654 OnInitializationCallbackReturned();
657 void MediaGalleriesPreferences::OnFinderDeviceID(const std::string
& device_id
) {
658 if (!device_id
.empty()) {
659 std::string gallery_name
;
660 if (StorageInfo::IsIPhotoDevice(device_id
))
661 gallery_name
= kIPhotoGalleryName
;
662 else if (StorageInfo::IsITunesDevice(device_id
))
663 gallery_name
= kITunesGalleryName
;
664 else if (StorageInfo::IsPicasaDevice(device_id
))
665 gallery_name
= kPicasaGalleryName
;
667 if (!gallery_name
.empty()) {
668 pre_initialization_callbacks_waiting_
++;
669 content::BrowserThread::PostTaskAndReply(
670 content::BrowserThread::FILE,
672 base::Bind(&InitializeImportedMediaGalleryRegistryOnFileThread
),
674 &MediaGalleriesPreferences::OnInitializationCallbackReturned
,
675 weak_factory_
.GetWeakPtr()));
678 if (!UpdateDeviceIDForSingletonType(device_id
)) {
679 DCHECK(!gallery_name
.empty());
680 AddOrUpdateGalleryInternal(
682 base::ASCIIToUTF16(gallery_name
),
684 MediaGalleryPrefInfo::kAutoDetected
,
694 kCurrentPrefsVersion
,
695 MediaGalleryPrefInfo::kNotDefault
);
699 OnInitializationCallbackReturned();
702 void MediaGalleriesPreferences::InitFromPrefs() {
703 known_galleries_
.clear();
706 PrefService
* prefs
= profile_
->GetPrefs();
707 const base::ListValue
* list
= prefs
->GetList(
708 prefs::kMediaGalleriesRememberedGalleries
);
710 for (base::ListValue::const_iterator it
= list
->begin();
711 it
!= list
->end(); ++it
) {
712 const base::DictionaryValue
* dict
= NULL
;
713 if (!(*it
)->GetAsDictionary(&dict
))
716 MediaGalleryPrefInfo gallery_info
;
717 if (!PopulateGalleryPrefInfoFromDictionary(*dict
, &gallery_info
))
720 known_galleries_
[gallery_info
.pref_id
] = gallery_info
;
721 device_map_
[gallery_info
.device_id
].insert(gallery_info
.pref_id
);
726 void MediaGalleriesPreferences::AddGalleryChangeObserver(
727 GalleryChangeObserver
* observer
) {
728 DCHECK(IsInitialized());
729 gallery_change_observers_
.AddObserver(observer
);
732 void MediaGalleriesPreferences::RemoveGalleryChangeObserver(
733 GalleryChangeObserver
* observer
) {
734 DCHECK(IsInitialized());
735 gallery_change_observers_
.RemoveObserver(observer
);
738 void MediaGalleriesPreferences::OnRemovableStorageAttached(
739 const StorageInfo
& info
) {
740 DCHECK(IsInitialized());
741 if (!StorageInfo::IsMediaDevice(info
.device_id()))
744 AddGallery(info
.device_id(), base::FilePath(),
745 MediaGalleryPrefInfo::kAutoDetected
, info
.storage_label(),
746 info
.vendor_name(), info
.model_name(), info
.total_size_in_bytes(),
747 base::Time::Now(), 0, 0, 0);
750 bool MediaGalleriesPreferences::LookUpGalleryByPath(
751 const base::FilePath
& path
,
752 MediaGalleryPrefInfo
* gallery_info
) const {
753 DCHECK(IsInitialized());
755 // First check if the path matches an imported gallery.
756 for (MediaGalleriesPrefInfoMap::const_iterator it
=
757 known_galleries_
.begin(); it
!= known_galleries_
.end(); ++it
) {
758 const std::string
& device_id
= it
->second
.device_id
;
759 if (iapps::PathIndicatesIPhotoLibrary(device_id
, path
) ||
760 iapps::PathIndicatesITunesLibrary(device_id
, path
)) {
761 *gallery_info
= it
->second
;
767 base::FilePath relative_path
;
768 if (!MediaStorageUtil::GetDeviceInfoFromPath(path
, &info
, &relative_path
)) {
770 *gallery_info
= MediaGalleryPrefInfo();
774 relative_path
= relative_path
.NormalizePathSeparators();
775 MediaGalleryPrefIdSet galleries_on_device
=
776 LookUpGalleriesByDeviceId(info
.device_id());
777 for (MediaGalleryPrefIdSet::const_iterator it
= galleries_on_device
.begin();
778 it
!= galleries_on_device
.end();
780 const MediaGalleryPrefInfo
& gallery
= known_galleries_
.find(*it
)->second
;
781 if (gallery
.path
!= relative_path
)
785 *gallery_info
= gallery
;
789 // This method is called by controller::FilesSelected when the user
790 // adds a new gallery. Control reaches here when the selected gallery is
791 // on a volume we know about, but have no gallery already for. Returns
792 // hypothetical data to the caller about what the prefs will look like
793 // if the gallery is added.
794 // TODO(gbillock): split this out into another function so it doesn't
797 gallery_info
->pref_id
= kInvalidMediaGalleryPrefId
;
798 gallery_info
->device_id
= info
.device_id();
799 gallery_info
->path
= relative_path
;
800 gallery_info
->type
= MediaGalleryPrefInfo::kInvalidType
;
801 gallery_info
->volume_label
= info
.storage_label();
802 gallery_info
->vendor_name
= info
.vendor_name();
803 gallery_info
->model_name
= info
.model_name();
804 gallery_info
->total_size_in_bytes
= info
.total_size_in_bytes();
805 gallery_info
->last_attach_time
= base::Time::Now();
806 gallery_info
->volume_metadata_valid
= true;
807 gallery_info
->prefs_version
= kCurrentPrefsVersion
;
812 MediaGalleryPrefIdSet
MediaGalleriesPreferences::LookUpGalleriesByDeviceId(
813 const std::string
& device_id
) const {
814 DeviceIdPrefIdsMap::const_iterator found
= device_map_
.find(device_id
);
815 if (found
== device_map_
.end())
816 return MediaGalleryPrefIdSet();
817 return found
->second
;
820 base::FilePath
MediaGalleriesPreferences::LookUpGalleryPathForExtension(
821 MediaGalleryPrefId gallery_id
,
822 const extensions::Extension
* extension
,
823 bool include_unpermitted_galleries
) {
824 DCHECK(IsInitialized());
826 if (!include_unpermitted_galleries
&&
827 !ContainsKey(GalleriesForExtension(*extension
), gallery_id
))
828 return base::FilePath();
830 MediaGalleriesPrefInfoMap::const_iterator it
=
831 known_galleries_
.find(gallery_id
);
832 if (it
== known_galleries_
.end())
833 return base::FilePath();
834 return MediaStorageUtil::FindDevicePathById(it
->second
.device_id
);
837 MediaGalleryPrefId
MediaGalleriesPreferences::AddGallery(
838 const std::string
& device_id
,
839 const base::FilePath
& relative_path
,
840 MediaGalleryPrefInfo::Type type
,
841 const base::string16
& volume_label
,
842 const base::string16
& vendor_name
,
843 const base::string16
& model_name
,
844 uint64 total_size_in_bytes
,
845 base::Time last_attach_time
,
849 DCHECK(IsInitialized());
850 return AddOrUpdateGalleryInternal(
864 kCurrentPrefsVersion
,
865 MediaGalleryPrefInfo::kNotDefault
);
868 MediaGalleryPrefId
MediaGalleriesPreferences::AddOrUpdateGalleryInternal(
869 const std::string
& device_id
, const base::string16
& display_name
,
870 const base::FilePath
& relative_path
, MediaGalleryPrefInfo::Type type
,
871 const base::string16
& volume_label
, const base::string16
& vendor_name
,
872 const base::string16
& model_name
, uint64 total_size_in_bytes
,
873 base::Time last_attach_time
, bool volume_metadata_valid
,
874 int audio_count
, int image_count
, int video_count
, int prefs_version
,
875 MediaGalleryPrefInfo::DefaultGalleryType default_gallery_type
) {
876 DCHECK(type
== MediaGalleryPrefInfo::kUserAdded
||
877 type
== MediaGalleryPrefInfo::kAutoDetected
||
878 type
== MediaGalleryPrefInfo::kScanResult
);
879 base::FilePath normalized_relative_path
=
880 relative_path
.NormalizePathSeparators();
881 MediaGalleryPrefIdSet galleries_on_device
=
882 LookUpGalleriesByDeviceId(device_id
);
884 for (MediaGalleryPrefIdSet::const_iterator pref_id_it
=
885 galleries_on_device
.begin();
886 pref_id_it
!= galleries_on_device
.end();
888 const MediaGalleryPrefInfo
& existing
=
889 known_galleries_
.find(*pref_id_it
)->second
;
890 if (existing
.path
!= normalized_relative_path
)
893 bool update_gallery_type
= false;
894 MediaGalleryPrefInfo::Type new_type
= existing
.type
;
895 if (type
== MediaGalleryPrefInfo::kUserAdded
) {
896 if (existing
.type
== MediaGalleryPrefInfo::kBlackListed
) {
897 new_type
= MediaGalleryPrefInfo::kAutoDetected
;
898 update_gallery_type
= true;
900 if (existing
.type
== MediaGalleryPrefInfo::kRemovedScan
) {
901 new_type
= MediaGalleryPrefInfo::kUserAdded
;
902 update_gallery_type
= true;
906 // Status quo: In M27 and M28, galleries added manually use version 0,
907 // and galleries added automatically (including default galleries) use
908 // version 1. The name override is used by default galleries as well
909 // as all device attach events.
910 // We want to upgrade the name if the existing version is < 2. Leave it
911 // alone if the existing display name is set with version >= 2 and the
912 // proposed new name is empty.
913 bool update_gallery_name
= existing
.display_name
!= display_name
;
914 if (existing
.prefs_version
>= 2 && !existing
.display_name
.empty() &&
915 display_name
.empty()) {
916 update_gallery_name
= false;
919 // Version 3 adds the default_gallery_type field.
920 bool update_default_gallery_type
=
921 existing
.prefs_version
<= 2 &&
922 default_gallery_type
!= existing
.default_gallery_type
;
924 bool update_gallery_metadata
= volume_metadata_valid
&&
925 ((existing
.volume_label
!= volume_label
) ||
926 (existing
.vendor_name
!= vendor_name
) ||
927 (existing
.model_name
!= model_name
) ||
928 (existing
.total_size_in_bytes
!= total_size_in_bytes
) ||
929 (existing
.last_attach_time
!= last_attach_time
));
931 bool update_scan_counts
=
932 new_type
!= MediaGalleryPrefInfo::kRemovedScan
&&
933 new_type
!= MediaGalleryPrefInfo::kBlackListed
&&
934 (audio_count
> 0 || image_count
> 0 || video_count
> 0 ||
935 existing
.audio_count
|| existing
.image_count
|| existing
.video_count
);
937 if (!update_gallery_name
&& !update_gallery_type
&&
938 !update_gallery_metadata
&& !update_scan_counts
&&
939 !update_default_gallery_type
)
942 PrefService
* prefs
= profile_
->GetPrefs();
943 scoped_ptr
<ListPrefUpdate
> update(
944 new ListPrefUpdate(prefs
, prefs::kMediaGalleriesRememberedGalleries
));
945 base::ListValue
* list
= update
->Get();
947 for (base::ListValue::const_iterator list_iter
= list
->begin();
948 list_iter
!= list
->end();
950 base::DictionaryValue
* dict
;
951 MediaGalleryPrefId iter_id
;
952 if ((*list_iter
)->GetAsDictionary(&dict
) &&
953 GetPrefId(*dict
, &iter_id
) &&
954 *pref_id_it
== iter_id
) {
955 if (update_gallery_type
)
956 dict
->SetString(kMediaGalleriesTypeKey
, TypeToStringValue(new_type
));
957 if (update_gallery_name
)
958 dict
->SetString(kMediaGalleriesDisplayNameKey
, display_name
);
959 if (update_gallery_metadata
) {
960 dict
->SetString(kMediaGalleriesVolumeLabelKey
, volume_label
);
961 dict
->SetString(kMediaGalleriesVendorNameKey
, vendor_name
);
962 dict
->SetString(kMediaGalleriesModelNameKey
, model_name
);
963 dict
->SetDouble(kMediaGalleriesSizeKey
, total_size_in_bytes
);
964 dict
->SetDouble(kMediaGalleriesLastAttachTimeKey
,
965 last_attach_time
.ToInternalValue());
967 if (update_scan_counts
) {
968 dict
->SetInteger(kMediaGalleriesScanAudioCountKey
, audio_count
);
969 dict
->SetInteger(kMediaGalleriesScanImageCountKey
, image_count
);
970 dict
->SetInteger(kMediaGalleriesScanVideoCountKey
, video_count
);
972 if (update_default_gallery_type
) {
974 kMediaGalleriesDefaultGalleryTypeKey
,
975 DefaultGalleryTypeToStringValue(default_gallery_type
));
977 dict
->SetInteger(kMediaGalleriesPrefsVersionKey
, prefs_version
);
982 // Commits the prefs update.
986 FOR_EACH_OBSERVER(GalleryChangeObserver
, gallery_change_observers_
,
987 OnGalleryInfoUpdated(this, *pref_id_it
));
991 PrefService
* prefs
= profile_
->GetPrefs();
993 MediaGalleryPrefInfo gallery_info
;
994 gallery_info
.pref_id
= prefs
->GetUint64(prefs::kMediaGalleriesUniqueId
);
995 prefs
->SetUint64(prefs::kMediaGalleriesUniqueId
, gallery_info
.pref_id
+ 1);
996 gallery_info
.display_name
= display_name
;
997 gallery_info
.device_id
= device_id
;
998 gallery_info
.path
= normalized_relative_path
;
999 gallery_info
.type
= type
;
1000 gallery_info
.volume_label
= volume_label
;
1001 gallery_info
.vendor_name
= vendor_name
;
1002 gallery_info
.model_name
= model_name
;
1003 gallery_info
.total_size_in_bytes
= total_size_in_bytes
;
1004 gallery_info
.last_attach_time
= last_attach_time
;
1005 gallery_info
.volume_metadata_valid
= volume_metadata_valid
;
1006 gallery_info
.audio_count
= audio_count
;
1007 gallery_info
.image_count
= image_count
;
1008 gallery_info
.video_count
= video_count
;
1009 gallery_info
.prefs_version
= prefs_version
;
1010 gallery_info
.default_gallery_type
= default_gallery_type
;
1013 ListPrefUpdate
update(prefs
, prefs::kMediaGalleriesRememberedGalleries
);
1014 base::ListValue
* list
= update
.Get();
1015 list
->Append(CreateGalleryPrefInfoDictionary(gallery_info
));
1018 FOR_EACH_OBSERVER(GalleryChangeObserver
,
1019 gallery_change_observers_
,
1020 OnGalleryAdded(this, gallery_info
.pref_id
));
1022 return gallery_info
.pref_id
;
1026 void MediaGalleriesPreferences::UpdateDefaultGalleriesPaths() {
1027 base::FilePath music_path
;
1028 base::FilePath pictures_path
;
1029 base::FilePath videos_path
;
1030 bool got_music_path
= PathService::Get(chrome::DIR_USER_MUSIC
, &music_path
);
1031 bool got_pictures_path
=
1032 PathService::Get(chrome::DIR_USER_PICTURES
, &pictures_path
);
1033 bool got_videos_path
=
1034 PathService::Get(chrome::DIR_USER_VIDEOS
, &videos_path
);
1036 PrefService
* prefs
= profile_
->GetPrefs();
1037 scoped_ptr
<ListPrefUpdate
> update(new ListPrefUpdate(
1038 prefs
, prefs::kMediaGalleriesRememberedGalleries
));
1039 base::ListValue
* list
= update
->Get();
1041 std::vector
<MediaGalleryPrefId
> pref_ids
;
1043 for (base::ListValue::iterator iter
= list
->begin();
1044 iter
!= list
->end();
1046 base::DictionaryValue
* dict
;
1047 MediaGalleryPrefId pref_id
;
1049 if (!((*iter
)->GetAsDictionary(&dict
) && GetPrefId(*dict
, &pref_id
)))
1052 std::string default_gallery_type_string
;
1054 // If the "default gallery type" key is set, just update the paths in place.
1055 // If it's not set, then AddOrUpdateGalleryInternal will take care of
1056 // setting it as part of migration to prefs version 3.
1057 if (dict
->GetString(kMediaGalleriesDefaultGalleryTypeKey
,
1058 &default_gallery_type_string
)) {
1059 std::string device_id
;
1060 if (got_music_path
&&
1061 default_gallery_type_string
==
1062 kMediaGalleriesDefaultGalleryTypeMusicDefaultValue
) {
1063 device_id
= StorageInfo::MakeDeviceId(
1064 StorageInfo::Type::FIXED_MASS_STORAGE
,
1065 music_path
.AsUTF8Unsafe());
1066 } else if (got_pictures_path
&&
1067 default_gallery_type_string
==
1068 kMediaGalleriesDefaultGalleryTypePicturesDefaultValue
) {
1069 device_id
= StorageInfo::MakeDeviceId(
1070 StorageInfo::Type::FIXED_MASS_STORAGE
,
1071 pictures_path
.AsUTF8Unsafe());
1072 } else if (got_videos_path
&&
1073 default_gallery_type_string
==
1074 kMediaGalleriesDefaultGalleryTypeVideosDefaultValue
) {
1075 device_id
= StorageInfo::MakeDeviceId(
1076 StorageInfo::Type::FIXED_MASS_STORAGE
,
1077 videos_path
.AsUTF8Unsafe());
1080 if (!device_id
.empty())
1081 dict
->SetString(kMediaGalleriesDeviceIdKey
, device_id
);
1084 pref_ids
.push_back(pref_id
);
1087 // Commit the prefs update.
1091 for (std::vector
<MediaGalleryPrefId
>::iterator iter
= pref_ids
.begin();
1092 iter
!= pref_ids
.end();
1094 FOR_EACH_OBSERVER(GalleryChangeObserver
,
1095 gallery_change_observers_
,
1096 OnGalleryInfoUpdated(this, *iter
));
1101 MediaGalleryPrefId
MediaGalleriesPreferences::AddGalleryByPath(
1102 const base::FilePath
& path
, MediaGalleryPrefInfo::Type type
) {
1103 DCHECK(IsInitialized());
1104 MediaGalleryPrefInfo gallery_info
;
1105 if (LookUpGalleryByPath(path
, &gallery_info
) &&
1106 !gallery_info
.IsBlackListedType()) {
1107 return gallery_info
.pref_id
;
1109 return AddOrUpdateGalleryInternal(gallery_info
.device_id
,
1110 gallery_info
.display_name
,
1113 gallery_info
.volume_label
,
1114 gallery_info
.vendor_name
,
1115 gallery_info
.model_name
,
1116 gallery_info
.total_size_in_bytes
,
1117 gallery_info
.last_attach_time
,
1118 gallery_info
.volume_metadata_valid
,
1120 kCurrentPrefsVersion
,
1121 MediaGalleryPrefInfo::kNotDefault
);
1124 void MediaGalleriesPreferences::ForgetGalleryById(MediaGalleryPrefId id
) {
1125 EraseOrBlacklistGalleryById(id
, false);
1128 void MediaGalleriesPreferences::EraseGalleryById(MediaGalleryPrefId id
) {
1129 EraseOrBlacklistGalleryById(id
, true);
1132 void MediaGalleriesPreferences::EraseOrBlacklistGalleryById(
1133 MediaGalleryPrefId id
, bool erase
) {
1134 DCHECK(IsInitialized());
1135 PrefService
* prefs
= profile_
->GetPrefs();
1136 scoped_ptr
<ListPrefUpdate
> update(new ListPrefUpdate(
1137 prefs
, prefs::kMediaGalleriesRememberedGalleries
));
1138 base::ListValue
* list
= update
->Get();
1140 if (!ContainsKey(known_galleries_
, id
))
1143 for (base::ListValue::iterator iter
= list
->begin();
1144 iter
!= list
->end(); ++iter
) {
1145 base::DictionaryValue
* dict
;
1146 MediaGalleryPrefId iter_id
;
1147 if ((*iter
)->GetAsDictionary(&dict
) && GetPrefId(*dict
, &iter_id
) &&
1149 RemoveGalleryPermissionsFromPrefs(id
);
1150 MediaGalleryPrefInfo::Type type
;
1151 if (!erase
&& GetType(*dict
, &type
) &&
1152 (type
== MediaGalleryPrefInfo::kAutoDetected
||
1153 type
== MediaGalleryPrefInfo::kScanResult
)) {
1154 if (type
== MediaGalleryPrefInfo::kAutoDetected
) {
1155 dict
->SetString(kMediaGalleriesTypeKey
,
1156 kMediaGalleriesTypeBlackListedValue
);
1158 dict
->SetString(kMediaGalleriesTypeKey
,
1159 kMediaGalleriesTypeRemovedScanValue
);
1160 dict
->SetInteger(kMediaGalleriesScanAudioCountKey
, 0);
1161 dict
->SetInteger(kMediaGalleriesScanImageCountKey
, 0);
1162 dict
->SetInteger(kMediaGalleriesScanVideoCountKey
, 0);
1165 list
->Erase(iter
, NULL
);
1167 update
.reset(NULL
); // commits the update.
1170 FOR_EACH_OBSERVER(GalleryChangeObserver
,
1171 gallery_change_observers_
,
1172 OnGalleryRemoved(this, id
));
1178 bool MediaGalleriesPreferences::NonAutoGalleryHasPermission(
1179 MediaGalleryPrefId id
) const {
1180 DCHECK(IsInitialized());
1181 DCHECK(!ContainsKey(known_galleries_
, id
) ||
1182 known_galleries_
.find(id
)->second
.type
!=
1183 MediaGalleryPrefInfo::kAutoDetected
);
1184 ExtensionPrefs
* prefs
= GetExtensionPrefs();
1185 const base::DictionaryValue
* extensions
=
1186 prefs
->pref_service()->GetDictionary(extensions::pref_names::kExtensions
);
1190 for (base::DictionaryValue::Iterator
iter(*extensions
); !iter
.IsAtEnd();
1192 if (!crx_file::id_util::IdIsValid(iter
.key())) {
1196 std::vector
<MediaGalleryPermission
> permissions
=
1197 GetGalleryPermissionsFromPrefs(iter
.key());
1198 for (std::vector
<MediaGalleryPermission
>::const_iterator it
=
1199 permissions
.begin(); it
!= permissions
.end(); ++it
) {
1200 if (it
->pref_id
== id
) {
1201 if (it
->has_permission
)
1210 MediaGalleryPrefIdSet
MediaGalleriesPreferences::GalleriesForExtension(
1211 const extensions::Extension
& extension
) {
1212 DCHECK(IsInitialized());
1213 MediaGalleryPrefIdSet result
;
1215 if (HasAutoDetectedGalleryPermission(extension
)) {
1216 for (MediaGalleriesPrefInfoMap::const_iterator it
=
1217 known_galleries_
.begin(); it
!= known_galleries_
.end(); ++it
) {
1218 if (it
->second
.type
== MediaGalleryPrefInfo::kAutoDetected
)
1219 result
.insert(it
->second
.pref_id
);
1223 std::vector
<MediaGalleryPermission
> stored_permissions
=
1224 GetGalleryPermissionsFromPrefs(extension
.id());
1225 for (std::vector
<MediaGalleryPermission
>::const_iterator it
=
1226 stored_permissions
.begin(); it
!= stored_permissions
.end(); ++it
) {
1227 if (!it
->has_permission
) {
1228 result
.erase(it
->pref_id
);
1230 MediaGalleriesPrefInfoMap::const_iterator gallery
=
1231 known_galleries_
.find(it
->pref_id
);
1233 // Handle a stored permission for an erased gallery. This should never
1234 // happen but, has caused crashes in the wild. http://crbug.com/374330.
1235 if (gallery
== known_galleries_
.end()) {
1236 RemoveGalleryPermissionsFromPrefs(it
->pref_id
);
1240 if (!gallery
->second
.IsBlackListedType()) {
1241 result
.insert(it
->pref_id
);
1243 NOTREACHED() << gallery
->second
.device_id
;
1250 bool MediaGalleriesPreferences::SetGalleryPermissionForExtension(
1251 const extensions::Extension
& extension
,
1252 MediaGalleryPrefId pref_id
,
1253 bool has_permission
) {
1254 DCHECK(IsInitialized());
1255 // The gallery may not exist anymore if the user opened a second config
1256 // surface concurrently and removed it. Drop the permission update if so.
1257 MediaGalleriesPrefInfoMap::const_iterator gallery_info
=
1258 known_galleries_
.find(pref_id
);
1259 if (gallery_info
== known_galleries_
.end())
1262 bool default_permission
= false;
1263 if (gallery_info
->second
.type
== MediaGalleryPrefInfo::kAutoDetected
)
1264 default_permission
= HasAutoDetectedGalleryPermission(extension
);
1265 // When the permission matches the default, we don't need to remember it.
1266 if (has_permission
== default_permission
) {
1267 if (!UnsetGalleryPermissionInPrefs(extension
.id(), pref_id
))
1268 // If permission wasn't set, assume nothing has changed.
1271 if (!SetGalleryPermissionInPrefs(extension
.id(), pref_id
, has_permission
))
1275 FOR_EACH_OBSERVER(GalleryChangeObserver
,
1276 gallery_change_observers_
,
1277 OnPermissionAdded(this, extension
.id(), pref_id
));
1279 FOR_EACH_OBSERVER(GalleryChangeObserver
,
1280 gallery_change_observers_
,
1281 OnPermissionRemoved(this, extension
.id(), pref_id
));
1285 const MediaGalleriesPrefInfoMap
& MediaGalleriesPreferences::known_galleries()
1287 DCHECK(IsInitialized());
1288 return known_galleries_
;
1291 base::Time
MediaGalleriesPreferences::GetLastScanCompletionTime() const {
1292 int64 last_scan_time_internal
=
1293 profile_
->GetPrefs()->GetInt64(prefs::kMediaGalleriesLastScanTime
);
1294 return base::Time::FromInternalValue(last_scan_time_internal
);
1297 void MediaGalleriesPreferences::SetLastScanCompletionTime(
1298 const base::Time
& time
) {
1299 profile_
->GetPrefs()->SetInt64(prefs::kMediaGalleriesLastScanTime
,
1300 time
.ToInternalValue());
1303 void MediaGalleriesPreferences::Shutdown() {
1304 weak_factory_
.InvalidateWeakPtrs();
1309 bool MediaGalleriesPreferences::APIHasBeenUsed(Profile
* profile
) {
1310 MediaGalleryPrefId current_id
=
1311 profile
->GetPrefs()->GetUint64(prefs::kMediaGalleriesUniqueId
);
1312 return current_id
!= kInvalidMediaGalleryPrefId
+ 1;
1316 void MediaGalleriesPreferences::RegisterProfilePrefs(
1317 user_prefs::PrefRegistrySyncable
* registry
) {
1318 registry
->RegisterListPref(prefs::kMediaGalleriesRememberedGalleries
,
1319 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF
);
1320 registry
->RegisterUint64Pref(
1321 prefs::kMediaGalleriesUniqueId
,
1322 kInvalidMediaGalleryPrefId
+ 1,
1323 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF
);
1324 registry
->RegisterInt64Pref(
1325 prefs::kMediaGalleriesLastScanTime
,
1326 base::Time().ToInternalValue(),
1327 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF
);
1330 bool MediaGalleriesPreferences::SetGalleryPermissionInPrefs(
1331 const std::string
& extension_id
,
1332 MediaGalleryPrefId gallery_id
,
1334 DCHECK(IsInitialized());
1335 ExtensionPrefs::ScopedListUpdate
update(GetExtensionPrefs(),
1337 kMediaGalleriesPermissions
);
1338 base::ListValue
* permissions
= update
.Get();
1340 permissions
= update
.Create();
1342 // If the gallery is already in the list, update the permission...
1343 for (base::ListValue::iterator iter
= permissions
->begin();
1344 iter
!= permissions
->end(); ++iter
) {
1345 base::DictionaryValue
* dict
= NULL
;
1346 if (!(*iter
)->GetAsDictionary(&dict
))
1348 MediaGalleryPermission perm
;
1349 if (!GetMediaGalleryPermissionFromDictionary(dict
, &perm
))
1351 if (perm
.pref_id
== gallery_id
) {
1352 if (has_access
!= perm
.has_permission
) {
1353 dict
->SetBoolean(kMediaGalleryHasPermissionKey
, has_access
);
1361 // ...Otherwise, add a new entry for the gallery.
1362 base::DictionaryValue
* dict
= new base::DictionaryValue
;
1363 dict
->SetString(kMediaGalleryIdKey
, base::Uint64ToString(gallery_id
));
1364 dict
->SetBoolean(kMediaGalleryHasPermissionKey
, has_access
);
1365 permissions
->Append(dict
);
1369 bool MediaGalleriesPreferences::UnsetGalleryPermissionInPrefs(
1370 const std::string
& extension_id
,
1371 MediaGalleryPrefId gallery_id
) {
1372 DCHECK(IsInitialized());
1373 ExtensionPrefs::ScopedListUpdate
update(GetExtensionPrefs(),
1375 kMediaGalleriesPermissions
);
1376 base::ListValue
* permissions
= update
.Get();
1380 for (base::ListValue::iterator iter
= permissions
->begin();
1381 iter
!= permissions
->end(); ++iter
) {
1382 const base::DictionaryValue
* dict
= NULL
;
1383 if (!(*iter
)->GetAsDictionary(&dict
))
1385 MediaGalleryPermission perm
;
1386 if (!GetMediaGalleryPermissionFromDictionary(dict
, &perm
))
1388 if (perm
.pref_id
== gallery_id
) {
1389 permissions
->Erase(iter
, NULL
);
1396 std::vector
<MediaGalleryPermission
>
1397 MediaGalleriesPreferences::GetGalleryPermissionsFromPrefs(
1398 const std::string
& extension_id
) const {
1399 DCHECK(IsInitialized());
1400 std::vector
<MediaGalleryPermission
> result
;
1401 const base::ListValue
* permissions
;
1402 if (!GetExtensionPrefs()->ReadPrefAsList(extension_id
,
1403 kMediaGalleriesPermissions
,
1408 for (base::ListValue::const_iterator iter
= permissions
->begin();
1409 iter
!= permissions
->end(); ++iter
) {
1410 base::DictionaryValue
* dict
= NULL
;
1411 if (!(*iter
)->GetAsDictionary(&dict
))
1413 MediaGalleryPermission perm
;
1414 if (!GetMediaGalleryPermissionFromDictionary(dict
, &perm
))
1416 result
.push_back(perm
);
1422 void MediaGalleriesPreferences::RemoveGalleryPermissionsFromPrefs(
1423 MediaGalleryPrefId gallery_id
) {
1424 DCHECK(IsInitialized());
1425 ExtensionPrefs
* prefs
= GetExtensionPrefs();
1426 const base::DictionaryValue
* extensions
=
1427 prefs
->pref_service()->GetDictionary(extensions::pref_names::kExtensions
);
1431 for (base::DictionaryValue::Iterator
iter(*extensions
); !iter
.IsAtEnd();
1433 if (!crx_file::id_util::IdIsValid(iter
.key())) {
1437 UnsetGalleryPermissionInPrefs(iter
.key(), gallery_id
);
1441 ExtensionPrefs
* MediaGalleriesPreferences::GetExtensionPrefs() const {
1442 DCHECK(IsInitialized());
1443 if (extension_prefs_for_testing_
)
1444 return extension_prefs_for_testing_
;
1445 return extensions::ExtensionPrefs::Get(profile_
);
1448 void MediaGalleriesPreferences::SetExtensionPrefsForTesting(
1449 extensions::ExtensionPrefs
* extension_prefs
) {
1450 DCHECK(IsInitialized());
1451 extension_prefs_for_testing_
= extension_prefs
;