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 23 class Profile; 24 25 namespace base { 26 class DictionaryValue; 27 } 28 29 namespace extensions { 30 class Extension; 31 class ExtensionPrefs; 32 } 33 34 namespace user_prefs { 35 class PrefRegistrySyncable; 36 } 37 38 typedef uint64 MediaGalleryPrefId; 39 const MediaGalleryPrefId kInvalidMediaGalleryPrefId = 0; 40 41 const char kMediaGalleriesPrefsVersionKey[] = "preferencesVersion"; 42 const char kMediaGalleriesDefaultGalleryTypeKey[] = "defaultGalleryType"; 43 44 struct MediaGalleryPermission { 45 MediaGalleryPrefId pref_id; 46 bool has_permission; 47 }; 48 49 struct 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 146 typedef std::map<MediaGalleryPrefId, MediaGalleryPrefInfo> 147 MediaGalleriesPrefInfoMap; 148 typedef 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. 152 class 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