Merge pull request #5401 from electron/ns-js-object

Fully support the userInfo object in app.setUserActivity and continue-activity event
This commit is contained in:
Cheng Zhao 2016-05-05 17:59:43 +09:00
commit 636570306a
17 changed files with 167 additions and 147 deletions

View file

@ -20,7 +20,6 @@
#include "atom/common/native_mate_converters/image_converter.h"
#include "atom/common/native_mate_converters/net_converter.h"
#include "atom/common/native_mate_converters/value_converter.h"
#include "atom/common/native_mate_converters/string_map_converter.h"
#include "atom/common/node_includes.h"
#include "atom/common/options_switches.h"
#include "base/command_line.h"
@ -250,11 +249,14 @@ void App::OnFinishLaunching() {
Emit("ready");
}
void App::OnContinueUserActivity(bool* prevent_default,
const std::string& type,
const std::map<std::string, std::string>& user_info) {
#if defined(OS_MACOSX)
void App::OnContinueUserActivity(
bool* prevent_default,
const std::string& type,
const base::DictionaryValue& user_info) {
*prevent_default = Emit("continue-activity", type, user_info);
}
#endif
void App::OnLogin(LoginHandler* login_handler) {
v8::Locker locker(isolate());

View file

@ -6,7 +6,6 @@
#define ATOM_BROWSER_API_ATOM_API_APP_H_
#include <string>
#include <map>
#include "atom/browser/api/event_emitter.h"
#include "atom/browser/atom_browser_client.h"
@ -72,9 +71,12 @@ class App : public AtomBrowserClient::Delegate,
void OnWillFinishLaunching() override;
void OnFinishLaunching() override;
void OnLogin(LoginHandler* login_handler) override;
void OnContinueUserActivity(bool* prevent_default,
const std::string& type,
const std::map<std::string, std::string>& user_info) override;
#if defined(OS_MACOSX)
void OnContinueUserActivity(
bool* prevent_default,
const std::string& type,
const base::DictionaryValue& user_info) override;
#endif
// content::ContentBrowserClient:
void AllowCertificateError(

View file

@ -137,19 +137,6 @@ void Browser::Activate(bool has_visible_windows) {
OnActivate(has_visible_windows));
}
#if defined(OS_MACOSX)
bool Browser::ContinueUserActivity(const std::string& type,
const std::map<std::string,
std::string>& user_info) {
bool prevent_default = false;
FOR_EACH_OBSERVER(BrowserObserver,
observers_,
OnContinueUserActivity(&prevent_default, type, user_info));
return prevent_default;
}
#endif
void Browser::WillFinishLaunching() {
FOR_EACH_OBSERVER(BrowserObserver, observers_, OnWillFinishLaunching());
}

View file

@ -7,7 +7,6 @@
#include <string>
#include <vector>
#include <map>
#include "base/macros.h"
#include "base/compiler_specific.h"
@ -95,14 +94,14 @@ class Browser : public WindowListObserver {
// Creates an activity and sets it as the one currently in use.
void SetUserActivity(const std::string& type,
const std::map<std::string, std::string>& user_info);
const base::DictionaryValue& user_info);
// Returns the type name of the current user activity.
std::string GetCurrentActivityType();
// Resumes an activity via hand-off.
bool ContinueUserActivity(const std::string& type,
const std::map<std::string, std::string>& user_info);
const base::DictionaryValue& user_info);
// Bounce the dock icon.
enum BounceType {

View file

@ -6,6 +6,7 @@
#include "atom/browser/mac/atom_application.h"
#include "atom/browser/mac/atom_application_delegate.h"
#include "atom/browser/mac/dict_util.h"
#include "atom/browser/native_window.h"
#include "atom/browser/window_list.h"
#include "base/mac/bundle_locations.h"
@ -87,28 +88,28 @@ bool Browser::IsDefaultProtocolClient(const std::string& protocol) {
void Browser::SetAppUserModelID(const base::string16& name) {
}
void Browser::SetUserActivity(const std::string& type, const std::map<std::string, std::string>& user_info) {
NSString* type_ns = [NSString stringWithUTF8String:type.c_str()];
NSUserActivity* user_activity = [[NSUserActivity alloc] initWithActivityType:type_ns];
base::scoped_nsobject<NSMutableDictionary> user_info_args([[NSMutableDictionary alloc] init]);
for (auto const &pair : user_info) {
NSString* value_ns = [NSString stringWithUTF8String:pair.second.c_str()];
NSString* key_ns = [NSString stringWithUTF8String:pair.first.c_str()];
[user_info_args.get() setObject:value_ns
forKey:key_ns];
}
user_activity.userInfo = user_info_args.get();
[user_activity becomeCurrent];
[[AtomApplication sharedApplication] setCurrentActivity:user_activity];
void Browser::SetUserActivity(
const std::string& type,
const base::DictionaryValue& user_info) {
[[AtomApplication sharedApplication]
setCurrentActivity:base::SysUTF8ToNSString(type)
withUserInfo:DictionaryValueToNSDictionary(user_info)];
}
std::string Browser::GetCurrentActivityType() {
NSUserActivity* user_activity = [[AtomApplication sharedApplication] getCurrentActivity];
return base::SysNSStringToUTF8(user_activity.activityType);
NSUserActivity* userActivity =
[[AtomApplication sharedApplication] getCurrentActivity];
return base::SysNSStringToUTF8(userActivity.activityType);
}
bool Browser::ContinueUserActivity(
const std::string& type,
const base::DictionaryValue& user_info) {
bool prevent_default = false;
FOR_EACH_OBSERVER(BrowserObserver,
observers_,
OnContinueUserActivity(&prevent_default, type, user_info));
return prevent_default;
}
std::string Browser::GetExecutableFileVersion() const {

View file

@ -6,7 +6,12 @@
#define ATOM_BROWSER_BROWSER_OBSERVER_H_
#include <string>
#include <map>
#include "build/build_config.h"
namespace base {
class DictionaryValue;
}
namespace atom {
@ -46,10 +51,13 @@ class BrowserObserver {
// The browser requests HTTP login.
virtual void OnLogin(LoginHandler* login_handler) {}
#if defined(OS_MACOSX)
// The browser wants to resume a user activity via handoff. (OS X only)
virtual void OnContinueUserActivity(bool* prevent_default,
const std::string& type,
const std::map<std::string, std::string>& user_info) {}
virtual void OnContinueUserActivity(
bool* prevent_default,
const std::string& type,
const base::DictionaryValue& user_info) {}
#endif
protected:
virtual ~BrowserObserver() {}

View file

@ -21,7 +21,6 @@
- (void)setHandlingSendEvent:(BOOL)handlingSendEvent;
- (NSUserActivity*)getCurrentActivity;
- (void)setCurrentActivity:(NSUserActivity*)userActivity;
- (void)setCurrentActivity:(NSString*)type withUserInfo:(NSDictionary*)userInfo;
@end

View file

@ -28,8 +28,12 @@
handlingSendEvent_ = handlingSendEvent;
}
- (void)setCurrentActivity:(NSUserActivity*)userActivity {
currentActivity_ = base::scoped_nsobject<NSUserActivity>(userActivity);
- (void)setCurrentActivity:(NSString*)type
withUserInfo:(NSDictionary*)userInfo {
currentActivity_ = base::scoped_nsobject<NSUserActivity>(
[[NSUserActivity alloc] initWithActivityType:type]);
[currentActivity_ setUserInfo:userInfo];
[currentActivity_ becomeCurrent];
}
- (NSUserActivity*)getCurrentActivity {

View file

@ -6,7 +6,9 @@
#import "atom/browser/mac/atom_application.h"
#include "atom/browser/browser.h"
#include "atom/browser/mac/dict_util.h"
#include "base/strings/sys_string_conversions.h"
#include "base/values.h"
@implementation AtomApplicationDelegate
@ -59,23 +61,17 @@
return flag;
}
- (BOOL)application:(NSApplication *)sender
continueUserActivity:(NSUserActivity *)userActivity
restorationHandler:(void (^)(NSArray *restorableObjects))restorationHandler {
- (BOOL)application:(NSApplication*)sender
continueUserActivity:(NSUserActivity*)userActivity
restorationHandler:(void (^)(NSArray*restorableObjects))restorationHandler {
std::string activity_type(base::SysNSStringToUTF8(userActivity.activityType));
std::map<std::string, std::string> user_info;
base::scoped_nsobject<NSArray> keys([userActivity.userInfo allKeys]);
for (NSString* key in keys.get()) {
NSString* value = [userActivity.userInfo objectForKey:key];
std::string key_str(base::SysNSStringToUTF8(key));
std::string value_str(base::SysNSStringToUTF8(value));
user_info[key_str] = value_str;
}
scoped_ptr<base::DictionaryValue> user_info =
atom::NSDictionaryToDictionaryValue(userActivity.userInfo);
if (!user_info)
return NO;
atom::Browser* browser = atom::Browser::Get();
return browser->ContinueUserActivity(activity_type, user_info) ? YES : NO;
return browser->ContinueUserActivity(activity_type, *user_info) ? YES : NO;
}
@end

View file

@ -0,0 +1,26 @@
// Copyright (c) 2016 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#ifndef ATOM_BROWSER_MAC_DICT_UTIL_H_
#define ATOM_BROWSER_MAC_DICT_UTIL_H_
#import <Foundation/Foundation.h>
#include "base/memory/scoped_ptr.h"
namespace base {
class Value;
class DictionaryValue;
}
namespace atom {
NSDictionary* DictionaryValueToNSDictionary(const base::DictionaryValue& value);
scoped_ptr<base::DictionaryValue> NSDictionaryToDictionaryValue(
NSDictionary* dict);
} // namespace atom
#endif // ATOM_BROWSER_MAC_DICT_UTIL_H_

View file

@ -0,0 +1,42 @@
// Copyright (c) 2016 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#include "atom/browser/mac/dict_util.h"
#include "base/mac/scoped_nsobject.h"
#include "base/json/json_reader.h"
#include "base/json/json_writer.h"
#include "base/values.h"
namespace atom {
NSDictionary* DictionaryValueToNSDictionary(const base::DictionaryValue& value) {
std::string json;
if (!base::JSONWriter::Write(value, &json))
return nil;
NSData* jsonData = [NSData dataWithBytes:json.c_str() length:json.length()];
id obj = [NSJSONSerialization JSONObjectWithData:jsonData
options:0
error:nil];
if (![obj isKindOfClass:[NSDictionary class]])
return nil;
return obj;
}
scoped_ptr<base::DictionaryValue> NSDictionaryToDictionaryValue(
NSDictionary* dict) {
NSData* data = [NSJSONSerialization dataWithJSONObject:dict
options:0
error:nil];
if (!data)
return nullptr;
base::scoped_nsobject<NSString> json =
[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
scoped_ptr<base::Value> value =
base::JSONReader::Read([json UTF8String]);
return base::DictionaryValue::From(std::move(value));
}
} // namespace atom

View file

@ -6,7 +6,6 @@
#include <string>
#include "atom/common/crash_reporter/crash_reporter.h"
#include "atom/common/native_mate_converters/string_map_converter.h"
#include "base/bind.h"
#include "native_mate/dictionary.h"
@ -16,6 +15,24 @@ using crash_reporter::CrashReporter;
namespace mate {
template<>
struct Converter<std::map<std::string, std::string> > {
static bool FromV8(v8::Isolate* isolate,
v8::Local<v8::Value> val,
std::map<std::string, std::string>* out) {
if (!val->IsObject())
return false;
v8::Local<v8::Object> dict = val->ToObject();
v8::Local<v8::Array> keys = dict->GetOwnPropertyNames();
for (uint32_t i = 0; i < keys->Length(); ++i) {
v8::Local<v8::Value> key = keys->Get(i);
(*out)[V8ToString(key)] = V8ToString(dict->Get(key));
}
return true;
}
};
template<>
struct Converter<CrashReporter::UploadReportResult> {
static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,

View file

@ -1,36 +0,0 @@
// Copyright (c) 2014 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#include "atom/common/native_mate_converters/string_map_converter.h"
namespace mate {
bool Converter<std::map<std::string, std::string>>::FromV8(v8::Isolate* isolate,
v8::Local<v8::Value> val,
std::map<std::string, std::string>* out) {
if (!val->IsObject())
return false;
v8::Local<v8::Object> dict = val->ToObject();
v8::Local<v8::Array> keys = dict->GetOwnPropertyNames();
for (uint32_t i = 0; i < keys->Length(); ++i) {
v8::Local<v8::Value> key = keys->Get(i);
(*out)[V8ToString(key)] = V8ToString(dict->Get(key));
}
return true;
}
v8::Local<v8::Value> Converter<std::map<std::string, std::string>>::ToV8(
v8::Isolate* isolate,
const std::map<std::string, std::string>& in) {
mate::Dictionary dict(isolate, v8::Object::New(isolate));
for (auto const &pair : in) {
dict.Set(pair.first, pair.second);
}
return dict.GetHandle();
}
} // namespace mate

View file

@ -1,28 +0,0 @@
// Copyright (c) 2014 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#ifndef ATOM_COMMON_NATIVE_MATE_CONVERTERS_STRING_MAP_CONVERTER_H_
#define ATOM_COMMON_NATIVE_MATE_CONVERTERS_STRING_MAP_CONVERTER_H_
#include <map>
#include <string>
#include "native_mate/converter.h"
#include "native_mate/dictionary.h"
namespace mate {
template<>
struct Converter<std::map<std::string, std::string>> {
static bool FromV8(v8::Isolate* isolate,
v8::Local<v8::Value> val,
std::map<std::string, std::string>* out);
static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
const std::map<std::string, std::string>& in);
};
} // namespace mate
#endif // ATOM_COMMON_NATIVE_MATE_CONVERTERS_STRING_MAP_CONVERTER_H_

View file

@ -116,17 +116,18 @@ the application's dock icon.
Returns:
* `event` Event
* `type` String - A string identifying the event. Maps to [`NSUserActivity.activityType`](https://developer.apple.com/library/ios/documentation/Foundation/Reference/NSUserActivity_Class/index.html#//apple_ref/occ/instp/NSUserActivity/activityType).
* `type` String - A string identifying the activity. Maps to
[`NSUserActivity.activityType`][activity-type].
* `userInfo` Object - Contains app-specific state stored by the activity on
another device. Currently only string data is supported.
another device.
Emitted during [handoff](https://developer.apple.com/library/ios/documentation/UserExperience/Conceptual/Handoff/HandoffFundamentals/HandoffFundamentals.html) when an activity from a different device wants to be
resumed. You should call `event.preventDefault()` if you want to handle this
event.
Emitted during [Handoff][handoff] when an activity from a different device wants
to be resumed. You should call `event.preventDefault()` if you want to handle
this event.
A user activity can be continued only in an app that has the same developer
Team 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
A user activity can be continued only in an app that has the same developer Team
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: 'browser-window-blur'
@ -502,13 +503,12 @@ app.on('ready', function() {
### `app.setUserActivity(type, userInfo)` _OS X_
* `type` String - Uniquely identifies the activity. It's recommended to use a
reverse-DNS string.
* `type` String - Uniquely identifies the activity. Maps to
[`NSUserActivity.activityType`][activity-type].
* `userInfo` Object - App-specific state to store for use by another device.
Currently only string data is supported.
Creates an `NSUserActivity` and sets it as the current activity. The activity
is eligible for [handoff](https://developer.apple.com/library/ios/documentation/UserExperience/Conceptual/Handoff/HandoffFundamentals/HandoffFundamentals.html) to another device afterward.
is eligible for [Handoff][handoff] to another device afterward.
### `app.getCurrentActivityType()` _OS X_
@ -600,5 +600,6 @@ Sets the `image` associated with this dock icon.
[tasks]:http://msdn.microsoft.com/en-us/library/windows/desktop/dd378460(v=vs.85).aspx#tasks
[app-user-model-id]: https://msdn.microsoft.com/en-us/library/windows/desktop/dd378459(v=vs.85).aspx
[CFBundleURLTypes]: https://developer.apple.com/library/ios/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html#//apple_ref/doc/uid/TP40009249-102207-TPXREF115
[LSCopyDefaultHandlerForURLScheme]:
https://developer.apple.com/library/mac/documentation/Carbon/Reference/LaunchServicesReference/#//apple_ref/c/func/LSCopyDefaultHandlerForURLScheme
[LSCopyDefaultHandlerForURLScheme]: https://developer.apple.com/library/mac/documentation/Carbon/Reference/LaunchServicesReference/#//apple_ref/c/func/LSCopyDefaultHandlerForURLScheme
[handoff]: https://developer.apple.com/library/ios/documentation/UserExperience/Conceptual/Handoff/HandoffFundamentals/HandoffFundamentals.html
[activity-type]: https://developer.apple.com/library/ios/documentation/Foundation/Reference/NSUserActivity_Class/index.html#//apple_ref/occ/instp/NSUserActivity/activityType

View file

@ -183,6 +183,8 @@
'atom/browser/mac/atom_application.mm',
'atom/browser/mac/atom_application_delegate.h',
'atom/browser/mac/atom_application_delegate.mm',
'atom/browser/mac/dict_util.h',
'atom/browser/mac/dict_util.mm',
'atom/browser/native_window.cc',
'atom/browser/native_window.h',
'atom/browser/native_window_views_win.cc',
@ -361,8 +363,6 @@
'atom/common/native_mate_converters/image_converter.h',
'atom/common/native_mate_converters/net_converter.cc',
'atom/common/native_mate_converters/net_converter.h',
'atom/common/native_mate_converters/string_map_converter.cc',
'atom/common/native_mate_converters/string_map_converter.h',
'atom/common/native_mate_converters/string16_converter.h',
'atom/common/native_mate_converters/ui_base_types_converter.h',
'atom/common/native_mate_converters/v8_value_converter.cc',

View file

@ -91,7 +91,7 @@ describe('app module', function () {
})
describe('app.setUserActivity(type, userInfo)', function () {
if (isCI && process.platform !== 'darwin') {
if (process.platform !== 'darwin') {
return
}