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.
5 #include "xwalk/application/extension/application_widget_extension.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"
32 using content::BrowserThread;
36 const char kCommandKey[] = "cmd";
37 const char kWidgetAttributeKey[] = "widgetKey";
38 const char kPreferencesItemKey[] = "preferencesItemKey";
39 const char kPreferencesItemValue[] = "preferencesItemValue";
41 void DispatchStorageEvent(
42 base::DictionaryValue* msg,
43 content::WebContents* web_contents,
44 content::RenderFrameHost* frame) {
45 if (frame == web_contents->GetFocusedFrame())
48 std::string key, oldValue, newValue;
49 msg->GetString("key", &key);
50 msg->GetString("oldValue", &oldValue);
51 msg->GetString("newValue", &newValue);
53 std::string code = base::StringPrintf(
55 " var old_value = '%s' == '' ? null : '%s';"
56 " var new_value = '%s' == '' ? null : '%s';"
59 " oldValue: old_value,"
60 " newValue: new_value,"
61 " url: window.location.href,"
62 " storageArea: widget.preferences"
64 " for (var key in event) {"
65 " Object.defineProperty(event, key, {"
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());
75 frame->ExecuteJavaScript(base::UTF8ToUTF16(code));
81 namespace application {
83 namespace widget_keys = xwalk::application_widget_keys;
85 ApplicationWidgetExtension::ApplicationWidgetExtension(
86 Application* application)
87 : application_(application) {
89 set_javascript_api(ResourceBundle::GetSharedInstance().GetRawDataResource(
90 IDR_XWALK_APPLICATION_WIDGET_API).as_string());
93 XWalkExtensionInstance* ApplicationWidgetExtension::CreateInstance() {
94 return new AppWidgetExtensionInstance(application_);
97 AppWidgetExtensionInstance::AppWidgetExtensionInstance(
98 Application* application)
99 : application_(application) {
100 DCHECK(application_);
101 base::ThreadRestrictions::SetIOAllowed(true);
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));
111 AppWidgetExtensionInstance::~AppWidgetExtensionInstance() {}
113 void AppWidgetExtensionInstance::HandleMessage(scoped_ptr<base::Value> msg) {
116 void AppWidgetExtensionInstance::HandleSyncMessage(
117 scoped_ptr<base::Value> msg) {
118 base::DictionaryValue* dict;
120 msg->GetAsDictionary(&dict);
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("")));
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());
144 LOG(ERROR) << command << " ASSERT NOT REACHED.";
147 SendSyncReplyToJS(result.Pass());
150 scoped_ptr<base::StringValue> AppWidgetExtensionInstance::GetWidgetInfo(
151 scoped_ptr<base::Value> msg) {
152 scoped_ptr<base::StringValue> result(new base::StringValue(""));
155 base::DictionaryValue* dict;
157 if (!msg->GetAsDictionary(&dict) ||
158 !dict->GetString(kWidgetAttributeKey, &key)) {
159 LOG(ERROR) << "Fail to get widget attribute key.";
160 return result.Pass();
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();
172 scoped_ptr<base::FundamentalValue>
173 AppWidgetExtensionInstance::SetPreferencesItem(scoped_ptr<base::Value> msg) {
174 scoped_ptr<base::FundamentalValue> result(
175 new base::FundamentalValue(false));
178 base::DictionaryValue* dict;
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();
187 std::string old_value;
188 if (!widget_storage_->GetValueByKey(key, &old_value)) {
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();
197 if (widget_storage_->AddEntry(key, value, false)) {
198 result.reset(new base::FundamentalValue(true));
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());
207 return result.Pass();
210 scoped_ptr<base::FundamentalValue>
211 AppWidgetExtensionInstance::RemovePreferencesItem(scoped_ptr<base::Value> msg) {
212 scoped_ptr<base::FundamentalValue> result(
213 new base::FundamentalValue(false));
215 base::DictionaryValue* dict;
217 if (!msg->GetAsDictionary(&dict) ||
218 !dict->GetString(kPreferencesItemKey, &key)) {
219 LOG(ERROR) << "Fail to remove preferences item.";
220 return result.Pass();
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();
231 if (widget_storage_->RemoveEntry(key)) {
232 result.reset(new base::FundamentalValue(true));
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());
241 return result.Pass();
244 scoped_ptr<base::FundamentalValue> AppWidgetExtensionInstance::ClearAllItems(
245 scoped_ptr<base::Value> msg) {
246 scoped_ptr<base::FundamentalValue> result(
247 new base::FundamentalValue(false));
249 scoped_ptr<base::DictionaryValue> entries(new base::DictionaryValue());
250 widget_storage_->GetAllEntries(entries.get());
252 if (!widget_storage_->Clear())
253 return result.Pass();
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());
269 result.reset(new base::FundamentalValue(true));
270 return result.Pass();
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());
278 return result.Pass();
281 scoped_ptr<base::StringValue> AppWidgetExtensionInstance::GetItemValueByKey(
282 scoped_ptr<base::Value> msg) {
283 base::DictionaryValue* dict;
284 msg->GetAsDictionary(&dict);
288 if (!dict->GetString(kPreferencesItemKey, &key) ||
289 !widget_storage_->GetValueByKey(key, &value))
291 scoped_ptr<base::StringValue> result(new base::StringValue(value));
292 return result.Pass();
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));
300 base::DictionaryValue* dict;
302 if (!msg->GetAsDictionary(&dict) ||
303 !dict->GetString(kPreferencesItemKey, &key)) {
304 LOG(ERROR) << "Fail to remove preferences item.";
305 return result.Pass();
308 if (widget_storage_->EntryExists(key))
309 result.reset(new base::FundamentalValue(true));
311 return result.Pass();
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,
326 } // namespace application