Browse Source

Exposes more Handoff related APIs to Electron.

Rafael Nobre 7 years ago
parent
commit
a870799c32

+ 24 - 2
atom/browser/api/atom_api_app.cc

@@ -584,17 +584,35 @@ 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(
+    const std::string& type,
+    const base::DictionaryValue& user_info) {
+  Emit("update-activity-state", type, user_info);
+}
 void App::OnNewWindowForTab() {
   Emit("new-window-for-tab");
 }
-
 #endif
 
 void App::OnLogin(LoginHandler* login_handler,
@@ -1139,6 +1157,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

+ 12 - 1
atom/browser/api/atom_api_app.h

@@ -113,11 +113,22 @@ 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(
+      const std::string& type,
+      const base::DictionaryValue& user_info) override;
   void OnNewWindowForTab() override;
 #endif
 

+ 22 - 0
atom/browser/browser.h

@@ -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.
+  void UpdateUserActivityState(const std::string& type,
+                               const base::DictionaryValue& user_info);
+
   // Bounce the dock icon.
   enum BounceType {
     BOUNCE_CRITICAL = 0,

+ 36 - 0
atom/browser/browser_mac.mm

@@ -144,6 +144,30 @@ std::string Browser::GetCurrentActivityType() {
   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;
@@ -151,6 +175,18 @@ bool Browser::ContinueUserActivity(const std::string& type,
     observer.OnContinueUserActivity(&prevent_default, type, user_info);
   return prevent_default;
 }
+  
+void Browser::UserActivityWasContinued(const std::string& type,
+                                       const base::DictionaryValue& user_info) {
+  for (BrowserObserver& observer : observers_)
+    observer.OnUserActivityWasContinued(type, user_info);
+}
+
+void Browser::UpdateUserActivityState(const std::string& type,
+                                      const base::DictionaryValue& user_info) {
+  for (BrowserObserver& observer : observers_)
+    observer.OnUpdateUserActivityState(type, user_info);
+}
 
 Browser::LoginItemSettings Browser::GetLoginItemSettings(
     const LoginItemSettings& options) {

+ 16 - 1
atom/browser/browser_observer.h

@@ -56,12 +56,27 @@ 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(
+      const std::string& type,
+      const base::DictionaryValue& user_info) {}
   // User clicked the native macOS new tab button. (macOS only)
   virtual void OnNewWindowForTab() {}
 #endif

+ 5 - 1
atom/browser/mac/atom_application.h

@@ -6,7 +6,8 @@
 #import "base/mac/scoped_nsobject.h"
 
 @interface AtomApplication : NSApplication<CrAppProtocol,
-                                           CrAppControlProtocol> {
+                                           CrAppControlProtocol,
+                                           NSUserActivityDelegate> {
  @private
   BOOL handlingSendEvent_;
   base::scoped_nsobject<NSUserActivity> currentActivity_;
@@ -24,5 +25,8 @@
 - (void)setCurrentActivity:(NSString*)type
               withUserInfo:(NSDictionary*)userInfo
             withWebpageURL:(NSURL*)webpageURL;
+- (void)invalidateCurrentActivity;
+- (void)updateCurrentActivity:(NSString *)type
+                 withUserInfo:(NSDictionary*)userInfo;
 
 @end

+ 38 - 0
atom/browser/mac/atom_application.mm

@@ -4,6 +4,7 @@
 
 #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"
@@ -35,6 +36,7 @@
       [[NSUserActivity alloc] initWithActivityType:type]);
   [currentActivity_ setUserInfo:userInfo];
   [currentActivity_ setWebpageURL:webpageURL];
+  [currentActivity_ setDelegate: self];
   [currentActivity_ becomeCurrent];
 }
 
@@ -42,6 +44,42 @@
   return currentActivity_.get();
 }
 
+- (void)invalidateCurrentActivity {
+  if (currentActivity_.get() != NULL) {
+    [currentActivity_.get() invalidate];
+    currentActivity_.reset();
+  }
+}
+
+- (void)updateCurrentActivity:(NSString *)type
+                 withUserInfo:(NSDictionary*)userInfo {
+  if (currentActivity_.get() != NULL) {
+    [currentActivity_.get() addUserInfoEntriesFromDictionary:userInfo];
+  }
+}
+
+- (void)updateUserActivityState:(NSUserActivity *)userActivity {
+  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->UpdateUserActivityState(activity_type, *user_info);
+  
+  [super updateUserActivityState:userActivity];
+}
+
+- (void)userActivityWasContinued:(NSUserActivity *)userActivity {
+  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

+ 15 - 0
atom/browser/mac/atom_application_delegate.mm

@@ -118,6 +118,21 @@ continueUserActivity:(NSUserActivity*)userActivity
   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();
 }

+ 66 - 0
docs/api/app.md

@@ -149,6 +149,53 @@ ID as the activity's source app and that supports the activity's type.
 Supported activity types are specified in the app's `Info.plist` under the
 `NSUserActivityTypes` key.
 
+### Event: 'will-continue-activity' _macOS_
+
+Returns:
+
+* `event` Event
+* `type` String - A string identifying the activity. Maps to
+  [`NSUserActivity.activityType`][activity-type].
+
+Emitted during [Handoff][handoff] before an activity from a different device wants
+to be resumed. You should call `event.preventDefault()` if you want to handle
+this event.
+
+### Event: 'continue-activity-error' _macOS_
+
+Returns:
+
+* `event` Event
+* `type` String - A string identifying the activity. Maps to
+  [`NSUserActivity.activityType`][activity-type].
+* `error` String - A string with the error's localized description.
+
+Emitted during [Handoff][handoff] when an activity from a different device
+fails to be resumed.
+
+### Event: 'activity-was-continued' _macOS_
+
+Returns:
+
+* `event` Event
+* `type` String - A string identifying the activity. Maps to
+  [`NSUserActivity.activityType`][activity-type].
+* `userInfo` Object - Contains app-specific state stored by the activity.
+
+Emitted during [Handoff][handoff] after an activity from this device was successfully
+resumed.
+
+### Event: 'update-activity-state' _macOS_
+
+Returns:
+
+* `event` Event
+* `type` String - A string identifying the activity. Maps to
+  [`NSUserActivity.activityType`][activity-type].
+* `userInfo` Object - Contains app-specific state stored by the activity.
+
+Emitted during [Handoff][handoff] when its user info should be updated before resuming.
+
 ### Event: 'new-window-for-tab' _macOS_
 
 Returns:
@@ -748,6 +795,25 @@ is eligible for [Handoff][handoff] to another device afterward.
 
 Returns `String` - The type of the currently running activity.
 
+### `app.invalidateCurrentActivity()` _macOS_
+
+* `type` String - Uniquely identifies the activity. Maps to
+  [`NSUserActivity.activityType`][activity-type].
+* `userInfo` Object - App-specific state to store for use by another device.
+* `webpageURL` String (optional) - The webpage to load in a browser if no suitable app is
+  installed on the resuming device. The scheme must be `http` or `https`.
+
+Invalidates de current Handoff user activity.
+
+### `app.updateCurrentActivity(type, userInfo[, webpageURL])` _macOS_
+
+* `type` String - Uniquely identifies the activity. Maps to
+  [`NSUserActivity.activityType`][activity-type].
+* `userInfo` Object - App-specific state to store for use by another device.
+
+Updates the current `NSUserActivity` if its type matches `type`, merging the entries from
+`userInfo` into its current userInfo dictionary.
+
 ### `app.setAppUserModelId(id)` _Windows_
 
 * `id` String