Upstream version 7.35.138.0
[platform/framework/web/crosswalk.git] / src / xwalk / application / extension / application_event_extension.cc
1 // Copyright (c) 2013 Intel Corporation. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "xwalk/application/extension/application_event_extension.h"
6
7 #include <set>
8
9 #include "base/stl_util.h"
10 #include "base/threading/thread_restrictions.h"
11 #include "content/public/browser/web_contents.h"
12 #include "grit/xwalk_application_resources.h"
13 #include "ipc/ipc_message.h"
14 #include "ui/base/resource/resource_bundle.h"
15 #include "xwalk/application/browser/application.h"
16 #include "xwalk/application/browser/application_event_manager.h"
17 #include "xwalk/application/browser/application_storage.h"
18 #include "xwalk/application/common/event_names.h"
19 #include "xwalk/runtime/browser/runtime.h"
20
21 namespace xwalk {
22 namespace application {
23
24 ApplicationEventExtension::ApplicationEventExtension(
25     ApplicationEventManager* event_manager,
26     ApplicationStorage* app_storage,
27     Application* app)
28   : event_manager_(event_manager),
29     app_storage_(app_storage),
30     application_(app) {
31   set_name("xwalk.app.events");
32   set_javascript_api(ResourceBundle::GetSharedInstance().GetRawDataResource(
33       IDR_XWALK_APPLICATION_EVENT_API).as_string());
34 }
35
36 XWalkExtensionInstance* ApplicationEventExtension::CreateInstance() {
37   int main_routing_id = MSG_ROUTING_NONE;
38
39   if (Runtime* runtime = application_->GetMainDocumentRuntime())
40     main_routing_id = runtime->web_contents()->GetRoutingID();
41
42   return new AppEventExtensionInstance(event_manager_, app_storage_,
43                                        application_, main_routing_id);
44 }
45
46 AppEventExtensionInstance::AppEventExtensionInstance(
47     ApplicationEventManager* event_manager,
48     ApplicationStorage* app_storage,
49     Application* app,
50     int main_routing_id)
51   : EventObserver(event_manager),
52     app_storage_(app_storage),
53     application_(app),
54     main_routing_id_(main_routing_id),
55     handler_(this) {
56   handler_.Register("registerEvent",
57                     base::Bind(&AppEventExtensionInstance::OnRegisterEvent,
58                     base::Unretained(this)));
59   handler_.Register("unregisterEvent",
60                     base::Bind(&AppEventExtensionInstance::OnUnregisterEvent,
61                     base::Unretained(this)));
62   handler_.Register("dispatchEventFinish",
63                     base::Bind(
64                         &AppEventExtensionInstance::OnDispatchEventFinish,
65                         base::Unretained(this)));
66   // FIXME: give UI thread I/O permission temporarily. The application storage
67   // database should be accessed on DB thread.
68   base::ThreadRestrictions::SetIOAllowed(true);
69 }
70
71 AppEventExtensionInstance::~AppEventExtensionInstance() {
72 }
73
74 void AppEventExtensionInstance::HandleMessage(scoped_ptr<base::Value> msg) {
75   handler_.HandleMessage(msg.Pass());
76 }
77
78 void AppEventExtensionInstance::OnRegisterEvent(
79     scoped_ptr<XWalkExtensionFunctionInfo> info) {
80   std::string event_name;
81   int routing_id;
82   if (info->arguments()->GetSize() != 2 ||
83       !info->arguments()->GetString(0, &event_name) ||
84       !info->arguments()->GetInteger(1, &routing_id))
85     return;
86
87   if (!ContainsKey(registered_events_, event_name)) {
88     registered_events_.insert(
89         std::make_pair(event_name, info->post_result_cb()));
90     event_manager_->AttachObserver(application_->id(), event_name, this);
91
92     if (routing_id != main_routing_id_)
93       return;
94
95     ApplicationData* app_data = application_->data();
96     if (!app_data)
97       return;
98
99     // If the event is from main document, add it into system database.
100     // If Crosswalk application is launched from unpacked path without
101     // installation, the registered events information will be saved in
102     // ApplicationData, no copy of it in ApplicationStorage.
103     std::set<std::string> events = app_data->GetEvents();
104     if (ContainsKey(events, event_name))
105       return;
106     events.insert(event_name);
107     app_data->SetEvents(events);
108     app_storage_->UpdateApplication(app_data);
109   }
110 }
111
112 void AppEventExtensionInstance::OnUnregisterEvent(
113     scoped_ptr<XWalkExtensionFunctionInfo> info) {
114   std::string event_name;
115   int routing_id;
116   if (info->arguments()->GetSize() != 2 ||
117       !info->arguments()->GetString(0, &event_name) ||
118       !info->arguments()->GetInteger(1, &routing_id))
119     return;
120
121   if (!ContainsKey(registered_events_, event_name))
122     return;
123
124   registered_events_.erase(event_name);
125   event_manager_->DetachObserver(application_->id(), event_name, this);
126
127   // If the event is from main document, remove it from system database.
128   if (routing_id == main_routing_id_) {
129     ApplicationData* app_data = application_->data();
130     if (!app_data)
131       return;
132
133     std::set<std::string> events = app_data->GetEvents();
134     if (!ContainsKey(events, event_name))
135       return;
136     events.erase(event_name);
137     app_data->SetEvents(events);
138     app_storage_->UpdateApplication(app_data);
139   }
140 }
141
142 void AppEventExtensionInstance::OnDispatchEventFinish(
143     scoped_ptr<XWalkExtensionFunctionInfo> info) {
144   std::string event_name;
145   if (info->arguments()->GetSize() != 1 ||
146       !info->arguments()->GetString(0, &event_name))
147     return;
148
149   scoped_ptr<base::ListValue> args(new base::ListValue());
150   args->AppendString(event_name);
151   scoped_refptr<Event> event = Event::CreateEvent(
152       kOnJavaScriptEventAck, args.Pass());
153   event_manager_->SendEvent(application_->id(), event);
154 }
155
156 void AppEventExtensionInstance::Observe(
157     const std::string& app_id, scoped_refptr<Event> event) {
158   DCHECK(application_->id() == app_id);
159   EventCallbackMap::iterator it = registered_events_.find(event->name());
160   if (it == registered_events_.end())
161     return;
162
163   scoped_ptr<base::ListValue> args(new base::ListValue());
164   args->Append(event->args()->DeepCopy());
165   it->second.Run(args.Pass());
166 }
167
168 }  // namespace application
169 }  // namespace xwalk