fb94b014d0b173900e82c63a4f7571eb7e3027a0
[platform/framework/web/crosswalk.git] / src / xwalk / application / extension / application_widget_extension.cc
1 // Copyright (c) 2014 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_widget_extension.h"
6
7 #include <vector>
8
9 #include "base/bind.h"
10 #include "base/path_service.h"
11 #include "base/strings/stringprintf.h"
12 #include "base/strings/string_util.h"
13 #include "base/strings/utf_string_conversions.h"
14 #include "content/public/browser/browser_thread.h"
15 #include "content/public/browser/render_frame_host.h"
16 #include "content/public/browser/render_process_host.h"
17 #include "content/public/browser/storage_partition.h"
18 #include "content/public/browser/web_contents.h"
19 #include "ipc/ipc_message.h"
20 #include "grit/xwalk_application_resources.h"
21 #include "ui/base/resource/resource_bundle.h"
22 #include "xwalk/application/browser/application.h"
23 #include "xwalk/application/common/application_data.h"
24 #include "xwalk/application/common/application_manifest_constants.h"
25 #include "xwalk/application/common/manifest_handlers/widget_handler.h"
26 #include "xwalk/application/extension/application_widget_storage.h"
27 #include "xwalk/runtime/browser/runtime.h"
28 #include "xwalk/runtime/browser/xwalk_browser_context.h"
29 #include "xwalk/runtime/browser/xwalk_runner.h"
30 #include "xwalk/runtime/common/xwalk_paths.h"
31
32 using content::BrowserThread;
33
34 namespace {
35
36 const char kCommandKey[] = "cmd";
37 const char kWidgetAttributeKey[] = "widgetKey";
38 const char kPreferencesItemKey[] = "preferencesItemKey";
39 const char kPreferencesItemValue[] = "preferencesItemValue";
40
41 void DispatchStorageEvent(
42     base::DictionaryValue* msg,
43     content::WebContents* web_contents,
44     content::RenderFrameHost* frame) {
45   if (frame == web_contents->GetFocusedFrame())
46     return;
47
48   std::string key, oldValue, newValue;
49   msg->GetString("key", &key);
50   msg->GetString("oldValue", &oldValue);
51   msg->GetString("newValue", &newValue);
52
53   std::string code = base::StringPrintf(
54       "(function() {"
55       "  var old_value = '%s' == '' ? null : '%s';"
56       "  var new_value = '%s' == '' ? null : '%s';"
57       "  var event = {"
58       "    key: '%s',"
59       "    oldValue: old_value,"
60       "    newValue: new_value,"
61       "    url: window.location.href,"
62       "    storageArea: widget.preferences"
63       "  };"
64       "  for (var key in event) {"
65       "    Object.defineProperty(event, key, {"
66       "      value: event[key],"
67       "      writable: false"
68       "    });"
69       "  }"
70       "  for (var i = 0; i < window.eventListenerList.length; i++)"
71       "    window.eventListenerList[i](event);"
72       "})();", oldValue.c_str(), oldValue.c_str(),
73       newValue.c_str(), newValue.c_str(), key.c_str());
74
75   frame->ExecuteJavaScript(base::UTF8ToUTF16(code));
76 }
77
78 }  // namespace
79
80 namespace xwalk {
81 namespace application {
82
83 namespace widget_keys = xwalk::application_widget_keys;
84
85 ApplicationWidgetExtension::ApplicationWidgetExtension(
86     Application* application)
87   : application_(application) {
88   set_name("widget");
89   set_javascript_api(ResourceBundle::GetSharedInstance().GetRawDataResource(
90       IDR_XWALK_APPLICATION_WIDGET_API).as_string());
91 }
92
93 XWalkExtensionInstance* ApplicationWidgetExtension::CreateInstance() {
94   return new AppWidgetExtensionInstance(application_);
95 }
96
97 AppWidgetExtensionInstance::AppWidgetExtensionInstance(
98     Application* application)
99   : application_(application) {
100   DCHECK(application_);
101   base::ThreadRestrictions::SetIOAllowed(true);
102
103   content::RenderProcessHost* rph =
104       content::RenderProcessHost::FromID(application->GetRenderProcessHostID());
105   content::StoragePartition* partition = rph->GetStoragePartition();
106   base::FilePath path = partition->GetPath().Append(
107       FILE_PATH_LITERAL("WidgetStorage"));
108   widget_storage_.reset(new AppWidgetStorage(application_, path));
109 }
110
111 AppWidgetExtensionInstance::~AppWidgetExtensionInstance() {}
112
113 void AppWidgetExtensionInstance::HandleMessage(scoped_ptr<base::Value> msg) {
114 }
115
116 void AppWidgetExtensionInstance::HandleSyncMessage(
117     scoped_ptr<base::Value> msg) {
118   base::DictionaryValue* dict;
119   std::string command;
120   msg->GetAsDictionary(&dict);
121
122   if (!msg->GetAsDictionary(&dict) || !dict->GetString(kCommandKey, &command)) {
123     LOG(ERROR) << "Fail to handle command sync message.";
124     SendSyncReplyToJS(scoped_ptr<base::Value>(new base::StringValue("")));
125     return;
126   }
127
128   scoped_ptr<base::Value> result(new base::StringValue(""));
129   if (command == "GetWidgetInfo") {
130     result = GetWidgetInfo(msg.Pass());
131   } else if (command == "SetPreferencesItem") {
132     result = SetPreferencesItem(msg.Pass());
133   } else if (command == "RemovePreferencesItem") {
134     result = RemovePreferencesItem(msg.Pass());
135   } else if (command == "ClearAllItems") {
136     result = ClearAllItems(msg.Pass());
137   } else if (command == "GetAllItems") {
138     result = GetAllItems(msg.Pass());
139   } else if (command == "GetItemValueByKey") {
140     result = GetItemValueByKey(msg.Pass());
141   } else if (command == "KeyExists") {
142     result = KeyExists(msg.Pass());
143   } else {
144     LOG(ERROR) << command << " ASSERT NOT REACHED.";
145   }
146
147   SendSyncReplyToJS(result.Pass());
148 }
149
150 scoped_ptr<base::StringValue> AppWidgetExtensionInstance::GetWidgetInfo(
151     scoped_ptr<base::Value> msg) {
152   scoped_ptr<base::StringValue> result(new base::StringValue(""));
153   std::string key;
154   std::string value;
155   base::DictionaryValue* dict;
156
157   if (!msg->GetAsDictionary(&dict) ||
158       !dict->GetString(kWidgetAttributeKey, &key)) {
159     LOG(ERROR) << "Fail to get widget attribute key.";
160     return result.Pass();
161   }
162
163   WidgetInfo* info =
164       static_cast<WidgetInfo*>(
165       application_->data()->GetManifestData(widget_keys::kWidgetKey));
166   base::DictionaryValue* widget_info = info->GetWidgetInfo();
167   widget_info->GetString(key, &value);
168   result.reset(new base::StringValue(value));
169   return result.Pass();
170 }
171
172 scoped_ptr<base::FundamentalValue>
173 AppWidgetExtensionInstance::SetPreferencesItem(scoped_ptr<base::Value> msg) {
174   scoped_ptr<base::FundamentalValue> result(
175       new base::FundamentalValue(false));
176   std::string key;
177   std::string value;
178   base::DictionaryValue* dict;
179
180   if (!msg->GetAsDictionary(&dict) ||
181       !dict->GetString(kPreferencesItemKey, &key) ||
182       !dict->GetString(kPreferencesItemValue, &value)) {
183     LOG(ERROR) << "Fail to set preferences item.";
184     return result.Pass();
185   }
186
187   std::string old_value;
188   if (!widget_storage_->GetValueByKey(key, &old_value)) {
189     old_value = "";
190   }
191   if (old_value == value) {
192     LOG(WARNING) << "You are trying to set the same value."
193                  << " Nothing will be done.";
194     result.reset(new base::FundamentalValue(true));
195     return result.Pass();
196   }
197   if (widget_storage_->AddEntry(key, value, false)) {
198     result.reset(new base::FundamentalValue(true));
199
200     scoped_ptr<base::DictionaryValue> event(new base::DictionaryValue());
201     event->SetString("key", key);
202     event->SetString("oldValue", old_value);
203     event->SetString("newValue", value);
204     PostMessageToOtherFrames(event.Pass());
205   }
206
207   return result.Pass();
208 }
209
210 scoped_ptr<base::FundamentalValue>
211 AppWidgetExtensionInstance::RemovePreferencesItem(scoped_ptr<base::Value> msg) {
212   scoped_ptr<base::FundamentalValue> result(
213       new base::FundamentalValue(false));
214   std::string key;
215   base::DictionaryValue* dict;
216
217   if (!msg->GetAsDictionary(&dict) ||
218       !dict->GetString(kPreferencesItemKey, &key)) {
219     LOG(ERROR) << "Fail to remove preferences item.";
220     return result.Pass();
221   }
222
223   std::string old_value;
224   if (!widget_storage_->GetValueByKey(key, &old_value)) {
225     LOG(WARNING) << "You are trying to remove an entry which doesn't exist."
226                  << " Nothing will be done.";
227     result.reset(new base::FundamentalValue(true));
228     return result.Pass();
229   }
230
231   if (widget_storage_->RemoveEntry(key)) {
232     result.reset(new base::FundamentalValue(true));
233
234     scoped_ptr<base::DictionaryValue> event(new base::DictionaryValue());
235     event->SetString("key", key);
236     event->SetString("oldValue", old_value);
237     event->SetString("newValue", "");
238     PostMessageToOtherFrames(event.Pass());
239   }
240
241   return result.Pass();
242 }
243
244 scoped_ptr<base::FundamentalValue> AppWidgetExtensionInstance::ClearAllItems(
245     scoped_ptr<base::Value> msg) {
246   scoped_ptr<base::FundamentalValue> result(
247       new base::FundamentalValue(false));
248
249   scoped_ptr<base::DictionaryValue> entries(new base::DictionaryValue());
250   widget_storage_->GetAllEntries(entries.get());
251
252   if (!widget_storage_->Clear())
253     return result.Pass();
254
255   for (base::DictionaryValue::Iterator it(*(entries.get()));
256       !it.IsAtEnd(); it.Advance()) {
257     std::string key = it.key();
258     if (!widget_storage_->EntryExists(key)) {
259       std::string old_value;
260       it.value().GetAsString(&old_value);
261       scoped_ptr<base::DictionaryValue> event(new base::DictionaryValue());
262       event->SetString("key", key);
263       event->SetString("oldValue", old_value);
264       event->SetString("newValue", "");
265       PostMessageToOtherFrames(event.Pass());
266     }
267   }
268
269   result.reset(new base::FundamentalValue(true));
270   return result.Pass();
271 }
272
273 scoped_ptr<base::DictionaryValue> AppWidgetExtensionInstance::GetAllItems(
274     scoped_ptr<base::Value> msg) {
275   scoped_ptr<base::DictionaryValue> result(new base::DictionaryValue());
276   widget_storage_->GetAllEntries(result.get());
277
278   return result.Pass();
279 }
280
281 scoped_ptr<base::StringValue> AppWidgetExtensionInstance::GetItemValueByKey(
282     scoped_ptr<base::Value> msg) {
283   base::DictionaryValue* dict;
284   msg->GetAsDictionary(&dict);
285
286   std::string key;
287   std::string value;
288   if (!dict->GetString(kPreferencesItemKey, &key) ||
289       !widget_storage_->GetValueByKey(key, &value))
290     value = "";
291   scoped_ptr<base::StringValue> result(new base::StringValue(value));
292   return result.Pass();
293 }
294
295 scoped_ptr<base::FundamentalValue> AppWidgetExtensionInstance::KeyExists(
296     scoped_ptr<base::Value> msg) const {
297   scoped_ptr<base::FundamentalValue> result(
298       new base::FundamentalValue(false));
299   std::string key;
300   base::DictionaryValue* dict;
301
302   if (!msg->GetAsDictionary(&dict) ||
303       !dict->GetString(kPreferencesItemKey, &key)) {
304     LOG(ERROR) << "Fail to remove preferences item.";
305     return result.Pass();
306   }
307
308   if (widget_storage_->EntryExists(key))
309     result.reset(new base::FundamentalValue(true));
310
311   return result.Pass();
312 }
313
314 void AppWidgetExtensionInstance::PostMessageToOtherFrames(
315     scoped_ptr<base::DictionaryValue> msg) {
316   const std::vector<Runtime*>& runtime_set = application_->runtimes();
317   std::vector<Runtime*>::const_iterator it;
318   for (it = runtime_set.begin(); it != runtime_set.end(); ++it) {
319     content::WebContents* web_contents = (*it)->web_contents();
320     web_contents->ForEachFrame(base::Bind(&DispatchStorageEvent,
321                                           msg.get(),
322                                           web_contents));
323   }
324 }
325
326 }  // namespace application
327 }  // namespace xwalk