Add onMetaInfoChanged event to bookmarkManagerPrivate.

This is needed in order to get notified when meta info fields change
outside of the bookmark manager, like when syncing.

BUG=

Review URL: https://codereview.chromium.org/189343002

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@256660 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/chrome/browser/extensions/api/bookmark_manager_private/bookmark_manager_private_api.cc b/chrome/browser/extensions/api/bookmark_manager_private/bookmark_manager_private_api.cc
index c9c89022..6564052 100644
--- a/chrome/browser/extensions/api/bookmark_manager_private/bookmark_manager_private_api.cc
+++ b/chrome/browser/extensions/api/bookmark_manager_private/bookmark_manager_private_api.cc
@@ -6,6 +6,7 @@
 
 #include <vector>
 
+#include "base/lazy_instance.h"
 #include "base/memory/linked_ptr.h"
 #include "base/prefs/pref_service.h"
 #include "base/strings/string_number_conversions.h"
@@ -32,7 +33,6 @@
 #include "content/public/browser/web_contents.h"
 #include "content/public/browser/web_contents_view.h"
 #include "content/public/browser/web_ui.h"
-#include "extensions/browser/event_router.h"
 #include "extensions/browser/extension_system.h"
 #include "extensions/browser/view_type_utils.h"
 #include "grit/generated_resources.h"
@@ -166,23 +166,95 @@
 }  // namespace
 
 BookmarkManagerPrivateEventRouter::BookmarkManagerPrivateEventRouter(
+    content::BrowserContext* browser_context,
+    BookmarkModel* bookmark_model)
+    : browser_context_(browser_context), bookmark_model_(bookmark_model) {
+  bookmark_model_->AddObserver(this);
+}
+
+BookmarkManagerPrivateEventRouter::~BookmarkManagerPrivateEventRouter() {
+  if (bookmark_model_)
+    bookmark_model_->RemoveObserver(this);
+}
+
+void BookmarkManagerPrivateEventRouter::DispatchEvent(
+    const std::string& event_name,
+    scoped_ptr<base::ListValue> event_args) {
+  extensions::ExtensionSystem::Get(browser_context_)
+      ->event_router()
+      ->BroadcastEvent(make_scoped_ptr(
+          new extensions::Event(event_name, event_args.Pass())));
+}
+
+void BookmarkManagerPrivateEventRouter::BookmarkModelChanged() {}
+
+void BookmarkManagerPrivateEventRouter::BookmarkModelBeingDeleted(
+    BookmarkModel* model) {
+  bookmark_model_ = NULL;
+}
+
+void BookmarkManagerPrivateEventRouter::BookmarkMetaInfoChanged(
+    BookmarkModel* model,
+    const BookmarkNode* node) {
+  DispatchEvent(bookmark_manager_private::OnMetaInfoChanged::kEventName,
+                bookmark_manager_private::OnMetaInfoChanged::Create(
+                    base::Int64ToString(node->id())));
+}
+
+BookmarkManagerPrivateAPI::BookmarkManagerPrivateAPI(
+    content::BrowserContext* browser_context)
+    : browser_context_(browser_context) {
+  EventRouter* event_router =
+      ExtensionSystem::Get(browser_context)->event_router();
+  event_router->RegisterObserver(
+      this, bookmark_manager_private::OnMetaInfoChanged::kEventName);
+}
+
+BookmarkManagerPrivateAPI::~BookmarkManagerPrivateAPI() {}
+
+void BookmarkManagerPrivateAPI::Shutdown() {
+  ExtensionSystem::Get(browser_context_)->event_router()->UnregisterObserver(
+      this);
+}
+
+static base::LazyInstance<
+    BrowserContextKeyedAPIFactory<BookmarkManagerPrivateAPI> > g_factory =
+    LAZY_INSTANCE_INITIALIZER;
+
+// static
+BrowserContextKeyedAPIFactory<BookmarkManagerPrivateAPI>*
+BookmarkManagerPrivateAPI::GetFactoryInstance() {
+  return g_factory.Pointer();
+}
+
+void BookmarkManagerPrivateAPI::OnListenerAdded(
+    const EventListenerInfo& details) {
+  ExtensionSystem::Get(browser_context_)->event_router()->UnregisterObserver(
+      this);
+  event_router_.reset(new BookmarkManagerPrivateEventRouter(
+      browser_context_,
+      BookmarkModelFactory::GetForProfile(
+          Profile::FromBrowserContext(browser_context_))));
+}
+
+BookmarkManagerPrivateDragEventRouter::BookmarkManagerPrivateDragEventRouter(
     Profile* profile,
     content::WebContents* web_contents)
-    : profile_(profile),
-      web_contents_(web_contents) {
+    : profile_(profile), web_contents_(web_contents) {
   BookmarkTabHelper* bookmark_tab_helper =
       BookmarkTabHelper::FromWebContents(web_contents_);
   bookmark_tab_helper->set_bookmark_drag_delegate(this);
 }
 
-BookmarkManagerPrivateEventRouter::~BookmarkManagerPrivateEventRouter() {
+BookmarkManagerPrivateDragEventRouter::
+    ~BookmarkManagerPrivateDragEventRouter() {
   BookmarkTabHelper* bookmark_tab_helper =
       BookmarkTabHelper::FromWebContents(web_contents_);
   if (bookmark_tab_helper->bookmark_drag_delegate() == this)
     bookmark_tab_helper->set_bookmark_drag_delegate(NULL);
 }
 
-void BookmarkManagerPrivateEventRouter::DispatchEvent(
+void BookmarkManagerPrivateDragEventRouter::DispatchEvent(
     const std::string& event_name,
     scoped_ptr<base::ListValue> args) {
   if (!ExtensionSystem::Get(profile_)->event_router())
@@ -192,7 +264,7 @@
   ExtensionSystem::Get(profile_)->event_router()->BroadcastEvent(event.Pass());
 }
 
-void BookmarkManagerPrivateEventRouter::OnDragEnter(
+void BookmarkManagerPrivateDragEventRouter::OnDragEnter(
     const BookmarkNodeData& data) {
   if (data.size() == 0)
     return;
@@ -201,13 +273,13 @@
                     *CreateApiBookmarkNodeData(profile_, data)));
 }
 
-void BookmarkManagerPrivateEventRouter::OnDragOver(
+void BookmarkManagerPrivateDragEventRouter::OnDragOver(
     const BookmarkNodeData& data) {
   // Intentionally empty since these events happens too often and floods the
   // message queue. We do not need this event for the bookmark manager anyway.
 }
 
-void BookmarkManagerPrivateEventRouter::OnDragLeave(
+void BookmarkManagerPrivateDragEventRouter::OnDragLeave(
     const BookmarkNodeData& data) {
   if (data.size() == 0)
     return;
@@ -216,7 +288,8 @@
                     *CreateApiBookmarkNodeData(profile_, data)));
 }
 
-void BookmarkManagerPrivateEventRouter::OnDrop(const BookmarkNodeData& data) {
+void BookmarkManagerPrivateDragEventRouter::OnDrop(
+    const BookmarkNodeData& data) {
   if (data.size() == 0)
     return;
   DispatchEvent(bookmark_manager_private::OnDrop::kEventName,
@@ -229,13 +302,13 @@
 }
 
 const BookmarkNodeData*
-BookmarkManagerPrivateEventRouter::GetBookmarkNodeData() {
+BookmarkManagerPrivateDragEventRouter::GetBookmarkNodeData() {
   if (bookmark_drag_data_.is_valid())
     return &bookmark_drag_data_;
   return NULL;
 }
 
-void BookmarkManagerPrivateEventRouter::ClearBookmarkNodeData() {
+void BookmarkManagerPrivateDragEventRouter::ClearBookmarkNodeData() {
   bookmark_drag_data_.Clear();
 }
 
@@ -474,8 +547,8 @@
     ExtensionWebUI* web_ui =
         static_cast<ExtensionWebUI*>(web_contents->GetWebUI()->GetController());
     CHECK(web_ui);
-    BookmarkManagerPrivateEventRouter* router =
-        web_ui->bookmark_manager_private_event_router();
+    BookmarkManagerPrivateDragEventRouter* router =
+        web_ui->bookmark_manager_private_drag_event_router();
 
     DCHECK(router);
     const BookmarkNodeData* drag_data = router->GetBookmarkNodeData();
diff --git a/chrome/browser/extensions/api/bookmark_manager_private/bookmark_manager_private_api.h b/chrome/browser/extensions/api/bookmark_manager_private/bookmark_manager_private_api.h
index 3ee4f2b..ded793b 100644
--- a/chrome/browser/extensions/api/bookmark_manager_private/bookmark_manager_private_api.h
+++ b/chrome/browser/extensions/api/bookmark_manager_private/bookmark_manager_private_api.h
@@ -5,30 +5,86 @@
 #ifndef CHROME_BROWSER_EXTENSIONS_API_BOOKMARK_MANAGER_PRIVATE_BOOKMARK_MANAGER_PRIVATE_API_H_
 #define CHROME_BROWSER_EXTENSIONS_API_BOOKMARK_MANAGER_PRIVATE_BOOKMARK_MANAGER_PRIVATE_API_H_
 
+#include "base/memory/scoped_ptr.h"
 #include "base/values.h"
+#include "chrome/browser/bookmarks/base_bookmark_model_observer.h"
 #include "chrome/browser/bookmarks/bookmark_node_data.h"
 #include "chrome/browser/extensions/api/bookmarks/bookmarks_api.h"
 #include "chrome/browser/extensions/chrome_extension_function.h"
 #include "chrome/browser/ui/bookmarks/bookmark_tab_helper.h"
 #include "chrome/browser/undo/bookmark_undo_service.h"
 #include "chrome/browser/undo/bookmark_undo_service_factory.h"
+#include "extensions/browser/browser_context_keyed_api_factory.h"
+#include "extensions/browser/event_router.h"
 
 struct BookmarkNodeData;
 class Profile;
 
 namespace content {
+class BrowserContext;
 class WebContents;
 }
 
 namespace extensions {
 
-// Class that handles the chrome.bookmarkManagerPrivate events.
-class BookmarkManagerPrivateEventRouter
+class BookmarkManagerPrivateEventRouter : public BaseBookmarkModelObserver {
+ public:
+  BookmarkManagerPrivateEventRouter(content::BrowserContext* browser_context,
+                                    BookmarkModel* bookmark_model);
+  virtual ~BookmarkManagerPrivateEventRouter();
+
+  // BaseBookmarkModelObserver:
+  virtual void BookmarkModelChanged() OVERRIDE;
+  virtual void BookmarkModelBeingDeleted(BookmarkModel* model) OVERRIDE;
+  virtual void BookmarkMetaInfoChanged(BookmarkModel* model,
+                                       const BookmarkNode* node) OVERRIDE;
+
+ private:
+  // Helper to actually dispatch an event to extension listeners.
+  void DispatchEvent(const std::string& event_name,
+                     scoped_ptr<base::ListValue> event_args);
+
+  content::BrowserContext* browser_context_;
+  BookmarkModel* bookmark_model_;
+};
+
+class BookmarkManagerPrivateAPI : public BrowserContextKeyedAPI,
+                                  public EventRouter::Observer {
+ public:
+  explicit BookmarkManagerPrivateAPI(content::BrowserContext* browser_context);
+  virtual ~BookmarkManagerPrivateAPI();
+
+  // BrowserContextKeyedService implementation.
+  virtual void Shutdown() OVERRIDE;
+
+  // BrowserContextKeyedAPI implementation.
+  static BrowserContextKeyedAPIFactory<BookmarkManagerPrivateAPI>*
+      GetFactoryInstance();
+
+  // EventRouter::Observer implementation.
+  virtual void OnListenerAdded(const EventListenerInfo& details) OVERRIDE;
+
+ private:
+  friend class BrowserContextKeyedAPIFactory<BookmarkManagerPrivateAPI>;
+
+  // BrowserContextKeyedAPI implementation.
+  static const char* service_name() { return "BookmarkManagerPrivateAPI"; }
+  static const bool kServiceIsNULLWhileTesting = true;
+
+  content::BrowserContext* browser_context_;
+
+  // Created lazily upon OnListenerAdded.
+  scoped_ptr<BookmarkManagerPrivateEventRouter> event_router_;
+};
+
+// Class that handles the drag and drop related chrome.bookmarkManagerPrivate
+// events. This class has one instance per bookmark manager tab.
+class BookmarkManagerPrivateDragEventRouter
     : public BookmarkTabHelper::BookmarkDrag {
  public:
-  BookmarkManagerPrivateEventRouter(Profile* profile,
-                                    content::WebContents* web_contents);
-  virtual ~BookmarkManagerPrivateEventRouter();
+  BookmarkManagerPrivateDragEventRouter(Profile* profile,
+                                        content::WebContents* web_contents);
+  virtual ~BookmarkManagerPrivateDragEventRouter();
 
   // BookmarkTabHelper::BookmarkDrag interface
   virtual void OnDragEnter(const BookmarkNodeData& data) OVERRIDE;
@@ -52,7 +108,7 @@
   content::WebContents* web_contents_;
   BookmarkNodeData bookmark_drag_data_;
 
-  DISALLOW_COPY_AND_ASSIGN(BookmarkManagerPrivateEventRouter);
+  DISALLOW_COPY_AND_ASSIGN(BookmarkManagerPrivateDragEventRouter);
 };
 
 class ClipboardBookmarkManagerFunction : public extensions::BookmarksFunction {
diff --git a/chrome/browser/extensions/extension_web_ui.cc b/chrome/browser/extensions/extension_web_ui.cc
index ce5277ed..9e346ae 100644
--- a/chrome/browser/extensions/extension_web_ui.cc
+++ b/chrome/browser/extensions/extension_web_ui.cc
@@ -142,8 +142,8 @@
 
   // Hack: A few things we specialize just for the bookmark manager.
   if (extension->id() == extension_misc::kBookmarkManagerId) {
-    bookmark_manager_private_event_router_.reset(
-        new extensions::BookmarkManagerPrivateEventRouter(
+    bookmark_manager_private_drag_event_router_.reset(
+        new extensions::BookmarkManagerPrivateDragEventRouter(
             profile, web_ui->GetWebContents()));
 
     web_ui->SetLinkTransitionType(content::PAGE_TRANSITION_AUTO_BOOKMARK);
@@ -152,9 +152,9 @@
 
 ExtensionWebUI::~ExtensionWebUI() {}
 
-extensions::BookmarkManagerPrivateEventRouter*
-ExtensionWebUI::bookmark_manager_private_event_router() {
-  return bookmark_manager_private_event_router_.get();
+extensions::BookmarkManagerPrivateDragEventRouter*
+ExtensionWebUI::bookmark_manager_private_drag_event_router() {
+  return bookmark_manager_private_drag_event_router_.get();
 }
 
 ////////////////////////////////////////////////////////////////////////////////
diff --git a/chrome/browser/extensions/extension_web_ui.h b/chrome/browser/extensions/extension_web_ui.h
index 0153f69..4bd2cc1 100644
--- a/chrome/browser/extensions/extension_web_ui.h
+++ b/chrome/browser/extensions/extension_web_ui.h
@@ -20,7 +20,7 @@
 }
 
 namespace extensions {
-class BookmarkManagerPrivateEventRouter;
+class BookmarkManagerPrivateDragEventRouter;
 }
 
 namespace user_prefs {
@@ -39,8 +39,8 @@
 
   virtual ~ExtensionWebUI();
 
-  virtual extensions::BookmarkManagerPrivateEventRouter*
-      bookmark_manager_private_event_router();
+  virtual extensions::BookmarkManagerPrivateDragEventRouter*
+      bookmark_manager_private_drag_event_router();
 
   // BrowserURLHandler
   static bool HandleChromeURLOverride(GURL* url,
@@ -79,8 +79,8 @@
 
   // TODO(aa): This seems out of place. Why is it not with the event routers for
   // the other extension APIs?
-  scoped_ptr<extensions::BookmarkManagerPrivateEventRouter>
-      bookmark_manager_private_event_router_;
+  scoped_ptr<extensions::BookmarkManagerPrivateDragEventRouter>
+      bookmark_manager_private_drag_event_router_;
 
   // The URL this WebUI was created for.
   GURL url_;
diff --git a/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc b/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc
index 556515b..81205ad0 100644
--- a/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc
+++ b/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc
@@ -58,6 +58,7 @@
 #include "chrome/browser/extensions/api/alarms/alarm_manager.h"
 #include "chrome/browser/extensions/api/audio/audio_api.h"
 #include "chrome/browser/extensions/api/bluetooth/bluetooth_api.h"
+#include "chrome/browser/extensions/api/bookmark_manager_private/bookmark_manager_private_api.h"
 #include "chrome/browser/extensions/api/bookmarks/bookmarks_api.h"
 #include "chrome/browser/extensions/api/braille_display_private/braille_display_private_api.h"
 #include "chrome/browser/extensions/api/commands/command_service.h"
@@ -254,6 +255,7 @@
   extensions::core_api::UDPSocketEventDispatcher::GetFactoryInstance();
   extensions::AudioAPI::GetFactoryInstance();
   extensions::BookmarksAPI::GetFactoryInstance();
+  extensions::BookmarkManagerPrivateAPI::GetFactoryInstance();
   extensions::BluetoothAPI::GetFactoryInstance();
   extensions::BrailleDisplayPrivateAPI::GetFactoryInstance();
   extensions::chromedirectsetting::ChromeDirectSettingAPI::GetFactoryInstance();