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