media_galleries_preferences.cc revision 2a99a7e74a7f215066514fe81d2bfa6639d9eddd
1// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "chrome/browser/media_galleries/media_galleries_preferences.h"
6
7#include "base/path_service.h"
8#include "base/prefs/pref_service.h"
9#include "base/stl_util.h"
10#include "base/strings/string_number_conversions.h"
11#include "base/values.h"
12#include "chrome/browser/browser_process.h"
13#include "chrome/browser/extensions/api/media_galleries_private/gallery_watch_state_tracker.h"
14#include "chrome/browser/extensions/extension_prefs.h"
15#include "chrome/browser/extensions/extension_service.h"
16#include "chrome/browser/extensions/extension_system.h"
17#include "chrome/browser/media_galleries/media_file_system_registry.h"
18#include "chrome/browser/prefs/scoped_user_pref_update.h"
19#include "chrome/browser/profiles/profile.h"
20#include "chrome/browser/storage_monitor/media_storage_util.h"
21#include "chrome/common/chrome_paths.h"
22#include "chrome/common/extensions/extension.h"
23#include "chrome/common/extensions/permissions/api_permission.h"
24#include "chrome/common/extensions/permissions/media_galleries_permission.h"
25#include "chrome/common/pref_names.h"
26#include "components/user_prefs/pref_registry_syncable.h"
27
28namespace chrome {
29
30namespace {
31
32const char kMediaGalleriesDeviceIdKey[] = "deviceId";
33const char kMediaGalleriesDisplayNameKey[] = "displayName";
34const char kMediaGalleriesPathKey[] = "path";
35const char kMediaGalleriesPrefIdKey[] = "prefId";
36const char kMediaGalleriesTypeKey[] = "type";
37const char kMediaGalleriesVolumeLabelKey[] = "volumeLabel";
38const char kMediaGalleriesVendorNameKey[] = "vendorName";
39const char kMediaGalleriesModelNameKey[] = "modelName";
40const char kMediaGalleriesSizeKey[] = "totalSize";
41const char kMediaGalleriesLastAttachTimeKey[] = "lastAttachTime";
42const char kMediaGalleriesPrefsVersionKey[] = "preferencesVersion";
43
44const char kMediaGalleriesTypeAutoDetectedValue[] = "autoDetected";
45const char kMediaGalleriesTypeUserAddedValue[] = "userAdded";
46const char kMediaGalleriesTypeBlackListedValue[] = "blackListed";
47
48bool GetPrefId(const DictionaryValue& dict, MediaGalleryPrefId* value) {
49  std::string string_id;
50  if (!dict.GetString(kMediaGalleriesPrefIdKey, &string_id) ||
51      !base::StringToUint64(string_id, value)) {
52    return false;
53  }
54
55  return true;
56}
57
58bool GetType(const DictionaryValue& dict, MediaGalleryPrefInfo::Type* type) {
59  std::string string_type;
60  if (!dict.GetString(kMediaGalleriesTypeKey, &string_type))
61    return false;
62
63  if (string_type == kMediaGalleriesTypeAutoDetectedValue) {
64    *type = MediaGalleryPrefInfo::kAutoDetected;
65    return true;
66  }
67  if (string_type == kMediaGalleriesTypeUserAddedValue) {
68    *type = MediaGalleryPrefInfo::kUserAdded;
69    return true;
70  }
71  if (string_type == kMediaGalleriesTypeBlackListedValue) {
72    *type = MediaGalleryPrefInfo::kBlackListed;
73    return true;
74  }
75
76  return false;
77}
78
79bool PopulateGalleryPrefInfoFromDictionary(
80    const DictionaryValue& dict, MediaGalleryPrefInfo* out_gallery_info) {
81  MediaGalleryPrefId pref_id;
82  string16 display_name;
83  std::string device_id;
84  base::FilePath::StringType path;
85  MediaGalleryPrefInfo::Type type = MediaGalleryPrefInfo::kAutoDetected;
86  string16 volume_label;
87  string16 vendor_name;
88  string16 model_name;
89  double total_size_in_bytes = 0.0;
90  double last_attach_time = 0.0;
91  bool volume_metadata_valid = false;
92  int prefs_version = 0;
93
94  if (!GetPrefId(dict, &pref_id) ||
95      !dict.GetString(kMediaGalleriesDeviceIdKey, &device_id) ||
96      !dict.GetString(kMediaGalleriesPathKey, &path) ||
97      !GetType(dict, &type)) {
98    return false;
99  }
100
101  dict.GetString(kMediaGalleriesDisplayNameKey, &display_name);
102  dict.GetInteger(kMediaGalleriesPrefsVersionKey, &prefs_version);
103
104  if (dict.GetString(kMediaGalleriesVolumeLabelKey, &volume_label) &&
105      dict.GetString(kMediaGalleriesVendorNameKey, &vendor_name) &&
106      dict.GetString(kMediaGalleriesModelNameKey, &model_name) &&
107      dict.GetDouble(kMediaGalleriesSizeKey, &total_size_in_bytes) &&
108      dict.GetDouble(kMediaGalleriesLastAttachTimeKey, &last_attach_time)) {
109    volume_metadata_valid = true;
110  }
111
112  out_gallery_info->pref_id = pref_id;
113  out_gallery_info->display_name = display_name;
114  out_gallery_info->device_id = device_id;
115  out_gallery_info->path = base::FilePath(path);
116  out_gallery_info->type = type;
117  out_gallery_info->volume_label = volume_label;
118  out_gallery_info->vendor_name = vendor_name;
119  out_gallery_info->model_name = model_name;
120  out_gallery_info->total_size_in_bytes = total_size_in_bytes;
121  out_gallery_info->last_attach_time =
122      base::Time::FromInternalValue(last_attach_time);
123  out_gallery_info->volume_metadata_valid = volume_metadata_valid;
124  out_gallery_info->prefs_version = prefs_version;
125
126  return true;
127}
128
129DictionaryValue* CreateGalleryPrefInfoDictionary(
130    const MediaGalleryPrefInfo& gallery) {
131  DictionaryValue* dict = new DictionaryValue();
132  dict->SetString(kMediaGalleriesPrefIdKey,
133                  base::Uint64ToString(gallery.pref_id));
134  if (!gallery.volume_metadata_valid)
135    dict->SetString(kMediaGalleriesDisplayNameKey, gallery.display_name);
136  dict->SetString(kMediaGalleriesDeviceIdKey, gallery.device_id);
137  dict->SetString(kMediaGalleriesPathKey, gallery.path.value());
138
139  const char* type = NULL;
140  switch (gallery.type) {
141    case MediaGalleryPrefInfo::kAutoDetected:
142      type = kMediaGalleriesTypeAutoDetectedValue;
143      break;
144    case MediaGalleryPrefInfo::kUserAdded:
145      type = kMediaGalleriesTypeUserAddedValue;
146      break;
147    case MediaGalleryPrefInfo::kBlackListed:
148      type = kMediaGalleriesTypeBlackListedValue;
149      break;
150    default:
151      NOTREACHED();
152      break;
153  }
154  dict->SetString(kMediaGalleriesTypeKey, type);
155
156  if (gallery.volume_metadata_valid) {
157    dict->SetString(kMediaGalleriesVolumeLabelKey, gallery.volume_label);
158    dict->SetString(kMediaGalleriesVendorNameKey, gallery.vendor_name);
159    dict->SetString(kMediaGalleriesModelNameKey, gallery.model_name);
160    dict->SetDouble(kMediaGalleriesSizeKey, gallery.total_size_in_bytes);
161    dict->SetDouble(kMediaGalleriesLastAttachTimeKey,
162                    gallery.last_attach_time.ToInternalValue());
163  }
164
165  // Version 0 of the prefs format was that the display_name was always
166  // used to show the user-visible name of the gallery. Version 1 means
167  // that there is an optional display_name, and when it is present, it
168  // overrides the name that would be built from the volume metadata, path,
169  // or whatever other data. So if we see a display_name with version 0, it
170  // means it may be overwritten simply by getting new volume metadata.
171  // A display_name with version 1 should not be overwritten.
172  dict->SetInteger(kMediaGalleriesPrefsVersionKey, gallery.prefs_version);
173
174  return dict;
175}
176
177bool HasAutoDetectedGalleryPermission(const extensions::Extension& extension) {
178  extensions::MediaGalleriesPermission::CheckParam param(
179      extensions::MediaGalleriesPermission::kAllAutoDetectedPermission);
180  return extension.CheckAPIPermissionWithParam(
181      extensions::APIPermission::kMediaGalleries, &param);
182}
183
184}  // namespace
185
186MediaGalleryPrefInfo::MediaGalleryPrefInfo()
187    : pref_id(kInvalidMediaGalleryPrefId),
188      type(kInvalidType),
189      total_size_in_bytes(0),
190      volume_metadata_valid(false),
191      prefs_version(0) {
192}
193
194MediaGalleryPrefInfo::~MediaGalleryPrefInfo() {}
195
196base::FilePath MediaGalleryPrefInfo::AbsolutePath() const {
197  base::FilePath base_path = MediaStorageUtil::FindDevicePathById(device_id);
198  return base_path.empty() ? base_path : base_path.Append(path);
199}
200
201MediaGalleriesPreferences::GalleryChangeObserver::~GalleryChangeObserver() {}
202
203MediaGalleriesPreferences::MediaGalleriesPreferences(Profile* profile)
204    : profile_(profile) {
205  AddDefaultGalleriesIfFreshProfile();
206  InitFromPrefs(false /*no notification*/);
207}
208
209MediaGalleriesPreferences::~MediaGalleriesPreferences() {}
210
211void MediaGalleriesPreferences::AddDefaultGalleriesIfFreshProfile() {
212  // Only add defaults the first time.
213  if (APIHasBeenUsed(profile_))
214    return;
215
216  // Fresh profile case.
217  const int kDirectoryKeys[] = {
218    DIR_USER_MUSIC,
219    DIR_USER_PICTURES,
220    DIR_USER_VIDEOS,
221  };
222
223  for (size_t i = 0; i < arraysize(kDirectoryKeys); ++i) {
224    base::FilePath path;
225    if (!PathService::Get(kDirectoryKeys[i], &path))
226      continue;
227
228    base::FilePath relative_path;
229    StorageInfo info;
230    if (MediaStorageUtil::GetDeviceInfoFromPath(path, &info, &relative_path)) {
231      // TODO(gbillock): Add in the volume metadata here when available.
232      AddGalleryWithName(info.device_id, info.name, relative_path,
233                         false /*user added*/);
234    }
235  }
236}
237
238void MediaGalleriesPreferences::InitFromPrefs(bool notify_observers) {
239  known_galleries_.clear();
240  device_map_.clear();
241
242  PrefService* prefs = profile_->GetPrefs();
243  const ListValue* list = prefs->GetList(
244      prefs::kMediaGalleriesRememberedGalleries);
245  if (list) {
246    for (ListValue::const_iterator it = list->begin();
247         it != list->end(); ++it) {
248      const DictionaryValue* dict = NULL;
249      if (!(*it)->GetAsDictionary(&dict))
250        continue;
251
252      MediaGalleryPrefInfo gallery_info;
253      if (!PopulateGalleryPrefInfoFromDictionary(*dict, &gallery_info))
254        continue;
255
256      known_galleries_[gallery_info.pref_id] = gallery_info;
257      device_map_[gallery_info.device_id].insert(gallery_info.pref_id);
258    }
259  }
260  if (notify_observers)
261    NotifyChangeObservers("");
262}
263
264void MediaGalleriesPreferences::NotifyChangeObservers(
265    const std::string& extension_id) {
266  FOR_EACH_OBSERVER(GalleryChangeObserver,
267                    gallery_change_observers_,
268                    OnGalleryChanged(this, extension_id));
269}
270
271void MediaGalleriesPreferences::AddGalleryChangeObserver(
272    GalleryChangeObserver* observer) {
273  gallery_change_observers_.AddObserver(observer);
274}
275
276void MediaGalleriesPreferences::RemoveGalleryChangeObserver(
277    GalleryChangeObserver* observer) {
278  gallery_change_observers_.RemoveObserver(observer);
279}
280
281void MediaGalleriesPreferences::OnRemovableStorageAttached(
282    const StorageInfo& info) {
283  if (!MediaStorageUtil::IsMediaDevice(info.device_id))
284    return;
285
286  if (info.name.empty()) {
287    AddGallery(info.device_id, base::FilePath(info.location),
288               false /*not user added*/,
289               info.storage_label,
290               info.vendor_name,
291               info.model_name,
292               info.total_size_in_bytes,
293               base::Time::Now());
294  } else {
295    AddGalleryWithName(info.device_id, info.name,
296                       base::FilePath(info.location), false);
297  }
298}
299
300bool MediaGalleriesPreferences::LookUpGalleryByPath(
301    const base::FilePath& path,
302    MediaGalleryPrefInfo* gallery_info) const {
303  StorageInfo info;
304  base::FilePath relative_path;
305  if (!MediaStorageUtil::GetDeviceInfoFromPath(path, &info, &relative_path)) {
306    if (gallery_info)
307      *gallery_info = MediaGalleryPrefInfo();
308    return false;
309  }
310
311  relative_path = relative_path.NormalizePathSeparators();
312  MediaGalleryPrefIdSet galleries_on_device =
313      LookUpGalleriesByDeviceId(info.device_id);
314  for (MediaGalleryPrefIdSet::const_iterator it = galleries_on_device.begin();
315       it != galleries_on_device.end();
316       ++it) {
317    const MediaGalleryPrefInfo& gallery = known_galleries_.find(*it)->second;
318    if (gallery.path != relative_path)
319      continue;
320
321    if (gallery_info)
322      *gallery_info = gallery;
323    return true;
324  }
325
326  // This method is called by controller::FilesSelected when the user
327  // adds a new gallery. Control reaches here when the selected gallery is
328  // on a volume we know about, but have no gallery already for. Returns
329  // hypothetical data to the caller about what the prefs will look like
330  // if the gallery is added.
331  // TODO(gbillock): split this out into another function so it doesn't
332  // conflate LookUp.
333  if (gallery_info) {
334    gallery_info->pref_id = kInvalidMediaGalleryPrefId;
335    gallery_info->display_name = info.name;
336    gallery_info->device_id = info.device_id;
337    gallery_info->path = relative_path;
338    gallery_info->type = MediaGalleryPrefInfo::kUserAdded;
339    // TODO(gbillock): Need to add volume metadata here from |info|.
340  }
341  return false;
342}
343
344MediaGalleryPrefIdSet MediaGalleriesPreferences::LookUpGalleriesByDeviceId(
345    const std::string& device_id) const {
346  DeviceIdPrefIdsMap::const_iterator found = device_map_.find(device_id);
347  if (found == device_map_.end())
348    return MediaGalleryPrefIdSet();
349  return found->second;
350}
351
352base::FilePath MediaGalleriesPreferences::LookUpGalleryPathForExtension(
353    MediaGalleryPrefId gallery_id,
354    const extensions::Extension* extension,
355    bool include_unpermitted_galleries) {
356  DCHECK(extension);
357  if (!include_unpermitted_galleries &&
358      !ContainsKey(GalleriesForExtension(*extension), gallery_id))
359    return base::FilePath();
360
361  MediaGalleriesPrefInfoMap::const_iterator it =
362      known_galleries_.find(gallery_id);
363  if (it == known_galleries_.end())
364    return base::FilePath();
365  return MediaStorageUtil::FindDevicePathById(it->second.device_id);
366}
367
368MediaGalleryPrefId MediaGalleriesPreferences::AddGallery(
369    const std::string& device_id,
370    const base::FilePath& relative_path, bool user_added,
371    const string16& volume_label, const string16& vendor_name,
372    const string16& model_name, uint64 total_size_in_bytes,
373    base::Time last_attach_time) {
374  return AddGalleryInternal(device_id, string16(), relative_path, user_added,
375                            volume_label, vendor_name, model_name,
376                            total_size_in_bytes, last_attach_time, true, 1);
377}
378
379MediaGalleryPrefId MediaGalleriesPreferences::AddGalleryWithName(
380    const std::string& device_id, const string16& display_name,
381    const base::FilePath& relative_path, bool user_added) {
382  return AddGalleryInternal(device_id, display_name, relative_path, user_added,
383                            string16(), string16(), string16(),
384                            0, base::Time(), false, 1);
385}
386
387MediaGalleryPrefId MediaGalleriesPreferences::AddGalleryInternal(
388    const std::string& device_id, const string16& display_name,
389    const base::FilePath& relative_path, bool user_added,
390    const string16& volume_label, const string16& vendor_name,
391    const string16& model_name, uint64 total_size_in_bytes,
392    base::Time last_attach_time,
393    bool volume_metadata_valid,
394    int prefs_version) {
395  base::FilePath normalized_relative_path =
396      relative_path.NormalizePathSeparators();
397  MediaGalleryPrefIdSet galleries_on_device =
398    LookUpGalleriesByDeviceId(device_id);
399  for (MediaGalleryPrefIdSet::const_iterator it = galleries_on_device.begin();
400       it != galleries_on_device.end();
401       ++it) {
402    const MediaGalleryPrefInfo& existing = known_galleries_.find(*it)->second;
403    if (existing.path != normalized_relative_path)
404      continue;
405
406    bool update_gallery_type =
407        user_added && (existing.type == MediaGalleryPrefInfo::kBlackListed);
408    bool update_gallery_name = existing.display_name != display_name;
409    bool update_gallery_metadata = volume_metadata_valid &&
410        ((existing.volume_label != volume_label) ||
411         (existing.vendor_name != vendor_name) ||
412         (existing.model_name != model_name) ||
413         (existing.total_size_in_bytes != total_size_in_bytes) ||
414         (existing.last_attach_time != last_attach_time));
415
416    if (!update_gallery_name && !update_gallery_type &&
417        !update_gallery_metadata)
418      return *it;
419
420    PrefService* prefs = profile_->GetPrefs();
421    scoped_ptr<ListPrefUpdate> update(
422        new ListPrefUpdate(prefs, prefs::kMediaGalleriesRememberedGalleries));
423    ListValue* list = update->Get();
424
425    for (ListValue::const_iterator list_iter = list->begin();
426         list_iter != list->end();
427         ++list_iter) {
428      DictionaryValue* dict;
429      MediaGalleryPrefId iter_id;
430      if ((*list_iter)->GetAsDictionary(&dict) &&
431          GetPrefId(*dict, &iter_id) &&
432          *it == iter_id) {
433        if (update_gallery_type) {
434          dict->SetString(kMediaGalleriesTypeKey,
435                          kMediaGalleriesTypeAutoDetectedValue);
436        }
437        if (update_gallery_name)
438          dict->SetString(kMediaGalleriesDisplayNameKey, display_name);
439        if (update_gallery_metadata) {
440          dict->SetString(kMediaGalleriesVolumeLabelKey, volume_label);
441          dict->SetString(kMediaGalleriesVendorNameKey, vendor_name);
442          dict->SetString(kMediaGalleriesModelNameKey, model_name);
443          dict->SetDouble(kMediaGalleriesSizeKey, total_size_in_bytes);
444          dict->SetDouble(kMediaGalleriesLastAttachTimeKey,
445                          last_attach_time.ToInternalValue());
446        }
447        dict->SetInteger(kMediaGalleriesPrefsVersionKey, prefs_version);
448        break;
449      }
450    }
451
452    // Commits the prefs update.
453    update.reset();
454
455    if (update_gallery_name || update_gallery_metadata || update_gallery_type)
456      InitFromPrefs(true /* notify observers */);
457    return *it;
458  }
459
460  PrefService* prefs = profile_->GetPrefs();
461
462  MediaGalleryPrefInfo gallery_info;
463  gallery_info.pref_id = prefs->GetUint64(prefs::kMediaGalleriesUniqueId);
464  prefs->SetUint64(prefs::kMediaGalleriesUniqueId, gallery_info.pref_id + 1);
465  gallery_info.display_name = display_name;
466  gallery_info.device_id = device_id;
467  gallery_info.path = normalized_relative_path;
468  gallery_info.type = MediaGalleryPrefInfo::kAutoDetected;
469  if (user_added)
470    gallery_info.type = MediaGalleryPrefInfo::kUserAdded;
471  if (volume_metadata_valid) {
472    gallery_info.volume_label = volume_label;
473    gallery_info.vendor_name = vendor_name;
474    gallery_info.model_name = model_name;
475    gallery_info.total_size_in_bytes = total_size_in_bytes;
476    gallery_info.last_attach_time = last_attach_time;
477  }
478  gallery_info.volume_metadata_valid = volume_metadata_valid;
479  gallery_info.prefs_version = prefs_version;
480
481  {
482    ListPrefUpdate update(prefs, prefs::kMediaGalleriesRememberedGalleries);
483    ListValue* list = update.Get();
484    list->Append(CreateGalleryPrefInfoDictionary(gallery_info));
485  }
486  InitFromPrefs(true /* notify observers */);
487
488  return gallery_info.pref_id;
489}
490
491MediaGalleryPrefId MediaGalleriesPreferences::AddGalleryByPath(
492    const base::FilePath& path) {
493  MediaGalleryPrefInfo gallery_info;
494  if (LookUpGalleryByPath(path, &gallery_info) &&
495      gallery_info.type != MediaGalleryPrefInfo::kBlackListed) {
496    return gallery_info.pref_id;
497  }
498  return AddGalleryInternal(gallery_info.device_id,
499                            gallery_info.display_name,
500                            gallery_info.path,
501                            true /*user added*/,
502                            gallery_info.volume_label,
503                            gallery_info.vendor_name,
504                            gallery_info.model_name,
505                            gallery_info.total_size_in_bytes,
506                            gallery_info.last_attach_time,
507                            gallery_info.volume_metadata_valid,
508                            gallery_info.prefs_version);
509}
510
511void MediaGalleriesPreferences::ForgetGalleryById(MediaGalleryPrefId pref_id) {
512  PrefService* prefs = profile_->GetPrefs();
513  ListPrefUpdate update(prefs, prefs::kMediaGalleriesRememberedGalleries);
514  ListValue* list = update.Get();
515
516  if (!ContainsKey(known_galleries_, pref_id))
517    return;
518
519  for (ListValue::iterator iter = list->begin(); iter != list->end(); ++iter) {
520    DictionaryValue* dict;
521    MediaGalleryPrefId iter_id;
522    if ((*iter)->GetAsDictionary(&dict) && GetPrefId(*dict, &iter_id) &&
523        pref_id == iter_id) {
524      GetExtensionPrefs()->RemoveMediaGalleryPermissions(pref_id);
525      MediaGalleryPrefInfo::Type type;
526      if (GetType(*dict, &type) &&
527          type == MediaGalleryPrefInfo::kAutoDetected) {
528        dict->SetString(kMediaGalleriesTypeKey,
529                        kMediaGalleriesTypeBlackListedValue);
530      } else {
531        list->Erase(iter, NULL);
532      }
533      InitFromPrefs(true /* notify observers */);
534      return;
535    }
536  }
537}
538
539MediaGalleryPrefIdSet MediaGalleriesPreferences::GalleriesForExtension(
540    const extensions::Extension& extension) const {
541  MediaGalleryPrefIdSet result;
542
543  if (HasAutoDetectedGalleryPermission(extension)) {
544    for (MediaGalleriesPrefInfoMap::const_iterator it =
545             known_galleries_.begin(); it != known_galleries_.end(); ++it) {
546      if (it->second.type == MediaGalleryPrefInfo::kAutoDetected)
547        result.insert(it->second.pref_id);
548    }
549  }
550
551  std::vector<MediaGalleryPermission> stored_permissions =
552      GetExtensionPrefs()->GetMediaGalleryPermissions(extension.id());
553
554  for (std::vector<MediaGalleryPermission>::const_iterator it =
555           stored_permissions.begin(); it != stored_permissions.end(); ++it) {
556    if (!it->has_permission) {
557      result.erase(it->pref_id);
558    } else {
559      MediaGalleriesPrefInfoMap::const_iterator gallery =
560          known_galleries_.find(it->pref_id);
561      DCHECK(gallery != known_galleries_.end());
562      if (gallery->second.type != MediaGalleryPrefInfo::kBlackListed) {
563        result.insert(it->pref_id);
564      } else {
565        NOTREACHED() << gallery->second.device_id;
566      }
567    }
568  }
569  return result;
570}
571
572void MediaGalleriesPreferences::SetGalleryPermissionForExtension(
573    const extensions::Extension& extension,
574    MediaGalleryPrefId pref_id,
575    bool has_permission) {
576  // The gallery may not exist anymore if the user opened a second config
577  // surface concurrently and removed it. Drop the permission update if so.
578  MediaGalleriesPrefInfoMap::const_iterator gallery_info =
579      known_galleries_.find(pref_id);
580  if (gallery_info == known_galleries_.end())
581    return;
582
583#if defined(ENABLE_EXTENSIONS)
584  extensions::GalleryWatchStateTracker* state_tracker =
585      extensions::GalleryWatchStateTracker::GetForProfile(profile_);
586#endif
587  bool all_permission = HasAutoDetectedGalleryPermission(extension);
588  if (has_permission && all_permission) {
589    if (gallery_info->second.type == MediaGalleryPrefInfo::kAutoDetected) {
590      GetExtensionPrefs()->UnsetMediaGalleryPermission(extension.id(), pref_id);
591      NotifyChangeObservers(extension.id());
592#if defined(ENABLE_EXTENSIONS)
593      if (state_tracker) {
594        state_tracker->OnGalleryPermissionChanged(extension.id(), pref_id,
595                                                  true);
596      }
597#endif
598      return;
599    }
600  }
601
602  if (!has_permission && !all_permission) {
603    GetExtensionPrefs()->UnsetMediaGalleryPermission(extension.id(), pref_id);
604  } else {
605    GetExtensionPrefs()->SetMediaGalleryPermission(extension.id(), pref_id,
606                                                   has_permission);
607  }
608  NotifyChangeObservers(extension.id());
609#if defined(ENABLE_EXTENSIONS)
610  if (state_tracker) {
611    state_tracker->OnGalleryPermissionChanged(extension.id(), pref_id,
612                                              has_permission);
613  }
614#endif
615}
616
617void MediaGalleriesPreferences::Shutdown() {
618  profile_ = NULL;
619}
620
621// static
622bool MediaGalleriesPreferences::APIHasBeenUsed(Profile* profile) {
623  MediaGalleryPrefId current_id =
624      profile->GetPrefs()->GetUint64(prefs::kMediaGalleriesUniqueId);
625  return current_id != kInvalidMediaGalleryPrefId + 1;
626}
627
628// static
629void MediaGalleriesPreferences::RegisterUserPrefs(
630    PrefRegistrySyncable* registry) {
631  registry->RegisterListPref(prefs::kMediaGalleriesRememberedGalleries,
632                             PrefRegistrySyncable::UNSYNCABLE_PREF);
633  registry->RegisterUint64Pref(prefs::kMediaGalleriesUniqueId,
634                               kInvalidMediaGalleryPrefId + 1,
635                               PrefRegistrySyncable::UNSYNCABLE_PREF);
636}
637
638extensions::ExtensionPrefs*
639MediaGalleriesPreferences::GetExtensionPrefs() const {
640  ExtensionService* extension_service =
641      extensions::ExtensionSystem::Get(profile_)->extension_service();
642  return extension_service->extension_prefs();
643}
644
645}  // namespace chrome
646