Skip to content

Commit

Permalink
Merge pull request #9869 from rafaelnobrepd/handoff-enhancements
Browse files Browse the repository at this point in the history
Exposes more Handoff related APIs to Electron
  • Loading branch information
zcbenz committed Sep 14, 2017
2 parents 787675a + ff02311 commit 0784090
Show file tree
Hide file tree
Showing 9 changed files with 275 additions and 4 deletions.
30 changes: 29 additions & 1 deletion atom/browser/api/atom_api_app.cc
Expand Up @@ -584,17 +584,41 @@ void App::OnAccessibilitySupportChanged() {
}

#if defined(OS_MACOSX)
void App::OnWillContinueUserActivity(
bool* prevent_default,
const std::string& type) {
*prevent_default = Emit("will-continue-activity", type);
}

void App::OnDidFailToContinueUserActivity(
const std::string& type,
const std::string& error) {
Emit("continue-activity-error", type, error);
}

void App::OnContinueUserActivity(
bool* prevent_default,
const std::string& type,
const base::DictionaryValue& user_info) {
*prevent_default = Emit("continue-activity", type, user_info);
}

void App::OnUserActivityWasContinued(
const std::string& type,
const base::DictionaryValue& user_info) {
Emit("activity-was-continued", type, user_info);
}

void App::OnUpdateUserActivityState(
bool* prevent_default,
const std::string& type,
const base::DictionaryValue& user_info) {
*prevent_default = Emit("update-activity-state", type, user_info);
}

void App::OnNewWindowForTab() {
Emit("new-window-for-tab");
}

#endif

void App::OnLogin(LoginHandler* login_handler,
Expand Down Expand Up @@ -1139,6 +1163,10 @@ void App::BuildPrototype(
base::Bind(&Browser::SetUserActivity, browser))
.SetMethod("getCurrentActivityType",
base::Bind(&Browser::GetCurrentActivityType, browser))
.SetMethod("invalidateCurrentActivity",
base::Bind(&Browser::InvalidateCurrentActivity, browser))
.SetMethod("updateCurrentActivity",
base::Bind(&Browser::UpdateCurrentActivity, browser))
.SetMethod("setAboutPanelOptions",
base::Bind(&Browser::SetAboutPanelOptions, browser))
#endif
Expand Down
14 changes: 13 additions & 1 deletion atom/browser/api/atom_api_app.h
Expand Up @@ -113,11 +113,23 @@ class App : public AtomBrowserClient::Delegate,
const base::DictionaryValue& request_details) override;
void OnAccessibilitySupportChanged() override;
#if defined(OS_MACOSX)
void OnWillContinueUserActivity(
bool* prevent_default,
const std::string& type) override;
void OnDidFailToContinueUserActivity(
const std::string& type,
const std::string& error) override;
void OnContinueUserActivity(
bool* prevent_default,
const std::string& type,
const base::DictionaryValue& user_info) override;

void OnUserActivityWasContinued(
const std::string& type,
const base::DictionaryValue& user_info) override;
void OnUpdateUserActivityState(
bool* prevent_default,
const std::string& type,
const base::DictionaryValue& user_info) override;
void OnNewWindowForTab() override;
#endif

Expand Down
22 changes: 22 additions & 0 deletions atom/browser/browser.h
Expand Up @@ -119,10 +119,32 @@ class Browser : public WindowListObserver {
// Returns the type name of the current user activity.
std::string GetCurrentActivityType();

// Invalidates the current user activity.
void InvalidateCurrentActivity();

// Updates the current user activity
void UpdateCurrentActivity(const std::string& type,
const base::DictionaryValue& user_info);

// Indicates that an user activity is about to be resumed.
bool WillContinueUserActivity(const std::string& type);

// Indicates a failure to resume a Handoff activity.
void DidFailToContinueUserActivity(const std::string& type,
const std::string& error);

// Resumes an activity via hand-off.
bool ContinueUserActivity(const std::string& type,
const base::DictionaryValue& user_info);

// Indicates that an activity was continued on another device.
void UserActivityWasContinued(const std::string& type,
const base::DictionaryValue& user_info);

// Gives an oportunity to update the Handoff payload.
bool UpdateUserActivityState(const std::string& type,
const base::DictionaryValue& user_info);

// Bounce the dock icon.
enum BounceType {
BOUNCE_CRITICAL = 0,
Expand Down
38 changes: 38 additions & 0 deletions atom/browser/browser_mac.mm
Expand Up @@ -144,6 +144,30 @@
return base::SysNSStringToUTF8(userActivity.activityType);
}

void Browser::InvalidateCurrentActivity() {
[[AtomApplication sharedApplication] invalidateCurrentActivity];
}

void Browser::UpdateCurrentActivity(const std::string& type,
const base::DictionaryValue& user_info) {
[[AtomApplication sharedApplication]
updateCurrentActivity:base::SysUTF8ToNSString(type)
withUserInfo:DictionaryValueToNSDictionary(user_info)];
}

bool Browser::WillContinueUserActivity(const std::string& type) {
bool prevent_default = false;
for (BrowserObserver& observer : observers_)
observer.OnWillContinueUserActivity(&prevent_default, type);
return prevent_default;
}

void Browser::DidFailToContinueUserActivity(const std::string& type,
const std::string& error) {
for (BrowserObserver& observer : observers_)
observer.OnDidFailToContinueUserActivity(type, error);
}

bool Browser::ContinueUserActivity(const std::string& type,
const base::DictionaryValue& user_info) {
bool prevent_default = false;
Expand All @@ -152,6 +176,20 @@
return prevent_default;
}

void Browser::UserActivityWasContinued(const std::string& type,
const base::DictionaryValue& user_info) {
for (BrowserObserver& observer : observers_)
observer.OnUserActivityWasContinued(type, user_info);
}

bool Browser::UpdateUserActivityState(const std::string& type,
const base::DictionaryValue& user_info) {
bool prevent_default = false;
for (BrowserObserver& observer : observers_)
observer.OnUpdateUserActivityState(&prevent_default, type, user_info);
return prevent_default;
}

Browser::LoginItemSettings Browser::GetLoginItemSettings(
const LoginItemSettings& options) {
LoginItemSettings settings;
Expand Down
18 changes: 17 additions & 1 deletion atom/browser/browser_observer.h
Expand Up @@ -56,12 +56,28 @@ class BrowserObserver {
virtual void OnAccessibilitySupportChanged() {}

#if defined(OS_MACOSX)
// The browser wants to report that an user activity will resume. (macOS only)
virtual void OnWillContinueUserActivity(
bool* prevent_default,
const std::string& type) {}
// The browser wants to report an user activity resuming error. (macOS only)
virtual void OnDidFailToContinueUserActivity(
const std::string& type,
const std::string& error) {}
// The browser wants to resume a user activity via handoff. (macOS only)
virtual void OnContinueUserActivity(
bool* prevent_default,
const std::string& type,
const base::DictionaryValue& user_info) {}

// The browser wants to notify that an user activity was resumed. (macOS only)
virtual void OnUserActivityWasContinued(
const std::string& type,
const base::DictionaryValue& user_info) {}
// The browser wants to update an user activity payload. (macOS only)
virtual void OnUpdateUserActivityState(
bool* prevent_default,
const std::string& type,
const base::DictionaryValue& user_info) {}
// User clicked the native macOS new tab button. (macOS only)
virtual void OnNewWindowForTab() {}
#endif
Expand Down
8 changes: 7 additions & 1 deletion atom/browser/mac/atom_application.h
Expand Up @@ -6,10 +6,13 @@
#import "base/mac/scoped_nsobject.h"

@interface AtomApplication : NSApplication<CrAppProtocol,
CrAppControlProtocol> {
CrAppControlProtocol,
NSUserActivityDelegate> {
@private
BOOL handlingSendEvent_;
base::scoped_nsobject<NSUserActivity> currentActivity_;
NSCondition* handoffLock_;
BOOL updateReceived_;
}

+ (AtomApplication*)sharedApplication;
Expand All @@ -24,5 +27,8 @@
- (void)setCurrentActivity:(NSString*)type
withUserInfo:(NSDictionary*)userInfo
withWebpageURL:(NSURL*)webpageURL;
- (void)invalidateCurrentActivity;
- (void)updateCurrentActivity:(NSString*)type
withUserInfo:(NSDictionary*)userInfo;

@end
71 changes: 71 additions & 0 deletions atom/browser/mac/atom_application.mm
Expand Up @@ -4,11 +4,23 @@

#import "atom/browser/mac/atom_application.h"

#include "atom/browser/mac/dict_util.h"
#include "atom/browser/browser.h"
#include "base/auto_reset.h"
#include "base/strings/sys_string_conversions.h"
#include "content/public/browser/browser_accessibility_state.h"

namespace {

inline void dispatch_sync_main(dispatch_block_t block) {
if ([NSThread isMainThread])
block();
else
dispatch_sync(dispatch_get_main_queue(), block);
}

} // namespace

@implementation AtomApplication

+ (AtomApplication*)sharedApplication {
Expand All @@ -35,19 +47,78 @@ - (void)setCurrentActivity:(NSString*)type
[[NSUserActivity alloc] initWithActivityType:type]);
[currentActivity_ setUserInfo:userInfo];
[currentActivity_ setWebpageURL:webpageURL];
[currentActivity_ setDelegate:self];
[currentActivity_ becomeCurrent];
[currentActivity_ setNeedsSave:YES];
}

- (NSUserActivity*)getCurrentActivity {
return currentActivity_.get();
}

- (void)invalidateCurrentActivity {
if (currentActivity_) {
[currentActivity_ invalidate];
currentActivity_.reset();
}
}

- (void)updateCurrentActivity:(NSString*)type
withUserInfo:(NSDictionary*)userInfo {
if (currentActivity_) {
[currentActivity_ addUserInfoEntriesFromDictionary:userInfo];
}

[handoffLock_ lock];
updateReceived_ = YES;
[handoffLock_ signal];
[handoffLock_ unlock];
}

- (void)userActivityWillSave:(NSUserActivity *)userActivity {
__block BOOL shouldWait = NO;
dispatch_sync_main(^{
std::string activity_type(base::SysNSStringToUTF8(userActivity.activityType));
std::unique_ptr<base::DictionaryValue> user_info =
atom::NSDictionaryToDictionaryValue(userActivity.userInfo);

atom::Browser* browser = atom::Browser::Get();
shouldWait = browser->UpdateUserActivityState(activity_type, *user_info) ? YES : NO;
});

if (shouldWait) {
[handoffLock_ lock];
updateReceived_ = NO;
while (!updateReceived_) {
BOOL isSignaled = [handoffLock_ waitUntilDate:[NSDate dateWithTimeIntervalSinceNow:1]];
if (!isSignaled) break;
}
[handoffLock_ unlock];
}

[userActivity setNeedsSave:YES];
}

- (void)userActivityWasContinued:(NSUserActivity *)userActivity {
dispatch_async(dispatch_get_main_queue(), ^{
std::string activity_type(base::SysNSStringToUTF8(userActivity.activityType));
std::unique_ptr<base::DictionaryValue> user_info =
atom::NSDictionaryToDictionaryValue(userActivity.userInfo);

atom::Browser* browser = atom::Browser::Get();
browser->UserActivityWasContinued(activity_type, *user_info);
});
[userActivity setNeedsSave:YES];
}

- (void)awakeFromNib {
[[NSAppleEventManager sharedAppleEventManager]
setEventHandler:self
andSelector:@selector(handleURLEvent:withReplyEvent:)
forEventClass:kInternetEventClass
andEventID:kAEGetURL];

handoffLock_ = [NSCondition new];
}

- (void)handleURLEvent:(NSAppleEventDescriptor*)event
Expand Down
15 changes: 15 additions & 0 deletions atom/browser/mac/atom_application_delegate.mm
Expand Up @@ -118,6 +118,21 @@ - (BOOL)application:(NSApplication*)sender
return browser->ContinueUserActivity(activity_type, *user_info) ? YES : NO;
}

- (BOOL)application:(NSApplication*)application willContinueUserActivityWithType:(NSString*)userActivityType {
std::string activity_type(base::SysNSStringToUTF8(userActivityType));

atom::Browser* browser = atom::Browser::Get();
return browser->WillContinueUserActivity(activity_type) ? YES : NO;
}

- (void)application:(NSApplication*)application didFailToContinueUserActivityWithType:(NSString*)userActivityType error:(NSError*)error {
std::string activity_type(base::SysNSStringToUTF8(userActivityType));
std::string error_message(base::SysNSStringToUTF8([error localizedDescription]));

atom::Browser* browser = atom::Browser::Get();
browser->DidFailToContinueUserActivity(activity_type, error_message);
}

- (IBAction)newWindowForTab:(id)sender {
atom::Browser::Get()->NewWindowForTab();
}
Expand Down

0 comments on commit 0784090

Please sign in to comment.