Change struct WMAction
[apps/agl-service-windowmanager.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& layer_name, unsigned surface, const string &role)
77 {
78     std::lock_guard<std::mutex> lock(this->mtx);
79     shared_ptr<WMClient> client = std::make_shared<WMClient>(appid, layer, layer_name, surface, 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 WMError AppList::popFloatingSurface(unsigned pid, unsigned *surface)
184 {
185     WMError ret = WMError::NO_ENTRY;
186
187     auto fwd_itr = std::remove_if(this->floating_surfaces.begin(), this->floating_surfaces.end(),
188                                     [pid, surface, &ret](FloatingSurface x) {
189                                         if(pid == x.pid){
190                                             *surface = x.surface_id;
191                                             ret = WMError::SUCCESS;
192                                             return true;
193                                         }
194                                         else{
195                                             return false;
196                                         }
197                                     });
198     if (fwd_itr != this->floating_surfaces.cend())
199     {
200         HMI_INFO("pop floating surface: %d", *surface);
201     }
202     this->floating_surfaces.erase(fwd_itr, this->floating_surfaces.end());
203     return ret;
204 }
205
206 // =================== Floating(Temporary) surface/client API ===================
207
208 WMError AppList::popFloatingSurface(const string &appid, unsigned *surface)
209 {
210     HMI_ERROR("This function is not implemented");
211     return WMError::SUCCESS;
212 }
213
214 void AppList::addFloatingClient(const string &appid, unsigned layer, const string &role)
215 {
216 }
217
218 void AppList::addFloatingSurface(const string &appid, unsigned surface, unsigned pid)
219 {
220     struct FloatingSurface fsurface{appid, surface, pid};
221     this->floating_surfaces.push_back(fsurface);
222     this->dumpFloatingSurfaces();
223 }
224
225 void AppList::removeFloatingSurface(unsigned surface)
226 {
227     this->dumpFloatingSurfaces();
228     auto fwd_itr = std::remove_if(
229         this->floating_surfaces.begin(), this->floating_surfaces.end(),
230         [surface](FloatingSurface x) {
231             return x.surface_id == surface;
232         });
233     if(fwd_itr != this->floating_surfaces.cend()){
234         HMI_INFO("remove floating surface: %d", surface);
235     }
236     this->floating_surfaces.erase(fwd_itr, this->floating_surfaces.end());
237 }
238
239 WMError AppList::appendRole(const string &id, const string &role)
240 {
241     WMError wm_err = WMError::NO_ENTRY;
242     if (this->contains(id))
243     {
244         auto x = this->lookUpClient(id);
245         x->appendRole(role);
246         wm_err = WMError::SUCCESS;
247     }
248     return wm_err;
249 }
250
251
252 // =================== Request Date container API ===================
253
254 /**
255  * Get current request number
256  *
257  * Request number is the numeric ID to designate the request.
258  * But returned request number from this function doesn't mean the request exists.
259  * This number is used as key to withdraw the WMRequest object.
260  *
261  * @param  None
262  * @return current request number.
263  * @note   request number is more than 0.
264  */
265 unsigned AppList::currentRequestNumber() const
266 {
267     return this->current_req;
268 }
269
270 /**
271  * Get request number
272  *
273  * Request number is the numeric ID to designate the request.
274  * But returned request number from this function doesn't mean the request exists.
275  * This number is used as key to withdraw the WMRequest object.
276  *
277  * @param     None
278  * @return    request number.
279  * @attention If returned value is 0, no request exists.
280  */
281 unsigned AppList::getRequestNumber(const string &appid) const
282 {
283     for (const auto &x : this->req_list)
284     {
285         // Since app will not request twice and more, comparing appid is enough?
286         if ((x.trigger.appid == appid))
287         {
288             return x.req_num;
289         }
290     }
291     return 0;
292 }
293
294 /**
295  * Add Request
296  *
297  * Request number is the numeric ID to designate the request.
298  * But returned request number from this function doesn't mean the request exists.
299  * This number is used as key to withdraw the WMRequest object.
300  *
301  * @param     WMRequest[in] WMRequest object caller creates
302  * @return    Request number
303  * @attention If the request number is different with curent request number,
304  *            it means the previous request is not finished.
305  */
306 unsigned AppList::addRequest(WMRequest req)
307 {
308     std::lock_guard<std::mutex> lock(this->mtx);
309     if (this->req_list.size() == 0)
310     {
311         req.req_num = current_req;
312     }
313     else
314     {
315         HMI_SEQ_INFO(this->current_req, "add: %d", this->req_list.back().req_num + 1);
316         req.req_num = this->req_list.back().req_num + 1;
317     }
318     this->req_list.push_back(req);
319     return req.req_num;
320 }
321
322 /**
323  * Get trigger which the application requests
324  *
325  * WMTrigger contains which application requests what role and where to put(area) and task.
326  * This is used for input event to Window Policy Manager(state machine).
327  *
328  * @param     unsigned[in] request number
329  * @param     bool[in,out] Check request number of the parameter is valid.
330  * @return    WMTrigger which associates with the request number
331  * @attention If the request number is not valid, parameter "found" is false
332  *            and return value will be meaningless value.
333  *            Caller can check the request parameter is valid.
334  */
335 struct WMTrigger AppList::getRequest(unsigned req_num, bool *found)
336 {
337     *found = false;
338     for (const auto &x : this->req_list)
339     {
340         if (req_num == x.req_num)
341         {
342             *found = true;
343             return x.trigger;
344         }
345     }
346     HMI_SEQ_ERROR(req_num, "Couldn't get request : %d", req_num);
347     return WMTrigger{"", "", "", Task::TASK_INVALID};
348 }
349
350 /**
351  * Get actions which the application requests
352  *
353  * WMAciton contains the information of state transition.
354  * In other words, it contains actions of Window Manager,
355  * which role should be put to the area.
356  *
357  * @param     unsigned[in] request number
358  * @param     bool[in,out] Check request number of the parameter is valid.
359  * @return    WMTrigger which associates with the request number
360  * @attention If the request number is not valid, parameter "found" is false
361  *            and return value will be no reference pointer.
362  *            Caller must check the request parameter is valid.
363  */
364 const vector<struct WMAction> &AppList::getActions(unsigned req_num, bool* found)
365 {
366     *found = false;
367     for (auto &x : this->req_list)
368     {
369         if (req_num == x.req_num)
370         {
371             *found = true;
372             return x.sync_draw_req;
373         }
374     }
375     HMI_SEQ_ERROR(req_num, "Couldn't get action with the request : %d", req_num);
376 }
377
378 /**
379  * Set actions to the request.
380  *
381  * Add actions to the request.
382  * This function can be called many times, and actions increase.
383  * This function is used for decision of actions of Window Manager
384  * according to the result of Window Policy Manager.
385  *
386  * @param     unsigned[in] request number
387  * @param     WMAction[in] Action of Window Manager.
388  * @return    WMError If request number is not valid, FAIL will be returned.
389  */
390 WMError AppList::setAction(unsigned req_num, const struct WMAction &action)
391 {
392     std::lock_guard<std::mutex> lock(this->mtx);
393     WMError result = WMError::FAIL;
394     for (auto &x : this->req_list)
395     {
396         if (req_num != x.req_num)
397         {
398             continue;
399         }
400         x.sync_draw_req.push_back(action);
401         result = WMError::SUCCESS;
402         break;
403     }
404     return result;
405 }
406
407 /**
408  * Note:
409  * @note This function set action with parameters.
410  *       If visible is true, it means app should be visible, so enddraw_finished parameter should be false.
411  *       otherwise (visible is false) app should be invisible. Then enddraw_finished param is set to true.
412  *       This function doesn't support actions for focus yet.
413  */
414 /**
415  * Set actions to the request.
416  *
417  * This function is overload function.
418  * The feature is same as other one.
419  *
420  * @param     unsigned[in] request number
421  * @param     string[in]   application id
422  * @param     string[in]   role
423  * @param     string[in]   area
424  * @param     Task[in]     the role should be visible or not.
425  * @return    WMError If request number is not valid, FAIL will be returned.
426  * @attention This function set action with parameters, then caller doesn't need to create WMAction object.
427  *            If visible is true, it means app should be visible, so enddraw_finished parameter will be false.
428  *            otherwise (visible is false) app should be invisible. Then enddraw_finished param is set to true.
429  *            This function doesn't support actions for focus yet.
430  */
431 WMError AppList::setAction(unsigned req_num, shared_ptr<WMClient> client, const string &role, const string &area, TaskVisible visible)
432 {
433     std::lock_guard<std::mutex> lock(this->mtx);
434     WMError result = WMError::FAIL;
435     for (auto &x : req_list)
436     {
437         if (req_num != x.req_num)
438         {
439             continue;
440         }
441         // If visible task is not invisible, redraw is required -> true
442         bool edraw_f = (visible != TaskVisible::INVISIBLE) ? false : true;
443         WMAction action{req_num, client, role, area, visible, edraw_f};
444
445         x.sync_draw_req.push_back(action);
446         result = WMError::SUCCESS;
447         break;
448     }
449     return result;
450 }
451
452 /**
453  * Set end_draw_finished param is true
454  *
455  * This function checks
456  *   - req_num is equal to current request number
457  *   - appid and role are equeal to the appid and role stored in action list
458  * If it is valid, set the action is finished.
459  *
460  * @param  unsigned[in] request number
461  * @param  string[in]   application id
462  * @param  string[in]   role
463  * @return If the parameters are not valid in action list, returns false
464  */
465 bool AppList::setEndDrawFinished(unsigned req_num, const string &appid, const string &role)
466 {
467     std::lock_guard<std::mutex> lock(this->mtx);
468     bool result = false;
469     for (auto &x : req_list)
470     {
471         if (req_num < x.req_num)
472         {
473             break;
474         }
475         if (req_num == x.req_num)
476         {
477             for (auto &y : x.sync_draw_req)
478             {
479                 if (y.client->appID() == appid && y.role == role)
480                 {
481                     HMI_SEQ_INFO(req_num, "Role %s finish redraw", y.role.c_str());
482                     y.end_draw_finished = true;
483                     result = true;
484                 }
485             }
486         }
487     }
488     this->reqDump();
489     return result;
490 }
491
492 /**
493  * Check all actions of the requested sequence is finished
494  *
495  * @param  unsigned[in] request_number
496  * @return true if all action is set.
497  */
498 bool AppList::endDrawFullfilled(unsigned req_num)
499 {
500     bool result = false;
501     for (const auto &x : req_list)
502     {
503         if (req_num < x.req_num)
504         {
505             break;
506         }
507         if (req_num == x.req_num)
508         {
509             result = true;
510             for (const auto &y : x.sync_draw_req)
511             {
512                 result &= y.end_draw_finished;
513                 if (!result)
514                 {
515                     break;
516                 }
517             }
518         }
519     }
520     return result;
521 }
522
523 /**
524  * Finish the request, then remove it.
525  *
526  * @param  unsigned[in] request_number
527  * @return None
528  * @note   Please call next after this function to receive or process next request.
529  */
530 void AppList::removeRequest(unsigned req_num)
531 {
532     std::lock_guard<std::mutex> lock(this->mtx);
533     this->req_list.erase(remove_if(this->req_list.begin(), this->req_list.end(),
534                                    [req_num](WMRequest x) {
535                                        return x.req_num == req_num;
536                                    }));
537 }
538
539 /**
540  * Move the current request to next
541  *
542  * @param  None
543  * @return None
544  */
545 void AppList::next()
546 {
547     std::lock_guard<std::mutex> lock(this->mtx);
548     ++this->current_req;
549     if (0 == this->current_req)
550     {
551         this->current_req = 1;
552     }
553 }
554
555 /**
556  * Check the request exists is in request list
557  *
558  * @param  None
559  * @return true if WMRequest exists in the request list
560  */
561 bool AppList::haveRequest() const
562 {
563     return !this->req_list.empty();
564 }
565
566 void AppList::clientDump()
567 {
568     DUMP("======= client dump =====");
569     for (const auto &x : this->app2client)
570     {
571         const auto &y = x.second;
572         y->dumpInfo();
573     }
574     DUMP("======= client dump end=====");
575 }
576
577 void AppList::reqDump()
578 {
579     DUMP("======= req dump =====");
580     DUMP("current request : %d", current_req);
581     for (const auto &x : req_list)
582     {
583         DUMP("requested       : %d", x.req_num);
584         DUMP("Trigger : (APPID :%s, ROLE :%s, AREA :%s, TASK: %d)",
585              x.trigger.appid.c_str(),
586              x.trigger.role.c_str(),
587              x.trigger.area.c_str(),
588              x.trigger.task);
589
590         for (const auto &y : x.sync_draw_req)
591         {
592             DUMP(
593                 "Action  : (APPID :%s, ROLE :%s, AREA :%s, VISIBLE : %s, END_DRAW_FINISHED: %d)",
594                 y.client->appID().c_str(),
595                 y.role.c_str(),
596                 y.area.c_str(),
597                 (y.visible == TaskVisible::INVISIBLE) ? "invisible" : "visible",
598                 y.end_draw_finished);
599         }
600     }
601     DUMP("======= req dump end =====");
602 }
603
604 void AppList::dumpFloatingSurfaces()
605 {
606     DUMP("======= floating surface dump =====");
607     for (const auto &x : this->floating_surfaces)
608     {
609         DUMP("surface : %d, pid : %d", x.surface_id, x.pid);
610     }
611     DUMP("======= floating surface dump end =====\n");
612 }
613
614 } // namespace wm