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 "chrome/grit/generated_resources.h"
30 #include "components/crx_file/id_util.h"
31 #include "components/pref_registry/pref_registry_syncable.h"
32 #include "components/storage_monitor/media_storage_util.h"
33 #include "components/storage_monitor/storage_monitor.h"
34 #include "content/public/browser/browser_thread.h"
35 #include "extensions/browser/extension_prefs.h"
36 #include "extensions/browser/extension_system.h"
37 #include "extensions/browser/pref_names.h"
38 #include "extensions/common/extension_set.h"
39 #include "extensions/common/permissions/api_permission.h"
40 #include "extensions/common/permissions/media_galleries_permission.h"
41 #include "extensions/common/permissions/permissions_data.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
;
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";
74 const char kMediaGalleriesTypeAutoDetectedValue
[] = "autoDetected";
75 const char kMediaGalleriesTypeBlackListedValue
[] = "blackListed";
76 const char kMediaGalleriesTypeRemovedScanValue
[] = "removedScan";
77 const char kMediaGalleriesTypeScanResultValue
[] = "scanResult";
78 const char kMediaGalleriesTypeUserAddedValue
[] = "userAdded";
80 const char kMediaGalleriesDefaultGalleryTypeNotDefaultValue
[] = "notDefault";
81 const char kMediaGalleriesDefaultGalleryTypeMusicDefaultValue
[] = "music";
82 const char kMediaGalleriesDefaultGalleryTypePicturesDefaultValue
[] = "pictures";
83 const char kMediaGalleriesDefaultGalleryTypeVideosDefaultValue
[] = "videos";
85 const char kIPhotoGalleryName
[] = "iPhoto";
86 const char kITunesGalleryName
[] = "iTunes";
87 const char kPicasaGalleryName
[] = "Picasa";
89 const int kCurrentPrefsVersion
= 3;
91 int NumberExtensionsUsingMediaGalleries(Profile
* profile
) {
95 ExtensionService
* extension_service
=
96 extensions::ExtensionSystem::Get(profile
)->extension_service();
97 if (!extension_service
)
100 const extensions::ExtensionSet
* extensions
= extension_service
->extensions();
101 for (extensions::ExtensionSet::const_iterator i
= extensions
->begin();
102 i
!= extensions
->end(); ++i
) {
103 const extensions::PermissionsData
* permissions_data
=
104 (*i
)->permissions_data();
105 if (permissions_data
->HasAPIPermission(
106 extensions::APIPermission::kMediaGalleries
) ||
107 permissions_data
->HasAPIPermission(
108 extensions::APIPermission::kMediaGalleriesPrivate
)) {
115 bool GetPrefId(const base::DictionaryValue
& dict
, MediaGalleryPrefId
* value
) {
116 std::string string_id
;
117 if (!dict
.GetString(kMediaGalleriesPrefIdKey
, &string_id
) ||
118 !base::StringToUint64(string_id
, value
)) {
125 bool GetType(const base::DictionaryValue
& dict
,
126 MediaGalleryPrefInfo::Type
* type
) {
127 std::string string_type
;
128 if (!dict
.GetString(kMediaGalleriesTypeKey
, &string_type
))
131 if (string_type
== kMediaGalleriesTypeUserAddedValue
) {
132 *type
= MediaGalleryPrefInfo::kUserAdded
;
135 if (string_type
== kMediaGalleriesTypeAutoDetectedValue
) {
136 *type
= MediaGalleryPrefInfo::kAutoDetected
;
139 if (string_type
== kMediaGalleriesTypeBlackListedValue
) {
140 *type
= MediaGalleryPrefInfo::kBlackListed
;
143 if (string_type
== kMediaGalleriesTypeScanResultValue
) {
144 *type
= MediaGalleryPrefInfo::kScanResult
;
147 if (string_type
== kMediaGalleriesTypeRemovedScanValue
) {
148 *type
= MediaGalleryPrefInfo::kRemovedScan
;
155 const char* TypeToStringValue(MediaGalleryPrefInfo::Type type
) {
156 const char* result
= NULL
;
158 case MediaGalleryPrefInfo::kUserAdded
:
159 result
= kMediaGalleriesTypeUserAddedValue
;
161 case MediaGalleryPrefInfo::kAutoDetected
:
162 result
= kMediaGalleriesTypeAutoDetectedValue
;
164 case MediaGalleryPrefInfo::kBlackListed
:
165 result
= kMediaGalleriesTypeBlackListedValue
;
167 case MediaGalleryPrefInfo::kScanResult
:
168 result
= kMediaGalleriesTypeScanResultValue
;
170 case MediaGalleryPrefInfo::kRemovedScan
:
171 result
= kMediaGalleriesTypeRemovedScanValue
;
180 MediaGalleryPrefInfo::DefaultGalleryType
GetDefaultGalleryType(
181 const base::DictionaryValue
& dict
) {
182 std::string default_gallery_type_string
;
184 kMediaGalleriesDefaultGalleryTypeKey
, &default_gallery_type_string
))
185 return MediaGalleryPrefInfo::kNotDefault
;
187 if (default_gallery_type_string
==
188 kMediaGalleriesDefaultGalleryTypeMusicDefaultValue
) {
189 return MediaGalleryPrefInfo::kMusicDefault
;
191 if (default_gallery_type_string
==
192 kMediaGalleriesDefaultGalleryTypePicturesDefaultValue
) {
193 return MediaGalleryPrefInfo::kPicturesDefault
;
195 if (default_gallery_type_string
==
196 kMediaGalleriesDefaultGalleryTypeVideosDefaultValue
) {
197 return MediaGalleryPrefInfo::kVideosDefault
;
199 return MediaGalleryPrefInfo::kNotDefault
;
202 const char* DefaultGalleryTypeToStringValue(
203 MediaGalleryPrefInfo::DefaultGalleryType default_gallery_type
) {
204 const char* result
= NULL
;
205 switch (default_gallery_type
) {
206 case MediaGalleryPrefInfo::kNotDefault
:
207 result
= kMediaGalleriesDefaultGalleryTypeNotDefaultValue
;
209 case MediaGalleryPrefInfo::kMusicDefault
:
210 result
= kMediaGalleriesDefaultGalleryTypeMusicDefaultValue
;
212 case MediaGalleryPrefInfo::kPicturesDefault
:
213 result
= kMediaGalleriesDefaultGalleryTypePicturesDefaultValue
;
215 case MediaGalleryPrefInfo::kVideosDefault
:
216 result
= kMediaGalleriesDefaultGalleryTypeVideosDefaultValue
;
225 bool PopulateGalleryPrefInfoFromDictionary(
226 const base::DictionaryValue
& dict
, MediaGalleryPrefInfo
* out_gallery_info
) {
227 MediaGalleryPrefId pref_id
;
228 base::string16 display_name
;
229 std::string device_id
;
230 base::FilePath::StringType path
;
231 MediaGalleryPrefInfo::Type type
= MediaGalleryPrefInfo::kInvalidType
;
232 base::string16 volume_label
;
233 base::string16 vendor_name
;
234 base::string16 model_name
;
235 double total_size_in_bytes
= 0.0;
236 double last_attach_time
= 0.0;
237 bool volume_metadata_valid
= false;
241 int prefs_version
= 0;
243 if (!GetPrefId(dict
, &pref_id
) ||
244 !dict
.GetString(kMediaGalleriesDeviceIdKey
, &device_id
) ||
245 !dict
.GetString(kMediaGalleriesPathKey
, &path
) ||
246 !GetType(dict
, &type
)) {
250 dict
.GetString(kMediaGalleriesDisplayNameKey
, &display_name
);
251 dict
.GetInteger(kMediaGalleriesPrefsVersionKey
, &prefs_version
);
253 if (dict
.GetString(kMediaGalleriesVolumeLabelKey
, &volume_label
) &&
254 dict
.GetString(kMediaGalleriesVendorNameKey
, &vendor_name
) &&
255 dict
.GetString(kMediaGalleriesModelNameKey
, &model_name
) &&
256 dict
.GetDouble(kMediaGalleriesSizeKey
, &total_size_in_bytes
) &&
257 dict
.GetDouble(kMediaGalleriesLastAttachTimeKey
, &last_attach_time
)) {
258 volume_metadata_valid
= true;
261 if (dict
.GetInteger(kMediaGalleriesScanAudioCountKey
, &audio_count
) &&
262 dict
.GetInteger(kMediaGalleriesScanImageCountKey
, &image_count
) &&
263 dict
.GetInteger(kMediaGalleriesScanVideoCountKey
, &video_count
)) {
264 out_gallery_info
->audio_count
= audio_count
;
265 out_gallery_info
->image_count
= image_count
;
266 out_gallery_info
->video_count
= video_count
;
268 out_gallery_info
->audio_count
= 0;
269 out_gallery_info
->image_count
= 0;
270 out_gallery_info
->video_count
= 0;
273 out_gallery_info
->pref_id
= pref_id
;
274 out_gallery_info
->display_name
= display_name
;
275 out_gallery_info
->device_id
= device_id
;
276 out_gallery_info
->path
= base::FilePath(path
);
277 out_gallery_info
->type
= type
;
278 out_gallery_info
->volume_label
= volume_label
;
279 out_gallery_info
->vendor_name
= vendor_name
;
280 out_gallery_info
->model_name
= model_name
;
281 out_gallery_info
->total_size_in_bytes
= total_size_in_bytes
;
282 out_gallery_info
->last_attach_time
=
283 base::Time::FromInternalValue(last_attach_time
);
284 out_gallery_info
->volume_metadata_valid
= volume_metadata_valid
;
285 out_gallery_info
->prefs_version
= prefs_version
;
286 out_gallery_info
->default_gallery_type
= GetDefaultGalleryType(dict
);
290 base::DictionaryValue
* CreateGalleryPrefInfoDictionary(
291 const MediaGalleryPrefInfo
& gallery
) {
292 base::DictionaryValue
* dict
= new base::DictionaryValue();
293 dict
->SetString(kMediaGalleriesPrefIdKey
,
294 base::Uint64ToString(gallery
.pref_id
));
295 dict
->SetString(kMediaGalleriesDeviceIdKey
, gallery
.device_id
);
296 dict
->SetString(kMediaGalleriesPathKey
, gallery
.path
.value());
297 dict
->SetString(kMediaGalleriesTypeKey
, TypeToStringValue(gallery
.type
));
299 if (gallery
.default_gallery_type
!= MediaGalleryPrefInfo::kNotDefault
) {
300 dict
->SetString(kMediaGalleriesDefaultGalleryTypeKey
,
301 DefaultGalleryTypeToStringValue(
302 gallery
.default_gallery_type
));
305 if (gallery
.volume_metadata_valid
) {
306 dict
->SetString(kMediaGalleriesVolumeLabelKey
, gallery
.volume_label
);
307 dict
->SetString(kMediaGalleriesVendorNameKey
, gallery
.vendor_name
);
308 dict
->SetString(kMediaGalleriesModelNameKey
, gallery
.model_name
);
309 dict
->SetDouble(kMediaGalleriesSizeKey
, gallery
.total_size_in_bytes
);
310 dict
->SetDouble(kMediaGalleriesLastAttachTimeKey
,
311 gallery
.last_attach_time
.ToInternalValue());
313 dict
->SetString(kMediaGalleriesDisplayNameKey
, gallery
.display_name
);
316 if (gallery
.audio_count
|| gallery
.image_count
|| gallery
.video_count
) {
317 dict
->SetInteger(kMediaGalleriesScanAudioCountKey
, gallery
.audio_count
);
318 dict
->SetInteger(kMediaGalleriesScanImageCountKey
, gallery
.image_count
);
319 dict
->SetInteger(kMediaGalleriesScanVideoCountKey
, gallery
.video_count
);
322 // Version 0 of the prefs format was that the display_name was always
323 // used to show the user-visible name of the gallery. Version 1 means
324 // that there is an optional display_name, and when it is present, it
325 // overrides the name that would be built from the volume metadata, path,
326 // or whatever other data. So if we see a display_name with version 0, it
327 // means it may be overwritten simply by getting new volume metadata.
328 // A display_name with version 1 should not be overwritten.
329 dict
->SetInteger(kMediaGalleriesPrefsVersionKey
, gallery
.prefs_version
);
334 bool HasAutoDetectedGalleryPermission(const extensions::Extension
& extension
) {
335 extensions::MediaGalleriesPermission::CheckParam
param(
336 extensions::MediaGalleriesPermission::kAllAutoDetectedPermission
);
337 return extension
.permissions_data()->CheckAPIPermissionWithParam(
338 extensions::APIPermission::kMediaGalleries
, ¶m
);
341 // Retrieves the MediaGalleryPermission from the given dictionary; DCHECKs on
343 bool GetMediaGalleryPermissionFromDictionary(
344 const base::DictionaryValue
* dict
,
345 MediaGalleryPermission
* out_permission
) {
346 std::string string_id
;
347 if (dict
->GetString(kMediaGalleryIdKey
, &string_id
) &&
348 base::StringToUint64(string_id
, &out_permission
->pref_id
) &&
349 dict
->GetBoolean(kMediaGalleryHasPermissionKey
,
350 &out_permission
->has_permission
)) {
357 // For a device with |device_name| and a relative path |sub_folder|, construct
358 // a display name. If |sub_folder| is empty, then just return |device_name|.
359 base::string16
GetDisplayNameForSubFolder(const base::string16
& device_name
,
360 const base::FilePath
& sub_folder
) {
361 if (sub_folder
.empty())
363 return (sub_folder
.BaseName().LossyDisplayName() +
364 base::ASCIIToUTF16(" - ") +
368 void InitializeImportedMediaGalleryRegistryOnFileThread() {
369 DCHECK_CURRENTLY_ON(content::BrowserThread::FILE);
370 ImportedMediaGalleryRegistry::GetInstance()->Initialize();
375 MediaGalleryPrefInfo::MediaGalleryPrefInfo()
376 : pref_id(kInvalidMediaGalleryPrefId
),
378 total_size_in_bytes(0),
379 volume_metadata_valid(false),
383 default_gallery_type(kNotDefault
),
387 MediaGalleryPrefInfo::~MediaGalleryPrefInfo() {}
389 base::FilePath
MediaGalleryPrefInfo::AbsolutePath() const {
390 base::FilePath base_path
= MediaStorageUtil::FindDevicePathById(device_id
);
391 DCHECK(!path
.IsAbsolute());
392 return base_path
.empty() ? base_path
: base_path
.Append(path
);
395 bool MediaGalleryPrefInfo::IsBlackListedType() const {
396 return type
== kBlackListed
|| type
== kRemovedScan
;
399 base::string16
MediaGalleryPrefInfo::GetGalleryDisplayName() const {
400 if (!StorageInfo::IsRemovableDevice(device_id
)) {
401 // For fixed storage, the default name is the fully qualified directory
402 // name, or in the case of a root directory, the root directory name.
403 // Exception: ChromeOS -- the full pathname isn't visible there, so only
404 // the directory name is used.
405 base::FilePath path
= AbsolutePath();
406 if (!display_name
.empty())
409 #if defined(OS_CHROMEOS)
410 // See chrome/browser/chromeos/fileapi/file_system_backend.cc
411 base::FilePath download_path
;
412 if (PathService::Get(chrome::DIR_DEFAULT_DOWNLOADS_SAFE
, &download_path
)) {
413 base::FilePath relative
;
414 if (download_path
.AppendRelativePath(path
, &relative
))
415 return relative
.LossyDisplayName();
417 return path
.BaseName().LossyDisplayName();
419 return path
.LossyDisplayName();
423 StorageInfo
info(device_id
,
424 MediaStorageUtil::FindDevicePathById(device_id
).value(),
425 volume_label
, vendor_name
, model_name
, total_size_in_bytes
);
426 base::string16 name
= info
.GetDisplayNameWithOverride(display_name
, true);
428 name
= GetDisplayNameForSubFolder(name
, path
);
432 base::string16
MediaGalleryPrefInfo::GetGalleryTooltip() const {
433 return AbsolutePath().LossyDisplayName();
436 base::string16
MediaGalleryPrefInfo::GetGalleryAdditionalDetails() const {
437 base::string16 attached
;
438 if (StorageInfo::IsRemovableDevice(device_id
)) {
439 if (MediaStorageUtil::IsRemovableStorageAttached(device_id
)) {
440 attached
= l10n_util::GetStringUTF16(
441 IDS_MEDIA_GALLERIES_DIALOG_DEVICE_ATTACHED
);
442 } else if (!last_attach_time
.is_null()) {
443 attached
= l10n_util::GetStringFUTF16(
444 IDS_MEDIA_GALLERIES_LAST_ATTACHED
,
445 base::TimeFormatShortDateNumeric(last_attach_time
));
447 attached
= l10n_util::GetStringUTF16(
448 IDS_MEDIA_GALLERIES_DIALOG_DEVICE_NOT_ATTACHED
);
455 bool MediaGalleryPrefInfo::IsGalleryAvailable() const {
456 return !StorageInfo::IsRemovableDevice(device_id
) ||
457 MediaStorageUtil::IsRemovableStorageAttached(device_id
);
460 MediaGalleriesPreferences::GalleryChangeObserver::~GalleryChangeObserver() {}
462 MediaGalleriesPreferences::MediaGalleriesPreferences(Profile
* profile
)
463 : initialized_(false),
464 pre_initialization_callbacks_waiting_(0),
466 extension_prefs_for_testing_(NULL
),
467 weak_factory_(this) {
470 MediaGalleriesPreferences::~MediaGalleriesPreferences() {
471 if (StorageMonitor::GetInstance())
472 StorageMonitor::GetInstance()->RemoveObserver(this);
475 void MediaGalleriesPreferences::EnsureInitialized(base::Closure callback
) {
476 DCHECK_CURRENTLY_ON(content::BrowserThread::UI
);
478 if (IsInitialized()) {
479 if (!callback
.is_null())
484 on_initialize_callbacks_
.push_back(callback
);
485 if (on_initialize_callbacks_
.size() > 1)
488 // This counter must match the number of async methods dispatched below.
489 // It cannot be incremented inline with each callback, as some may return
490 // synchronously, decrement the counter to 0, and prematurely trigger
491 // FinishInitialization.
492 pre_initialization_callbacks_waiting_
= 4;
494 // Check whether we should be initializing -- are there any extensions that
495 // are using media galleries?
496 media_galleries::UsageCount(media_galleries::PREFS_INITIALIZED
);
497 if (NumberExtensionsUsingMediaGalleries(profile_
) == 0) {
498 media_galleries::UsageCount(media_galleries::PREFS_INITIALIZED_ERROR
);
501 // We determine the freshness of the profile here, before any of the finders
502 // return and add media galleries to it (hence why the APIHasBeenUsed check
503 // needs to happen here rather than inside OnStorageMonitorInit itself).
504 StorageMonitor::GetInstance()->EnsureInitialized(
505 base::Bind(&MediaGalleriesPreferences::OnStorageMonitorInit
,
506 weak_factory_
.GetWeakPtr(),
507 APIHasBeenUsed(profile_
)));
509 // Look for optional default galleries every time.
510 iapps::FindITunesLibrary(
511 base::Bind(&MediaGalleriesPreferences::OnFinderDeviceID
,
512 weak_factory_
.GetWeakPtr()));
514 picasa::FindPicasaDatabase(
515 base::Bind(&MediaGalleriesPreferences::OnFinderDeviceID
,
516 weak_factory_
.GetWeakPtr()));
518 iapps::FindIPhotoLibrary(
519 base::Bind(&MediaGalleriesPreferences::OnFinderDeviceID
,
520 weak_factory_
.GetWeakPtr()));
523 bool MediaGalleriesPreferences::IsInitialized() const { return initialized_
; }
525 Profile
* MediaGalleriesPreferences::profile() { return profile_
; }
527 void MediaGalleriesPreferences::OnInitializationCallbackReturned() {
528 DCHECK(!IsInitialized());
529 DCHECK_GT(pre_initialization_callbacks_waiting_
, 0);
530 if (--pre_initialization_callbacks_waiting_
== 0)
531 FinishInitialization();
534 void MediaGalleriesPreferences::FinishInitialization() {
535 DCHECK(!IsInitialized());
539 StorageMonitor
* monitor
= StorageMonitor::GetInstance();
540 DCHECK(monitor
->IsInitialized());
544 StorageMonitor::GetInstance()->AddObserver(this);
546 std::vector
<StorageInfo
> existing_devices
=
547 monitor
->GetAllAvailableStorages();
548 for (size_t i
= 0; i
< existing_devices
.size(); i
++) {
549 if (!(StorageInfo::IsMediaDevice(existing_devices
[i
].device_id()) &&
550 StorageInfo::IsRemovableDevice(existing_devices
[i
].device_id())))
552 AddGallery(existing_devices
[i
].device_id(),
554 MediaGalleryPrefInfo::kAutoDetected
,
555 existing_devices
[i
].storage_label(),
556 existing_devices
[i
].vendor_name(),
557 existing_devices
[i
].model_name(),
558 existing_devices
[i
].total_size_in_bytes(),
559 base::Time::Now(), 0, 0, 0);
562 for (std::vector
<base::Closure
>::iterator iter
=
563 on_initialize_callbacks_
.begin();
564 iter
!= on_initialize_callbacks_
.end();
568 on_initialize_callbacks_
.clear();
571 void MediaGalleriesPreferences::AddDefaultGalleries() {
572 const struct DefaultTypes
{
574 MediaGalleryPrefInfo::DefaultGalleryType default_gallery_type
;
576 {chrome::DIR_USER_MUSIC
, MediaGalleryPrefInfo::kMusicDefault
},
577 {chrome::DIR_USER_PICTURES
, MediaGalleryPrefInfo::kPicturesDefault
},
578 {chrome::DIR_USER_VIDEOS
, MediaGalleryPrefInfo::kVideosDefault
},
581 for (size_t i
= 0; i
< arraysize(kDirectories
); ++i
) {
583 if (!PathService::Get(kDirectories
[i
].directory_key
, &path
))
586 base::FilePath relative_path
;
588 if (MediaStorageUtil::GetDeviceInfoFromPath(path
, &info
, &relative_path
)) {
589 MediaGalleryPrefInfo::DefaultGalleryType default_gallery_type
=
590 kDirectories
[i
].default_gallery_type
;
591 DCHECK_NE(default_gallery_type
, MediaGalleryPrefInfo::kNotDefault
);
593 AddOrUpdateGalleryInternal(
597 MediaGalleryPrefInfo::kAutoDetected
,
598 info
.storage_label(),
601 info
.total_size_in_bytes(),
607 kCurrentPrefsVersion
,
608 default_gallery_type
);
613 bool MediaGalleriesPreferences::UpdateDeviceIDForSingletonType(
614 const std::string
& device_id
) {
615 StorageInfo::Type singleton_type
;
616 if (!StorageInfo::CrackDeviceId(device_id
, &singleton_type
, NULL
))
619 PrefService
* prefs
= profile_
->GetPrefs();
620 scoped_ptr
<ListPrefUpdate
> update(new ListPrefUpdate(
621 prefs
, prefs::kMediaGalleriesRememberedGalleries
));
622 base::ListValue
* list
= update
->Get();
623 for (base::ListValue::iterator iter
= list
->begin();
624 iter
!= list
->end(); ++iter
) {
625 // All of these calls should succeed, but preferences file can be corrupt.
626 base::DictionaryValue
* dict
;
627 if (!(*iter
)->GetAsDictionary(&dict
))
629 std::string this_device_id
;
630 if (!dict
->GetString(kMediaGalleriesDeviceIdKey
, &this_device_id
))
632 if (this_device_id
== device_id
)
633 return true; // No update is necessary.
634 StorageInfo::Type device_type
;
635 if (!StorageInfo::CrackDeviceId(this_device_id
, &device_type
, NULL
))
638 if (device_type
== singleton_type
) {
639 dict
->SetString(kMediaGalleriesDeviceIdKey
, device_id
);
640 update
.reset(); // commits the update.
642 MediaGalleryPrefId pref_id
;
643 if (GetPrefId(*dict
, &pref_id
)) {
644 FOR_EACH_OBSERVER(GalleryChangeObserver
,
645 gallery_change_observers_
,
646 OnGalleryInfoUpdated(this, pref_id
));
654 void MediaGalleriesPreferences::OnStorageMonitorInit(
655 bool api_has_been_used
) {
656 if (api_has_been_used
)
657 UpdateDefaultGalleriesPaths();
659 // Invoke this method even if the API has been used before, in order to ensure
660 // we upgrade (migrate) prefs for galleries with prefs version prior to 3.
661 AddDefaultGalleries();
663 OnInitializationCallbackReturned();
666 void MediaGalleriesPreferences::OnFinderDeviceID(const std::string
& device_id
) {
667 if (!device_id
.empty()) {
668 std::string gallery_name
;
669 if (StorageInfo::IsIPhotoDevice(device_id
))
670 gallery_name
= kIPhotoGalleryName
;
671 else if (StorageInfo::IsITunesDevice(device_id
))
672 gallery_name
= kITunesGalleryName
;
673 else if (StorageInfo::IsPicasaDevice(device_id
))
674 gallery_name
= kPicasaGalleryName
;
676 if (!gallery_name
.empty()) {
677 pre_initialization_callbacks_waiting_
++;
678 content::BrowserThread::PostTaskAndReply(
679 content::BrowserThread::FILE,
681 base::Bind(&InitializeImportedMediaGalleryRegistryOnFileThread
),
683 &MediaGalleriesPreferences::OnInitializationCallbackReturned
,
684 weak_factory_
.GetWeakPtr()));
687 if (!UpdateDeviceIDForSingletonType(device_id
)) {
688 DCHECK(!gallery_name
.empty());
689 AddOrUpdateGalleryInternal(
691 base::ASCIIToUTF16(gallery_name
),
693 MediaGalleryPrefInfo::kAutoDetected
,
703 kCurrentPrefsVersion
,
704 MediaGalleryPrefInfo::kNotDefault
);
708 OnInitializationCallbackReturned();
711 void MediaGalleriesPreferences::InitFromPrefs() {
712 known_galleries_
.clear();
715 PrefService
* prefs
= profile_
->GetPrefs();
716 const base::ListValue
* list
= prefs
->GetList(
717 prefs::kMediaGalleriesRememberedGalleries
);
719 for (base::ListValue::const_iterator it
= list
->begin();
720 it
!= list
->end(); ++it
) {
721 const base::DictionaryValue
* dict
= NULL
;
722 if (!(*it
)->GetAsDictionary(&dict
))
725 MediaGalleryPrefInfo gallery_info
;
726 if (!PopulateGalleryPrefInfoFromDictionary(*dict
, &gallery_info
))
729 known_galleries_
[gallery_info
.pref_id
] = gallery_info
;
730 device_map_
[gallery_info
.device_id
].insert(gallery_info
.pref_id
);
735 void MediaGalleriesPreferences::AddGalleryChangeObserver(
736 GalleryChangeObserver
* observer
) {
737 DCHECK(IsInitialized());
738 gallery_change_observers_
.AddObserver(observer
);
741 void MediaGalleriesPreferences::RemoveGalleryChangeObserver(
742 GalleryChangeObserver
* observer
) {
743 DCHECK(IsInitialized());
744 gallery_change_observers_
.RemoveObserver(observer
);
747 void MediaGalleriesPreferences::OnRemovableStorageAttached(
748 const StorageInfo
& info
) {
749 DCHECK(IsInitialized());
750 if (!StorageInfo::IsMediaDevice(info
.device_id()))
753 AddGallery(info
.device_id(), base::FilePath(),
754 MediaGalleryPrefInfo::kAutoDetected
, info
.storage_label(),
755 info
.vendor_name(), info
.model_name(), info
.total_size_in_bytes(),
756 base::Time::Now(), 0, 0, 0);
759 bool MediaGalleriesPreferences::LookUpGalleryByPath(
760 const base::FilePath
& path
,
761 MediaGalleryPrefInfo
* gallery_info
) const {
762 DCHECK(IsInitialized());
764 // First check if the path matches an imported gallery.
765 for (MediaGalleriesPrefInfoMap::const_iterator it
=
766 known_galleries_
.begin(); it
!= known_galleries_
.end(); ++it
) {
767 const std::string
& device_id
= it
->second
.device_id
;
768 if (iapps::PathIndicatesIPhotoLibrary(device_id
, path
) ||
769 iapps::PathIndicatesITunesLibrary(device_id
, path
)) {
770 *gallery_info
= it
->second
;
776 base::FilePath relative_path
;
777 if (!MediaStorageUtil::GetDeviceInfoFromPath(path
, &info
, &relative_path
)) {
779 *gallery_info
= MediaGalleryPrefInfo();
783 relative_path
= relative_path
.NormalizePathSeparators();
784 MediaGalleryPrefIdSet galleries_on_device
=
785 LookUpGalleriesByDeviceId(info
.device_id());
786 for (MediaGalleryPrefIdSet::const_iterator it
= galleries_on_device
.begin();
787 it
!= galleries_on_device
.end();
789 const MediaGalleryPrefInfo
& gallery
= known_galleries_
.find(*it
)->second
;
790 if (gallery
.path
!= relative_path
)
794 *gallery_info
= gallery
;
798 // This method is called by controller::FilesSelected when the user
799 // adds a new gallery. Control reaches here when the selected gallery is
800 // on a volume we know about, but have no gallery already for. Returns
801 // hypothetical data to the caller about what the prefs will look like
802 // if the gallery is added.
803 // TODO(gbillock): split this out into another function so it doesn't
806 gallery_info
->pref_id
= kInvalidMediaGalleryPrefId
;
807 gallery_info
->device_id
= info
.device_id();
808 gallery_info
->path
= relative_path
;
809 gallery_info
->type
= MediaGalleryPrefInfo::kInvalidType
;
810 gallery_info
->volume_label
= info
.storage_label();
811 gallery_info
->vendor_name
= info
.vendor_name();
812 gallery_info
->model_name
= info
.model_name();
813 gallery_info
->total_size_in_bytes
= info
.total_size_in_bytes();
814 gallery_info
->last_attach_time
= base::Time::Now();
815 gallery_info
->volume_metadata_valid
= true;
816 gallery_info
->prefs_version
= kCurrentPrefsVersion
;
821 MediaGalleryPrefIdSet
MediaGalleriesPreferences::LookUpGalleriesByDeviceId(
822 const std::string
& device_id
) const {
823 DeviceIdPrefIdsMap::const_iterator found
= device_map_
.find(device_id
);
824 if (found
== device_map_
.end())
825 return MediaGalleryPrefIdSet();
826 return found
->second
;
829 base::FilePath
MediaGalleriesPreferences::LookUpGalleryPathForExtension(
830 MediaGalleryPrefId gallery_id
,
831 const extensions::Extension
* extension
,
832 bool include_unpermitted_galleries
) {
833 DCHECK(IsInitialized());
835 if (!include_unpermitted_galleries
&&
836 !ContainsKey(GalleriesForExtension(*extension
), gallery_id
))
837 return base::FilePath();
839 MediaGalleriesPrefInfoMap::const_iterator it
=
840 known_galleries_
.find(gallery_id
);
841 if (it
== known_galleries_
.end())
842 return base::FilePath();
843 return MediaStorageUtil::FindDevicePathById(it
->second
.device_id
);
846 MediaGalleryPrefId
MediaGalleriesPreferences::AddGallery(
847 const std::string
& device_id
,
848 const base::FilePath
& relative_path
,
849 MediaGalleryPrefInfo::Type type
,
850 const base::string16
& volume_label
,
851 const base::string16
& vendor_name
,
852 const base::string16
& model_name
,
853 uint64 total_size_in_bytes
,
854 base::Time last_attach_time
,
858 DCHECK(IsInitialized());
859 return AddOrUpdateGalleryInternal(
873 kCurrentPrefsVersion
,
874 MediaGalleryPrefInfo::kNotDefault
);
877 MediaGalleryPrefId
MediaGalleriesPreferences::AddOrUpdateGalleryInternal(
878 const std::string
& device_id
, const base::string16
& display_name
,
879 const base::FilePath
& relative_path
, MediaGalleryPrefInfo::Type type
,
880 const base::string16
& volume_label
, const base::string16
& vendor_name
,
881 const base::string16
& model_name
, uint64 total_size_in_bytes
,
882 base::Time last_attach_time
, bool volume_metadata_valid
,
883 int audio_count
, int image_count
, int video_count
, int prefs_version
,
884 MediaGalleryPrefInfo::DefaultGalleryType default_gallery_type
) {
885 DCHECK(type
== MediaGalleryPrefInfo::kUserAdded
||
886 type
== MediaGalleryPrefInfo::kAutoDetected
||
887 type
== MediaGalleryPrefInfo::kScanResult
);
888 base::FilePath normalized_relative_path
=
889 relative_path
.NormalizePathSeparators();
890 MediaGalleryPrefIdSet galleries_on_device
=
891 LookUpGalleriesByDeviceId(device_id
);
893 for (MediaGalleryPrefIdSet::const_iterator pref_id_it
=
894 galleries_on_device
.begin();
895 pref_id_it
!= galleries_on_device
.end();
897 const MediaGalleryPrefInfo
& existing
=
898 known_galleries_
.find(*pref_id_it
)->second
;
899 if (existing
.path
!= normalized_relative_path
)
902 bool update_gallery_type
= false;
903 MediaGalleryPrefInfo::Type new_type
= existing
.type
;
904 if (type
== MediaGalleryPrefInfo::kUserAdded
) {
905 if (existing
.type
== MediaGalleryPrefInfo::kBlackListed
) {
906 new_type
= MediaGalleryPrefInfo::kAutoDetected
;
907 update_gallery_type
= true;
909 if (existing
.type
== MediaGalleryPrefInfo::kRemovedScan
) {
910 new_type
= MediaGalleryPrefInfo::kUserAdded
;
911 update_gallery_type
= true;
915 // Status quo: In M27 and M28, galleries added manually use version 0,
916 // and galleries added automatically (including default galleries) use
917 // version 1. The name override is used by default galleries as well
918 // as all device attach events.
919 // We want to upgrade the name if the existing version is < 2. Leave it
920 // alone if the existing display name is set with version >= 2 and the
921 // proposed new name is empty.
922 bool update_gallery_name
= existing
.display_name
!= display_name
;
923 if (existing
.prefs_version
>= 2 && !existing
.display_name
.empty() &&
924 display_name
.empty()) {
925 update_gallery_name
= false;
928 // Version 3 adds the default_gallery_type field.
929 bool update_default_gallery_type
=
930 existing
.prefs_version
<= 2 &&
931 default_gallery_type
!= existing
.default_gallery_type
;
933 bool update_gallery_metadata
= volume_metadata_valid
&&
934 ((existing
.volume_label
!= volume_label
) ||
935 (existing
.vendor_name
!= vendor_name
) ||
936 (existing
.model_name
!= model_name
) ||
937 (existing
.total_size_in_bytes
!= total_size_in_bytes
) ||
938 (existing
.last_attach_time
!= last_attach_time
));
940 bool update_scan_counts
=
941 new_type
!= MediaGalleryPrefInfo::kRemovedScan
&&
942 new_type
!= MediaGalleryPrefInfo::kBlackListed
&&
943 (audio_count
> 0 || image_count
> 0 || video_count
> 0 ||
944 existing
.audio_count
|| existing
.image_count
|| existing
.video_count
);
946 if (!update_gallery_name
&& !update_gallery_type
&&
947 !update_gallery_metadata
&& !update_scan_counts
&&
948 !update_default_gallery_type
)
951 PrefService
* prefs
= profile_
->GetPrefs();
952 scoped_ptr
<ListPrefUpdate
> update(
953 new ListPrefUpdate(prefs
, prefs::kMediaGalleriesRememberedGalleries
));
954 base::ListValue
* list
= update
->Get();
956 for (base::ListValue::const_iterator list_iter
= list
->begin();
957 list_iter
!= list
->end();
959 base::DictionaryValue
* dict
;
960 MediaGalleryPrefId iter_id
;
961 if ((*list_iter
)->GetAsDictionary(&dict
) &&
962 GetPrefId(*dict
, &iter_id
) &&
963 *pref_id_it
== iter_id
) {
964 if (update_gallery_type
)
965 dict
->SetString(kMediaGalleriesTypeKey
, TypeToStringValue(new_type
));
966 if (update_gallery_name
)
967 dict
->SetString(kMediaGalleriesDisplayNameKey
, display_name
);
968 if (update_gallery_metadata
) {
969 dict
->SetString(kMediaGalleriesVolumeLabelKey
, volume_label
);
970 dict
->SetString(kMediaGalleriesVendorNameKey
, vendor_name
);
971 dict
->SetString(kMediaGalleriesModelNameKey
, model_name
);
972 dict
->SetDouble(kMediaGalleriesSizeKey
, total_size_in_bytes
);
973 dict
->SetDouble(kMediaGalleriesLastAttachTimeKey
,
974 last_attach_time
.ToInternalValue());
976 if (update_scan_counts
) {
977 dict
->SetInteger(kMediaGalleriesScanAudioCountKey
, audio_count
);
978 dict
->SetInteger(kMediaGalleriesScanImageCountKey
, image_count
);
979 dict
->SetInteger(kMediaGalleriesScanVideoCountKey
, video_count
);
981 if (update_default_gallery_type
) {
983 kMediaGalleriesDefaultGalleryTypeKey
,
984 DefaultGalleryTypeToStringValue(default_gallery_type
));
986 dict
->SetInteger(kMediaGalleriesPrefsVersionKey
, prefs_version
);
991 // Commits the prefs update.
995 FOR_EACH_OBSERVER(GalleryChangeObserver
, gallery_change_observers_
,
996 OnGalleryInfoUpdated(this, *pref_id_it
));
1000 PrefService
* prefs
= profile_
->GetPrefs();
1002 MediaGalleryPrefInfo gallery_info
;
1003 gallery_info
.pref_id
= prefs
->GetUint64(prefs::kMediaGalleriesUniqueId
);
1004 prefs
->SetUint64(prefs::kMediaGalleriesUniqueId
, gallery_info
.pref_id
+ 1);
1005 gallery_info
.display_name
= display_name
;
1006 gallery_info
.device_id
= device_id
;
1007 gallery_info
.path
= normalized_relative_path
;
1008 gallery_info
.type
= type
;
1009 gallery_info
.volume_label
= volume_label
;
1010 gallery_info
.vendor_name
= vendor_name
;
1011 gallery_info
.model_name
= model_name
;
1012 gallery_info
.total_size_in_bytes
= total_size_in_bytes
;
1013 gallery_info
.last_attach_time
= last_attach_time
;
1014 gallery_info
.volume_metadata_valid
= volume_metadata_valid
;
1015 gallery_info
.audio_count
= audio_count
;
1016 gallery_info
.image_count
= image_count
;
1017 gallery_info
.video_count
= video_count
;
1018 gallery_info
.prefs_version
= prefs_version
;
1019 gallery_info
.default_gallery_type
= default_gallery_type
;
1022 ListPrefUpdate
update(prefs
, prefs::kMediaGalleriesRememberedGalleries
);
1023 base::ListValue
* list
= update
.Get();
1024 list
->Append(CreateGalleryPrefInfoDictionary(gallery_info
));
1027 FOR_EACH_OBSERVER(GalleryChangeObserver
,
1028 gallery_change_observers_
,
1029 OnGalleryAdded(this, gallery_info
.pref_id
));
1031 return gallery_info
.pref_id
;
1035 void MediaGalleriesPreferences::UpdateDefaultGalleriesPaths() {
1036 base::FilePath music_path
;
1037 base::FilePath pictures_path
;
1038 base::FilePath videos_path
;
1039 bool got_music_path
= PathService::Get(chrome::DIR_USER_MUSIC
, &music_path
);
1040 bool got_pictures_path
=
1041 PathService::Get(chrome::DIR_USER_PICTURES
, &pictures_path
);
1042 bool got_videos_path
=
1043 PathService::Get(chrome::DIR_USER_VIDEOS
, &videos_path
);
1045 PrefService
* prefs
= profile_
->GetPrefs();
1046 scoped_ptr
<ListPrefUpdate
> update(new ListPrefUpdate(
1047 prefs
, prefs::kMediaGalleriesRememberedGalleries
));
1048 base::ListValue
* list
= update
->Get();
1050 std::vector
<MediaGalleryPrefId
> pref_ids
;
1052 for (base::ListValue::iterator iter
= list
->begin();
1053 iter
!= list
->end();
1055 base::DictionaryValue
* dict
;
1056 MediaGalleryPrefId pref_id
;
1058 if (!((*iter
)->GetAsDictionary(&dict
) && GetPrefId(*dict
, &pref_id
)))
1061 std::string default_gallery_type_string
;
1063 // If the "default gallery type" key is set, just update the paths in place.
1064 // If it's not set, then AddOrUpdateGalleryInternal will take care of
1065 // setting it as part of migration to prefs version 3.
1066 if (dict
->GetString(kMediaGalleriesDefaultGalleryTypeKey
,
1067 &default_gallery_type_string
)) {
1068 std::string device_id
;
1069 if (got_music_path
&&
1070 default_gallery_type_string
==
1071 kMediaGalleriesDefaultGalleryTypeMusicDefaultValue
) {
1072 device_id
= StorageInfo::MakeDeviceId(
1073 StorageInfo::Type::FIXED_MASS_STORAGE
,
1074 music_path
.AsUTF8Unsafe());
1075 } else if (got_pictures_path
&&
1076 default_gallery_type_string
==
1077 kMediaGalleriesDefaultGalleryTypePicturesDefaultValue
) {
1078 device_id
= StorageInfo::MakeDeviceId(
1079 StorageInfo::Type::FIXED_MASS_STORAGE
,
1080 pictures_path
.AsUTF8Unsafe());
1081 } else if (got_videos_path
&&
1082 default_gallery_type_string
==
1083 kMediaGalleriesDefaultGalleryTypeVideosDefaultValue
) {
1084 device_id
= StorageInfo::MakeDeviceId(
1085 StorageInfo::Type::FIXED_MASS_STORAGE
,
1086 videos_path
.AsUTF8Unsafe());
1089 if (!device_id
.empty())
1090 dict
->SetString(kMediaGalleriesDeviceIdKey
, device_id
);
1093 pref_ids
.push_back(pref_id
);
1096 // Commit the prefs update.
1100 for (std::vector
<MediaGalleryPrefId
>::iterator iter
= pref_ids
.begin();
1101 iter
!= pref_ids
.end();
1103 FOR_EACH_OBSERVER(GalleryChangeObserver
,
1104 gallery_change_observers_
,
1105 OnGalleryInfoUpdated(this, *iter
));
1110 MediaGalleryPrefId
MediaGalleriesPreferences::AddGalleryByPath(
1111 const base::FilePath
& path
, MediaGalleryPrefInfo::Type type
) {
1112 DCHECK(IsInitialized());
1113 MediaGalleryPrefInfo gallery_info
;
1114 if (LookUpGalleryByPath(path
, &gallery_info
) &&
1115 !gallery_info
.IsBlackListedType()) {
1116 return gallery_info
.pref_id
;
1118 return AddOrUpdateGalleryInternal(gallery_info
.device_id
,
1119 gallery_info
.display_name
,
1122 gallery_info
.volume_label
,
1123 gallery_info
.vendor_name
,
1124 gallery_info
.model_name
,
1125 gallery_info
.total_size_in_bytes
,
1126 gallery_info
.last_attach_time
,
1127 gallery_info
.volume_metadata_valid
,
1129 kCurrentPrefsVersion
,
1130 MediaGalleryPrefInfo::kNotDefault
);
1133 void MediaGalleriesPreferences::ForgetGalleryById(MediaGalleryPrefId id
) {
1134 EraseOrBlacklistGalleryById(id
, false);
1137 void MediaGalleriesPreferences::EraseGalleryById(MediaGalleryPrefId id
) {
1138 EraseOrBlacklistGalleryById(id
, true);
1141 void MediaGalleriesPreferences::EraseOrBlacklistGalleryById(
1142 MediaGalleryPrefId id
, bool erase
) {
1143 DCHECK(IsInitialized());
1144 PrefService
* prefs
= profile_
->GetPrefs();
1145 scoped_ptr
<ListPrefUpdate
> update(new ListPrefUpdate(
1146 prefs
, prefs::kMediaGalleriesRememberedGalleries
));
1147 base::ListValue
* list
= update
->Get();
1149 if (!ContainsKey(known_galleries_
, id
))
1152 for (base::ListValue::iterator iter
= list
->begin();
1153 iter
!= list
->end(); ++iter
) {
1154 base::DictionaryValue
* dict
;
1155 MediaGalleryPrefId iter_id
;
1156 if ((*iter
)->GetAsDictionary(&dict
) && GetPrefId(*dict
, &iter_id
) &&
1158 RemoveGalleryPermissionsFromPrefs(id
);
1159 MediaGalleryPrefInfo::Type type
;
1160 if (!erase
&& GetType(*dict
, &type
) &&
1161 (type
== MediaGalleryPrefInfo::kAutoDetected
||
1162 type
== MediaGalleryPrefInfo::kScanResult
)) {
1163 if (type
== MediaGalleryPrefInfo::kAutoDetected
) {
1164 dict
->SetString(kMediaGalleriesTypeKey
,
1165 kMediaGalleriesTypeBlackListedValue
);
1167 dict
->SetString(kMediaGalleriesTypeKey
,
1168 kMediaGalleriesTypeRemovedScanValue
);
1169 dict
->SetInteger(kMediaGalleriesScanAudioCountKey
, 0);
1170 dict
->SetInteger(kMediaGalleriesScanImageCountKey
, 0);
1171 dict
->SetInteger(kMediaGalleriesScanVideoCountKey
, 0);
1174 list
->Erase(iter
, NULL
);
1176 update
.reset(NULL
); // commits the update.
1179 FOR_EACH_OBSERVER(GalleryChangeObserver
,
1180 gallery_change_observers_
,
1181 OnGalleryRemoved(this, id
));
1187 bool MediaGalleriesPreferences::NonAutoGalleryHasPermission(
1188 MediaGalleryPrefId id
) const {
1189 DCHECK(IsInitialized());
1190 DCHECK(!ContainsKey(known_galleries_
, id
) ||
1191 known_galleries_
.find(id
)->second
.type
!=
1192 MediaGalleryPrefInfo::kAutoDetected
);
1193 ExtensionPrefs
* prefs
= GetExtensionPrefs();
1194 const base::DictionaryValue
* extensions
=
1195 prefs
->pref_service()->GetDictionary(extensions::pref_names::kExtensions
);
1199 for (base::DictionaryValue::Iterator
iter(*extensions
); !iter
.IsAtEnd();
1201 if (!crx_file::id_util::IdIsValid(iter
.key())) {
1205 std::vector
<MediaGalleryPermission
> permissions
=
1206 GetGalleryPermissionsFromPrefs(iter
.key());
1207 for (std::vector
<MediaGalleryPermission
>::const_iterator it
=
1208 permissions
.begin(); it
!= permissions
.end(); ++it
) {
1209 if (it
->pref_id
== id
) {
1210 if (it
->has_permission
)
1219 MediaGalleryPrefIdSet
MediaGalleriesPreferences::GalleriesForExtension(
1220 const extensions::Extension
& extension
) {
1221 DCHECK(IsInitialized());
1222 MediaGalleryPrefIdSet result
;
1224 if (HasAutoDetectedGalleryPermission(extension
)) {
1225 for (MediaGalleriesPrefInfoMap::const_iterator it
=
1226 known_galleries_
.begin(); it
!= known_galleries_
.end(); ++it
) {
1227 if (it
->second
.type
== MediaGalleryPrefInfo::kAutoDetected
)
1228 result
.insert(it
->second
.pref_id
);
1232 std::vector
<MediaGalleryPermission
> stored_permissions
=
1233 GetGalleryPermissionsFromPrefs(extension
.id());
1234 for (std::vector
<MediaGalleryPermission
>::const_iterator it
=
1235 stored_permissions
.begin(); it
!= stored_permissions
.end(); ++it
) {
1236 if (!it
->has_permission
) {
1237 result
.erase(it
->pref_id
);
1239 MediaGalleriesPrefInfoMap::const_iterator gallery
=
1240 known_galleries_
.find(it
->pref_id
);
1242 // Handle a stored permission for an erased gallery. This should never
1243 // happen but, has caused crashes in the wild. http://crbug.com/374330.
1244 if (gallery
== known_galleries_
.end()) {
1245 RemoveGalleryPermissionsFromPrefs(it
->pref_id
);
1249 if (!gallery
->second
.IsBlackListedType()) {
1250 result
.insert(it
->pref_id
);
1252 NOTREACHED() << gallery
->second
.device_id
;
1259 bool MediaGalleriesPreferences::SetGalleryPermissionForExtension(
1260 const extensions::Extension
& extension
,
1261 MediaGalleryPrefId pref_id
,
1262 bool has_permission
) {
1263 DCHECK(IsInitialized());
1264 // The gallery may not exist anymore if the user opened a second config
1265 // surface concurrently and removed it. Drop the permission update if so.
1266 MediaGalleriesPrefInfoMap::const_iterator gallery_info
=
1267 known_galleries_
.find(pref_id
);
1268 if (gallery_info
== known_galleries_
.end())
1271 bool default_permission
= false;
1272 if (gallery_info
->second
.type
== MediaGalleryPrefInfo::kAutoDetected
)
1273 default_permission
= HasAutoDetectedGalleryPermission(extension
);
1274 // When the permission matches the default, we don't need to remember it.
1275 if (has_permission
== default_permission
) {
1276 if (!UnsetGalleryPermissionInPrefs(extension
.id(), pref_id
))
1277 // If permission wasn't set, assume nothing has changed.
1280 if (!SetGalleryPermissionInPrefs(extension
.id(), pref_id
, has_permission
))
1284 FOR_EACH_OBSERVER(GalleryChangeObserver
,
1285 gallery_change_observers_
,
1286 OnPermissionAdded(this, extension
.id(), pref_id
));
1288 FOR_EACH_OBSERVER(GalleryChangeObserver
,
1289 gallery_change_observers_
,
1290 OnPermissionRemoved(this, extension
.id(), pref_id
));
1294 const MediaGalleriesPrefInfoMap
& MediaGalleriesPreferences::known_galleries()
1296 DCHECK(IsInitialized());
1297 return known_galleries_
;
1300 base::Time
MediaGalleriesPreferences::GetLastScanCompletionTime() const {
1301 int64 last_scan_time_internal
=
1302 profile_
->GetPrefs()->GetInt64(prefs::kMediaGalleriesLastScanTime
);
1303 return base::Time::FromInternalValue(last_scan_time_internal
);
1306 void MediaGalleriesPreferences::SetLastScanCompletionTime(
1307 const base::Time
& time
) {
1308 profile_
->GetPrefs()->SetInt64(prefs::kMediaGalleriesLastScanTime
,
1309 time
.ToInternalValue());
1312 void MediaGalleriesPreferences::Shutdown() {
1313 weak_factory_
.InvalidateWeakPtrs();
1318 bool MediaGalleriesPreferences::APIHasBeenUsed(Profile
* profile
) {
1319 MediaGalleryPrefId current_id
=
1320 profile
->GetPrefs()->GetUint64(prefs::kMediaGalleriesUniqueId
);
1321 return current_id
!= kInvalidMediaGalleryPrefId
+ 1;
1325 void MediaGalleriesPreferences::RegisterProfilePrefs(
1326 user_prefs::PrefRegistrySyncable
* registry
) {
1327 registry
->RegisterListPref(prefs::kMediaGalleriesRememberedGalleries
,
1328 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF
);
1329 registry
->RegisterUint64Pref(
1330 prefs::kMediaGalleriesUniqueId
,
1331 kInvalidMediaGalleryPrefId
+ 1,
1332 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF
);
1333 registry
->RegisterInt64Pref(
1334 prefs::kMediaGalleriesLastScanTime
,
1335 base::Time().ToInternalValue(),
1336 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF
);
1339 bool MediaGalleriesPreferences::SetGalleryPermissionInPrefs(
1340 const std::string
& extension_id
,
1341 MediaGalleryPrefId gallery_id
,
1343 DCHECK(IsInitialized());
1344 ExtensionPrefs::ScopedListUpdate
update(GetExtensionPrefs(),
1346 kMediaGalleriesPermissions
);
1347 base::ListValue
* permissions
= update
.Get();
1349 permissions
= update
.Create();
1351 // If the gallery is already in the list, update the permission...
1352 for (base::ListValue::iterator iter
= permissions
->begin();
1353 iter
!= permissions
->end(); ++iter
) {
1354 base::DictionaryValue
* dict
= NULL
;
1355 if (!(*iter
)->GetAsDictionary(&dict
))
1357 MediaGalleryPermission perm
;
1358 if (!GetMediaGalleryPermissionFromDictionary(dict
, &perm
))
1360 if (perm
.pref_id
== gallery_id
) {
1361 if (has_access
!= perm
.has_permission
) {
1362 dict
->SetBoolean(kMediaGalleryHasPermissionKey
, has_access
);
1370 // ...Otherwise, add a new entry for the gallery.
1371 base::DictionaryValue
* dict
= new base::DictionaryValue
;
1372 dict
->SetString(kMediaGalleryIdKey
, base::Uint64ToString(gallery_id
));
1373 dict
->SetBoolean(kMediaGalleryHasPermissionKey
, has_access
);
1374 permissions
->Append(dict
);
1378 bool MediaGalleriesPreferences::UnsetGalleryPermissionInPrefs(
1379 const std::string
& extension_id
,
1380 MediaGalleryPrefId gallery_id
) {
1381 DCHECK(IsInitialized());
1382 ExtensionPrefs::ScopedListUpdate
update(GetExtensionPrefs(),
1384 kMediaGalleriesPermissions
);
1385 base::ListValue
* permissions
= update
.Get();
1389 for (base::ListValue::iterator iter
= permissions
->begin();
1390 iter
!= permissions
->end(); ++iter
) {
1391 const base::DictionaryValue
* dict
= NULL
;
1392 if (!(*iter
)->GetAsDictionary(&dict
))
1394 MediaGalleryPermission perm
;
1395 if (!GetMediaGalleryPermissionFromDictionary(dict
, &perm
))
1397 if (perm
.pref_id
== gallery_id
) {
1398 permissions
->Erase(iter
, NULL
);
1405 std::vector
<MediaGalleryPermission
>
1406 MediaGalleriesPreferences::GetGalleryPermissionsFromPrefs(
1407 const std::string
& extension_id
) const {
1408 DCHECK(IsInitialized());
1409 std::vector
<MediaGalleryPermission
> result
;
1410 const base::ListValue
* permissions
;
1411 if (!GetExtensionPrefs()->ReadPrefAsList(extension_id
,
1412 kMediaGalleriesPermissions
,
1417 for (base::ListValue::const_iterator iter
= permissions
->begin();
1418 iter
!= permissions
->end(); ++iter
) {
1419 base::DictionaryValue
* dict
= NULL
;
1420 if (!(*iter
)->GetAsDictionary(&dict
))
1422 MediaGalleryPermission perm
;
1423 if (!GetMediaGalleryPermissionFromDictionary(dict
, &perm
))
1425 result
.push_back(perm
);
1431 void MediaGalleriesPreferences::RemoveGalleryPermissionsFromPrefs(
1432 MediaGalleryPrefId gallery_id
) {
1433 DCHECK(IsInitialized());
1434 ExtensionPrefs
* prefs
= GetExtensionPrefs();
1435 const base::DictionaryValue
* extensions
=
1436 prefs
->pref_service()->GetDictionary(extensions::pref_names::kExtensions
);
1440 for (base::DictionaryValue::Iterator
iter(*extensions
); !iter
.IsAtEnd();
1442 if (!crx_file::id_util::IdIsValid(iter
.key())) {
1446 UnsetGalleryPermissionInPrefs(iter
.key(), gallery_id
);
1450 ExtensionPrefs
* MediaGalleriesPreferences::GetExtensionPrefs() const {
1451 DCHECK(IsInitialized());
1452 if (extension_prefs_for_testing_
)
1453 return extension_prefs_for_testing_
;
1454 return extensions::ExtensionPrefs::Get(profile_
);
1457 void MediaGalleriesPreferences::SetExtensionPrefsForTesting(
1458 extensions::ExtensionPrefs
* extension_prefs
) {
1459 DCHECK(IsInitialized());
1460 extension_prefs_for_testing_
= extension_prefs
;