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