diff options
author | erikchen <erikchen@chromium.org> | 2014-12-11 16:17:38 -0800 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2014-12-12 00:18:30 +0000 |
commit | 600f7962455cb8479168eb2c6678eda05365460a (patch) | |
tree | 0485cd68bf693af4ef9e925ee1e594da813d6463 /chrome/browser | |
parent | d01af9d9c924bcca8e965a89eb21e6299b2eb3e0 (diff) | |
download | chromium_src-600f7962455cb8479168eb2c6678eda05365460a.zip chromium_src-600f7962455cb8479168eb2c6678eda05365460a.tar.gz chromium_src-600f7962455cb8479168eb2c6678eda05365460a.tar.bz2 |
Reland 1: "mac: Allow Chrome to hand off its active URL to other devices."
The original CL used instance variables in a class extension and automatic
generation of ivars for synthesized properties, features only available on
64-bit builds. The Mac Memory bots are still compiling Chromium in 32-bits.
This reland removes the usage of those features.
> This CL adds the class HandoffManager, which is responsible for interfacing
> with Apple's Handoff APIs. It takes a GURL, and exposes that GURL to Handoff.
>
> This CL adds the class ActiveWebContentsObserver, which is responsible for
> listening to changes to the active browser, the active tab, and the visible
> URL. It notifies its delegate when any of this state might have changed.
>
> AppControllerMac is the delegate of ActiveWebContentsObserver, as well as the
> owner of the HandoffManager. When it receives a delegate callback, it passes an
> updated GURL to the HandoffManager. There is some minimal logic in
> AppControllerMac that prevents URLs from incognito windows from being passed to
> the HandoffManager.
>
> BUG=431051, 438823
> Committed: https://crrev.com/708abc5b0abb5e0916d779bf6d1342fd472a2aa1
> Cr-Commit-Position: refs/heads/master@{#307846}
BUG=431051, 438823
TBR=sky, erikwright, mmenke, avi
Review URL: https://codereview.chromium.org/794853004
Cr-Commit-Position: refs/heads/master@{#308005}
Diffstat (limited to 'chrome/browser')
-rw-r--r-- | chrome/browser/app_controller_mac.h | 9 | ||||
-rw-r--r-- | chrome/browser/app_controller_mac.mm | 82 | ||||
-rw-r--r-- | chrome/browser/app_controller_mac_browsertest.mm | 143 | ||||
-rw-r--r-- | chrome/browser/ui/cocoa/handoff_active_url_observer.cc | 124 | ||||
-rw-r--r-- | chrome/browser/ui/cocoa/handoff_active_url_observer.h | 83 | ||||
-rw-r--r-- | chrome/browser/ui/cocoa/handoff_active_url_observer_bridge.h | 47 | ||||
-rw-r--r-- | chrome/browser/ui/cocoa/handoff_active_url_observer_bridge.mm | 21 | ||||
-rw-r--r-- | chrome/browser/ui/cocoa/handoff_active_url_observer_delegate.h | 27 |
8 files changed, 534 insertions, 2 deletions
diff --git a/chrome/browser/app_controller_mac.h b/chrome/browser/app_controller_mac.h index 6eb522c..a3f6481 100644 --- a/chrome/browser/app_controller_mac.h +++ b/chrome/browser/app_controller_mac.h @@ -22,6 +22,8 @@ class AppControllerProfileObserver; class BookmarkMenuBridge; class CommandUpdater; class GURL; +class HandoffActiveURLObserverBridge; +@class HandoffManager; class HistoryMenuBridge; class Profile; @class ProfileMenuController; @@ -97,6 +99,13 @@ class WorkAreaWatcherObserver; // Displays a notification when quitting while apps are running. scoped_refptr<QuitWithAppsController> quitWithAppsController_; + + // Responsible for maintaining all state related to the Handoff feature. + base::scoped_nsobject<HandoffManager> handoffManager_; + + // Observes changes to the active URL. + scoped_ptr<HandoffActiveURLObserverBridge> + handoff_active_url_observer_bridge_; } @property(readonly, nonatomic) BOOL startupComplete; diff --git a/chrome/browser/app_controller_mac.mm b/chrome/browser/app_controller_mac.mm index 2e2dfe5..604f217 100644 --- a/chrome/browser/app_controller_mac.mm +++ b/chrome/browser/app_controller_mac.mm @@ -63,6 +63,7 @@ #import "chrome/browser/ui/cocoa/confirm_quit.h" #import "chrome/browser/ui/cocoa/confirm_quit_panel_controller.h" #import "chrome/browser/ui/cocoa/encoding_menu_controller_delegate_mac.h" +#include "chrome/browser/ui/cocoa/handoff_active_url_observer_bridge.h" #import "chrome/browser/ui/cocoa/history_menu_bridge.h" #include "chrome/browser/ui/cocoa/last_active_browser_cocoa.h" #import "chrome/browser/ui/cocoa/profiles/profile_menu_controller.h" @@ -83,6 +84,7 @@ #include "chrome/common/url_constants.h" #include "chrome/grit/chromium_strings.h" #include "chrome/grit/generated_resources.h" +#include "components/handoff/handoff_manager.h" #include "components/handoff/handoff_utility.h" #include "components/signin/core/browser/signin_manager.h" #include "components/signin/core/common/profile_management_switches.h" @@ -209,9 +211,10 @@ bool IsProfileSignedOut(Profile* profile) { return cache.ProfileIsSigninRequiredAtIndex(profile_index); } -} // anonymous namespace +} // namespace + +@interface AppController () <HandoffActiveURLObserverBridgeDelegate> -@interface AppController (Private) - (void)initMenuState; - (void)initProfileMenu; - (void)updateConfirmToQuitPrefMenuItem:(NSMenuItem*)item; @@ -240,6 +243,25 @@ bool IsProfileSignedOut(Profile* profile) { // this method is called, and that tab is the NTP, then this method closes the // NTP after all the |urls| have been opened. - (void)openUrlsReplacingNTP:(const std::vector<GURL>&)urls; + +// Whether instances of this class should use the Handoff feature. +- (BOOL)shouldUseHandoff; + +// This method passes |handoffURL| to |handoffManager_|. +- (void)passURLToHandoffManager:(const GURL&)handoffURL; + +// Lazily creates the Handoff Manager. Updates the state of the Handoff +// Manager. This method is idempotent. This should be called: +// - During initialization. +// - When the current tab navigates to a new URL. +// - When the active browser changes. +// - When the active browser's active tab switches. +// |webContents| should be the new, active WebContents. +- (void)updateHandoffManager:(content::WebContents*)webContents; + +// Given |webContents|, extracts a GURL to be used for Handoff. This may return +// the empty GURL. +- (GURL)handoffURLFromWebContents:(content::WebContents*)webContents; @end class AppControllerProfileObserver : public ProfileInfoCacheObserver { @@ -776,6 +798,12 @@ class AppControllerProfileObserver : public ProfileInfoCacheObserver { startupComplete_ = YES; + Browser* browser = + FindLastActiveWithHostDesktopType(chrome::HOST_DESKTOP_TYPE_NATIVE); + content::WebContents* activeWebContents = nullptr; + if (browser) + activeWebContents = browser->tab_strip_model()->GetActiveWebContents(); + [self updateHandoffManager:activeWebContents]; [self openStartupUrls]; PrefService* localState = g_browser_process->local_state(); @@ -786,6 +814,9 @@ class AppControllerProfileObserver : public ProfileInfoCacheObserver { base::Bind(&chrome::BrowserCommandController::UpdateOpenFileState, menuState_.get())); } + + handoff_active_url_observer_bridge_.reset( + new HandoffActiveURLObserverBridge(self)); } // This is called after profiles have been loaded and preferences registered. @@ -1638,6 +1669,53 @@ class AppControllerProfileObserver : public ProfileInfoCacheObserver { error:(NSError*)error { } +#pragma mark - Handoff Manager + +- (BOOL)shouldUseHandoff { + return base::mac::IsOSYosemiteOrLater(); +} + +- (void)passURLToHandoffManager:(const GURL&)handoffURL { + [handoffManager_ updateActiveURL:handoffURL]; +} + +- (void)updateHandoffManager:(content::WebContents*)webContents { + if (![self shouldUseHandoff]) + return; + + if (!handoffManager_) + handoffManager_.reset([[HandoffManager alloc] init]); + + GURL handoffURL = [self handoffURLFromWebContents:webContents]; + [self passURLToHandoffManager:handoffURL]; +} + +- (GURL)handoffURLFromWebContents:(content::WebContents*)webContents { + if (!webContents) + return GURL(); + + Profile* profile = + Profile::FromBrowserContext(webContents->GetBrowserContext()); + if (!profile) + return GURL(); + + // Handoff is not allowed from an incognito profile. To err on the safe side, + // also disallow Handoff from a guest profile. + if (profile->GetProfileType() != Profile::REGULAR_PROFILE) + return GURL(); + + if (!webContents) + return GURL(); + + return webContents->GetVisibleURL(); +} + +#pragma mark - HandoffActiveURLObserverBridgeDelegate + +- (void)handoffActiveURLChanged:(content::WebContents*)webContents { + [self updateHandoffManager:webContents]; +} + @end // @implementation AppController //--------------------------------------------------------------------------- diff --git a/chrome/browser/app_controller_mac_browsertest.mm b/chrome/browser/app_controller_mac_browsertest.mm index a136a12..0400188 100644 --- a/chrome/browser/app_controller_mac_browsertest.mm +++ b/chrome/browser/app_controller_mac_browsertest.mm @@ -35,9 +35,11 @@ #include "chrome/common/pref_names.h" #include "chrome/common/url_constants.h" #include "chrome/test/base/in_process_browser_test.h" +#include "chrome/test/base/ui_test_utils.h" #include "components/bookmarks/test/bookmark_test_helpers.h" #include "components/signin/core/common/profile_management_switches.h" #include "content/public/browser/web_contents.h" +#include "content/public/test/browser_test_utils.h" #include "content/public/test/test_navigation_observer.h" #include "extensions/browser/app_window/app_window_registry.h" #include "extensions/common/extension.h" @@ -481,3 +483,144 @@ IN_PROC_BROWSER_TEST_F(AppControllerMainMenuBrowserTest, } } // namespace + +//--------------------------AppControllerHandoffBrowserTest--------------------- + +static GURL g_handoff_url; + +@interface AppController (BrowserTest) +- (BOOL)new_shouldUseHandoff; +- (void)new_passURLToHandoffManager:(const GURL&)handoffURL; +@end + +@implementation AppController (BrowserTest) +- (BOOL)new_shouldUseHandoff { + return YES; +} + +- (void)new_passURLToHandoffManager:(const GURL&)handoffURL { + g_handoff_url = handoffURL; +} +@end + +namespace { + +class AppControllerHandoffBrowserTest : public InProcessBrowserTest { + protected: + AppControllerHandoffBrowserTest() {} + + // Exchanges the implementations of the two selectors on the class + // AppController. + void ExchangeSelectors(SEL originalMethod, SEL newMethod) { + Class appControllerClass = NSClassFromString(@"AppController"); + + ASSERT_TRUE(appControllerClass != nil); + + Method original = + class_getInstanceMethod(appControllerClass, originalMethod); + Method destination = class_getInstanceMethod(appControllerClass, newMethod); + + ASSERT_TRUE(original != NULL); + ASSERT_TRUE(destination != NULL); + + method_exchangeImplementations(original, destination); + } + + // Swizzle Handoff related implementations. + void SetUpInProcessBrowserTestFixture() override { + // Handoff is only available on OSX 10.10+. This swizzle makes the logic + // run on all OSX versions. + SEL originalMethod = @selector(shouldUseHandoff); + SEL newMethod = @selector(new_shouldUseHandoff); + ExchangeSelectors(originalMethod, newMethod); + + // This swizzle intercepts the URL that would be sent to the Handoff + // Manager, and instead puts it into a variable accessible to this test. + originalMethod = @selector(passURLToHandoffManager:); + newMethod = @selector(new_passURLToHandoffManager:); + ExchangeSelectors(originalMethod, newMethod); + } + + // Closes the tab, and waits for the close to finish. + void CloseTab(Browser* browser, int index) { + content::WebContentsDestroyedWatcher destroyed_watcher( + browser->tab_strip_model()->GetWebContentsAt(index)); + browser->tab_strip_model()->CloseWebContentsAt( + index, TabStripModel::CLOSE_CREATE_HISTORICAL_TAB); + destroyed_watcher.Wait(); + } +}; + +// Tests that as a user switches between tabs, navigates within a tab, and +// switches between browser windows, the correct URL is being passed to the +// Handoff. +IN_PROC_BROWSER_TEST_F(AppControllerHandoffBrowserTest, TestHandoffURLs) { + ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady()); + EXPECT_EQ(g_handoff_url, GURL(url::kAboutBlankURL)); + + // Test that navigating to a URL updates the handoff URL. + GURL test_url1 = embedded_test_server()->GetURL("/title1.html"); + ui_test_utils::NavigateToURL(browser(), test_url1); + EXPECT_EQ(g_handoff_url, test_url1); + + // Test that opening a new tab updates the handoff URL. + GURL test_url2 = embedded_test_server()->GetURL("/title2.html"); + chrome::NavigateParams params(browser(), test_url2, ui::PAGE_TRANSITION_LINK); + params.disposition = NEW_FOREGROUND_TAB; + ui_test_utils::NavigateToURL(¶ms); + EXPECT_EQ(g_handoff_url, test_url2); + + // Test that switching tabs updates the handoff URL. + browser()->tab_strip_model()->ActivateTabAt(0, true); + EXPECT_EQ(g_handoff_url, test_url1); + + // Test that closing the current tab updates the handoff URL. + CloseTab(browser(), 0); + EXPECT_EQ(g_handoff_url, test_url2); + + // Test that opening a new browser window updates the handoff URL. + GURL test_url3 = embedded_test_server()->GetURL("/title3.html"); + ui_test_utils::NavigateToURLWithDisposition( + browser(), GURL(test_url3), NEW_WINDOW, + ui_test_utils::BROWSER_TEST_WAIT_FOR_BROWSER); + EXPECT_EQ(g_handoff_url, test_url3); + + // Check that there are exactly 2 browsers. + BrowserList* active_browser_list = + BrowserList::GetInstance(chrome::GetActiveDesktop()); + EXPECT_EQ(2u, active_browser_list->size()); + + // Close the one and only tab for the second browser window. + Browser* browser2 = active_browser_list->get(1); + CloseTab(browser2, 0); + base::RunLoop().RunUntilIdle(); + EXPECT_EQ(g_handoff_url, test_url2); + + // The URLs of incognito windows should not be passed to Handoff. + GURL test_url4 = embedded_test_server()->GetURL("/simple.html"); + ui_test_utils::NavigateToURLWithDisposition( + browser(), GURL(test_url4), OFF_THE_RECORD, + ui_test_utils::BROWSER_TEST_WAIT_FOR_BROWSER); + EXPECT_EQ(g_handoff_url, GURL()); + + // Open a new tab in the incognito window. + EXPECT_EQ(2u, active_browser_list->size()); + Browser* browser3 = active_browser_list->get(1); + ui_test_utils::NavigateToURLWithDisposition( + browser3, test_url4, NEW_FOREGROUND_TAB, + ui_test_utils::BROWSER_TEST_WAIT_FOR_TAB); + EXPECT_EQ(g_handoff_url, GURL()); + + // Navigate the current tab in the incognito window. + ui_test_utils::NavigateToURLWithDisposition( + browser3, test_url1, CURRENT_TAB, + ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION); + EXPECT_EQ(g_handoff_url, GURL()); + + // Activate the original browser window. + Browser* browser1 = active_browser_list->get(0); + browser1->window()->Show(); + EXPECT_EQ(g_handoff_url, test_url2); +} + +} // namespace diff --git a/chrome/browser/ui/cocoa/handoff_active_url_observer.cc b/chrome/browser/ui/cocoa/handoff_active_url_observer.cc new file mode 100644 index 0000000..592a757 --- /dev/null +++ b/chrome/browser/ui/cocoa/handoff_active_url_observer.cc @@ -0,0 +1,124 @@ +// Copyright 2014 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/ui/cocoa/handoff_active_url_observer.h" + +#include "base/logging.h" +#include "chrome/browser/ui/browser_finder.h" +#include "chrome/browser/ui/browser_list.h" +#include "chrome/browser/ui/cocoa/handoff_active_url_observer_delegate.h" +#include "chrome/browser/ui/tabs/tab_strip_model.h" +#include "content/public/browser/web_contents.h" + +HandoffActiveURLObserver::HandoffActiveURLObserver( + HandoffActiveURLObserverDelegate* delegate) + : delegate_(delegate), + active_tab_strip_model_(nullptr), + active_browser_(nullptr) { + DCHECK(delegate_); + + active_browser_ = chrome::FindLastActiveWithHostDesktopType( + chrome::HOST_DESKTOP_TYPE_NATIVE); + BrowserList::AddObserver(this); + UpdateObservations(); +} + +HandoffActiveURLObserver::~HandoffActiveURLObserver() { + BrowserList::RemoveObserver(this); + StopObservingTabStripModel(); + StopObservingWebContents(); +} + +void HandoffActiveURLObserver::OnBrowserSetLastActive(Browser* browser) { + active_browser_ = browser; + UpdateObservations(); + delegate_->HandoffActiveURLChanged(GetActiveWebContents()); +} + +void HandoffActiveURLObserver::OnBrowserRemoved(Browser* removed_browser) { + if (active_browser_ != removed_browser) + return; + + active_browser_ = chrome::FindLastActiveWithHostDesktopType( + chrome::HOST_DESKTOP_TYPE_NATIVE); + UpdateObservations(); + delegate_->HandoffActiveURLChanged(GetActiveWebContents()); +} + +void HandoffActiveURLObserver::ActiveTabChanged( + content::WebContents* old_contents, + content::WebContents* new_contents, + int index, + int reason) { + StartObservingWebContents(new_contents); + delegate_->HandoffActiveURLChanged(new_contents); +} + +void HandoffActiveURLObserver::TabStripModelDeleted() { + StopObservingTabStripModel(); + StopObservingWebContents(); +} + +void HandoffActiveURLObserver::DidNavigateMainFrame( + const content::LoadCommittedDetails& details, + const content::FrameNavigateParams& params) { + delegate_->HandoffActiveURLChanged(web_contents()); +} + +void HandoffActiveURLObserver::WebContentsDestroyed() { + StopObservingWebContents(); +} + +void HandoffActiveURLObserver::UpdateObservations() { + if (!active_browser_) { + StopObservingTabStripModel(); + StopObservingWebContents(); + return; + } + + TabStripModel* model = active_browser_->tab_strip_model(); + StartObservingTabStripModel(model); + + content::WebContents* web_contents = model->GetActiveWebContents(); + if (web_contents) + StartObservingWebContents(web_contents); + else + StopObservingWebContents(); +} + +void HandoffActiveURLObserver::StartObservingTabStripModel( + TabStripModel* tab_strip_model) { + DCHECK(tab_strip_model); + + if (active_tab_strip_model_ == tab_strip_model) + return; + + StopObservingTabStripModel(); + tab_strip_model->AddObserver(this); + active_tab_strip_model_ = tab_strip_model; +} + +void HandoffActiveURLObserver::StopObservingTabStripModel() { + if (active_tab_strip_model_) { + active_tab_strip_model_->RemoveObserver(this); + active_tab_strip_model_ = nullptr; + } +} + +void HandoffActiveURLObserver::StartObservingWebContents( + content::WebContents* web_contents) { + DCHECK(web_contents); + Observe(web_contents); +} + +void HandoffActiveURLObserver::StopObservingWebContents() { + Observe(nullptr); +} + +content::WebContents* HandoffActiveURLObserver::GetActiveWebContents() { + if (!active_browser_) + return nullptr; + + return active_browser_->tab_strip_model()->GetActiveWebContents(); +} diff --git a/chrome/browser/ui/cocoa/handoff_active_url_observer.h b/chrome/browser/ui/cocoa/handoff_active_url_observer.h new file mode 100644 index 0000000..a46ed98 --- /dev/null +++ b/chrome/browser/ui/cocoa/handoff_active_url_observer.h @@ -0,0 +1,83 @@ +// Copyright 2014 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_UI_COCOA_HANDOFF_ACTIVE_URL_OBSERVER_H_ +#define CHROME_BROWSER_UI_COCOA_HANDOFF_ACTIVE_URL_OBSERVER_H_ + +#include "chrome/browser/ui/browser_list_observer.h" +#include "chrome/browser/ui/tabs/tab_strip_model_observer.h" +#include "content/public/browser/web_contents_observer.h" + +namespace content { +class WebContents; +} + +class Browser; +class HandoffActiveURLObserverDelegate; +class TabStripModel; + +// This class observes changes to the "active URL". This is defined as the +// visible URL of the WebContents of the selected tab of the most recently +// focused browser window. +class HandoffActiveURLObserver : public chrome::BrowserListObserver, + public TabStripModelObserver, + public content::WebContentsObserver { + public: + explicit HandoffActiveURLObserver(HandoffActiveURLObserverDelegate* delegate); + ~HandoffActiveURLObserver() override; + + private: + // chrome::BrowserListObserver + void OnBrowserSetLastActive(Browser* browser) override; + void OnBrowserRemoved(Browser* browser) override; + + // TabStripModelObserver + void ActiveTabChanged(content::WebContents* old_contents, + content::WebContents* new_contents, + int index, + int reason) override; + void TabStripModelDeleted() override; + + // content::WebContentsObserver + void DidNavigateMainFrame( + const content::LoadCommittedDetails& details, + const content::FrameNavigateParams& params) override; + void WebContentsDestroyed() override; + + // This method ensures that the instance is registered as an observer of the + // correct TabStripModel and WebContents for |active_browser_|. + void UpdateObservations(); + + // Makes this object start observing the TabStripModel, if it is not already + // doing so. This method is idempotent. + void StartObservingTabStripModel(TabStripModel* tab_strip_model); + + // Makes this object stop observing the TabStripModel. + void StopObservingTabStripModel(); + + // Makes this object start observing the WebContents, if it is not already + // doing so. This method is idempotent. + void StartObservingWebContents(content::WebContents* web_contents); + + // Makes this object stop observing the WebContents. + void StopObservingWebContents(); + + // Returns the active WebContents. May return nullptr. + content::WebContents* GetActiveWebContents(); + + // Instances of this class should be owned by their |delegate_|. + HandoffActiveURLObserverDelegate* delegate_; + + // When this pointer is not nullptr, this object is registered as an observer + // of the TabStripModel. + TabStripModel* active_tab_strip_model_; + + // This pointer is always up to date, and points to the most recently + // activated browser, or nullptr if no browsers exist. + Browser* active_browser_; + + DISALLOW_COPY_AND_ASSIGN(HandoffActiveURLObserver); +}; + +#endif // CHROME_BROWSER_UI_COCOA_HANDOFF_ACTIVE_URL_OBSERVER_H_ diff --git a/chrome/browser/ui/cocoa/handoff_active_url_observer_bridge.h b/chrome/browser/ui/cocoa/handoff_active_url_observer_bridge.h new file mode 100644 index 0000000..0d00961 --- /dev/null +++ b/chrome/browser/ui/cocoa/handoff_active_url_observer_bridge.h @@ -0,0 +1,47 @@ +// Copyright 2014 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_UI_COCOA_HANDOFF_ACTIVE_URL_OBSERVER_BRIDGE_H_ +#define CHROME_BROWSER_UI_COCOA_HANDOFF_ACTIVE_URL_OBSERVER_BRIDGE_H_ + +#import <Cocoa/Cocoa.h> + +#include "base/macros.h" +#include "base/memory/scoped_ptr.h" +#include "chrome/browser/ui/cocoa/handoff_active_url_observer_delegate.h" + +namespace content { +class WebContents; +} + +class HandoffActiveURLObserver; + +// A protocol that allows ObjC objects to receive delegate callbacks from +// HandoffActiveURLObserver. +@protocol HandoffActiveURLObserverBridgeDelegate +- (void)handoffActiveURLChanged:(content::WebContents*)webContents; +@end + +// This class allows an ObjC object to receive the delegate callbacks from an +// HandoffActiveURLObserver. +class HandoffActiveURLObserverBridge : public HandoffActiveURLObserverDelegate { + public: + explicit HandoffActiveURLObserverBridge( + NSObject<HandoffActiveURLObserverBridgeDelegate>* delegate); + + ~HandoffActiveURLObserverBridge() override; + + private: + void HandoffActiveURLChanged(content::WebContents* web_contents) override; + + // Instances of this class should be owned by their |delegate_|. + NSObject<HandoffActiveURLObserverBridgeDelegate>* delegate_; + + // The C++ object that this class acts as a bridge for. + scoped_ptr<HandoffActiveURLObserver> observer_; + + DISALLOW_COPY_AND_ASSIGN(HandoffActiveURLObserverBridge); +}; + +#endif // CHROME_BROWSER_UI_COCOA_HANDOFF_ACTIVE_URL_OBSERVER_BRIDGE_H_ diff --git a/chrome/browser/ui/cocoa/handoff_active_url_observer_bridge.mm b/chrome/browser/ui/cocoa/handoff_active_url_observer_bridge.mm new file mode 100644 index 0000000..639ae93 --- /dev/null +++ b/chrome/browser/ui/cocoa/handoff_active_url_observer_bridge.mm @@ -0,0 +1,21 @@ +// Copyright 2014 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/ui/cocoa/handoff_active_url_observer_bridge.h" + +#include "chrome/browser/ui/cocoa/handoff_active_url_observer.h" + +HandoffActiveURLObserverBridge::HandoffActiveURLObserverBridge( + NSObject<HandoffActiveURLObserverBridgeDelegate>* delegate) + : delegate_(delegate) { + DCHECK(delegate_); + observer_.reset(new HandoffActiveURLObserver(this)); +} + +HandoffActiveURLObserverBridge::~HandoffActiveURLObserverBridge(){}; + +void HandoffActiveURLObserverBridge::HandoffActiveURLChanged( + content::WebContents* web_contents) { + [delegate_ handoffActiveURLChanged:web_contents]; +} diff --git a/chrome/browser/ui/cocoa/handoff_active_url_observer_delegate.h b/chrome/browser/ui/cocoa/handoff_active_url_observer_delegate.h new file mode 100644 index 0000000..d0d0fff --- /dev/null +++ b/chrome/browser/ui/cocoa/handoff_active_url_observer_delegate.h @@ -0,0 +1,27 @@ +// Copyright 2014 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_UI_COCOA_HANDOFF_ACTIVE_URL_OBSERVER_DELEGATE_H_ +#define CHROME_BROWSER_UI_COCOA_HANDOFF_ACTIVE_URL_OBSERVER_DELEGATE_H_ + +namespace content { +class WebContents; +} + +// The delegate for a HandoffActiveURLObserver. +class HandoffActiveURLObserverDelegate { + public: + // Called when: + // 1. The most recently focused browser changes. + // 2. The active tab of the browser changes. + // 3. After a navigation of the web contents of the active tab. + // |web_contents| is the WebContents whose VisibleURL is considered the + // "Active URL" of Chrome. + virtual void HandoffActiveURLChanged(content::WebContents* web_contents) = 0; + + protected: + virtual ~HandoffActiveURLObserverDelegate(){}; +}; + +#endif // CHROME_BROWSER_UI_COCOA_HANDOFF_ACTIVE_URL_OBSERVER_DELEGATE_H_ |