diff options
| author | dewittj@chromium.org <dewittj@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-12-17 22:10:49 +0000 | 
|---|---|---|
| committer | dewittj@chromium.org <dewittj@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-12-17 22:10:49 +0000 | 
| commit | f0eb58a08b934b3982956cb0a6b6e4c6274b3c6d (patch) | |
| tree | f41bfbd32255c5cf810f4a6ff4a0e02eeb3f1224 | |
| parent | 6561eef2828180ec55c8361d371a5d796e32e305 (diff) | |
| download | chromium_src-f0eb58a08b934b3982956cb0a6b6e4c6274b3c6d.zip chromium_src-f0eb58a08b934b3982956cb0a6b6e4c6274b3c6d.tar.gz chromium_src-f0eb58a08b934b3982956cb0a6b6e4c6274b3c6d.tar.bz2 | |
Add systray icon and click functionality to systemIndicator API.
The system tray will be the location of the system indicator icon for the Linux,
Mac OSX, and Windows OS (Vista and earlier).  Yet to come is ChromeOS/Win7 
taskbar integration, and Win8 integration.
BUG=142450
TBR=ben@chromium.org
Review URL: https://chromiumcodereview.appspot.com/11445018
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@173551 0039d316-1c4b-4281-b951-d872f2087c98
15 files changed, 469 insertions, 8 deletions
| diff --git a/chrome/browser/extensions/api/extension_action/extension_actions_api.cc b/chrome/browser/extensions/api/extension_action/extension_actions_api.cc index 54172d9..1361d62 100644 --- a/chrome/browser/extensions/api/extension_action/extension_actions_api.cc +++ b/chrome/browser/extensions/api/extension_action/extension_actions_api.cc @@ -392,7 +392,7 @@ void ExtensionActionFunction::NotifyChange() {        NotifyLocationBarChange();        return;      case extensions::Extension::ActionInfo::TYPE_SYSTEM_INDICATOR: -      NotifyStatusTrayChange(); +      NotifySystemIndicatorChange();        return;    }    NOTREACHED(); @@ -410,9 +410,11 @@ void ExtensionActionFunction::NotifyLocationBarChange() {        location_bar_controller()->NotifyChange();  } -void ExtensionActionFunction::NotifyStatusTrayChange() { -  // TODO(dewittj) Implement status tray behavior here. -  // See http://crbug.com/142450. +void ExtensionActionFunction::NotifySystemIndicatorChange() { +  content::NotificationService::current()->Notify( +      chrome::NOTIFICATION_EXTENSION_SYSTEM_INDICATOR_UPDATED, +      content::Source<Profile>(profile()), +      content::Details<ExtensionAction>(extension_action_));  }  // static @@ -453,6 +455,8 @@ bool ExtensionActionFunction::ParseCSSColorString(  }  bool ExtensionActionFunction::SetVisible(bool visible) { +  if (extension_action_->GetIsVisible(tab_id_) == visible) +    return true;    extension_action_->SetAppearance(        tab_id_, visible ? ExtensionAction::ACTIVE : ExtensionAction::INVISIBLE);    NotifyChange(); diff --git a/chrome/browser/extensions/api/extension_action/extension_actions_api.h b/chrome/browser/extensions/api/extension_action/extension_actions_api.h index b21da7f..63c940d 100644 --- a/chrome/browser/extensions/api/extension_action/extension_actions_api.h +++ b/chrome/browser/extensions/api/extension_action/extension_actions_api.h @@ -72,7 +72,7 @@ class ExtensionActionFunction : public SyncExtensionFunction {    void NotifyChange();    void NotifyBrowserActionChange();    void NotifyLocationBarChange(); -  void NotifyStatusTrayChange(); +  void NotifySystemIndicatorChange();    bool SetVisible(bool visible);    // Extension-related information for |tab_id_|. diff --git a/chrome/browser/extensions/api/system_indicator/system_indicator_apitest.cc b/chrome/browser/extensions/api/system_indicator/system_indicator_apitest.cc index 446a576..daa8bc8 100644 --- a/chrome/browser/extensions/api/system_indicator/system_indicator_apitest.cc +++ b/chrome/browser/extensions/api/system_indicator/system_indicator_apitest.cc @@ -2,8 +2,67 @@  // Use of this source code is governed by a BSD-style license that can be  // found in the LICENSE file. +#include "chrome/browser/extensions/api/system_indicator/system_indicator_manager.h" +#include "chrome/browser/extensions/api/system_indicator/system_indicator_manager_factory.h" +#include "chrome/browser/extensions/extension_action.h" +#include "chrome/browser/extensions/extension_action_manager.h"  #include "chrome/browser/extensions/extension_apitest.h" +#include "chrome/browser/extensions/extension_process_manager.h" +#include "chrome/browser/extensions/extension_system.h" +#include "chrome/browser/extensions/lazy_background_page_test_util.h" +#include "chrome/browser/ui/browser.h" +#include "chrome/common/chrome_switches.h" +#include "chrome/common/extensions/extension.h" + +class SystemIndicatorApiTest : public ExtensionApiTest { + public: +  void SetUpCommandLine(CommandLine* command_line) { +    ExtensionApiTest::SetUpCommandLine(command_line); +    // Set shorter delays to prevent test timeouts in tests that need to wait +    // for the event page to unload. +    command_line->AppendSwitchASCII(switches::kEventPageIdleTime, "1"); +    command_line->AppendSwitchASCII(switches::kEventPageUnloadingTime, "1"); +  } + +  const extensions::Extension* LoadExtensionAndWait( +      const std::string& test_name) { +    LazyBackgroundObserver page_complete; +    FilePath extdir = test_data_dir_.AppendASCII(test_name); +    const extensions::Extension* extension = LoadExtension(extdir); +    if (extension) +      page_complete.Wait(); +    return extension; +  } +};  IN_PROC_BROWSER_TEST_F(ExtensionApiTest, SystemIndicator) { -  ASSERT_TRUE(RunExtensionTest("system_indicator/basics")) << message_; +  // Only run this test on supported platforms.  SystemIndicatorManagerFactory +  // returns NULL on unsupported platforms. +  extensions::SystemIndicatorManager* manager = +      extensions::SystemIndicatorManagerFactory::GetForProfile(profile()); +  if (manager) { +    ASSERT_TRUE(RunExtensionTest("system_indicator/basics")) << message_; +  } +} + +IN_PROC_BROWSER_TEST_F(SystemIndicatorApiTest, SystemIndicator) { +  // Only run this test on supported platforms.  SystemIndicatorManagerFactory +  // returns NULL on unsupported platforms. +  extensions::SystemIndicatorManager* manager = +      extensions::SystemIndicatorManagerFactory::GetForProfile(profile()); +  if (manager) { +    ResultCatcher catcher; + +    const extensions::Extension* extension = +        LoadExtensionAndWait("system_indicator/unloaded"); +    ASSERT_TRUE(extension) << message_; + +    // Lazy Background Page has been shut down. +    ExtensionProcessManager* pm = +        extensions::ExtensionSystem::Get(profile())->process_manager(); +    EXPECT_FALSE(pm->GetBackgroundHostForExtension(last_loaded_extension_id_)); + +    EXPECT_TRUE(manager->SendClickEventToExtensionForTest(extension->id())); +    EXPECT_TRUE(catcher.GetNextResult()) << catcher.message(); +  }  } diff --git a/chrome/browser/extensions/api/system_indicator/system_indicator_manager.cc b/chrome/browser/extensions/api/system_indicator/system_indicator_manager.cc new file mode 100644 index 0000000..d02942e --- /dev/null +++ b/chrome/browser/extensions/api/system_indicator/system_indicator_manager.cc @@ -0,0 +1,183 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/extensions/api/system_indicator/system_indicator_manager.h" + +#include "chrome/browser/extensions/event_names.h" +#include "chrome/browser/extensions/event_router.h" +#include "chrome/browser/extensions/extension_action.h" +#include "chrome/browser/extensions/extension_service.h" +#include "chrome/browser/extensions/extension_system.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/browser/status_icons/status_icon.h" +#include "chrome/browser/status_icons/status_icon_observer.h" +#include "chrome/browser/status_icons/status_tray.h" +#include "chrome/common/extensions/api/system_indicator.h" +#include "chrome/common/extensions/extension.h" +#include "ui/gfx/image/image.h" + +namespace extensions { + +// Observes clicks on a given status icon and forwards the event to the +// appropriate extension.  Handles icon updates, and responsible for creating +// and removing the icon from the notification area during construction and +// destruction. +class ExtensionIndicatorIcon : public StatusIconObserver, +                               public ExtensionActionIconFactory::Observer { + public: +  ExtensionIndicatorIcon(const Extension* extension, +                         const ExtensionAction* action, +                         Profile* profile, +                         StatusTray* status_tray, +                         StatusIcon* status_icon); +  virtual ~ExtensionIndicatorIcon(); + +  // StatusIconObserver implementation. +  virtual void OnStatusIconClicked() OVERRIDE; + +  // ExtensionActionIconFactory::Observer implementation. +  virtual void OnIconUpdated() OVERRIDE; + + private: +  const extensions::Extension* extension_; +  StatusTray* status_tray_; +  StatusIcon* icon_; +  Profile* profile_; +  ExtensionActionIconFactory icon_factory_; +}; + +ExtensionIndicatorIcon::ExtensionIndicatorIcon(const Extension* extension, +                                               const ExtensionAction* action, +                                               Profile* profile, +                                               StatusTray* status_tray, +                                               StatusIcon* status_icon) +    : extension_(extension), +      status_tray_(status_tray), +      icon_(status_icon), +      profile_(profile), +      ALLOW_THIS_IN_INITIALIZER_LIST(icon_factory_(extension, action, this)) { +  icon_->AddObserver(this); +  OnIconUpdated(); +} + +ExtensionIndicatorIcon::~ExtensionIndicatorIcon() { +  icon_->RemoveObserver(this); +  status_tray_->RemoveStatusIcon(icon_); +} + +void ExtensionIndicatorIcon::OnStatusIconClicked() { +  scoped_ptr<base::ListValue> params( +      api::system_indicator::OnClicked::Create()); + +  EventRouter* event_router = +      ExtensionSystem::Get(profile_)->event_router(); +  scoped_ptr<Event> event(new Event( +      event_names::kOnSystemIndicatorClicked, +      params.Pass(), +      profile_)); +  event_router->DispatchEventToExtension( +      extension_->id(), event.Pass()); +} + +void ExtensionIndicatorIcon::OnIconUpdated() { +  icon_->SetImage( +      icon_factory_.GetIcon(ExtensionAction::kDefaultTabId).AsImageSkia()); +} + +SystemIndicatorManager::SystemIndicatorManager(Profile* profile, +                                               StatusTray* status_tray) +    : profile_(profile), +      status_tray_(status_tray) { +  registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNLOADED, +                 content::Source<Profile>(profile_->GetOriginalProfile())); +  registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_SYSTEM_INDICATOR_UPDATED, +                 content::Source<Profile>(profile_->GetOriginalProfile())); +} + +SystemIndicatorManager::~SystemIndicatorManager() { +  DCHECK(thread_checker_.CalledOnValidThread()); +} + +void SystemIndicatorManager::Shutdown() { +  DCHECK(thread_checker_.CalledOnValidThread()); +} + +void SystemIndicatorManager::Observe( +    int type, +    const content::NotificationSource& source, +    const content::NotificationDetails& details) { +  DCHECK(thread_checker_.CalledOnValidThread()); + +  switch (type) { +    case chrome::NOTIFICATION_EXTENSION_UNLOADED: +      RemoveIndicator( +          content::Details<UnloadedExtensionInfo>(details)->extension->id()); +      break; +    case chrome::NOTIFICATION_EXTENSION_SYSTEM_INDICATOR_UPDATED: +      OnSystemIndicatorChanged( +          content::Details<ExtensionAction>(details).ptr()); +      break; +    default: +      NOTREACHED(); +      break; +  } +} + +void SystemIndicatorManager::OnSystemIndicatorChanged( +    const ExtensionAction* extension_action) { +  DCHECK(thread_checker_.CalledOnValidThread()); +  std::string extension_id = extension_action->extension_id(); +  ExtensionService* service = +      ExtensionSystem::Get(profile_)->extension_service(); + +  if (extension_action->GetIsVisible(ExtensionAction::kDefaultTabId)) { +    const Extension* extension = +        service->GetExtensionById(extension_id, false); +    CreateOrUpdateIndicator(extension, extension_action); +  } else { +    RemoveIndicator(extension_id); +  } +} + +bool SystemIndicatorManager::SendClickEventToExtensionForTest( +    const std::string extension_id) { + +    extensions::SystemIndicatorManager::SystemIndicatorMap::iterator it = +        system_indicators_.find(extension_id); + +    if (it == system_indicators_.end()) +      return false; + +    it->second->OnStatusIconClicked(); +    return true; +} + +void SystemIndicatorManager::CreateOrUpdateIndicator( +    const Extension* extension, +    const ExtensionAction* extension_action) { +  DCHECK(thread_checker_.CalledOnValidThread()); +  SystemIndicatorMap::iterator it = system_indicators_.find(extension->id()); +  if (it != system_indicators_.end()) { +    it->second->OnIconUpdated(); +    return; +  } + +  StatusIcon* indicator_icon = status_tray_->CreateStatusIcon(); +  if (indicator_icon != NULL) { +    ExtensionIndicatorIcon* status_icon = new ExtensionIndicatorIcon( +        extension, +        extension_action, +        profile_, +        status_tray_, +        indicator_icon); +    system_indicators_.insert(std::make_pair(extension->id(), status_icon)); +  } +} + +void SystemIndicatorManager::RemoveIndicator(const std::string& extension_id) { +  DCHECK(thread_checker_.CalledOnValidThread()); +  system_indicators_.erase(extension_id); +} + +}  // namespace extensions diff --git a/chrome/browser/extensions/api/system_indicator/system_indicator_manager.h b/chrome/browser/extensions/api/system_indicator/system_indicator_manager.h new file mode 100644 index 0000000..d13ef1c --- /dev/null +++ b/chrome/browser/extensions/api/system_indicator/system_indicator_manager.h @@ -0,0 +1,78 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_EXTENSIONS_API_SYSTEM_INDICATOR_SYSTEM_INDICATOR_MANAGER_H_ +#define CHROME_BROWSER_EXTENSIONS_API_SYSTEM_INDICATOR_SYSTEM_INDICATOR_MANAGER_H_ + +#include <map> +#include <string> + +#include "chrome/browser/extensions/event_router.h" +#include "chrome/browser/extensions/extension_action_icon_factory.h" +#include "chrome/browser/profiles/profile_keyed_service.h" +#include "content/public/browser/notification_observer.h" +#include "content/public/browser/notification_registrar.h" + +class ExtensionAction; +class Profile; +class StatusTray; + +FORWARD_DECLARE_TEST(SystemIndicatorApiTest, SystemIndicator); + +namespace extensions { + +class ExtensionIndicatorIcon; + +// Keeps track of all the systemIndicator icons created for a given Profile +// that are currently visible in the UI.  Use SystemIndicatorManagerFactory to +// create a SystemIndicatorManager object. +class SystemIndicatorManager : public content::NotificationObserver, +                               public ProfileKeyedService { + public: +  SystemIndicatorManager(Profile* profile, StatusTray* status_tray); +  virtual ~SystemIndicatorManager(); + +  // ProfileKeyedService implementation. +  virtual void Shutdown() OVERRIDE; + +  // content::NotificationDelegate implementation. +  virtual void Observe(int type, +                       const content::NotificationSource& source, +                       const content::NotificationDetails& details) OVERRIDE; + + private: +  FRIEND_TEST_ALL_PREFIXES(::SystemIndicatorApiTest, SystemIndicator); + +  // Determines whether the indicator should be hidden or shown and calls the +  // appropriate function. +  void OnSystemIndicatorChanged(const ExtensionAction* extension_action); + +  // Causes a call to OnStatusIconClicked for the specified extension_id. +  // Returns false if no ExtensionIndicatorIcon is found for the extension. +  bool SendClickEventToExtensionForTest(const std::string extension_id); + +  // Causes an indicator to be shown for the given extension_action.  Creates +  // the indicator if necessary. +  void CreateOrUpdateIndicator( +      const Extension* extension, +      const ExtensionAction* extension_action); + +  // Causes the indicator for the given extension to be hidden. +  void RemoveIndicator(const std::string &extension_id); + +  typedef std::map<const std::string, linked_ptr<ExtensionIndicatorIcon> > +      SystemIndicatorMap; + +  Profile* profile_; +  StatusTray* status_tray_; +  SystemIndicatorMap system_indicators_; +  content::NotificationRegistrar registrar_; +  base::ThreadChecker thread_checker_; + +  DISALLOW_COPY_AND_ASSIGN(SystemIndicatorManager); +}; + +}  // namespace extensions + +#endif  // CHROME_BROWSER_EXTENSIONS_API_SYSTEM_INDICATOR_SYSTEM_INDICATOR_MANAGER_H_ diff --git a/chrome/browser/extensions/api/system_indicator/system_indicator_manager_factory.cc b/chrome/browser/extensions/api/system_indicator/system_indicator_manager_factory.cc new file mode 100644 index 0000000..b5b3ae7 --- /dev/null +++ b/chrome/browser/extensions/api/system_indicator/system_indicator_manager_factory.cc @@ -0,0 +1,44 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/extensions/api/system_indicator/system_indicator_manager_factory.h" + +#include "chrome/browser/browser_process.h" +#include "chrome/browser/extensions/api/system_indicator/system_indicator_manager.h" +#include "chrome/browser/extensions/extension_system_factory.h" +#include "chrome/browser/profiles/profile_dependency_manager.h" + +namespace extensions { + +// static +SystemIndicatorManager* SystemIndicatorManagerFactory::GetForProfile( +    Profile* profile) { +  return static_cast<SystemIndicatorManager*>( +      GetInstance()->GetServiceForProfile(profile, true)); +} + +// static +SystemIndicatorManagerFactory* SystemIndicatorManagerFactory::GetInstance() { +  return Singleton<SystemIndicatorManagerFactory>::get(); +} + +SystemIndicatorManagerFactory::SystemIndicatorManagerFactory() +    : ProfileKeyedServiceFactory("SystemIndicatorManager", +                                 ProfileDependencyManager::GetInstance()) { +  DependsOn(ExtensionSystemFactory::GetInstance()); +} + +SystemIndicatorManagerFactory::~SystemIndicatorManagerFactory() {} + +ProfileKeyedService* SystemIndicatorManagerFactory::BuildServiceInstanceFor( +    Profile* profile) const { + +  StatusTray* status_tray = g_browser_process->status_tray(); +  if (status_tray == NULL) +    return NULL; + +  return new SystemIndicatorManager(profile, status_tray); +} + +}  // namespace extensions diff --git a/chrome/browser/extensions/api/system_indicator/system_indicator_manager_factory.h b/chrome/browser/extensions/api/system_indicator/system_indicator_manager_factory.h new file mode 100644 index 0000000..bb07769 --- /dev/null +++ b/chrome/browser/extensions/api/system_indicator/system_indicator_manager_factory.h @@ -0,0 +1,34 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_EXTENSIONS_API_SYSTEM_INDICATOR_SYSTEM_INDICATOR_MANAGER_FACTORY_H__ +#define CHROME_BROWSER_EXTENSIONS_API_SYSTEM_INDICATOR_SYSTEM_INDICATOR_MANAGER_FACTORY_H__ + +#include "base/memory/singleton.h" +#include "chrome/browser/profiles/profile_keyed_service_factory.h" + +namespace extensions { +class SystemIndicatorManager; + +// ProfileKeyedServiceFactory for each SystemIndicatorManager. +class SystemIndicatorManagerFactory : public ProfileKeyedServiceFactory { + public: +  static SystemIndicatorManager* GetForProfile(Profile* profile); + +  static SystemIndicatorManagerFactory* GetInstance(); + + private: +  friend struct DefaultSingletonTraits<SystemIndicatorManagerFactory>; + +  SystemIndicatorManagerFactory(); +  virtual ~SystemIndicatorManagerFactory(); + +  // ProfileKeyedBaseFactory implementation. +  virtual ProfileKeyedService* BuildServiceInstanceFor( +      Profile* profile) const OVERRIDE; +}; + +}  // namespace extensions + +#endif  // CHROME_BROWSER_EXTENSIONS_API_SYSTEM_INDICATOR_SYSTEM_INDICATOR_MANAGER_FACTORY_H__ diff --git a/chrome/browser/extensions/event_router.cc b/chrome/browser/extensions/event_router.cc index 519e501..dd5142c 100644 --- a/chrome/browser/extensions/event_router.cc +++ b/chrome/browser/extensions/event_router.cc @@ -356,7 +356,6 @@ void EventRouter::DispatchEventImpl(const std::string& restrict_to_extension_id,      const EventListener* listener = *it;      if (restrict_to_extension_id.empty() ||          restrict_to_extension_id == listener->extension_id) { -        if (listener->process) {          EventDispatchIdentifier dispatch_id(              listener->process->GetBrowserContext(), listener->extension_id); @@ -613,6 +612,16 @@ Event::Event(const std::string& event_name,  }  Event::Event(const std::string& event_name, +             scoped_ptr<base::ListValue> event_args, +             Profile* restrict_to_profile) +    : event_name(event_name), +      event_args(event_args.Pass()), +      restrict_to_profile(restrict_to_profile), +      user_gesture(EventRouter::USER_GESTURE_UNKNOWN) { +  DCHECK(this->event_args.get()); +} + +Event::Event(const std::string& event_name,               scoped_ptr<ListValue> event_args,               Profile* restrict_to_profile,               const GURL& event_url, diff --git a/chrome/browser/extensions/event_router.h b/chrome/browser/extensions/event_router.h index 0e49fbc..9df75ea 100644 --- a/chrome/browser/extensions/event_router.h +++ b/chrome/browser/extensions/event_router.h @@ -270,6 +270,10 @@ struct Event {    Event(const std::string& event_name,          scoped_ptr<base::ListValue> event_args, +        Profile* restrict_to_profile); + +  Event(const std::string& event_name, +        scoped_ptr<base::ListValue> event_args,          Profile* restrict_to_profile,          const GURL& event_url,          EventRouter::UserGestureState user_gesture, diff --git a/chrome/browser/extensions/extension_action_manager.cc b/chrome/browser/extensions/extension_action_manager.cc index 8df52df..1632cdd2 100644 --- a/chrome/browser/extensions/extension_action_manager.cc +++ b/chrome/browser/extensions/extension_action_manager.cc @@ -4,6 +4,8 @@  #include "chrome/browser/extensions/extension_action_manager.h" +#include "chrome/browser/extensions/api/system_indicator/system_indicator_manager.h" +#include "chrome/browser/extensions/api/system_indicator/system_indicator_manager_factory.h"  #include "chrome/browser/extensions/extension_action.h"  #include "chrome/browser/extensions/extension_system.h"  #include "chrome/browser/profiles/profile.h" @@ -55,7 +57,8 @@ ExtensionActionManagerFactory::GetInstance() {  }  // namespace -ExtensionActionManager::ExtensionActionManager(Profile* profile) { +ExtensionActionManager::ExtensionActionManager(Profile* profile) +    : profile_(profile) {    CHECK_EQ(profile, profile->GetOriginalProfile())        << "Don't instantiate this with an incognito profile.";    registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNLOADED, @@ -82,6 +85,7 @@ void ExtensionActionManager::Observe(        page_actions_.erase(extension->id());        browser_actions_.erase(extension->id());        script_badges_.erase(extension->id()); +      system_indicators_.erase(extension->id());        break;      }    } @@ -139,6 +143,13 @@ ExtensionAction* ExtensionActionManager::GetBrowserAction(  ExtensionAction* ExtensionActionManager::GetSystemIndicator(      const extensions::Extension& extension) const { +  // If it does not already exist, create the SystemIndicatorManager for the +  // given profile.  This could return NULL if the system indicator area is +  // unavailable on the current system.  If so, return NULL to signal that +  // the system indicator area is unusable. +  if (!extensions::SystemIndicatorManagerFactory::GetForProfile(profile_)) +    return NULL; +    return GetOrCreateOrNull(&system_indicators_, extension.id(),                             Extension::ActionInfo::TYPE_SYSTEM_INDICATOR,                             extension.system_indicator_info()); diff --git a/chrome/browser/extensions/extension_action_manager.h b/chrome/browser/extensions/extension_action_manager.h index 1cad26d..b9ac2ec 100644 --- a/chrome/browser/extensions/extension_action_manager.h +++ b/chrome/browser/extensions/extension_action_manager.h @@ -49,6 +49,7 @@ class ExtensionActionManager : public ProfileKeyedService,                         const content::NotificationDetails& details) OVERRIDE;    content::NotificationRegistrar registrar_; +  Profile* profile_;    // Keyed by Extension ID.  These maps are populated lazily when their    // ExtensionAction is first requested, and the entries are removed when the diff --git a/chrome/chrome_browser_extensions.gypi b/chrome/chrome_browser_extensions.gypi index 176c8ba..fdef8fc 100644 --- a/chrome/chrome_browser_extensions.gypi +++ b/chrome/chrome_browser_extensions.gypi @@ -332,6 +332,10 @@          'browser/extensions/api/sync_file_system/sync_file_system_api.cc',          'browser/extensions/api/sync_file_system/sync_file_system_api.h',          'browser/extensions/api/system_indicator/system_indicator_api.h', +        'browser/extensions/api/system_indicator/system_indicator_manager.cc', +        'browser/extensions/api/system_indicator/system_indicator_manager.h', +        'browser/extensions/api/system_indicator/system_indicator_manager_factory.cc', +        'browser/extensions/api/system_indicator/system_indicator_manager_factory.h',          'browser/extensions/api/system_info_cpu/cpu_info_provider.cc',          'browser/extensions/api/system_info_cpu/cpu_info_provider.h',          'browser/extensions/api/system_info_cpu/cpu_info_provider_linux.cc', diff --git a/chrome/common/chrome_notification_types.h b/chrome/common/chrome_notification_types.h index b1bc41e..c52b32b 100644 --- a/chrome/common/chrome_notification_types.h +++ b/chrome/common/chrome_notification_types.h @@ -575,6 +575,11 @@ enum NotificationType {    // ExtensionAction* that changed. The details are a WebContents*.    NOTIFICATION_EXTENSION_PAGE_ACTION_VISIBILITY_CHANGED, +  // Sent when a system indicator action's state has changed. The source is the +  // Profile* that the browser action belongs to. The details are the +  // ExtensionAction* that changed. +  NOTIFICATION_EXTENSION_SYSTEM_INDICATOR_UPDATED, +    // Sent when an extension command has been removed. The source is the profile    // and the details is a std::pair of two std::string objects (an extension ID    // and the name of the command being removed). diff --git a/chrome/test/data/extensions/api_test/system_indicator/unloaded/manifest.json b/chrome/test/data/extensions/api_test/system_indicator/unloaded/manifest.json new file mode 100644 index 0000000..da51d91 --- /dev/null +++ b/chrome/test/data/extensions/api_test/system_indicator/unloaded/manifest.json @@ -0,0 +1,13 @@ +{ +  "name": "chrome.systemIndicator.unloaded", +  "version": "0.1", +  "manifest_version": 2, +  "description": "Ensure clicks work even after app is unloaded", +  "app" : { +    "background": { +      "scripts": ["test.js"] +    } +  }, +  "system_indicator": {}, +  "permissions": ["systemIndicator"] +} diff --git a/chrome/test/data/extensions/api_test/system_indicator/unloaded/test.js b/chrome/test/data/extensions/api_test/system_indicator/unloaded/test.js new file mode 100644 index 0000000..ee8d469 --- /dev/null +++ b/chrome/test/data/extensions/api_test/system_indicator/unloaded/test.js @@ -0,0 +1,12 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +chrome.test.runTests([function unload_then_click() { +  chrome.systemIndicator.enable(); +}]); + +chrome.systemIndicator.onClicked.addListener(function() { +    chrome.test.succeed(); +}); | 
