// 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, &param);
}

// 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;
}
