7f11417bcf044352cf1d13ddb40ea75ef53838a2
[platform/framework/web/crosswalk.git] / src / xwalk / application / browser / application.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/browser/application.h"
6
7 #include <string>
8
9 #include "base/json/json_reader.h"
10 #include "base/message_loop/message_loop.h"
11 #include "base/stl_util.h"
12 #include "base/values.h"
13 #include "content/public/browser/web_contents.h"
14 #include "content/public/browser/render_process_host.h"
15 #include "net/base/net_util.h"
16 #include "xwalk/application/browser/application_event_manager.h"
17 #include "xwalk/application/browser/application_service.h"
18 #include "xwalk/application/browser/application_storage.h"
19 #include "xwalk/application/browser/application_system.h"
20 #include "xwalk/application/common/application_manifest_constants.h"
21 #include "xwalk/application/common/constants.h"
22 #include "xwalk/application/common/manifest_handlers/main_document_handler.h"
23 #include "xwalk/application/common/event_names.h"
24 #include "xwalk/runtime/browser/runtime.h"
25 #include "xwalk/runtime/browser/runtime_context.h"
26 #include "xwalk/runtime/browser/xwalk_runner.h"
27
28 namespace xwalk {
29
30 namespace keys = application_manifest_keys;
31 namespace widget_keys = application_widget_keys;
32
33 namespace application {
34
35 class FinishEventObserver : public EventObserver {
36  public:
37   FinishEventObserver(
38       ApplicationEventManager* event_manager,
39       Application* application)
40       : EventObserver(event_manager),
41         application_(application) {
42   }
43
44   virtual void Observe(const std::string& app_id,
45                        scoped_refptr<Event> event) OVERRIDE {
46     DCHECK(xwalk::application::kOnJavaScriptEventAck == event->name());
47     std::string ack_event_name;
48     event->args()->GetString(0, &ack_event_name);
49     if (ack_event_name == xwalk::application::kOnSuspend)
50       application_->CloseMainDocument();
51   }
52
53  private:
54   Application* application_;
55 };
56
57 Application::Application(
58     scoped_refptr<ApplicationData> data,
59     RuntimeContext* runtime_context,
60     Observer* observer)
61     : runtime_context_(runtime_context),
62       application_data_(data),
63       main_runtime_(NULL),
64       observer_(observer),
65       entry_point_used_(Default),
66       termination_mode_used_(Normal),
67       weak_factory_(this) {
68   DCHECK(runtime_context_);
69   DCHECK(application_data_);
70   DCHECK(observer_);
71 }
72
73 Application::~Application() {
74   Terminate(Immediate);
75 }
76
77 bool Application::Launch(const LaunchParams& launch_params) {
78   if (!runtimes_.empty()) {
79     LOG(ERROR) << "Attempt to launch app: " << id()
80                << " that was already launched.";
81     return false;
82   }
83
84   GURL url = GetURLForLaunch(launch_params, &entry_point_used_);
85   if (!url.is_valid())
86     return false;
87
88   main_runtime_ = Runtime::Create(runtime_context_, this);
89   main_runtime_->LoadURL(url);
90   if (entry_point_used_ != AppMainKey) {
91     NativeAppWindow::CreateParams params;
92     params.net_wm_pid = launch_params.launcher_pid;
93     main_runtime_->AttachWindow(params);
94   }
95
96   return true;
97 }
98
99 GURL Application::GetURLForLaunch(const LaunchParams& params,
100                                   LaunchEntryPoint* used) {
101   if (params.entry_points & AppMainKey) {
102     GURL url = GetURLFromAppMainKey();
103     if (url.is_valid()) {
104       *used = AppMainKey;
105       return url;
106     }
107   }
108
109   if (params.entry_points & LaunchLocalPathKey) {
110     GURL url = GetURLFromLocalPathKey();
111     if (url.is_valid()) {
112       *used = LaunchLocalPathKey;
113       return url;
114     }
115   }
116
117   if (params.entry_points & URLKey) {
118     GURL url = GetURLFromURLKey();
119     if (url.is_valid()) {
120       *used = URLKey;
121       return url;
122     }
123   }
124   LOG(WARNING) << "Failed to find a valid launch URL for the app.";
125   return GURL();
126 }
127
128 GURL Application::GetURLFromAppMainKey() {
129   MainDocumentInfo* main_info = ToMainDocumentInfo(
130     application_data_->GetManifestData(keys::kAppMainKey));
131   if (!main_info)
132     return GURL();
133
134   DCHECK(application_data_->HasMainDocument());
135   return main_info->GetMainURL();
136 }
137
138 GURL Application::GetURLFromLocalPathKey() {
139   const Manifest* manifest = application_data_->GetManifest();
140   std::string entry_page;
141   std::string key(GetLaunchLocalPathKey(
142       application_data_->GetPackageType()));
143
144   if (!manifest->GetString(key, &entry_page)
145       || entry_page.empty())
146     return GURL();
147
148   return application_data_->GetResourceURL(entry_page);
149 }
150
151 GURL Application::GetURLFromURLKey() {
152   const Manifest* manifest = application_data_->GetManifest();
153   std::string url_string;
154   if (!manifest->GetString(keys::kURLKey, &url_string))
155     return GURL();
156
157   return GURL(url_string);
158 }
159
160 void Application::Terminate(TerminationMode mode) {
161   termination_mode_used_ = mode;
162   if (IsTerminating()) {
163     LOG(WARNING) << "Attempt to Terminate app: " << id()
164                  << ", which is already in the process of being terminated.";
165     if (mode == Immediate)
166       CloseMainDocument();
167
168     return;
169   }
170
171   std::set<Runtime*> to_be_closed(runtimes_);
172   if (HasMainDocument() && to_be_closed.size() > 1) {
173     // The main document runtime is closed separately
174     // (needs some extra logic) in Application::OnRuntimeRemoved.
175     to_be_closed.erase(main_runtime_);
176   }
177
178   std::for_each(to_be_closed.begin(), to_be_closed.end(),
179                 std::mem_fun(&Runtime::Close));
180 }
181
182 Runtime* Application::GetMainDocumentRuntime() const {
183   return HasMainDocument() ? main_runtime_ : NULL;
184 }
185
186 int Application::GetRenderProcessHostID() const {
187   DCHECK(main_runtime_);
188   return main_runtime_->web_contents()->
189           GetRenderProcessHost()->GetID();
190 }
191
192 bool Application::HasMainDocument() const {
193   return entry_point_used_ == AppMainKey;
194 }
195
196 void Application::OnRuntimeAdded(Runtime* runtime) {
197   DCHECK(runtime);
198   runtimes_.insert(runtime);
199 }
200
201 void Application::OnRuntimeRemoved(Runtime* runtime) {
202   DCHECK(runtime);
203   runtimes_.erase(runtime);
204
205   if (runtimes_.empty()) {
206 #if defined(OS_TIZEN)
207     runtime->CloseRootWindow();
208 #endif
209     base::MessageLoop::current()->PostTask(FROM_HERE,
210         base::Bind(&Application::NotifyTermination,
211                    weak_factory_.GetWeakPtr()));
212     return;
213   }
214
215   if (runtimes_.size() == 1 && HasMainDocument() &&
216       ContainsKey(runtimes_, main_runtime_)) {
217     ApplicationSystem* system = XWalkRunner::GetInstance()->app_system();
218     ApplicationEventManager* event_manager = system->event_manager();
219
220     // If onSuspend is not registered in main document,
221     // we close the main document immediately.
222     if (!IsOnSuspendHandlerRegistered() ||
223         termination_mode_used_ == Immediate) {
224       CloseMainDocument();
225       return;
226     }
227
228     DCHECK(!finish_observer_);
229     finish_observer_.reset(
230         new FinishEventObserver(event_manager, this));
231     event_manager->AttachObserver(
232         application_data_->ID(), kOnJavaScriptEventAck,
233         finish_observer_.get());
234
235     scoped_ptr<base::ListValue> event_args(new base::ListValue);
236     scoped_refptr<Event> event = Event::CreateEvent(
237         xwalk::application::kOnSuspend, event_args.Pass());
238     event_manager->SendEvent(application_data_->ID(), event);
239   }
240 }
241
242 void Application::CloseMainDocument() {
243   DCHECK(main_runtime_);
244
245   finish_observer_.reset();
246   main_runtime_->Close();
247   main_runtime_ = NULL;
248 }
249
250 void Application::NotifyTermination() {
251   observer_->OnApplicationTerminated(this);
252 }
253
254 bool Application::IsOnSuspendHandlerRegistered() const {
255   const std::set<std::string>& events = data()->GetEvents();
256   if (events.find(kOnSuspend) == events.end())
257     return false;
258
259   return true;
260 }
261
262 bool Application::UseExtension(const std::string& extension_name) const {
263   // TODO(Bai): Tells whether the application contains the specified extension
264   return true;
265 }
266
267 bool Application::RegisterPermissions(const std::string& extension_name,
268                                       const std::string& perm_table) {
269   // TODO(Bai): Parse the permission table and fill in the name_perm_map_
270   // The perm_table format is a simple JSON string, like
271   // [{"permission_name":"echo","apis":["add","remove","get"]}]
272   scoped_ptr<base::Value> root;
273   root.reset(base::JSONReader().ReadToValue(perm_table));
274   if (root.get() == NULL || !root->IsType(base::Value::TYPE_LIST))
275     return false;
276
277   base::ListValue* permission_list = static_cast<base::ListValue*>(root.get());
278   if (permission_list->GetSize() == 0)
279     return false;
280
281   for (base::ListValue::const_iterator iter = permission_list->begin();
282       iter != permission_list->end(); ++iter) {
283     if (!(*iter)->IsType(base::Value::TYPE_DICTIONARY))
284         return false;
285
286     base::DictionaryValue* dict_val =
287         static_cast<base::DictionaryValue*>(*iter);
288     std::string permission_name;
289     if (!dict_val->GetString("permission_name", &permission_name))
290       return false;
291
292     base::ListValue* api_list = NULL;
293     if (!dict_val->GetList("apis", &api_list))
294       return false;
295
296     for (base::ListValue::const_iterator api_iter = api_list->begin();
297         api_iter != api_list->end(); ++api_iter) {
298       std::string api;
299       if (!((*api_iter)->IsType(base::Value::TYPE_STRING)
300           && (*api_iter)->GetAsString(&api)))
301         return false;
302       // register the permission and api
303       name_perm_map_[api] = permission_name;
304       DLOG(INFO) << "Permission Registered [PERM] " << permission_name
305                  << " [API] " << api;
306     }
307   }
308
309   return true;
310 }
311
312 std::string Application::GetRegisteredPermissionName(
313     const std::string& extension_name,
314     const std::string& api_name) const {
315   std::map<std::string, std::string>::const_iterator iter =
316       name_perm_map_.find(api_name);
317   if (iter == name_perm_map_.end())
318     return std::string("");
319   return iter->second;
320 }
321
322 StoredPermission Application::GetPermission(PermissionType type,
323                                std::string& permission_name) const {
324   if (type == SESSION_PERMISSION) {
325     StoredPermissionMap::const_iterator iter =
326         permission_map_.find(permission_name);
327     if (iter == permission_map_.end())
328       return UNDEFINED_STORED_PERM;
329     return iter->second;
330   }
331   if (type == PERSISTENT_PERMISSION) {
332     return application_data_->GetPermission(permission_name);
333   }
334   NOTREACHED();
335   return UNDEFINED_STORED_PERM;
336 }
337
338 bool Application::SetPermission(PermissionType type,
339                                 const std::string& permission_name,
340                                 StoredPermission perm) {
341   if (type == SESSION_PERMISSION) {
342     permission_map_[permission_name] = perm;
343     return true;
344   }
345   if (type == PERSISTENT_PERMISSION)
346     return application_data_->SetPermission(permission_name, perm);
347
348   NOTREACHED();
349   return false;
350 }
351
352 }  // namespace application
353 }  // namespace xwalk