922a89eec438e37ff77154ba0bf6cc2853d199ee
[apps/agl-service-windowmanager-2017.git] / src / applist.cpp
1 /*
2  * Copyright (c) 2017 TOYOTA MOTOR CORPORATION
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 #include <iostream>
17 #include <algorithm>
18 #include "applist.hpp"
19 #include "util.hpp"
20
21 using std::shared_ptr;
22 using std::string;
23 using std::vector;
24
25 namespace wm
26 {
27
28 const static int kReserveClientSize = 100;
29 const static int kReserveReqSize    = 10;
30
31 /**
32  * AppList Constructor.
33  *
34  * Reserve the container size to avoid re-allocating memory.
35  *
36  * @note Size should be changed according to the system.
37  *       If the number of applications becomes over the size, re-allocating memory will happen.
38  */
39 AppList::AppList()
40     : req_list(),
41       app2client(),
42       current_req(1)
43 {
44     this->app2client.reserve(kReserveClientSize);
45     this->req_list.reserve(kReserveReqSize);
46 }
47
48 AppList::~AppList() {}
49
50 // =================== Client Date container API ===================
51
52 /**
53  * Add Client to the list
54  *
55  * Add Client to the list.
56  * The Client means application which has role, layer, surface
57  * This function should be called once for the app.
58  * Caller should take care not to be called more than once.
59  *
60  * @param     string[in]   Application id. This will be the key to withdraw the information.
61  * @param     unsigned[in] Layer ID in which the application is
62  * @param     unsigned[in] surface ID which the application has
63  * @param     string[in]   Role which means what behavior the application will do.
64  * @return    None
65  * @attention This function should be called once for the app
66  *            Caller should take care not to be called more than once.
67  */
68 void AppList::addClient(const string &appid, unsigned layer, unsigned surface, const string &role)
69 {
70     std::lock_guard<std::mutex> lock(this->mtx);
71     shared_ptr<WMClient> client = std::make_shared<WMClient>(appid, layer, surface, role);
72     this->app2client[appid] = client;
73     this->clientDump();
74 }
75
76 void AppList::addClient(const string &appid, unsigned layer, const string &role)
77 {
78     std::lock_guard<std::mutex> lock(this->mtx);
79     shared_ptr<WMClient> client = std::make_shared<WMClient>(appid, layer, role);
80     this->app2client[appid] = client;
81     this->clientDump();
82 }
83
84 /**
85  * Remove WMClient from the list
86  *
87  * @param string[in] Application id. This will be the key to withdraw the information.
88  */
89 void AppList::removeClient(const string &appid)
90 {
91     std::lock_guard<std::mutex> lock(this->mtx);
92     this->app2client.erase(appid);
93     HMI_INFO("Remove client %s", appid.c_str());
94 }
95
96 /**
97  * Check this class stores the appid.
98  *
99  * @param     string[in] Application id. This will be the key to withdraw the information.
100  * @return    true if the class has the requested key(appid)
101  */
102 bool AppList::contains(const string &appid) const
103 {
104     auto result = this->app2client.find(appid);
105     return (this->app2client.end() != result) ? true : false;
106 }
107
108 /**
109  * Remove surface from client
110  *
111  * @param     unsigned[in] surface id.
112  * @return    None
113  */
114 void AppList::removeSurface(unsigned surface){
115     // This function may be very slow
116     std::lock_guard<std::mutex> lock(this->mtx);
117     bool ret = false;
118     for (auto &x : this->app2client)
119     {
120         ret = x.second->removeSurfaceIfExist(surface);
121         if(ret){
122             HMI_DEBUG("remove surface %d from Client %s finish",
123                         surface, x.second->appID().c_str());
124             break;
125         }
126     }
127
128 }
129
130 /**
131  * Get WMClient object.
132  *
133  * After get the WMClient object, caller can call the client method.
134  * Before call this function, caller must call "contains"
135  * to check the key is contained, otherwise, you have to take care of std::out_of_range.
136  *
137  * @param     string[in] application id(key)
138  * @return    WMClient object
139  * @attention Must call cantains to check appid is stored before this function.
140  */
141 shared_ptr<WMClient> AppList::lookUpClient(const string &appid)
142 {
143     return this->app2client.at(appid);
144 }
145
146 /**
147  * Count Client.
148  *
149  * Returns the number of client stored in the list.
150  *
151  * @param  None
152  * @return The number of client
153  */
154 int AppList::countClient() const
155 {
156     return this->app2client.size();
157 }
158
159 /**
160  * Get AppID with surface and role.
161  *
162  * Returns AppID if found.
163  *
164  * @param     unsigned[in] surfaceID
165  * @param     string[in]   role
166  * @param     bool[in,out] AppID is found or not
167  * @return    AppID
168  * @attention If AppID is not found, param found will be false.
169  */
170 /* string AppList::getAppID(unsigned surface, const string& role, bool* found) const
171 {
172     *found = false;
173     for (const auto &x : this->app2client)
174     {
175         if(x.second->surfaceID(role) == surface){
176             *found = true;
177             return x.second->appID();
178         }
179     }
180     return string("");
181 } */
182
183 string AppList::getAppID(unsigned surface, bool* found) const
184 {
185     *found = false;
186     for (const auto &x : this->app2client)
187     {
188         if(x.second->surfaceID() == surface){
189             *found = true;
190             return x.second->appID();
191         }
192     }
193     return string("");
194 }
195
196 WMError AppList::popFloatingSurface(unsigned pid, unsigned *surface)
197 {
198     WMError ret = WMError::NO_ENTRY;
199
200     auto fwd_itr = std::remove_if(this->floating_surfaces.begin(), this->floating_surfaces.end(),
201                                     [pid, surface, &ret](FloatingSurface x) {
202                                         if(pid == x.pid){
203                                             *surface = x.surface_id;
204                                             ret = WMError::SUCCESS;
205                                             return true;
206                                         }
207                                         else{
208                                             return false;
209                                         }
210                                     });
211     if (fwd_itr != this->floating_surfaces.cend())
212     {
213         HMI_INFO("pop floating surface: %d", *surface);
214     }
215     this->floating_surfaces.erase(fwd_itr, this->floating_surfaces.end());
216     return ret;
217 }
218
219 // =================== Floating(Temporary) surface/client API ===================
220
221 WMError AppList::popFloatingSurface(const string &appid, unsigned *surface)
222 {
223     HMI_ERROR("This function is not implemented");
224     return WMError::SUCCESS;
225 }
226
227 void AppList::addFloatingClient(const string &appid, unsigned layer, const string &role)
228 {
229 }
230
231 void AppList::addFloatingSurface(const string &appid, unsigned surface, unsigned pid)
232 {
233     struct FloatingSurface fsurface{appid, surface, pid};
234     this->floating_surfaces.push_back(fsurface);
235     this->dumpFloatingSurfaces();
236 }
237
238 void AppList::removeFloatingSurface(unsigned surface)
239 {
240     this->dumpFloatingSurfaces();
241     auto fwd_itr = std::remove_if(
242         this->floating_surfaces.begin(), this->floating_surfaces.end(),
243         [surface](FloatingSurface x) {
244             return x.surface_id == surface;
245         });
246     if(fwd_itr != this->floating_surfaces.cend()){
247         HMI_INFO("remove floating surface: %d", surface);
248     }
249     this->floating_surfaces.erase(fwd_itr, this->floating_surfaces.end());
250 }
251
252 WMError AppList::appendRole(const string &id, const string &role)
253 {
254     WMError wm_err = WMError::NO_ENTRY;
255     if (this->contains(id))
256     {
257         auto x = this->lookUpClient(id);
258         x->appendRole(role);
259         wm_err = WMError::SUCCESS;
260     }
261     return wm_err;
262 }
263
264
265 // =================== Request Date container API ===================
266
267 /**
268  * Get current request number
269  *
270  * Request number is the numeric ID to designate the request.
271  * But returned request number from this function doesn't mean the request exists.
272  * This number is used as key to withdraw the WMRequest object.
273  *
274  * @param  None
275  * @return current request number.
276  * @note   request number is more than 0.
277  */
278 unsigned AppList::currentRequestNumber() const
279 {
280     return this->current_req;
281 }
282
283 /**
284  * Get request number
285  *
286  * Request number is the numeric ID to designate the request.
287  * But returned request number from this function doesn't mean the request exists.
288  * This number is used as key to withdraw the WMRequest object.
289  *
290  * @param     None
291  * @return    request number.
292  * @attention If returned value is 0, no request exists.
293  */
294 unsigned AppList::getRequestNumber(const string &appid) const
295 {
296     for (const auto &x : this->req_list)
297     {
298         // Since app will not request twice and more, comparing appid is enough?
299         if ((x.trigger.appid == appid))
300         {
301             return x.req_num;
302         }
303     }
304     return 0;
305 }
306
307 /**
308  * Add Request
309  *
310  * Request number is the numeric ID to designate the request.
311  * But returned request number from this function doesn't mean the request exists.
312  * This number is used as key to withdraw the WMRequest object.
313  *
314  * @param     WMRequest[in] WMRequest object caller creates
315  * @return    Request number
316  * @attention If the request number is different with curent request number,
317  *            it means the previous request is not finished.
318  */
319 unsigned AppList::addRequest(WMRequest req)
320 {
321     std::lock_guard<std::mutex> lock(this->mtx);
322     if (this->req_list.size() == 0)
323     {
324         req.req_num = current_req;
325     }
326     else
327     {
328         HMI_SEQ_INFO(this->current_req, "add: %d", this->req_list.back().req_num + 1);
329         req.req_num = this->req_list.back().req_num + 1;
330     }
331     this->req_list.push_back(req);
332     return req.req_num;
333 }
334
335 /**
336  * Get trigger which the application requests
337  *
338  * WMTrigger contains which application requests what role and where to put(area) and task.
339  * This is used for input event to Window Policy Manager(state machine).
340  *
341  * @param     unsigned[in] request number
342  * @param     bool[in,out] Check request number of the parameter is valid.
343  * @return    WMTrigger which associates with the request number
344  * @attention If the request number is not valid, parameter "found" is false
345  *            and return value will be meaningless value.
346  *            Caller can check the request parameter is valid.
347  */
348 struct WMTrigger AppList::getRequest(unsigned req_num, bool *found)
349 {
350     *found = false;
351     for (const auto &x : this->req_list)
352     {
353         if (req_num == x.req_num)
354         {
355             *found = true;
356             return x.trigger;
357         }
358     }
359     HMI_SEQ_ERROR(req_num, "Couldn't get request : %d", req_num);
360     return WMTrigger{"", "", "", Task::TASK_INVALID};
361 }
362
363 /**
364  * Get actions which the application requests
365  *
366  * WMAciton contains the information of state transition.
367  * In other words, it contains actions of Window Manager,
368  * which role should be put to the area.
369  *
370  * @param     unsigned[in] request number
371  * @param     bool[in,out] Check request number of the parameter is valid.
372  * @return    WMTrigger which associates with the request number
373  * @attention If the request number is not valid, parameter "found" is false
374  *            and return value will be no reference pointer.
375  *            Caller must check the request parameter is valid.
376  */
377 const vector<struct WMAction> &AppList::getActions(unsigned req_num, bool* found)
378 {
379     *found = false;
380     for (auto &x : this->req_list)
381     {
382         if (req_num == x.req_num)
383         {
384             *found = true;
385             return x.sync_draw_req;
386         }
387     }
388     HMI_SEQ_ERROR(req_num, "Couldn't get action with the request : %d", req_num);
389 }
390
391 /**
392  * Set actions to the request.
393  *
394  * Add actions to the request.
395  * This function can be called many times, and actions increase.
396  * This function is used for decision of actions of Window Manager
397  * according to the result of Window Policy Manager.
398  *
399  * @param     unsigned[in] request number
400  * @param     WMAction[in] Action of Window Manager.
401  * @return    WMError If request number is not valid, FAIL will be returned.
402  */
403 WMError AppList::setAction(unsigned req_num, const struct WMAction &action)
404 {
405     std::lock_guard<std::mutex> lock(this->mtx);
406     WMError result = WMError::FAIL;
407     for (auto &x : this->req_list)
408     {
409         if (req_num != x.req_num)
410         {
411             continue;
412         }
413         x.sync_draw_req.push_back(action);
414         result = WMError::SUCCESS;
415         break;
416     }
417     return result;
418 }
419
420 /**
421  * Note:
422  * @note This function set action with parameters.
423  *       If visible is true, it means app should be visible, so enddraw_finished parameter should be false.
424  *       otherwise (visible is false) app should be invisible. Then enddraw_finished param is set to true.
425  *       This function doesn't support actions for focus yet.
426  */
427 /**
428  * Set actions to the request.
429  *
430  * This function is overload function.
431  * The feature is same as other one.
432  *
433  * @param     unsigned[in] request number
434  * @param     string[in]   application id
435  * @param     string[in]   role
436  * @param     string[in]   area
437  * @param     Task[in]     the role should be visible or not.
438  * @return    WMError If request number is not valid, FAIL will be returned.
439  * @attention This function set action with parameters, then caller doesn't need to create WMAction object.
440  *            If visible is true, it means app should be visible, so enddraw_finished parameter will be false.
441  *            otherwise (visible is false) app should be invisible. Then enddraw_finished param is set to true.
442  *            This function doesn't support actions for focus yet.
443  */
444 WMError AppList::setAction(unsigned req_num, shared_ptr<WMClient> client, const string &role, const string &area, TaskVisible visible)
445 {
446     std::lock_guard<std::mutex> lock(this->mtx);
447     WMError result = WMError::FAIL;
448     for (auto &x : req_list)
449     {
450         if (req_num != x.req_num)
451         {
452             continue;
453         }
454         // If visible task is not invisible, redraw is required -> true
455         bool edraw_f = (visible != TaskVisible::INVISIBLE) ? false : true;
456         WMAction action{req_num, client, role, area, visible, edraw_f};
457
458         x.sync_draw_req.push_back(action);
459         result = WMError::SUCCESS;
460         break;
461     }
462     return result;
463 }
464
465 /**
466  * Set end_draw_finished param is true
467  *
468  * This function checks
469  *   - req_num is equal to current request number
470  *   - appid and role are equeal to the appid and role stored in action list
471  * If it is valid, set the action is finished.
472  *
473  * @param  unsigned[in] request number
474  * @param  string[in]   application id
475  * @param  string[in]   role
476  * @return If the parameters are not valid in action list, returns false
477  */
478 bool AppList::setEndDrawFinished(unsigned req_num, const string &appid, const string &role)
479 {
480     std::lock_guard<std::mutex> lock(this->mtx);
481     bool result = false;
482     for (auto &x : req_list)
483     {
484         if (req_num < x.req_num)
485         {
486             break;
487         }
488         if (req_num == x.req_num)
489         {
490             for (auto &y : x.sync_draw_req)
491             {
492                 if (y.client->appID() == appid && y.role == role)
493                 {
494                     HMI_SEQ_INFO(req_num, "Role %s finish redraw", y.role.c_str());
495                     y.end_draw_finished = true;
496                     result = true;
497                 }
498             }
499         }
500     }
501     this->reqDump();
502     return result;
503 }
504
505 /**
506  * Check all actions of the requested sequence is finished
507  *
508  * @param  unsigned[in] request_number
509  * @return true if all action is set.
510  */
511 bool AppList::endDrawFullfilled(unsigned req_num)
512 {
513     bool result = false;
514     for (const auto &x : req_list)
515     {
516         if (req_num < x.req_num)
517         {
518             break;
519         }
520         if (req_num == x.req_num)
521         {
522             result = true;
523             for (const auto &y : x.sync_draw_req)
524             {
525                 result &= y.end_draw_finished;
526                 if (!result)
527                 {
528                     break;
529                 }
530             }
531         }
532     }
533     return result;
534 }
535
536 /**
537  * Finish the request, then remove it.
538  *
539  * @param  unsigned[in] request_number
540  * @return None
541  * @note   Please call next after this function to receive or process next request.
542  */
543 void AppList::removeRequest(unsigned req_num)
544 {
545     std::lock_guard<std::mutex> lock(this->mtx);
546     this->req_list.erase(remove_if(this->req_list.begin(), this->req_list.end(),
547                                    [req_num](WMRequest x) {
548                                        return x.req_num == req_num;
549                                    }));
550 }
551
552 /**
553  * Move the current request to next
554  *
555  * @param  None
556  * @return None
557  */
558 void AppList::next()
559 {
560     std::lock_guard<std::mutex> lock(this->mtx);
561     ++this->current_req;
562     if (0 == this->current_req)
563     {
564         this->current_req = 1;
565     }
566 }
567
568 /**
569  * Check the request exists is in request list
570  *
571  * @param  None
572  * @return true if WMRequest exists in the request list
573  */
574 bool AppList::haveRequest() const
575 {
576     return !this->req_list.empty();
577 }
578
579 void AppList::clientDump()
580 {
581     DUMP("======= client dump =====");
582     for (const auto &x : this->app2client)
583     {
584         const auto &y = x.second;
585         y->dumpInfo();
586     }
587     DUMP("======= client dump end=====");
588 }
589
590 void AppList::reqDump()
591 {
592     DUMP("======= req dump =====");
593     DUMP("current request : %d", current_req);
594     for (const auto &x : req_list)
595     {
596         DUMP("requested       : %d", x.req_num);
597         DUMP("Trigger : (APPID :%s, ROLE :%s, AREA :%s, TASK: %d)",
598              x.trigger.appid.c_str(),
599              x.trigger.role.c_str(),
600              x.trigger.area.c_str(),
601              x.trigger.task);
602
603         for (const auto &y : x.sync_draw_req)
604         {
605             DUMP(
606                 "Action  : (APPID :%s, ROLE :%s, AREA :%s, VISIBLE : %s, END_DRAW_FINISHED: %d)",
607                 y.client->appID().c_str(),
608                 y.role.c_str(),
609                 y.area.c_str(),
610                 (y.visible == TaskVisible::INVISIBLE) ? "invisible" : "visible",
611                 y.end_draw_finished);
612         }
613     }
614     DUMP("======= req dump end =====");
615 }
616
617 void AppList::dumpFloatingSurfaces()
618 {
619     DUMP("======= floating surface dump =====");
620     for (const auto &x : this->floating_surfaces)
621     {
622         DUMP("surface : %d, pid : %d", x.surface_id, x.pid);
623     }
624     DUMP("======= floating surface dump end =====\n");
625 }
626
627 } // namespace wm