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#ifndef CHROME_BROWSER_MEDIA_GALLERIES_MEDIA_GALLERIES_PREFERENCES_H_
6#define CHROME_BROWSER_MEDIA_GALLERIES_MEDIA_GALLERIES_PREFERENCES_H_
7
8#include <map>
9#include <set>
10#include <string>
11#include <vector>
12
13#include "base/basictypes.h"
14#include "base/callback_forward.h"
15#include "base/files/file_path.h"
16#include "base/memory/weak_ptr.h"
17#include "base/observer_list.h"
18#include "base/strings/string16.h"
19#include "base/time/time.h"
20#include "components/keyed_service/core/keyed_service.h"
21#include "components/storage_monitor/removable_storage_observer.h"
22
23class Profile;
24
25namespace base {
26class DictionaryValue;
27}
28
29namespace extensions {
30class Extension;
31class ExtensionPrefs;
32}
33
34namespace user_prefs {
35class PrefRegistrySyncable;
36}
37
38typedef uint64 MediaGalleryPrefId;
39const MediaGalleryPrefId kInvalidMediaGalleryPrefId = 0;
40
41const char kMediaGalleriesPrefsVersionKey[] = "preferencesVersion";
42const char kMediaGalleriesDefaultGalleryTypeKey[] = "defaultGalleryType";
43
44struct MediaGalleryPermission {
45  MediaGalleryPrefId pref_id;
46  bool has_permission;
47};
48
49struct MediaGalleryPrefInfo {
50  enum Type {
51    kUserAdded,     // Explicitly added by the user.
52    kAutoDetected,  // Auto added to the list of galleries.
53    kBlackListed,   // Auto added but then removed by the user.
54    kScanResult,    // Discovered by a disk scan.
55    kRemovedScan,   // Discovered by a disk scan but then removed by the user.
56    kInvalidType,
57  };
58
59  enum DefaultGalleryType {
60    kNotDefault,    // Normal gallery
61    kMusicDefault,
62    kPicturesDefault,
63    kVideosDefault,
64  };
65
66  MediaGalleryPrefInfo();
67  ~MediaGalleryPrefInfo();
68
69  // The absolute path of the gallery.
70  base::FilePath AbsolutePath() const;
71
72  // True if the gallery should not be displayed to the user
73  // i.e. kBlackListed || kRemovedScan.
74  bool IsBlackListedType() const;
75
76  // The ID that identifies this gallery in this Profile.
77  MediaGalleryPrefId pref_id;
78
79  // The user-visible name of this gallery.
80  base::string16 display_name;
81
82  // A string which uniquely and persistently identifies the device that the
83  // gallery lives on.
84  std::string device_id;
85
86  // The root of the gallery, relative to the root of the device.
87  base::FilePath path;
88
89  // The type of gallery.
90  Type type;
91
92  // The volume label of the volume/device on which the gallery
93  // resides. Empty if there is no such label or it is unknown.
94  base::string16 volume_label;
95
96  // Vendor name for the volume/device on which the gallery is located.
97  // Will be empty if unknown.
98  base::string16 vendor_name;
99
100  // Model name for the volume/device on which the gallery is located.
101  // Will be empty if unknown.
102  base::string16 model_name;
103
104  // The capacity in bytes of the volume/device on which the gallery is
105  // located. Will be zero if unknown.
106  uint64 total_size_in_bytes;
107
108  // If the gallery is on a removable device, the time that device was last
109  // attached. It is stored in preferences by the base::Time internal value,
110  // which is microseconds since the epoch.
111  base::Time last_attach_time;
112
113  // Set to true if the volume metadata fields (volume_label, vendor_name,
114  // model_name, total_size_in_bytes) were set. False if these fields were
115  // never written.
116  bool volume_metadata_valid;
117
118  // The following fields are populated with the audio, image, and video file
119  // counts from the last scan. For files where it is hard to determine the
120  // exact type, the file should be counted in all possible counts.
121  int audio_count;
122  int image_count;
123  int video_count;
124
125  // Which default gallery this corresponds to (or not default at all).
126  DefaultGalleryType default_gallery_type;
127
128  // 0 if the display_name is set externally and always used for display.
129  // 1 if the display_name is only set externally when it is overriding
130  // the name constructed from volume metadata.
131  // 2 if the display_name is set in a consistent manner that has resolved
132  // the issues in earlier versions.
133  // 3 if the default_gallery_type is set (new field for this version).
134  int prefs_version;
135
136  // Called by views to provide details for the gallery permission entries.
137  base::string16 GetGalleryDisplayName() const;
138  base::string16 GetGalleryTooltip() const;
139  base::string16 GetGalleryAdditionalDetails() const;
140
141  // Returns true if the gallery is currently a removable device gallery which
142  // is now attached, or a fixed storage gallery.
143  bool IsGalleryAvailable() const;
144};
145
146typedef std::map<MediaGalleryPrefId, MediaGalleryPrefInfo>
147    MediaGalleriesPrefInfoMap;
148typedef std::set<MediaGalleryPrefId> MediaGalleryPrefIdSet;
149
150// A class to manage the media gallery preferences.  There is one instance per
151// user profile. This class lives on the UI thread.
152class MediaGalleriesPreferences
153    : public KeyedService,
154      public storage_monitor::RemovableStorageObserver {
155 public:
156  class GalleryChangeObserver {
157   public:
158    // |extension_id| specifies the extension affected by this change.
159    // |pref_id| refers to the gallery.
160    virtual void OnPermissionAdded(MediaGalleriesPreferences* pref,
161                                   const std::string& extension_id,
162                                   MediaGalleryPrefId pref_id) {}
163
164    virtual void OnPermissionRemoved(MediaGalleriesPreferences* pref,
165                                     const std::string& extension_id,
166                                     MediaGalleryPrefId pref_id) {}
167
168    virtual void OnGalleryAdded(MediaGalleriesPreferences* pref,
169                                MediaGalleryPrefId pref_id) {}
170
171    virtual void OnGalleryRemoved(MediaGalleriesPreferences* pref,
172                                  MediaGalleryPrefId pref_id) {}
173
174    virtual void OnGalleryInfoUpdated(MediaGalleriesPreferences* pref,
175                                      MediaGalleryPrefId pref_id) {}
176
177   protected:
178    virtual ~GalleryChangeObserver();
179  };
180
181  explicit MediaGalleriesPreferences(Profile* profile);
182  virtual ~MediaGalleriesPreferences();
183
184  // Ensures that the preferences is initialized. The provided callback, if
185  // non-null, will be called when initialization is complete. If initialization
186  // has already completed, this callback will be invoked in the calling stack.
187  // Before the callback is run, other calls may not return the correct results.
188  // Should be invoked on the UI thread; callbacks will be run on the UI thread.
189  // This call also ensures that the StorageMonitor is initialized.
190  // Note for unit tests: This requires an active FILE thread and
191  // EnsureMediaDirectoriesExists instance to complete reliably.
192  void EnsureInitialized(base::Closure callback);
193
194  // Return true if the storage monitor has already been initialized.
195  bool IsInitialized() const;
196
197  Profile* profile();
198
199  void AddGalleryChangeObserver(GalleryChangeObserver* observer);
200  void RemoveGalleryChangeObserver(GalleryChangeObserver* observer);
201
202  // RemovableStorageObserver implementation.
203  virtual void OnRemovableStorageAttached(
204      const storage_monitor::StorageInfo& info) OVERRIDE;
205
206  // Lookup a media gallery and fill in information about it and return true if
207  // it exists. Return false if it does not, filling in default information.
208  bool LookUpGalleryByPath(const base::FilePath& path,
209                           MediaGalleryPrefInfo* gallery) const;
210
211  MediaGalleryPrefIdSet LookUpGalleriesByDeviceId(
212      const std::string& device_id) const;
213
214  // Returns the absolute file path of the gallery specified by the
215  // |gallery_id|. Returns an empty file path if the |gallery_id| is invalid.
216  // Set |include_unpermitted_galleries| to true to get the file path of the
217  // gallery to which this |extension| has no access permission.
218  //
219  // TODO(tommycli): Remove this function after Media Galleries API Private
220  // is transitioned over to public. Also, the body of the function wrong.
221  // It just returns the absolute path to the device, not the gallery.
222  base::FilePath LookUpGalleryPathForExtension(
223      MediaGalleryPrefId gallery_id,
224      const extensions::Extension* extension,
225      bool include_unpermitted_galleries);
226
227  // Teaches the registry about a new gallery. If the gallery is in a
228  // blacklisted state, it is unblacklisted. |type| should not be a blacklisted
229  // type. Returns the gallery's pref id.
230  MediaGalleryPrefId AddGallery(const std::string& device_id,
231                                const base::FilePath& relative_path,
232                                MediaGalleryPrefInfo::Type type,
233                                const base::string16& volume_label,
234                                const base::string16& vendor_name,
235                                const base::string16& model_name,
236                                uint64 total_size_in_bytes,
237                                base::Time last_attach_time,
238                                int audio_count,
239                                int image_count,
240                                int video_count);
241
242  // Teach the registry about a gallery simply from the path. If the gallery is
243  // in a blacklisted state, it is unblacklisted. |type| should not be a
244  // blacklisted type. Returns the gallery's pref id.
245  MediaGalleryPrefId AddGalleryByPath(const base::FilePath& path,
246                                      MediaGalleryPrefInfo::Type type);
247
248  // Logically removes the gallery identified by |id| from the store. For
249  // auto added or scan result galleries, this means moving them into a
250  // blacklisted state, otherwise they may come back when they are detected
251  // again.
252  void ForgetGalleryById(MediaGalleryPrefId id);
253
254  // Remove the gallery identified by |id| from the store entirely. If it is an
255  // auto added or scan result gallery, it could get added again when the
256  // location is noticed again.
257  void EraseGalleryById(MediaGalleryPrefId id);
258
259  // Returns true if some extension has permission for |id|, which may not be
260  // an auto detected type.
261  bool NonAutoGalleryHasPermission(MediaGalleryPrefId id) const;
262
263  MediaGalleryPrefIdSet GalleriesForExtension(
264      const extensions::Extension& extension);
265
266  // Returns true if the permission changed. Returns false if there was
267  // no change.
268  bool SetGalleryPermissionForExtension(const extensions::Extension& extension,
269                                        MediaGalleryPrefId pref_id,
270                                        bool has_permission);
271
272  const MediaGalleriesPrefInfoMap& known_galleries() const;
273
274  // These keep track of when we last successfully completed a media scan.
275  // This is used to provide cached results when appropriate.
276  base::Time GetLastScanCompletionTime() const;
277  void SetLastScanCompletionTime(const base::Time& time);
278
279  // KeyedService implementation:
280  virtual void Shutdown() OVERRIDE;
281
282  static void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry);
283
284  // Returns true if the media gallery preferences system has ever been used
285  // for this profile. To be exact, it checks if a gallery has ever been added
286  // (including defaults).
287  static bool APIHasBeenUsed(Profile* profile);
288
289 private:
290  friend class MediaGalleriesPreferencesTest;
291  friend class MediaGalleriesPermissionsTest;
292
293  typedef std::map<std::string /*device id*/, MediaGalleryPrefIdSet>
294      DeviceIdPrefIdsMap;
295
296  // These must be called on the UI thread.
297  void OnInitializationCallbackReturned();
298  void FinishInitialization();
299
300  // Populates the default galleries. Call only on fresh profiles.
301  void AddDefaultGalleries();
302
303  // This is a hack - Some devices (iTunes, Picasa) are singletons in that only
304  // one instance of that type is supported at a time. As such, the device id
305  // should just be "itunes:" or "picasa:" but that would mean finding the
306  // location of the database file multiple times, which may be an async
307  // operation. Storing the location of the backing database in the device
308  // id allows that look up to be avoided. However, the cost is that if the
309  // database moves, the device id in preferences has to be updated.  This
310  // method searches for a gallery of the type passed in and updates its
311  // device id.  It returns true if the device id is up to date.
312  bool UpdateDeviceIDForSingletonType(const std::string& device_id);
313
314  void OnStorageMonitorInit(bool api_has_been_used);
315
316  // Handle an iPhoto, iTunes, or Picasa finder returning a device ID to us.
317  void OnFinderDeviceID(const std::string& device_id);
318
319  // Builds |known_galleries_| from the persistent store.
320  void InitFromPrefs();
321
322  // Adds a new gallery with the given parameters, or updates in-place an
323  // existing gallery with the given device_id if one exists.
324  // TODO(orenb): Simplify this and reduce the number of parameters.
325  MediaGalleryPrefId AddOrUpdateGalleryInternal(
326      const std::string& device_id,
327      const base::string16& display_name,
328      const base::FilePath& relative_path,
329      MediaGalleryPrefInfo::Type type,
330      const base::string16& volume_label,
331      const base::string16& vendor_name,
332      const base::string16& model_name,
333      uint64 total_size_in_bytes,
334      base::Time last_attach_time,
335      bool volume_metadata_valid,
336      int audio_count,
337      int image_count,
338      int video_count,
339      int prefs_version,
340      MediaGalleryPrefInfo::DefaultGalleryType default_gallery_type);
341
342  void EraseOrBlacklistGalleryById(MediaGalleryPrefId id, bool erase);
343
344  // Updates the default galleries: finds the previously default galleries
345  // and updates their device IDs (i.e., their paths) inplace if they have
346  // changed.
347  void UpdateDefaultGalleriesPaths();
348
349  // Sets permission for the media galleries identified by |gallery_id| for the
350  // extension in the given |prefs|. Returns true only if anything changed.
351  bool SetGalleryPermissionInPrefs(const std::string& extension_id,
352                                   MediaGalleryPrefId gallery_id,
353                                   bool has_access);
354
355  // Removes the entry for the media galleries permissions identified by
356  // |gallery_id| for the extension in the given |prefs|.
357  // Returns true only if anything changed.
358  bool UnsetGalleryPermissionInPrefs(const std::string& extension_id,
359                                     MediaGalleryPrefId gallery_id);
360
361  // Return all media gallery permissions for the extension in the given
362  // |prefs|.
363  std::vector<MediaGalleryPermission> GetGalleryPermissionsFromPrefs(
364      const std::string& extension_id) const;
365
366  // Remove all the media gallery permissions in |prefs| for the gallery
367  // specified by |gallery_id|.
368  void RemoveGalleryPermissionsFromPrefs(MediaGalleryPrefId gallery_id);
369
370  // Get the ExtensionPrefs to use; this will be either the ExtensionPrefs
371  // object associated with |profile_|, or extension_prefs_for_testing_, if
372  // SetExtensionPrefsForTesting() has been called.
373  extensions::ExtensionPrefs* GetExtensionPrefs() const;
374
375  // Set the ExtensionPrefs object to be returned by GetExtensionPrefs().
376  void SetExtensionPrefsForTesting(extensions::ExtensionPrefs* extension_prefs);
377
378  bool initialized_;
379  std::vector<base::Closure> on_initialize_callbacks_;
380  int pre_initialization_callbacks_waiting_;
381
382  // The profile that owns |this|.
383  Profile* profile_;
384
385  // The ExtensionPrefs used in a testing environment, where KeyedServices
386  // aren't used. This will be NULL unless it is set with
387  // SetExtensionPrefsForTesting().
388  extensions::ExtensionPrefs* extension_prefs_for_testing_;
389
390  // An in-memory cache of known galleries.
391  MediaGalleriesPrefInfoMap known_galleries_;
392
393  // A mapping from device id to the set of gallery pref ids on that device.
394  // All pref ids in |device_map_| are also in |known_galleries_|.
395  DeviceIdPrefIdsMap device_map_;
396
397  ObserverList<GalleryChangeObserver> gallery_change_observers_;
398
399  base::WeakPtrFactory<MediaGalleriesPreferences> weak_factory_;
400
401  DISALLOW_COPY_AND_ASSIGN(MediaGalleriesPreferences);
402};
403
404#endif  // CHROME_BROWSER_MEDIA_GALLERIES_MEDIA_GALLERIES_PREFERENCES_H_
405