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/sync_file_system/extension_sync_event_observer.h" 6 7#include "base/lazy_instance.h" 8#include "chrome/browser/extensions/api/sync_file_system/sync_file_system_api_helpers.h" 9#include "chrome/browser/sync_file_system/sync_event_observer.h" 10#include "chrome/browser/sync_file_system/sync_file_system_service.h" 11#include "chrome/browser/sync_file_system/sync_file_system_service_factory.h" 12#include "chrome/browser/sync_file_system/syncable_file_system_util.h" 13#include "chrome/common/extensions/api/sync_file_system.h" 14#include "content/public/browser/browser_context.h" 15#include "extensions/browser/event_router.h" 16#include "extensions/browser/extension_registry.h" 17#include "extensions/browser/extension_system_provider.h" 18#include "extensions/browser/extensions_browser_client.h" 19#include "extensions/common/extension_set.h" 20#include "storage/browser/fileapi/file_system_url.h" 21#include "storage/common/fileapi/file_system_util.h" 22 23using sync_file_system::SyncEventObserver; 24 25namespace extensions { 26 27static base::LazyInstance< 28 BrowserContextKeyedAPIFactory<ExtensionSyncEventObserver> > g_factory = 29 LAZY_INSTANCE_INITIALIZER; 30 31// static 32BrowserContextKeyedAPIFactory<ExtensionSyncEventObserver>* 33ExtensionSyncEventObserver::GetFactoryInstance() { 34 return g_factory.Pointer(); 35} 36 37ExtensionSyncEventObserver::ExtensionSyncEventObserver( 38 content::BrowserContext* context) 39 : browser_context_(context), sync_service_(NULL) {} 40 41void ExtensionSyncEventObserver::InitializeForService( 42 sync_file_system::SyncFileSystemService* sync_service) { 43 DCHECK(sync_service); 44 if (sync_service_ != NULL) { 45 DCHECK_EQ(sync_service_, sync_service); 46 return; 47 } 48 sync_service_ = sync_service; 49 sync_service_->AddSyncEventObserver(this); 50} 51 52ExtensionSyncEventObserver::~ExtensionSyncEventObserver() {} 53 54void ExtensionSyncEventObserver::Shutdown() { 55 if (sync_service_ != NULL) 56 sync_service_->RemoveSyncEventObserver(this); 57} 58 59std::string ExtensionSyncEventObserver::GetExtensionId( 60 const GURL& app_origin) { 61 const Extension* app = ExtensionRegistry::Get(browser_context_) 62 ->enabled_extensions().GetAppByURL(app_origin); 63 if (!app) { 64 // The app is uninstalled or disabled. 65 return std::string(); 66 } 67 return app->id(); 68} 69 70void ExtensionSyncEventObserver::OnSyncStateUpdated( 71 const GURL& app_origin, 72 sync_file_system::SyncServiceState state, 73 const std::string& description) { 74 // Convert state and description into SyncState Object. 75 api::sync_file_system::ServiceInfo service_info; 76 service_info.state = SyncServiceStateToExtensionEnum(state); 77 service_info.description = description; 78 scoped_ptr<base::ListValue> params( 79 api::sync_file_system::OnServiceStatusChanged::Create(service_info)); 80 81 BroadcastOrDispatchEvent( 82 app_origin, 83 api::sync_file_system::OnServiceStatusChanged::kEventName, 84 params.Pass()); 85} 86 87void ExtensionSyncEventObserver::OnFileSynced( 88 const storage::FileSystemURL& url, 89 sync_file_system::SyncFileStatus status, 90 sync_file_system::SyncAction action, 91 sync_file_system::SyncDirection direction) { 92 scoped_ptr<base::ListValue> params(new base::ListValue()); 93 94 // For now we always assume events come only for files (not directories). 95 scoped_ptr<base::DictionaryValue> entry( 96 CreateDictionaryValueForFileSystemEntry( 97 url, sync_file_system::SYNC_FILE_TYPE_FILE)); 98 if (!entry) 99 return; 100 params->Append(entry.release()); 101 102 // Status, SyncAction and any optional notes to go here. 103 api::sync_file_system::FileStatus status_enum = 104 SyncFileStatusToExtensionEnum(status); 105 api::sync_file_system::SyncAction action_enum = 106 SyncActionToExtensionEnum(action); 107 api::sync_file_system::SyncDirection direction_enum = 108 SyncDirectionToExtensionEnum(direction); 109 params->AppendString(api::sync_file_system::ToString(status_enum)); 110 params->AppendString(api::sync_file_system::ToString(action_enum)); 111 params->AppendString(api::sync_file_system::ToString(direction_enum)); 112 113 BroadcastOrDispatchEvent( 114 url.origin(), 115 api::sync_file_system::OnFileStatusChanged::kEventName, 116 params.Pass()); 117} 118 119void ExtensionSyncEventObserver::BroadcastOrDispatchEvent( 120 const GURL& app_origin, 121 const std::string& event_name, 122 scoped_ptr<base::ListValue> values) { 123 // Check to see whether the event should be broadcasted to all listening 124 // extensions or sent to a specific extension ID. 125 bool broadcast_mode = app_origin.is_empty(); 126 EventRouter* event_router = EventRouter::Get(browser_context_); 127 DCHECK(event_router); 128 129 scoped_ptr<Event> event(new Event(event_name, values.Pass())); 130 event->restrict_to_browser_context = browser_context_; 131 132 // No app_origin, broadcast to all listening extensions for this event name. 133 if (broadcast_mode) { 134 event_router->BroadcastEvent(event.Pass()); 135 return; 136 } 137 138 // Dispatch to single extension ID. 139 const std::string extension_id = GetExtensionId(app_origin); 140 if (extension_id.empty()) 141 return; 142 event_router->DispatchEventToExtension(extension_id, event.Pass()); 143} 144 145template <> 146void BrowserContextKeyedAPIFactory< 147 ExtensionSyncEventObserver>::DeclareFactoryDependencies() { 148 DependsOn(sync_file_system::SyncFileSystemServiceFactory::GetInstance()); 149 DependsOn(ExtensionsBrowserClient::Get()->GetExtensionSystemFactory()); 150} 151 152} // namespace extensions 153