| // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "chrome/browser/media_galleries/media_galleries_preferences.h" |
| |
| #include <stddef.h> |
| |
| #include <memory> |
| #include <utility> |
| |
| #include "base/base_paths_posix.h" |
| #include "base/callback.h" |
| #include "base/i18n/time_formatting.h" |
| #include "base/macros.h" |
| #include "base/memory/ptr_util.h" |
| #include "base/path_service.h" |
| #include "base/stl_util.h" |
| #include "base/strings/string16.h" |
| #include "base/strings/string_number_conversions.h" |
| #include "base/strings/utf_string_conversions.h" |
| #include "base/values.h" |
| #include "build/build_config.h" |
| #include "chrome/browser/browser_process.h" |
| #include "chrome/browser/media_galleries/fileapi/iapps_finder.h" |
| #include "chrome/browser/media_galleries/fileapi/picasa_finder.h" |
| #include "chrome/browser/media_galleries/imported_media_gallery_registry.h" |
| #include "chrome/browser/media_galleries/media_file_system_registry.h" |
| #include "chrome/browser/media_galleries/media_galleries_histograms.h" |
| #include "chrome/browser/profiles/profile.h" |
| #include "chrome/common/chrome_paths.h" |
| #include "chrome/common/pref_names.h" |
| #include "chrome/grit/generated_resources.h" |
| #include "components/crx_file/id_util.h" |
| #include "components/pref_registry/pref_registry_syncable.h" |
| #include "components/prefs/pref_service.h" |
| #include "components/prefs/scoped_user_pref_update.h" |
| #include "components/storage_monitor/media_storage_util.h" |
| #include "components/storage_monitor/storage_monitor.h" |
| #include "content/public/browser/browser_thread.h" |
| #include "extensions/browser/extension_prefs.h" |
| #include "extensions/browser/extension_registry.h" |
| #include "extensions/browser/pref_names.h" |
| #include "extensions/common/extension_set.h" |
| #include "extensions/common/permissions/api_permission.h" |
| #include "extensions/common/permissions/media_galleries_permission.h" |
| #include "extensions/common/permissions/permissions_data.h" |
| #include "ui/base/l10n/l10n_util.h" |
| |
| using base::DictionaryValue; |
| using base::ListValue; |
| using extensions::ExtensionPrefs; |
| using storage_monitor::MediaStorageUtil; |
| using storage_monitor::StorageInfo; |
| using storage_monitor::StorageMonitor; |
| |
| namespace { |
| |
| // Pref key for the list of media gallery permissions. |
| const char kMediaGalleriesPermissions[] = "media_galleries_permissions"; |
| // Pref key for Media Gallery ID. |
| const char kMediaGalleryIdKey[] = "id"; |
| // Pref key for Media Gallery Permission Value. |
| const char kMediaGalleryHasPermissionKey[] = "has_permission"; |
| |
| const char kMediaGalleriesDeviceIdKey[] = "deviceId"; |
| const char kMediaGalleriesDisplayNameKey[] = "displayName"; |
| const char kMediaGalleriesPathKey[] = "path"; |
| const char kMediaGalleriesPrefIdKey[] = "prefId"; |
| const char kMediaGalleriesTypeKey[] = "type"; |
| const char kMediaGalleriesVolumeLabelKey[] = "volumeLabel"; |
| const char kMediaGalleriesVendorNameKey[] = "vendorName"; |
| const char kMediaGalleriesModelNameKey[] = "modelName"; |
| const char kMediaGalleriesSizeKey[] = "totalSize"; |
| const char kMediaGalleriesLastAttachTimeKey[] = "lastAttachTime"; |
| const char kMediaGalleriesScanAudioCountKey[] = "audioCount"; |
| const char kMediaGalleriesScanImageCountKey[] = "imageCount"; |
| const char kMediaGalleriesScanVideoCountKey[] = "videoCount"; |
| |
| const char kMediaGalleriesTypeAutoDetectedValue[] = "autoDetected"; |
| const char kMediaGalleriesTypeBlackListedValue[] = "blackListed"; |
| const char kMediaGalleriesTypeRemovedScanValue[] = "removedScan"; |
| const char kMediaGalleriesTypeScanResultValue[] = "scanResult"; |
| const char kMediaGalleriesTypeUserAddedValue[] = "userAdded"; |
| |
| const char kMediaGalleriesDefaultGalleryTypeNotDefaultValue[] = "notDefault"; |
| const char kMediaGalleriesDefaultGalleryTypeMusicDefaultValue[] = "music"; |
| const char kMediaGalleriesDefaultGalleryTypePicturesDefaultValue[] = "pictures"; |
| const char kMediaGalleriesDefaultGalleryTypeVideosDefaultValue[] = "videos"; |
| |
| const char kITunesGalleryName[] = "iTunes"; |
| const char kPicasaGalleryName[] = "Picasa"; |
| |
| const int kCurrentPrefsVersion = 3; |
| |
| int NumberExtensionsUsingMediaGalleries(Profile* profile) { |
| int count = 0; |
| if (!profile) |
| return count; |
| |
| for (const scoped_refptr<const extensions::Extension>& extension : |
| extensions::ExtensionRegistry::Get(profile)->enabled_extensions()) { |
| const extensions::PermissionsData* permissions_data = |
| extension->permissions_data(); |
| if (permissions_data->HasAPIPermission( |
| extensions::APIPermission::kMediaGalleries)) { |
| count++; |
| } |
| } |
| return count; |
| } |
| |
| bool GetPrefId(const base::DictionaryValue& dict, MediaGalleryPrefId* value) { |
| std::string string_id; |
| if (!dict.GetString(kMediaGalleriesPrefIdKey, &string_id) || |
| !base::StringToUint64(string_id, value)) { |
| return false; |
| } |
| |
| return true; |
| } |
| |
| bool GetType(const base::DictionaryValue& dict, |
| MediaGalleryPrefInfo::Type* type) { |
| std::string string_type; |
| if (!dict.GetString(kMediaGalleriesTypeKey, &string_type)) |
| return false; |
| |
| if (string_type == kMediaGalleriesTypeUserAddedValue) { |
| *type = MediaGalleryPrefInfo::kUserAdded; |
| return true; |
| } |
| if (string_type == kMediaGalleriesTypeAutoDetectedValue) { |
| *type = MediaGalleryPrefInfo::kAutoDetected; |
| return true; |
| } |
| if (string_type == kMediaGalleriesTypeBlackListedValue) { |
| *type = MediaGalleryPrefInfo::kBlackListed; |
| return true; |
| } |
| if (string_type == kMediaGalleriesTypeScanResultValue) { |
| *type = MediaGalleryPrefInfo::kScanResult; |
| return true; |
| } |
| if (string_type == kMediaGalleriesTypeRemovedScanValue) { |
| *type = MediaGalleryPrefInfo::kRemovedScan; |
| return true; |
| } |
| |
| return false; |
| } |
| |
| const char* TypeToStringValue(MediaGalleryPrefInfo::Type type) { |
| const char* result = NULL; |
| switch (type) { |
| case MediaGalleryPrefInfo::kUserAdded: |
| result = kMediaGalleriesTypeUserAddedValue; |
| break; |
| case MediaGalleryPrefInfo::kAutoDetected: |
| result = kMediaGalleriesTypeAutoDetectedValue; |
| break; |
| case MediaGalleryPrefInfo::kBlackListed: |
| result = kMediaGalleriesTypeBlackListedValue; |
| break; |
| case MediaGalleryPrefInfo::kScanResult: |
| result = kMediaGalleriesTypeScanResultValue; |
| break; |
| case MediaGalleryPrefInfo::kRemovedScan: |
| result = kMediaGalleriesTypeRemovedScanValue; |
| break; |
| default: |
| NOTREACHED(); |
| break; |
| } |
| return result; |
| } |
| |
| MediaGalleryPrefInfo::DefaultGalleryType GetDefaultGalleryType( |
| const base::DictionaryValue& dict) { |
| std::string default_gallery_type_string; |
| if (!dict.GetString( |
| kMediaGalleriesDefaultGalleryTypeKey, &default_gallery_type_string)) |
| return MediaGalleryPrefInfo::kNotDefault; |
| |
| if (default_gallery_type_string == |
| kMediaGalleriesDefaultGalleryTypeMusicDefaultValue) { |
| return MediaGalleryPrefInfo::kMusicDefault; |
| } |
| if (default_gallery_type_string == |
| kMediaGalleriesDefaultGalleryTypePicturesDefaultValue) { |
| return MediaGalleryPrefInfo::kPicturesDefault; |
| } |
| if (default_gallery_type_string == |
| kMediaGalleriesDefaultGalleryTypeVideosDefaultValue) { |
| return MediaGalleryPrefInfo::kVideosDefault; |
| } |
| return MediaGalleryPrefInfo::kNotDefault; |
| } |
| |
| const char* DefaultGalleryTypeToStringValue( |
| MediaGalleryPrefInfo::DefaultGalleryType default_gallery_type) { |
| const char* result = NULL; |
| switch (default_gallery_type) { |
| case MediaGalleryPrefInfo::kNotDefault: |
| result = kMediaGalleriesDefaultGalleryTypeNotDefaultValue; |
| break; |
| case MediaGalleryPrefInfo::kMusicDefault: |
| result = kMediaGalleriesDefaultGalleryTypeMusicDefaultValue; |
| break; |
| case MediaGalleryPrefInfo::kPicturesDefault: |
| result = kMediaGalleriesDefaultGalleryTypePicturesDefaultValue; |
| break; |
| case MediaGalleryPrefInfo::kVideosDefault: |
| result = kMediaGalleriesDefaultGalleryTypeVideosDefaultValue; |
| break; |
| default: |
| NOTREACHED(); |
| break; |
| } |
| return result; |
| } |
| |
| bool PopulateGalleryPrefInfoFromDictionary( |
| const base::DictionaryValue& dict, MediaGalleryPrefInfo* out_gallery_info) { |
| MediaGalleryPrefId pref_id; |
| base::string16 display_name; |
| std::string device_id; |
| base::FilePath::StringType path; |
| MediaGalleryPrefInfo::Type type = MediaGalleryPrefInfo::kInvalidType; |
| base::string16 volume_label; |
| base::string16 vendor_name; |
| base::string16 model_name; |
| double total_size_in_bytes = 0.0; |
| double last_attach_time = 0.0; |
| bool volume_metadata_valid = false; |
| int audio_count = 0; |
| int image_count = 0; |
| int video_count = 0; |
| int prefs_version = 0; |
| |
| if (!GetPrefId(dict, &pref_id) || |
| !dict.GetString(kMediaGalleriesDeviceIdKey, &device_id) || |
| !dict.GetString(kMediaGalleriesPathKey, &path) || |
| !GetType(dict, &type)) { |
| return false; |
| } |
| |
| dict.GetString(kMediaGalleriesDisplayNameKey, &display_name); |
| dict.GetInteger(kMediaGalleriesPrefsVersionKey, &prefs_version); |
| |
| if (dict.GetString(kMediaGalleriesVolumeLabelKey, &volume_label) && |
| dict.GetString(kMediaGalleriesVendorNameKey, &vendor_name) && |
| dict.GetString(kMediaGalleriesModelNameKey, &model_name) && |
| dict.GetDouble(kMediaGalleriesSizeKey, &total_size_in_bytes) && |
| dict.GetDouble(kMediaGalleriesLastAttachTimeKey, &last_attach_time)) { |
| volume_metadata_valid = true; |
| } |
| |
| if (dict.GetInteger(kMediaGalleriesScanAudioCountKey, &audio_count) && |
| dict.GetInteger(kMediaGalleriesScanImageCountKey, &image_count) && |
| dict.GetInteger(kMediaGalleriesScanVideoCountKey, &video_count)) { |
| out_gallery_info->audio_count = audio_count; |
| out_gallery_info->image_count = image_count; |
| out_gallery_info->video_count = video_count; |
| } else { |
| out_gallery_info->audio_count = 0; |
| out_gallery_info->image_count = 0; |
| out_gallery_info->video_count = 0; |
| } |
| |
| out_gallery_info->pref_id = pref_id; |
| out_gallery_info->display_name = display_name; |
| out_gallery_info->device_id = device_id; |
| out_gallery_info->path = base::FilePath(path); |
| out_gallery_info->type = type; |
| out_gallery_info->volume_label = volume_label; |
| out_gallery_info->vendor_name = vendor_name; |
| out_gallery_info->model_name = model_name; |
| out_gallery_info->total_size_in_bytes = total_size_in_bytes; |
| out_gallery_info->last_attach_time = |
| base::Time::FromInternalValue(last_attach_time); |
| out_gallery_info->volume_metadata_valid = volume_metadata_valid; |
| out_gallery_info->prefs_version = prefs_version; |
| out_gallery_info->default_gallery_type = GetDefaultGalleryType(dict); |
| return true; |
| } |
| |
| std::unique_ptr<base::DictionaryValue> CreateGalleryPrefInfoDictionary( |
| const MediaGalleryPrefInfo& gallery) { |
| auto dict = base::MakeUnique<base::DictionaryValue>(); |
| dict->SetString(kMediaGalleriesPrefIdKey, |
| base::Uint64ToString(gallery.pref_id)); |
| dict->SetString(kMediaGalleriesDeviceIdKey, gallery.device_id); |
| dict->SetString(kMediaGalleriesPathKey, gallery.path.value()); |
| dict->SetString(kMediaGalleriesTypeKey, TypeToStringValue(gallery.type)); |
| |
| if (gallery.default_gallery_type != MediaGalleryPrefInfo::kNotDefault) { |
| dict->SetString(kMediaGalleriesDefaultGalleryTypeKey, |
| DefaultGalleryTypeToStringValue( |
| gallery.default_gallery_type)); |
| } |
| |
| if (gallery.volume_metadata_valid) { |
| dict->SetString(kMediaGalleriesVolumeLabelKey, gallery.volume_label); |
| dict->SetString(kMediaGalleriesVendorNameKey, gallery.vendor_name); |
| dict->SetString(kMediaGalleriesModelNameKey, gallery.model_name); |
| dict->SetDouble(kMediaGalleriesSizeKey, gallery.total_size_in_bytes); |
| dict->SetDouble(kMediaGalleriesLastAttachTimeKey, |
| gallery.last_attach_time.ToInternalValue()); |
| } else { |
| dict->SetString(kMediaGalleriesDisplayNameKey, gallery.display_name); |
| } |
| |
| if (gallery.audio_count || gallery.image_count || gallery.video_count) { |
| dict->SetInteger(kMediaGalleriesScanAudioCountKey, gallery.audio_count); |
| dict->SetInteger(kMediaGalleriesScanImageCountKey, gallery.image_count); |
| dict->SetInteger(kMediaGalleriesScanVideoCountKey, gallery.video_count); |
| } |
| |
| // Version 0 of the prefs format was that the display_name was always |
| // used to show the user-visible name of the gallery. Version 1 means |
| // that there is an optional display_name, and when it is present, it |
| // overrides the name that would be built from the volume metadata, path, |
| // or whatever other data. So if we see a display_name with version 0, it |
| // means it may be overwritten simply by getting new volume metadata. |
| // A display_name with version 1 should not be overwritten. |
| dict->SetInteger(kMediaGalleriesPrefsVersionKey, gallery.prefs_version); |
| |
| return dict; |
| } |
| |
| bool HasAutoDetectedGalleryPermission(const extensions::Extension& extension) { |
| extensions::MediaGalleriesPermission::CheckParam param( |
| extensions::MediaGalleriesPermission::kAllAutoDetectedPermission); |
| return extension.permissions_data()->CheckAPIPermissionWithParam( |
| extensions::APIPermission::kMediaGalleries, ¶m); |
| } |
| |
| // Retrieves the MediaGalleryPermission from the given dictionary; DCHECKs on |
| // failure. |
| bool GetMediaGalleryPermissionFromDictionary( |
| const base::DictionaryValue* dict, |
| MediaGalleryPermission* out_permission) { |
| std::string string_id; |
| if (dict->GetString(kMediaGalleryIdKey, &string_id) && |
| base::StringToUint64(string_id, &out_permission->pref_id) && |
| dict->GetBoolean(kMediaGalleryHasPermissionKey, |
| &out_permission->has_permission)) { |
| return true; |
| } |
| NOTREACHED(); |
| return false; |
| } |
| |
| // For a device with |device_name| and a relative path |sub_folder|, construct |
| // a display name. If |sub_folder| is empty, then just return |device_name|. |
| base::string16 GetDisplayNameForSubFolder(const base::string16& device_name, |
| const base::FilePath& sub_folder) { |
| if (sub_folder.empty()) |
| return device_name; |
| return (sub_folder.BaseName().LossyDisplayName() + |
| base::ASCIIToUTF16(" - ") + |
| device_name); |
| } |
| |
| void InitializeImportedMediaGalleryRegistryOnFileThread() { |
| DCHECK_CURRENTLY_ON(content::BrowserThread::FILE); |
| ImportedMediaGalleryRegistry::GetInstance()->Initialize(); |
| } |
| |
| } // namespace |
| |
| MediaGalleryPrefInfo::MediaGalleryPrefInfo() |
| : pref_id(kInvalidMediaGalleryPrefId), |
| type(kInvalidType), |
| total_size_in_bytes(0), |
| volume_metadata_valid(false), |
| audio_count(0), |
| image_count(0), |
| video_count(0), |
| default_gallery_type(kNotDefault), |
| prefs_version(0) { |
| } |
| |
| MediaGalleryPrefInfo::MediaGalleryPrefInfo(const MediaGalleryPrefInfo& other) = |
| default; |
| |
| MediaGalleryPrefInfo::~MediaGalleryPrefInfo() {} |
| |
| base::FilePath MediaGalleryPrefInfo::AbsolutePath() const { |
| base::FilePath base_path = MediaStorageUtil::FindDevicePathById(device_id); |
| DCHECK(!path.IsAbsolute()); |
| return base_path.empty() ? base_path : base_path.Append(path); |
| } |
| |
| bool MediaGalleryPrefInfo::IsBlackListedType() const { |
| return type == kBlackListed || type == kRemovedScan; |
| } |
| |
| base::string16 MediaGalleryPrefInfo::GetGalleryDisplayName() const { |
| if (!StorageInfo::IsRemovableDevice(device_id)) { |
| // For fixed storage, the default name is the fully qualified directory |
| // name, or in the case of a root directory, the root directory name. |
| // Exception: ChromeOS -- the full pathname isn't visible there, so only |
| // the directory name is used. |
| base::FilePath path = AbsolutePath(); |
| if (!display_name.empty()) |
| return display_name; |
| |
| #if defined(OS_CHROMEOS) |
| // See chrome/browser/chromeos/fileapi/file_system_backend.cc |
| base::FilePath download_path; |
| if (PathService::Get(chrome::DIR_DEFAULT_DOWNLOADS_SAFE, &download_path)) { |
| base::FilePath relative; |
| if (download_path.AppendRelativePath(path, &relative)) |
| return relative.LossyDisplayName(); |
| } |
| return path.BaseName().LossyDisplayName(); |
| #else |
| return path.LossyDisplayName(); |
| #endif |
| } |
| |
| StorageInfo info(device_id, |
| MediaStorageUtil::FindDevicePathById(device_id).value(), |
| volume_label, vendor_name, model_name, total_size_in_bytes); |
| base::string16 name = info.GetDisplayNameWithOverride(display_name, true); |
| if (!path.empty()) |
| name = GetDisplayNameForSubFolder(name, path); |
| return name; |
| } |
| |
| base::string16 MediaGalleryPrefInfo::GetGalleryTooltip() const { |
| return AbsolutePath().LossyDisplayName(); |
| } |
| |
| base::string16 MediaGalleryPrefInfo::GetGalleryAdditionalDetails() const { |
| base::string16 attached; |
| if (StorageInfo::IsRemovableDevice(device_id)) { |
| if (MediaStorageUtil::IsRemovableStorageAttached(device_id)) { |
| attached = l10n_util::GetStringUTF16( |
| IDS_MEDIA_GALLERIES_DIALOG_DEVICE_ATTACHED); |
| } else if (!last_attach_time.is_null()) { |
| attached = l10n_util::GetStringFUTF16( |
| IDS_MEDIA_GALLERIES_LAST_ATTACHED, |
| base::TimeFormatShortDateNumeric(last_attach_time)); |
| } else { |
| attached = l10n_util::GetStringUTF16( |
| IDS_MEDIA_GALLERIES_DIALOG_DEVICE_NOT_ATTACHED); |
| } |
| } |
| |
| return attached; |
| } |
| |
| bool MediaGalleryPrefInfo::IsGalleryAvailable() const { |
| return !StorageInfo::IsRemovableDevice(device_id) || |
| MediaStorageUtil::IsRemovableStorageAttached(device_id); |
| } |
| |
| MediaGalleriesPreferences::GalleryChangeObserver::~GalleryChangeObserver() {} |
| |
| MediaGalleriesPreferences::MediaGalleriesPreferences(Profile* profile) |
| : initialized_(false), |
| pre_initialization_callbacks_waiting_(0), |
| profile_(profile), |
| extension_prefs_for_testing_(NULL), |
| weak_factory_(this) { |
| } |
| |
| MediaGalleriesPreferences::~MediaGalleriesPreferences() { |
| if (StorageMonitor::GetInstance()) |
| StorageMonitor::GetInstance()->RemoveObserver(this); |
| } |
| |
| void MediaGalleriesPreferences::EnsureInitialized(base::Closure callback) { |
| DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| |
| if (IsInitialized()) { |
| if (!callback.is_null()) |
| callback.Run(); |
| return; |
| } |
| |
| on_initialize_callbacks_.push_back(callback); |
| if (on_initialize_callbacks_.size() > 1) |
| return; |
| |
| // This counter must match the number of async methods dispatched below. |
| // It cannot be incremented inline with each callback, as some may return |
| // synchronously, decrement the counter to 0, and prematurely trigger |
| // FinishInitialization. |
| pre_initialization_callbacks_waiting_ = 3; |
| |
| // Check whether we should be initializing -- are there any extensions that |
| // are using media galleries? |
| media_galleries::UsageCount(media_galleries::PREFS_INITIALIZED); |
| if (NumberExtensionsUsingMediaGalleries(profile_) == 0) { |
| media_galleries::UsageCount(media_galleries::PREFS_INITIALIZED_ERROR); |
| } |
| |
| // We determine the freshness of the profile here, before any of the finders |
| // return and add media galleries to it (hence why the APIHasBeenUsed check |
| // needs to happen here rather than inside OnStorageMonitorInit itself). |
| StorageMonitor::GetInstance()->EnsureInitialized( |
| base::Bind(&MediaGalleriesPreferences::OnStorageMonitorInit, |
| weak_factory_.GetWeakPtr(), |
| APIHasBeenUsed(profile_))); |
| |
| // Look for optional default galleries every time. |
| iapps::FindITunesLibrary( |
| base::Bind(&MediaGalleriesPreferences::OnFinderDeviceID, |
| weak_factory_.GetWeakPtr())); |
| |
| picasa::FindPicasaDatabase( |
| base::Bind(&MediaGalleriesPreferences::OnFinderDeviceID, |
| weak_factory_.GetWeakPtr())); |
| } |
| |
| bool MediaGalleriesPreferences::IsInitialized() const { return initialized_; } |
| |
| Profile* MediaGalleriesPreferences::profile() { return profile_; } |
| |
| void MediaGalleriesPreferences::OnInitializationCallbackReturned() { |
| DCHECK(!IsInitialized()); |
| DCHECK_GT(pre_initialization_callbacks_waiting_, 0); |
| if (--pre_initialization_callbacks_waiting_ == 0) |
| FinishInitialization(); |
| } |
| |
| void MediaGalleriesPreferences::FinishInitialization() { |
| DCHECK(!IsInitialized()); |
| |
| initialized_ = true; |
| |
| StorageMonitor* monitor = StorageMonitor::GetInstance(); |
| DCHECK(monitor->IsInitialized()); |
| |
| InitFromPrefs(); |
| |
| StorageMonitor::GetInstance()->AddObserver(this); |
| |
| std::vector<StorageInfo> existing_devices = |
| monitor->GetAllAvailableStorages(); |
| for (size_t i = 0; i < existing_devices.size(); i++) { |
| if (!(StorageInfo::IsMediaDevice(existing_devices[i].device_id()) && |
| StorageInfo::IsRemovableDevice(existing_devices[i].device_id()))) |
| continue; |
| AddGallery(existing_devices[i].device_id(), |
| base::FilePath(), |
| MediaGalleryPrefInfo::kAutoDetected, |
| existing_devices[i].storage_label(), |
| existing_devices[i].vendor_name(), |
| existing_devices[i].model_name(), |
| existing_devices[i].total_size_in_bytes(), |
| base::Time::Now(), 0, 0, 0); |
| } |
| |
| for (std::vector<base::Closure>::iterator iter = |
| on_initialize_callbacks_.begin(); |
| iter != on_initialize_callbacks_.end(); |
| ++iter) { |
| iter->Run(); |
| } |
| on_initialize_callbacks_.clear(); |
| } |
| |
| void MediaGalleriesPreferences::AddDefaultGalleries() { |
| const struct DefaultTypes { |
| int directory_key; |
| MediaGalleryPrefInfo::DefaultGalleryType default_gallery_type; |
| } kDirectories[] = { |
| {chrome::DIR_USER_MUSIC, MediaGalleryPrefInfo::kMusicDefault}, |
| {chrome::DIR_USER_PICTURES, MediaGalleryPrefInfo::kPicturesDefault}, |
| {chrome::DIR_USER_VIDEOS, MediaGalleryPrefInfo::kVideosDefault}, |
| }; |
| |
| for (size_t i = 0; i < arraysize(kDirectories); ++i) { |
| base::FilePath path; |
| if (!PathService::Get(kDirectories[i].directory_key, &path)) |
| continue; |
| |
| base::FilePath relative_path; |
| StorageInfo info; |
| if (MediaStorageUtil::GetDeviceInfoFromPath(path, &info, &relative_path)) { |
| MediaGalleryPrefInfo::DefaultGalleryType default_gallery_type = |
| kDirectories[i].default_gallery_type; |
| DCHECK_NE(default_gallery_type, MediaGalleryPrefInfo::kNotDefault); |
| |
| AddOrUpdateGalleryInternal( |
| info.device_id(), |
| base::string16(), |
| relative_path, |
| MediaGalleryPrefInfo::kAutoDetected, |
| info.storage_label(), |
| info.vendor_name(), |
| info.model_name(), |
| info.total_size_in_bytes(), |
| base::Time(), |
| true, |
| 0, |
| 0, |
| 0, |
| kCurrentPrefsVersion, |
| default_gallery_type); |
| } |
| } |
| } |
| |
| bool MediaGalleriesPreferences::UpdateDeviceIDForSingletonType( |
| const std::string& device_id) { |
| StorageInfo::Type singleton_type; |
| if (!StorageInfo::CrackDeviceId(device_id, &singleton_type, NULL)) |
| return false; |
| |
| PrefService* prefs = profile_->GetPrefs(); |
| std::unique_ptr<ListPrefUpdate> update( |
| new ListPrefUpdate(prefs, prefs::kMediaGalleriesRememberedGalleries)); |
| base::ListValue* list = update->Get(); |
| for (base::ListValue::iterator iter = list->begin(); |
| iter != list->end(); ++iter) { |
| // All of these calls should succeed, but preferences file can be corrupt. |
| base::DictionaryValue* dict; |
| if (!(*iter)->GetAsDictionary(&dict)) |
| continue; |
| std::string this_device_id; |
| if (!dict->GetString(kMediaGalleriesDeviceIdKey, &this_device_id)) |
| continue; |
| if (this_device_id == device_id) |
| return true; // No update is necessary. |
| StorageInfo::Type device_type; |
| if (!StorageInfo::CrackDeviceId(this_device_id, &device_type, NULL)) |
| continue; |
| |
| if (device_type == singleton_type) { |
| dict->SetString(kMediaGalleriesDeviceIdKey, device_id); |
| update.reset(); // commits the update. |
| InitFromPrefs(); |
| MediaGalleryPrefId pref_id; |
| if (GetPrefId(*dict, &pref_id)) { |
| FOR_EACH_OBSERVER(GalleryChangeObserver, |
| gallery_change_observers_, |
| OnGalleryInfoUpdated(this, pref_id)); |
| } |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| void MediaGalleriesPreferences::OnStorageMonitorInit( |
| bool api_has_been_used) { |
| if (api_has_been_used) |
| UpdateDefaultGalleriesPaths(); |
| |
| // Invoke this method even if the API has been used before, in order to ensure |
| // we upgrade (migrate) prefs for galleries with prefs version prior to 3. |
| AddDefaultGalleries(); |
| |
| OnInitializationCallbackReturned(); |
| } |
| |
| void MediaGalleriesPreferences::OnFinderDeviceID(const std::string& device_id) { |
| if (!device_id.empty()) { |
| std::string gallery_name; |
| if (StorageInfo::IsITunesDevice(device_id)) |
| gallery_name = kITunesGalleryName; |
| else if (StorageInfo::IsPicasaDevice(device_id)) |
| gallery_name = kPicasaGalleryName; |
| |
| if (!gallery_name.empty()) { |
| pre_initialization_callbacks_waiting_++; |
| content::BrowserThread::PostTaskAndReply( |
| content::BrowserThread::FILE, |
| FROM_HERE, |
| base::Bind(&InitializeImportedMediaGalleryRegistryOnFileThread), |
| base::Bind( |
| &MediaGalleriesPreferences::OnInitializationCallbackReturned, |
| weak_factory_.GetWeakPtr())); |
| } |
| |
| if (!UpdateDeviceIDForSingletonType(device_id)) { |
| DCHECK(!gallery_name.empty()); |
| AddOrUpdateGalleryInternal( |
| device_id, |
| base::ASCIIToUTF16(gallery_name), |
| base::FilePath(), |
| MediaGalleryPrefInfo::kAutoDetected, |
| base::string16(), |
| base::string16(), |
| base::string16(), |
| 0, |
| base::Time(), |
| false, |
| 0, |
| 0, |
| 0, |
| kCurrentPrefsVersion, |
| MediaGalleryPrefInfo::kNotDefault); |
| } |
| } |
| |
| OnInitializationCallbackReturned(); |
| } |
| |
| void MediaGalleriesPreferences::InitFromPrefs() { |
| known_galleries_.clear(); |
| device_map_.clear(); |
| |
| PrefService* prefs = profile_->GetPrefs(); |
| const base::ListValue* list = prefs->GetList( |
| prefs::kMediaGalleriesRememberedGalleries); |
| if (list) { |
| for (base::ListValue::const_iterator it = list->begin(); |
| it != list->end(); ++it) { |
| const base::DictionaryValue* dict = NULL; |
| if (!(*it)->GetAsDictionary(&dict)) |
| continue; |
| |
| MediaGalleryPrefInfo gallery_info; |
| if (!PopulateGalleryPrefInfoFromDictionary(*dict, &gallery_info)) |
| continue; |
| |
| known_galleries_[gallery_info.pref_id] = gallery_info; |
| device_map_[gallery_info.device_id].insert(gallery_info.pref_id); |
| } |
| } |
| } |
| |
| void MediaGalleriesPreferences::AddGalleryChangeObserver( |
| GalleryChangeObserver* observer) { |
| DCHECK(IsInitialized()); |
| gallery_change_observers_.AddObserver(observer); |
| } |
| |
| void MediaGalleriesPreferences::RemoveGalleryChangeObserver( |
| GalleryChangeObserver* observer) { |
| DCHECK(IsInitialized()); |
| gallery_change_observers_.RemoveObserver(observer); |
| } |
| |
| void MediaGalleriesPreferences::OnRemovableStorageAttached( |
| const StorageInfo& info) { |
| DCHECK(IsInitialized()); |
| if (!StorageInfo::IsMediaDevice(info.device_id())) |
| return; |
| |
| AddGallery(info.device_id(), base::FilePath(), |
| MediaGalleryPrefInfo::kAutoDetected, info.storage_label(), |
| info.vendor_name(), info.model_name(), info.total_size_in_bytes(), |
| base::Time::Now(), 0, 0, 0); |
| } |
| |
| bool MediaGalleriesPreferences::LookUpGalleryByPath( |
| const base::FilePath& path, |
| MediaGalleryPrefInfo* gallery_info) const { |
| DCHECK(IsInitialized()); |
| |
| // First check if the path matches an imported gallery. |
| for (MediaGalleriesPrefInfoMap::const_iterator it = |
| known_galleries_.begin(); it != known_galleries_.end(); ++it) { |
| const std::string& device_id = it->second.device_id; |
| if (iapps::PathIndicatesITunesLibrary(device_id, path)) { |
| *gallery_info = it->second; |
| return true; |
| } |
| } |
| |
| StorageInfo info; |
| base::FilePath relative_path; |
| if (!MediaStorageUtil::GetDeviceInfoFromPath(path, &info, &relative_path)) { |
| if (gallery_info) |
| *gallery_info = MediaGalleryPrefInfo(); |
| return false; |
| } |
| |
| relative_path = relative_path.NormalizePathSeparators(); |
| MediaGalleryPrefIdSet galleries_on_device = |
| LookUpGalleriesByDeviceId(info.device_id()); |
| for (MediaGalleryPrefIdSet::const_iterator it = galleries_on_device.begin(); |
| it != galleries_on_device.end(); |
| ++it) { |
| const MediaGalleryPrefInfo& gallery = known_galleries_.find(*it)->second; |
| if (gallery.path != relative_path) |
| continue; |
| |
| if (gallery_info) |
| *gallery_info = gallery; |
| return true; |
| } |
| |
| // This method is called by controller::FilesSelected when the user |
| // adds a new gallery. Control reaches here when the selected gallery is |
| // on a volume we know about, but have no gallery already for. Returns |
| // hypothetical data to the caller about what the prefs will look like |
| // if the gallery is added. |
| // TODO(gbillock): split this out into another function so it doesn't |
| // conflate LookUp. |
| if (gallery_info) { |
| gallery_info->pref_id = kInvalidMediaGalleryPrefId; |
| gallery_info->device_id = info.device_id(); |
| gallery_info->path = relative_path; |
| gallery_info->type = MediaGalleryPrefInfo::kInvalidType; |
| gallery_info->volume_label = info.storage_label(); |
| gallery_info->vendor_name = info.vendor_name(); |
| gallery_info->model_name = info.model_name(); |
| gallery_info->total_size_in_bytes = info.total_size_in_bytes(); |
| gallery_info->last_attach_time = base::Time::Now(); |
| gallery_info->volume_metadata_valid = true; |
| gallery_info->prefs_version = kCurrentPrefsVersion; |
| } |
| return false; |
| } |
| |
| MediaGalleryPrefIdSet MediaGalleriesPreferences::LookUpGalleriesByDeviceId( |
| const std::string& device_id) const { |
| DeviceIdPrefIdsMap::const_iterator found = device_map_.find(device_id); |
| if (found == device_map_.end()) |
| return MediaGalleryPrefIdSet(); |
| return found->second; |
| } |
| |
| base::FilePath MediaGalleriesPreferences::LookUpGalleryPathForExtension( |
| MediaGalleryPrefId gallery_id, |
| const extensions::Extension* extension, |
| bool include_unpermitted_galleries) { |
| DCHECK(IsInitialized()); |
| DCHECK(extension); |
| if (!include_unpermitted_galleries && |
| !base::ContainsKey(GalleriesForExtension(*extension), gallery_id)) |
| return base::FilePath(); |
| |
| MediaGalleriesPrefInfoMap::const_iterator it = |
| known_galleries_.find(gallery_id); |
| if (it == known_galleries_.end()) |
| return base::FilePath(); |
| |
| // This seems wrong: it just returns the absolute path to the device, which |
| // is not necessarily the gallery path. |
| return MediaStorageUtil::FindDevicePathById(it->second.device_id); |
| } |
| |
| MediaGalleryPrefId MediaGalleriesPreferences::AddGallery( |
| const std::string& device_id, |
| const base::FilePath& relative_path, |
| MediaGalleryPrefInfo::Type type, |
| const base::string16& volume_label, |
| const base::string16& vendor_name, |
| const base::string16& model_name, |
| uint64_t total_size_in_bytes, |
| base::Time last_attach_time, |
| int audio_count, |
| int image_count, |
| int video_count) { |
| DCHECK(IsInitialized()); |
| return AddOrUpdateGalleryInternal( |
| device_id, |
| base::string16(), |
| relative_path, |
| type, |
| volume_label, |
| vendor_name, |
| model_name, |
| total_size_in_bytes, |
| last_attach_time, |
| true, |
| audio_count, |
| image_count, |
| video_count, |
| kCurrentPrefsVersion, |
| MediaGalleryPrefInfo::kNotDefault); |
| } |
| |
| MediaGalleryPrefId MediaGalleriesPreferences::AddOrUpdateGalleryInternal( |
| const std::string& device_id, |
| const base::string16& display_name, |
| const base::FilePath& relative_path, |
| MediaGalleryPrefInfo::Type type, |
| const base::string16& volume_label, |
| const base::string16& vendor_name, |
| const base::string16& model_name, |
| uint64_t total_size_in_bytes, |
| base::Time last_attach_time, |
| bool volume_metadata_valid, |
| int audio_count, |
| int image_count, |
| int video_count, |
| int prefs_version, |
| MediaGalleryPrefInfo::DefaultGalleryType default_gallery_type) { |
| DCHECK(type == MediaGalleryPrefInfo::kUserAdded || |
| type == MediaGalleryPrefInfo::kAutoDetected || |
| type == MediaGalleryPrefInfo::kScanResult); |
| base::FilePath normalized_relative_path = |
| relative_path.NormalizePathSeparators(); |
| MediaGalleryPrefIdSet galleries_on_device = |
| LookUpGalleriesByDeviceId(device_id); |
| |
| for (MediaGalleryPrefIdSet::const_iterator pref_id_it = |
| galleries_on_device.begin(); |
| pref_id_it != galleries_on_device.end(); |
| ++pref_id_it) { |
| const MediaGalleryPrefInfo& existing = |
| known_galleries_.find(*pref_id_it)->second; |
| if (existing.path != normalized_relative_path) |
| continue; |
| |
| bool update_gallery_type = false; |
| MediaGalleryPrefInfo::Type new_type = existing.type; |
| if (type == MediaGalleryPrefInfo::kUserAdded) { |
| if (existing.type == MediaGalleryPrefInfo::kBlackListed) { |
| new_type = MediaGalleryPrefInfo::kAutoDetected; |
| update_gallery_type = true; |
| } |
| if (existing.type == MediaGalleryPrefInfo::kRemovedScan) { |
| new_type = MediaGalleryPrefInfo::kUserAdded; |
| update_gallery_type = true; |
| } |
| } |
| |
| // Status quo: In M27 and M28, galleries added manually use version 0, |
| // and galleries added automatically (including default galleries) use |
| // version 1. The name override is used by default galleries as well |
| // as all device attach events. |
| // We want to upgrade the name if the existing version is < 2. Leave it |
| // alone if the existing display name is set with version >= 2 and the |
| // proposed new name is empty. |
| bool update_gallery_name = existing.display_name != display_name; |
| if (existing.prefs_version >= 2 && !existing.display_name.empty() && |
| display_name.empty()) { |
| update_gallery_name = false; |
| } |
| |
| // Version 3 adds the default_gallery_type field. |
| bool update_default_gallery_type = |
| existing.prefs_version <= 2 && |
| default_gallery_type != existing.default_gallery_type; |
| |
| bool update_gallery_metadata = volume_metadata_valid && |
| ((existing.volume_label != volume_label) || |
| (existing.vendor_name != vendor_name) || |
| (existing.model_name != model_name) || |
| (existing.total_size_in_bytes != total_size_in_bytes) || |
| (existing.last_attach_time != last_attach_time)); |
| |
| bool update_scan_counts = |
| new_type != MediaGalleryPrefInfo::kRemovedScan && |
| new_type != MediaGalleryPrefInfo::kBlackListed && |
| (audio_count > 0 || image_count > 0 || video_count > 0 || |
| existing.audio_count || existing.image_count || existing.video_count); |
| |
| if (!update_gallery_name && !update_gallery_type && |
| !update_gallery_metadata && !update_scan_counts && |
| !update_default_gallery_type) |
| return *pref_id_it; |
| |
| PrefService* prefs = profile_->GetPrefs(); |
| std::unique_ptr<ListPrefUpdate> update( |
| new ListPrefUpdate(prefs, prefs::kMediaGalleriesRememberedGalleries)); |
| base::ListValue* list = update->Get(); |
| |
| for (base::ListValue::const_iterator list_iter = list->begin(); |
| list_iter != list->end(); |
| ++list_iter) { |
| base::DictionaryValue* dict; |
| MediaGalleryPrefId iter_id; |
| if ((*list_iter)->GetAsDictionary(&dict) && |
| GetPrefId(*dict, &iter_id) && |
| *pref_id_it == iter_id) { |
| if (update_gallery_type) |
| dict->SetString(kMediaGalleriesTypeKey, TypeToStringValue(new_type)); |
| if (update_gallery_name) |
| dict->SetString(kMediaGalleriesDisplayNameKey, display_name); |
| if (update_gallery_metadata) { |
| dict->SetString(kMediaGalleriesVolumeLabelKey, volume_label); |
| dict->SetString(kMediaGalleriesVendorNameKey, vendor_name); |
| dict->SetString(kMediaGalleriesModelNameKey, model_name); |
| dict->SetDouble(kMediaGalleriesSizeKey, total_size_in_bytes); |
| dict->SetDouble(kMediaGalleriesLastAttachTimeKey, |
| last_attach_time.ToInternalValue()); |
| } |
| if (update_scan_counts) { |
| dict->SetInteger(kMediaGalleriesScanAudioCountKey, audio_count); |
| dict->SetInteger(kMediaGalleriesScanImageCountKey, image_count); |
| dict->SetInteger(kMediaGalleriesScanVideoCountKey, video_count); |
| } |
| if (update_default_gallery_type) { |
| dict->SetString( |
| kMediaGalleriesDefaultGalleryTypeKey, |
| DefaultGalleryTypeToStringValue(default_gallery_type)); |
| } |
| dict->SetInteger(kMediaGalleriesPrefsVersionKey, prefs_version); |
| break; |
| } |
| } |
| |
| // Commits the prefs update. |
| update.reset(); |
| |
| InitFromPrefs(); |
| FOR_EACH_OBSERVER(GalleryChangeObserver, gallery_change_observers_, |
| OnGalleryInfoUpdated(this, *pref_id_it)); |
| return *pref_id_it; |
| } |
| |
| PrefService* prefs = profile_->GetPrefs(); |
| |
| MediaGalleryPrefInfo gallery_info; |
| gallery_info.pref_id = prefs->GetUint64(prefs::kMediaGalleriesUniqueId); |
| prefs->SetUint64(prefs::kMediaGalleriesUniqueId, gallery_info.pref_id + 1); |
| gallery_info.display_name = display_name; |
| gallery_info.device_id = device_id; |
| gallery_info.path = normalized_relative_path; |
| gallery_info.type = type; |
| gallery_info.volume_label = volume_label; |
| gallery_info.vendor_name = vendor_name; |
| gallery_info.model_name = model_name; |
| gallery_info.total_size_in_bytes = total_size_in_bytes; |
| gallery_info.last_attach_time = last_attach_time; |
| gallery_info.volume_metadata_valid = volume_metadata_valid; |
| gallery_info.audio_count = audio_count; |
| gallery_info.image_count = image_count; |
| gallery_info.video_count = video_count; |
| gallery_info.prefs_version = prefs_version; |
| gallery_info.default_gallery_type = default_gallery_type; |
| |
| { |
| ListPrefUpdate update(prefs, prefs::kMediaGalleriesRememberedGalleries); |
| base::ListValue* list = update.Get(); |
| list->Append(CreateGalleryPrefInfoDictionary(gallery_info)); |
| } |
| InitFromPrefs(); |
| FOR_EACH_OBSERVER(GalleryChangeObserver, |
| gallery_change_observers_, |
| OnGalleryAdded(this, gallery_info.pref_id)); |
| |
| return gallery_info.pref_id; |
| } |
| |
| |
| void MediaGalleriesPreferences::UpdateDefaultGalleriesPaths() { |
| base::FilePath music_path; |
| base::FilePath pictures_path; |
| base::FilePath videos_path; |
| bool got_music_path = PathService::Get(chrome::DIR_USER_MUSIC, &music_path); |
| bool got_pictures_path = |
| PathService::Get(chrome::DIR_USER_PICTURES, &pictures_path); |
| bool got_videos_path = |
| PathService::Get(chrome::DIR_USER_VIDEOS, &videos_path); |
| |
| PrefService* prefs = profile_->GetPrefs(); |
| std::unique_ptr<ListPrefUpdate> update( |
| new ListPrefUpdate(prefs, prefs::kMediaGalleriesRememberedGalleries)); |
| base::ListValue* list = update->Get(); |
| |
| std::vector<MediaGalleryPrefId> pref_ids; |
| |
| for (base::ListValue::iterator iter = list->begin(); |
| iter != list->end(); |
| ++iter) { |
| base::DictionaryValue* dict; |
| MediaGalleryPrefId pref_id; |
| |
| if (!((*iter)->GetAsDictionary(&dict) && GetPrefId(*dict, &pref_id))) |
| continue; |
| |
| std::string default_gallery_type_string; |
| |
| // If the "default gallery type" key is set, just update the paths in place. |
| // If it's not set, then AddOrUpdateGalleryInternal will take care of |
| // setting it as part of migration to prefs version 3. |
| if (dict->GetString(kMediaGalleriesDefaultGalleryTypeKey, |
| &default_gallery_type_string)) { |
| std::string device_id; |
| if (got_music_path && |
| default_gallery_type_string == |
| kMediaGalleriesDefaultGalleryTypeMusicDefaultValue) { |
| device_id = StorageInfo::MakeDeviceId( |
| StorageInfo::Type::FIXED_MASS_STORAGE, |
| music_path.AsUTF8Unsafe()); |
| } else if (got_pictures_path && |
| default_gallery_type_string == |
| kMediaGalleriesDefaultGalleryTypePicturesDefaultValue) { |
| device_id = StorageInfo::MakeDeviceId( |
| StorageInfo::Type::FIXED_MASS_STORAGE, |
| pictures_path.AsUTF8Unsafe()); |
| } else if (got_videos_path && |
| default_gallery_type_string == |
| kMediaGalleriesDefaultGalleryTypeVideosDefaultValue) { |
| device_id = StorageInfo::MakeDeviceId( |
| StorageInfo::Type::FIXED_MASS_STORAGE, |
| videos_path.AsUTF8Unsafe()); |
| } |
| |
| if (!device_id.empty()) |
| dict->SetString(kMediaGalleriesDeviceIdKey, device_id); |
| } |
| |
| pref_ids.push_back(pref_id); |
| } |
| |
| // Commit the prefs update. |
| update.reset(); |
| InitFromPrefs(); |
| |
| for (std::vector<MediaGalleryPrefId>::iterator iter = pref_ids.begin(); |
| iter != pref_ids.end(); |
| ++iter) { |
| FOR_EACH_OBSERVER(GalleryChangeObserver, |
| gallery_change_observers_, |
| OnGalleryInfoUpdated(this, *iter)); |
| } |
| } |
| |
| |
| MediaGalleryPrefId MediaGalleriesPreferences::AddGalleryByPath( |
| const base::FilePath& path, MediaGalleryPrefInfo::Type type) { |
| DCHECK(IsInitialized()); |
| MediaGalleryPrefInfo gallery_info; |
| if (LookUpGalleryByPath(path, &gallery_info) && |
| !gallery_info.IsBlackListedType()) { |
| return gallery_info.pref_id; |
| } |
| return AddOrUpdateGalleryInternal(gallery_info.device_id, |
| gallery_info.display_name, |
| gallery_info.path, |
| type, |
| gallery_info.volume_label, |
| gallery_info.vendor_name, |
| gallery_info.model_name, |
| gallery_info.total_size_in_bytes, |
| gallery_info.last_attach_time, |
| gallery_info.volume_metadata_valid, |
| 0, 0, 0, |
| kCurrentPrefsVersion, |
| MediaGalleryPrefInfo::kNotDefault); |
| } |
| |
| void MediaGalleriesPreferences::ForgetGalleryById(MediaGalleryPrefId id) { |
| EraseOrBlacklistGalleryById(id, false); |
| } |
| |
| void MediaGalleriesPreferences::EraseGalleryById(MediaGalleryPrefId id) { |
| EraseOrBlacklistGalleryById(id, true); |
| } |
| |
| void MediaGalleriesPreferences::EraseOrBlacklistGalleryById( |
| MediaGalleryPrefId id, bool erase) { |
| DCHECK(IsInitialized()); |
| PrefService* prefs = profile_->GetPrefs(); |
| std::unique_ptr<ListPrefUpdate> update( |
| new ListPrefUpdate(prefs, prefs::kMediaGalleriesRememberedGalleries)); |
| base::ListValue* list = update->Get(); |
| |
| if (!base::ContainsKey(known_galleries_, id)) |
| return; |
| |
| for (base::ListValue::iterator iter = list->begin(); |
| iter != list->end(); ++iter) { |
| base::DictionaryValue* dict; |
| MediaGalleryPrefId iter_id; |
| if ((*iter)->GetAsDictionary(&dict) && GetPrefId(*dict, &iter_id) && |
| id == iter_id) { |
| RemoveGalleryPermissionsFromPrefs(id); |
| MediaGalleryPrefInfo::Type type; |
| if (!erase && GetType(*dict, &type) && |
| (type == MediaGalleryPrefInfo::kAutoDetected || |
| type == MediaGalleryPrefInfo::kScanResult)) { |
| if (type == MediaGalleryPrefInfo::kAutoDetected) { |
| dict->SetString(kMediaGalleriesTypeKey, |
| kMediaGalleriesTypeBlackListedValue); |
| } else { |
| dict->SetString(kMediaGalleriesTypeKey, |
| kMediaGalleriesTypeRemovedScanValue); |
| dict->SetInteger(kMediaGalleriesScanAudioCountKey, 0); |
| dict->SetInteger(kMediaGalleriesScanImageCountKey, 0); |
| dict->SetInteger(kMediaGalleriesScanVideoCountKey, 0); |
| } |
| } else { |
| list->Erase(iter, NULL); |
| } |
| update.reset(NULL); // commits the update. |
| |
| InitFromPrefs(); |
| FOR_EACH_OBSERVER(GalleryChangeObserver, |
| gallery_change_observers_, |
| OnGalleryRemoved(this, id)); |
| return; |
| } |
| } |
| } |
| |
| bool MediaGalleriesPreferences::NonAutoGalleryHasPermission( |
| MediaGalleryPrefId id) const { |
| DCHECK(IsInitialized()); |
| DCHECK(!base::ContainsKey(known_galleries_, id) || |
| known_galleries_.find(id)->second.type != |
| MediaGalleryPrefInfo::kAutoDetected); |
| ExtensionPrefs* prefs = GetExtensionPrefs(); |
| const base::DictionaryValue* extensions = |
| prefs->pref_service()->GetDictionary(extensions::pref_names::kExtensions); |
| if (!extensions) |
| return true; |
| |
| for (base::DictionaryValue::Iterator iter(*extensions); !iter.IsAtEnd(); |
| iter.Advance()) { |
| if (!crx_file::id_util::IdIsValid(iter.key())) { |
| NOTREACHED(); |
| continue; |
| } |
| std::vector<MediaGalleryPermission> permissions = |
| GetGalleryPermissionsFromPrefs(iter.key()); |
| for (std::vector<MediaGalleryPermission>::const_iterator it = |
| permissions.begin(); it != permissions.end(); ++it) { |
| if (it->pref_id == id) { |
| if (it->has_permission) |
| return true; |
| break; |
| } |
| } |
| } |
| return false; |
| } |
| |
| MediaGalleryPrefIdSet MediaGalleriesPreferences::GalleriesForExtension( |
| const extensions::Extension& extension) { |
| DCHECK(IsInitialized()); |
| MediaGalleryPrefIdSet result; |
| |
| if (HasAutoDetectedGalleryPermission(extension)) { |
| for (MediaGalleriesPrefInfoMap::const_iterator it = |
| known_galleries_.begin(); it != known_galleries_.end(); ++it) { |
| if (it->second.type == MediaGalleryPrefInfo::kAutoDetected) |
| result.insert(it->second.pref_id); |
| } |
| } |
| |
| std::vector<MediaGalleryPermission> stored_permissions = |
| GetGalleryPermissionsFromPrefs(extension.id()); |
| for (std::vector<MediaGalleryPermission>::const_iterator it = |
| stored_permissions.begin(); it != stored_permissions.end(); ++it) { |
| if (!it->has_permission) { |
| result.erase(it->pref_id); |
| } else { |
| MediaGalleriesPrefInfoMap::const_iterator gallery = |
| known_galleries_.find(it->pref_id); |
| |
| // Handle a stored permission for an erased gallery. This should never |
| // happen but, has caused crashes in the wild. http://crbug.com/374330. |
| if (gallery == known_galleries_.end()) { |
| RemoveGalleryPermissionsFromPrefs(it->pref_id); |
| continue; |
| } |
| |
| if (!gallery->second.IsBlackListedType()) { |
| result.insert(it->pref_id); |
| } else { |
| NOTREACHED() << gallery->second.device_id; |
| } |
| } |
| } |
| return result; |
| } |
| |
| bool MediaGalleriesPreferences::SetGalleryPermissionForExtension( |
| const extensions::Extension& extension, |
| MediaGalleryPrefId pref_id, |
| bool has_permission) { |
| DCHECK(IsInitialized()); |
| // The gallery may not exist anymore if the user opened a second config |
| // surface concurrently and removed it. Drop the permission update if so. |
| MediaGalleriesPrefInfoMap::const_iterator gallery_info = |
| known_galleries_.find(pref_id); |
| if (gallery_info == known_galleries_.end()) |
| return false; |
| |
| bool default_permission = false; |
| if (gallery_info->second.type == MediaGalleryPrefInfo::kAutoDetected) |
| default_permission = HasAutoDetectedGalleryPermission(extension); |
| // When the permission matches the default, we don't need to remember it. |
| if (has_permission == default_permission) { |
| if (!UnsetGalleryPermissionInPrefs(extension.id(), pref_id)) |
| // If permission wasn't set, assume nothing has changed. |
| return false; |
| } else { |
| if (!SetGalleryPermissionInPrefs(extension.id(), pref_id, has_permission)) |
| return false; |
| } |
| if (has_permission) |
| FOR_EACH_OBSERVER(GalleryChangeObserver, |
| gallery_change_observers_, |
| OnPermissionAdded(this, extension.id(), pref_id)); |
| else |
| FOR_EACH_OBSERVER(GalleryChangeObserver, |
| gallery_change_observers_, |
| OnPermissionRemoved(this, extension.id(), pref_id)); |
| return true; |
| } |
| |
| const MediaGalleriesPrefInfoMap& MediaGalleriesPreferences::known_galleries() |
| const { |
| DCHECK(IsInitialized()); |
| return known_galleries_; |
| } |
| |
| void MediaGalleriesPreferences::Shutdown() { |
| weak_factory_.InvalidateWeakPtrs(); |
| profile_ = NULL; |
| } |
| |
| // static |
| bool MediaGalleriesPreferences::APIHasBeenUsed(Profile* profile) { |
| MediaGalleryPrefId current_id = |
| profile->GetPrefs()->GetUint64(prefs::kMediaGalleriesUniqueId); |
| return current_id != kInvalidMediaGalleryPrefId + 1; |
| } |
| |
| // static |
| void MediaGalleriesPreferences::RegisterProfilePrefs( |
| user_prefs::PrefRegistrySyncable* registry) { |
| registry->RegisterListPref(prefs::kMediaGalleriesRememberedGalleries); |
| registry->RegisterUint64Pref(prefs::kMediaGalleriesUniqueId, |
| kInvalidMediaGalleryPrefId + 1); |
| } |
| |
| bool MediaGalleriesPreferences::SetGalleryPermissionInPrefs( |
| const std::string& extension_id, |
| MediaGalleryPrefId gallery_id, |
| bool has_access) { |
| DCHECK(IsInitialized()); |
| ExtensionPrefs::ScopedListUpdate update(GetExtensionPrefs(), |
| extension_id, |
| kMediaGalleriesPermissions); |
| base::ListValue* permissions = update.Get(); |
| if (!permissions) { |
| permissions = update.Create(); |
| } else { |
| // If the gallery is already in the list, update the permission... |
| for (base::ListValue::iterator iter = permissions->begin(); |
| iter != permissions->end(); ++iter) { |
| base::DictionaryValue* dict = NULL; |
| if (!(*iter)->GetAsDictionary(&dict)) |
| continue; |
| MediaGalleryPermission perm; |
| if (!GetMediaGalleryPermissionFromDictionary(dict, &perm)) |
| continue; |
| if (perm.pref_id == gallery_id) { |
| if (has_access != perm.has_permission) { |
| dict->SetBoolean(kMediaGalleryHasPermissionKey, has_access); |
| return true; |
| } else { |
| return false; |
| } |
| } |
| } |
| } |
| // ...Otherwise, add a new entry for the gallery. |
| std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue); |
| dict->SetString(kMediaGalleryIdKey, base::Uint64ToString(gallery_id)); |
| dict->SetBoolean(kMediaGalleryHasPermissionKey, has_access); |
| permissions->Append(std::move(dict)); |
| return true; |
| } |
| |
| bool MediaGalleriesPreferences::UnsetGalleryPermissionInPrefs( |
| const std::string& extension_id, |
| MediaGalleryPrefId gallery_id) { |
| DCHECK(IsInitialized()); |
| ExtensionPrefs::ScopedListUpdate update(GetExtensionPrefs(), |
| extension_id, |
| kMediaGalleriesPermissions); |
| base::ListValue* permissions = update.Get(); |
| if (!permissions) |
| return false; |
| |
| for (base::ListValue::iterator iter = permissions->begin(); |
| iter != permissions->end(); ++iter) { |
| const base::DictionaryValue* dict = NULL; |
| if (!(*iter)->GetAsDictionary(&dict)) |
| continue; |
| MediaGalleryPermission perm; |
| if (!GetMediaGalleryPermissionFromDictionary(dict, &perm)) |
| continue; |
| if (perm.pref_id == gallery_id) { |
| permissions->Erase(iter, NULL); |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| std::vector<MediaGalleryPermission> |
| MediaGalleriesPreferences::GetGalleryPermissionsFromPrefs( |
| const std::string& extension_id) const { |
| DCHECK(IsInitialized()); |
| std::vector<MediaGalleryPermission> result; |
| const base::ListValue* permissions; |
| if (!GetExtensionPrefs()->ReadPrefAsList(extension_id, |
| kMediaGalleriesPermissions, |
| &permissions)) { |
| return result; |
| } |
| |
| for (base::ListValue::const_iterator iter = permissions->begin(); |
| iter != permissions->end(); ++iter) { |
| base::DictionaryValue* dict = NULL; |
| if (!(*iter)->GetAsDictionary(&dict)) |
| continue; |
| MediaGalleryPermission perm; |
| if (!GetMediaGalleryPermissionFromDictionary(dict, &perm)) |
| continue; |
| result.push_back(perm); |
| } |
| |
| return result; |
| } |
| |
| void MediaGalleriesPreferences::RemoveGalleryPermissionsFromPrefs( |
| MediaGalleryPrefId gallery_id) { |
| DCHECK(IsInitialized()); |
| ExtensionPrefs* prefs = GetExtensionPrefs(); |
| const base::DictionaryValue* extensions = |
| prefs->pref_service()->GetDictionary(extensions::pref_names::kExtensions); |
| if (!extensions) |
| return; |
| |
| for (base::DictionaryValue::Iterator iter(*extensions); !iter.IsAtEnd(); |
| iter.Advance()) { |
| if (!crx_file::id_util::IdIsValid(iter.key())) { |
| NOTREACHED(); |
| continue; |
| } |
| UnsetGalleryPermissionInPrefs(iter.key(), gallery_id); |
| } |
| } |
| |
| ExtensionPrefs* MediaGalleriesPreferences::GetExtensionPrefs() const { |
| DCHECK(IsInitialized()); |
| if (extension_prefs_for_testing_) |
| return extension_prefs_for_testing_; |
| return extensions::ExtensionPrefs::Get(profile_); |
| } |
| |
| void MediaGalleriesPreferences::SetExtensionPrefsForTesting( |
| extensions::ExtensionPrefs* extension_prefs) { |
| DCHECK(IsInitialized()); |
| extension_prefs_for_testing_ = extension_prefs; |
| } |