12a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// found in the LICENSE file.
42a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/extensions/api/sync_file_system/extension_sync_event_observer.h"
62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "base/lazy_instance.h"
8c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/browser/extensions/api/sync_file_system/sync_file_system_api_helpers.h"
92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/sync_file_system/sync_event_observer.h"
102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/sync_file_system/sync_file_system_service.h"
11a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "chrome/browser/sync_file_system/sync_file_system_service_factory.h"
122385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch#include "chrome/browser/sync_file_system/syncable_file_system_util.h"
132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/common/extensions/api/sync_file_system.h"
14a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "content/public/browser/browser_context.h"
15f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "extensions/browser/event_router.h"
16a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch#include "extensions/browser/extension_registry.h"
17a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "extensions/browser/extension_system_provider.h"
18a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "extensions/browser/extensions_browser_client.h"
19a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch#include "extensions/common/extension_set.h"
201320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "storage/browser/fileapi/file_system_url.h"
211320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "storage/common/fileapi/file_system_util.h"
222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)using sync_file_system::SyncEventObserver;
242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace extensions {
262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
27a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)static base::LazyInstance<
28a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    BrowserContextKeyedAPIFactory<ExtensionSyncEventObserver> > g_factory =
29a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    LAZY_INSTANCE_INITIALIZER;
30a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
31a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// static
32a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)BrowserContextKeyedAPIFactory<ExtensionSyncEventObserver>*
33a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)ExtensionSyncEventObserver::GetFactoryInstance() {
34a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return g_factory.Pointer();
35a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
36a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)ExtensionSyncEventObserver::ExtensionSyncEventObserver(
38a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    content::BrowserContext* context)
39a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    : browser_context_(context), sync_service_(NULL) {}
402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ExtensionSyncEventObserver::InitializeForService(
42868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    sync_file_system::SyncFileSystemService* sync_service) {
432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(sync_service);
442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (sync_service_ != NULL) {
452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    DCHECK_EQ(sync_service_, sync_service);
462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  sync_service_ = sync_service;
492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  sync_service_->AddSyncEventObserver(this);
502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)ExtensionSyncEventObserver::~ExtensionSyncEventObserver() {}
532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ExtensionSyncEventObserver::Shutdown() {
552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (sync_service_ != NULL)
562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    sync_service_->RemoveSyncEventObserver(this);
572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)std::string ExtensionSyncEventObserver::GetExtensionId(
602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const GURL& app_origin) {
61a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  const Extension* app = ExtensionRegistry::Get(browser_context_)
62a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch      ->enabled_extensions().GetAppByURL(app_origin);
632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!app) {
642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // The app is uninstalled or disabled.
652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return std::string();
662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return app->id();
682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ExtensionSyncEventObserver::OnSyncStateUpdated(
712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const GURL& app_origin,
72c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    sync_file_system::SyncServiceState state,
732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& description) {
742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Convert state and description into SyncState Object.
752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  api::sync_file_system::ServiceInfo service_info;
76c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  service_info.state = SyncServiceStateToExtensionEnum(state);
772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  service_info.description = description;
782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_ptr<base::ListValue> params(
792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      api::sync_file_system::OnServiceStatusChanged::Create(service_info));
802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
813551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  BroadcastOrDispatchEvent(
823551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      app_origin,
833551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      api::sync_file_system::OnServiceStatusChanged::kEventName,
843551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      params.Pass());
852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ExtensionSyncEventObserver::OnFileSynced(
8803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    const storage::FileSystemURL& url,
892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    sync_file_system::SyncFileStatus status,
902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    sync_file_system::SyncAction action,
912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    sync_file_system::SyncDirection direction) {
92eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  scoped_ptr<base::ListValue> params(new base::ListValue());
93c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
94c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // For now we always assume events come only for files (not directories).
95010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  scoped_ptr<base::DictionaryValue> entry(
96010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      CreateDictionaryValueForFileSystemEntry(
97010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)          url, sync_file_system::SYNC_FILE_TYPE_FILE));
98010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  if (!entry)
99010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    return;
100010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  params->Append(entry.release());
1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Status, SyncAction and any optional notes to go here.
1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  api::sync_file_system::FileStatus status_enum =
1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      SyncFileStatusToExtensionEnum(status);
1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  api::sync_file_system::SyncAction action_enum =
1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      SyncActionToExtensionEnum(action);
1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  api::sync_file_system::SyncDirection direction_enum =
1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      SyncDirectionToExtensionEnum(direction);
1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  params->AppendString(api::sync_file_system::ToString(status_enum));
1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  params->AppendString(api::sync_file_system::ToString(action_enum));
1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  params->AppendString(api::sync_file_system::ToString(direction_enum));
1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1133551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  BroadcastOrDispatchEvent(
1143551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      url.origin(),
1153551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      api::sync_file_system::OnFileStatusChanged::kEventName,
1163551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      params.Pass());
1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ExtensionSyncEventObserver::BroadcastOrDispatchEvent(
1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const GURL& app_origin,
1212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& event_name,
1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    scoped_ptr<base::ListValue> values) {
1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Check to see whether the event should be broadcasted to all listening
1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // extensions or sent to a specific extension ID.
1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool broadcast_mode = app_origin.is_empty();
1260529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  EventRouter* event_router = EventRouter::Get(browser_context_);
1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(event_router);
1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_ptr<Event> event(new Event(event_name, values.Pass()));
130a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  event->restrict_to_browser_context = browser_context_;
1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // No app_origin, broadcast to all listening extensions for this event name.
1332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (broadcast_mode) {
1342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    event_router->BroadcastEvent(event.Pass());
1352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
1362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Dispatch to single extension ID.
1392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const std::string extension_id = GetExtensionId(app_origin);
1402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (extension_id.empty())
1412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
1422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  event_router->DispatchEventToExtension(extension_id, event.Pass());
1432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
145a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)template <>
146a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void BrowserContextKeyedAPIFactory<
147a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    ExtensionSyncEventObserver>::DeclareFactoryDependencies() {
148a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  DependsOn(sync_file_system::SyncFileSystemServiceFactory::GetInstance());
149a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  DependsOn(ExtensionsBrowserClient::Get()->GetExtensionSystemFactory());
150a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
151a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
1522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace extensions
153