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/extensions/api/media_galleries_private/media_galleries_private_api.h" 6 7 #include "base/basictypes.h" 8 #include "base/bind.h" 9 #include "base/files/file_path.h" 10 #include "base/lazy_instance.h" 11 #include "base/location.h" 12 #include "base/prefs/pref_service.h" 13 #include "base/strings/string_number_conversions.h" 14 #include "chrome/browser/browser_process.h" 15 #include "chrome/browser/extensions/api/media_galleries_private/gallery_watch_manager.h" 16 #include "chrome/browser/extensions/api/media_galleries_private/media_galleries_private_event_router.h" 17 #include "chrome/browser/extensions/extension_util.h" 18 #include "chrome/browser/media_galleries/media_file_system_registry.h" 19 #include "chrome/browser/media_galleries/media_galleries_preferences.h" 20 #include "chrome/browser/profiles/profile.h" 21 #include "content/public/browser/browser_thread.h" 22 #include "content/public/browser/render_view_host.h" 23 #include "extensions/browser/event_router.h" 24 #include "extensions/browser/extension_function.h" 25 #include "extensions/browser/extension_system.h" 26 27 using base::DictionaryValue; 28 using base::ListValue; 29 30 namespace extensions { 31 32 namespace AddGalleryWatch = 33 extensions::api::media_galleries_private::AddGalleryWatch; 34 namespace RemoveGalleryWatch = 35 extensions::api::media_galleries_private::RemoveGalleryWatch; 36 namespace GetAllGalleryWatch = 37 extensions::api::media_galleries_private::GetAllGalleryWatch; 38 namespace media_galleries_private = 39 api::media_galleries_private; 40 41 namespace { 42 43 const char kInvalidGalleryIDError[] = "Invalid gallery ID"; 44 45 // Handles the profile shutdown event on the file thread to clean up 46 // GalleryWatchManager. 47 void HandleProfileShutdownOnFileThread(void* profile_id) { 48 DCHECK_CURRENTLY_ON(content::BrowserThread::FILE); 49 GalleryWatchManager::OnProfileShutdown(profile_id); 50 } 51 52 // Gets the |gallery_file_path| and |gallery_pref_id| of the gallery specified 53 // by the |gallery_id|. Returns true and set |gallery_file_path| and 54 // |gallery_pref_id| if the |gallery_id| is valid and returns false otherwise. 55 bool GetGalleryFilePathAndId(const std::string& gallery_id, 56 Profile* profile, 57 const Extension* extension, 58 base::FilePath* gallery_file_path, 59 MediaGalleryPrefId* gallery_pref_id) { 60 MediaGalleryPrefId pref_id; 61 if (!base::StringToUint64(gallery_id, &pref_id)) 62 return false; 63 MediaGalleriesPreferences* preferences = 64 g_browser_process->media_file_system_registry()->GetPreferences(profile); 65 base::FilePath file_path( 66 preferences->LookUpGalleryPathForExtension(pref_id, extension, false)); 67 if (file_path.empty()) 68 return false; 69 *gallery_pref_id = pref_id; 70 *gallery_file_path = file_path; 71 return true; 72 } 73 74 } // namespace 75 76 77 /////////////////////////////////////////////////////////////////////////////// 78 // MediaGalleriesPrivateAPI // 79 /////////////////////////////////////////////////////////////////////////////// 80 81 MediaGalleriesPrivateAPI::MediaGalleriesPrivateAPI( 82 content::BrowserContext* context) 83 : profile_(Profile::FromBrowserContext(context)), weak_ptr_factory_(this) { 84 DCHECK(profile_); 85 EventRouter* event_router = EventRouter::Get(profile_); 86 event_router->RegisterObserver( 87 this, media_galleries_private::OnGalleryChanged::kEventName); 88 } 89 90 MediaGalleriesPrivateAPI::~MediaGalleriesPrivateAPI() { 91 } 92 93 void MediaGalleriesPrivateAPI::Shutdown() { 94 EventRouter::Get(profile_)->UnregisterObserver(this); 95 weak_ptr_factory_.InvalidateWeakPtrs(); 96 content::BrowserThread::PostTask( 97 content::BrowserThread::FILE, FROM_HERE, 98 base::Bind(&HandleProfileShutdownOnFileThread, profile_)); 99 } 100 101 static base::LazyInstance< 102 BrowserContextKeyedAPIFactory<MediaGalleriesPrivateAPI> > g_factory = 103 LAZY_INSTANCE_INITIALIZER; 104 105 // static 106 BrowserContextKeyedAPIFactory<MediaGalleriesPrivateAPI>* 107 MediaGalleriesPrivateAPI::GetFactoryInstance() { 108 return g_factory.Pointer(); 109 } 110 111 // static 112 MediaGalleriesPrivateAPI* MediaGalleriesPrivateAPI::Get( 113 content::BrowserContext* context) { 114 return BrowserContextKeyedAPIFactory<MediaGalleriesPrivateAPI>::Get(context); 115 } 116 117 void MediaGalleriesPrivateAPI::OnListenerAdded( 118 const EventListenerInfo& details) { 119 // Make sure MediaGalleriesPreferences is initialized. After that, 120 // try to initialize the event router for the listener. 121 // This method is called synchronously with the message handler for the 122 // JS invocation. 123 124 MediaGalleriesPreferences* preferences = 125 g_browser_process->media_file_system_registry()->GetPreferences(profile_); 126 preferences->EnsureInitialized(base::Bind( 127 &MediaGalleriesPrivateAPI::MaybeInitializeEventRouterAndTracker, 128 weak_ptr_factory_.GetWeakPtr())); 129 } 130 131 MediaGalleriesPrivateEventRouter* MediaGalleriesPrivateAPI::GetEventRouter() { 132 MaybeInitializeEventRouterAndTracker(); 133 return media_galleries_private_event_router_.get(); 134 } 135 136 GalleryWatchStateTracker* 137 MediaGalleriesPrivateAPI::GetGalleryWatchStateTracker() { 138 MaybeInitializeEventRouterAndTracker(); 139 return tracker_.get(); 140 } 141 142 void MediaGalleriesPrivateAPI::MaybeInitializeEventRouterAndTracker() { 143 if (media_galleries_private_event_router_.get()) 144 return; 145 media_galleries_private_event_router_.reset( 146 new MediaGalleriesPrivateEventRouter(profile_)); 147 DCHECK(g_browser_process->media_file_system_registry()-> 148 GetPreferences(profile_)->IsInitialized()); 149 tracker_.reset( 150 new GalleryWatchStateTracker(profile_)); 151 } 152 153 /////////////////////////////////////////////////////////////////////////////// 154 // MediaGalleriesPrivateAddGalleryWatchFunction // 155 /////////////////////////////////////////////////////////////////////////////// 156 MediaGalleriesPrivateAddGalleryWatchFunction:: 157 ~MediaGalleriesPrivateAddGalleryWatchFunction() { 158 } 159 160 bool MediaGalleriesPrivateAddGalleryWatchFunction::RunAsync() { 161 DCHECK(GetProfile()); 162 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); 163 if (!render_view_host() || !render_view_host()->GetProcess()) 164 return false; 165 166 scoped_ptr<AddGalleryWatch::Params> params( 167 AddGalleryWatch::Params::Create(*args_)); 168 EXTENSION_FUNCTION_VALIDATE(params.get()); 169 170 MediaGalleriesPreferences* preferences = 171 g_browser_process->media_file_system_registry()->GetPreferences( 172 GetProfile()); 173 preferences->EnsureInitialized(base::Bind( 174 &MediaGalleriesPrivateAddGalleryWatchFunction::OnPreferencesInit, 175 this, 176 params->gallery_id)); 177 178 return true; 179 } 180 181 void MediaGalleriesPrivateAddGalleryWatchFunction::OnPreferencesInit( 182 const std::string& pref_id) { 183 base::FilePath gallery_file_path; 184 MediaGalleryPrefId gallery_pref_id = 0; 185 if (!GetGalleryFilePathAndId(pref_id, 186 GetProfile(), 187 GetExtension(), 188 &gallery_file_path, 189 &gallery_pref_id)) { 190 error_ = kInvalidGalleryIDError; 191 HandleResponse(gallery_pref_id, false); 192 return; 193 } 194 195 MediaGalleriesPrivateEventRouter* router = 196 MediaGalleriesPrivateAPI::Get(GetProfile())->GetEventRouter(); 197 DCHECK(router); 198 content::BrowserThread::PostTaskAndReplyWithResult( 199 content::BrowserThread::FILE, 200 FROM_HERE, 201 base::Bind(&GalleryWatchManager::SetupGalleryWatch, 202 GetProfile(), 203 gallery_pref_id, 204 gallery_file_path, 205 extension_id(), 206 router->AsWeakPtr()), 207 base::Bind(&MediaGalleriesPrivateAddGalleryWatchFunction::HandleResponse, 208 this, 209 gallery_pref_id)); 210 } 211 212 void MediaGalleriesPrivateAddGalleryWatchFunction::HandleResponse( 213 MediaGalleryPrefId gallery_id, 214 bool success) { 215 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); 216 media_galleries_private::AddGalleryWatchResult result; 217 result.gallery_id = base::Uint64ToString(gallery_id); 218 result.success = success; 219 SetResult(result.ToValue().release()); 220 if (success) { 221 DCHECK(g_browser_process->media_file_system_registry() 222 ->GetPreferences(GetProfile()) 223 ->IsInitialized()); 224 GalleryWatchStateTracker* state_tracker = MediaGalleriesPrivateAPI::Get( 225 GetProfile())->GetGalleryWatchStateTracker(); 226 state_tracker->OnGalleryWatchAdded(extension_id(), gallery_id); 227 } 228 SendResponse(true); 229 } 230 231 232 /////////////////////////////////////////////////////////////////////////////// 233 // MediaGalleriesPrivateRemoveGalleryWatchFunction // 234 /////////////////////////////////////////////////////////////////////////////// 235 236 MediaGalleriesPrivateRemoveGalleryWatchFunction:: 237 ~MediaGalleriesPrivateRemoveGalleryWatchFunction() { 238 } 239 240 bool MediaGalleriesPrivateRemoveGalleryWatchFunction::RunAsync() { 241 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); 242 if (!render_view_host() || !render_view_host()->GetProcess()) 243 return false; 244 245 scoped_ptr<RemoveGalleryWatch::Params> params( 246 RemoveGalleryWatch::Params::Create(*args_)); 247 EXTENSION_FUNCTION_VALIDATE(params.get()); 248 249 MediaGalleriesPreferences* preferences = 250 g_browser_process->media_file_system_registry()->GetPreferences( 251 GetProfile()); 252 preferences->EnsureInitialized(base::Bind( 253 &MediaGalleriesPrivateRemoveGalleryWatchFunction::OnPreferencesInit, 254 this, 255 params->gallery_id)); 256 return true; 257 } 258 259 void MediaGalleriesPrivateRemoveGalleryWatchFunction::OnPreferencesInit( 260 const std::string& pref_id) { 261 base::FilePath gallery_file_path; 262 MediaGalleryPrefId gallery_pref_id = 0; 263 if (!GetGalleryFilePathAndId(pref_id, 264 GetProfile(), 265 GetExtension(), 266 &gallery_file_path, 267 &gallery_pref_id)) { 268 error_ = kInvalidGalleryIDError; 269 SendResponse(false); 270 return; 271 } 272 273 content::BrowserThread::PostTask( 274 content::BrowserThread::FILE, 275 FROM_HERE, 276 base::Bind(&GalleryWatchManager::RemoveGalleryWatch, 277 GetProfile(), 278 gallery_file_path, 279 extension_id())); 280 281 GalleryWatchStateTracker* state_tracker = MediaGalleriesPrivateAPI::Get( 282 GetProfile())->GetGalleryWatchStateTracker(); 283 state_tracker->OnGalleryWatchRemoved(extension_id(), gallery_pref_id); 284 SendResponse(true); 285 } 286 287 /////////////////////////////////////////////////////////////////////////////// 288 // MediaGalleriesPrivateGetAllGalleryWatchFunction // 289 /////////////////////////////////////////////////////////////////////////////// 290 291 MediaGalleriesPrivateGetAllGalleryWatchFunction:: 292 ~MediaGalleriesPrivateGetAllGalleryWatchFunction() { 293 } 294 295 bool MediaGalleriesPrivateGetAllGalleryWatchFunction::RunAsync() { 296 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); 297 if (!render_view_host() || !render_view_host()->GetProcess()) 298 return false; 299 300 MediaGalleriesPreferences* preferences = 301 g_browser_process->media_file_system_registry()->GetPreferences( 302 GetProfile()); 303 preferences->EnsureInitialized(base::Bind( 304 &MediaGalleriesPrivateGetAllGalleryWatchFunction::OnPreferencesInit, 305 this)); 306 return true; 307 } 308 309 void MediaGalleriesPrivateGetAllGalleryWatchFunction::OnPreferencesInit() { 310 std::vector<std::string> result; 311 GalleryWatchStateTracker* state_tracker = MediaGalleriesPrivateAPI::Get( 312 GetProfile())->GetGalleryWatchStateTracker(); 313 MediaGalleryPrefIdSet gallery_ids = 314 state_tracker->GetAllWatchedGalleryIDsForExtension(extension_id()); 315 for (MediaGalleryPrefIdSet::const_iterator iter = gallery_ids.begin(); 316 iter != gallery_ids.end(); ++iter) { 317 result.push_back(base::Uint64ToString(*iter)); 318 } 319 results_ = GetAllGalleryWatch::Results::Create(result); 320 SendResponse(true); 321 } 322 323 /////////////////////////////////////////////////////////////////////////////// 324 // MediaGalleriesPrivateRemoveAllGalleryWatchFunction // 325 /////////////////////////////////////////////////////////////////////////////// 326 327 MediaGalleriesPrivateRemoveAllGalleryWatchFunction:: 328 ~MediaGalleriesPrivateRemoveAllGalleryWatchFunction() { 329 } 330 331 bool MediaGalleriesPrivateRemoveAllGalleryWatchFunction::RunAsync() { 332 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); 333 if (!render_view_host() || !render_view_host()->GetProcess()) 334 return false; 335 336 MediaGalleriesPreferences* preferences = 337 g_browser_process->media_file_system_registry()->GetPreferences( 338 GetProfile()); 339 preferences->EnsureInitialized(base::Bind( 340 &MediaGalleriesPrivateRemoveAllGalleryWatchFunction::OnPreferencesInit, 341 this)); 342 return true; 343 } 344 345 void MediaGalleriesPrivateRemoveAllGalleryWatchFunction::OnPreferencesInit() { 346 MediaGalleriesPreferences* preferences = 347 g_browser_process->media_file_system_registry()->GetPreferences( 348 GetProfile()); 349 GalleryWatchStateTracker* state_tracker = MediaGalleriesPrivateAPI::Get( 350 GetProfile())->GetGalleryWatchStateTracker(); 351 state_tracker->RemoveAllGalleryWatchersForExtension( 352 extension_id(), preferences); 353 SendResponse(true); 354 } 355 356 } // namespace extensions 357