Add gitlab issue/merge request templates
[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 &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  * Add Client to the list
86  *
87  * This function is overload function.
88  * But this function just register application.
89  * So an application does not have role, surface, layer.
90  * Client need to register role and layer afterward.
91  *
92  * @param     string[in]   Application id. This will be the key to withdraw the information.
93  * @return    None
94  * @attention This function should be called once for the app
95  *            Caller should take care not to be called more than once.
96  */
97 void AppList::addClient(const string &appid)
98 {
99     std::lock_guard<std::mutex> lock(this->mtx);
100     shared_ptr<WMClient> client = std::make_shared<WMClient>(appid, 0, "");
101     this->app2client[appid] = client;
102     this->clientDump();
103 }
104
105 /**
106  * Remove WMClient from the list
107  *
108  * @param string[in] Application id. This will be the key to withdraw the information.
109  */
110 void AppList::removeClient(const string &appid)
111 {
112     std::lock_guard<std::mutex> lock(this->mtx);
113     this->app2client.erase(appid);
114     HMI_INFO("Remove client %s", appid.c_str());
115 }
116
117 /**
118  * Check this class stores the appid.
119  *
120  * @param     string[in] Application id. This will be the key to withdraw the information.
121  * @return    true if the class has the requested key(appid)
122  */
123 bool AppList::contains(const string &appid) const
124 {
125     auto result = this->app2client.find(appid);
126     return (this->app2client.end() != result) ? true : false;
127 }
128
129 /**
130  * Remove surface from client
131  *
132  * @param     unsigned[in] surface id.
133  * @return    None
134  */
135 void AppList::removeSurface(unsigned surface){
136     // This function may be very slow
137     std::lock_guard<std::mutex> lock(this->mtx);
138     bool ret = false;
139     for (auto &x : this->app2client)
140     {
141         ret = x.second->removeSurfaceIfExist(surface);
142         if(ret){
143             HMI_DEBUG("remove surface %d from Client %s finish",
144                         surface, x.second->appID().c_str());
145             break;
146         }
147     }
148
149 }
150
151 /**
152  * Get WMClient object.
153  *
154  * After get the WMClient object, caller can call the client method.
155  * Before call this function, caller must call "contains"
156  * to check the key is contained, otherwise, you have to take care of std::out_of_range.
157  *
158  * @param     string[in] application id(key)
159  * @return    WMClient object
160  * @attention Must call cantains to check appid is stored before this function.
161  */
162 shared_ptr<WMClient> AppList::lookUpClient(const string &appid)
163 {
164     if(this->app2client.count(appid) != 0)
165     {
166         return this->app2client.at(appid);
167     }
168     else
169     {
170         return nullptr;
171     }
172 }
173
174 /**
175  * Count Client.
176  *
177  * Returns the number of client stored in the list.
178  *
179  * @param  None
180  * @return The number of client
181  */
182 int AppList::countClient() const
183 {
184     return this->app2client.size();
185 }
186
187 /**
188  * Get AppID with surface and role.
189  *
190  * Returns AppID if found.
191  *
192  * @param     unsigned[in] surfaceID
193  * @param     bool[in,out] AppID is found or not
194  * @return    AppID
195  * @attention If AppID is not found, param found will be false.
196  */
197 string AppList::getAppID(unsigned surface, bool* found) const
198 {
199     *found = false;
200     for (const auto &x : this->app2client)
201     {
202         if(x.second->surfaceID() == surface){
203             *found = true;
204             return x.second->appID();
205         }
206     }
207     return string("");
208 }
209
210 // =================== Request Date container API ===================
211
212 /**
213  * Get current request number
214  *
215  * Request number is the numeric ID to designate the request.
216  * But returned request number from this function doesn't mean the request exists.
217  * This number is used as key to withdraw the WMRequest object.
218  *
219  * @param  None
220  * @return current request number.
221  * @note   request number is more than 0.
222  */
223 unsigned AppList::currentRequestNumber() const
224 {
225     return this->current_req;
226 }
227
228 /**
229  * Get request number
230  *
231  * Request number is the numeric ID to designate the request.
232  * But returned request number from this function doesn't mean the request exists.
233  * This number is used as key to withdraw the WMRequest object.
234  *
235  * @param     None
236  * @return    request number.
237  * @attention If returned value is 0, no request exists.
238  */
239 unsigned AppList::getRequestNumber(const string &appid) const
240 {
241     for (const auto &x : this->req_list)
242     {
243         // Since app will not request twice and more, comparing appid is enough?
244         if ((x.trigger.appid == appid))
245         {
246             return x.req_num;
247         }
248     }
249     return 0;
250 }
251
252 /**
253  * Add Request
254  *
255  * Request number is the numeric ID to designate the request.
256  * But returned request number from this function doesn't mean the request exists.
257  * This number is used as key to withdraw the WMRequest object.
258  *
259  * @param     WMRequest[in] WMRequest object caller creates
260  * @return    Request number
261  * @attention If the request number is different with curent request number,
262  *            it means the previous request is not finished.
263  */
264 unsigned AppList::addRequest(WMRequest req)
265 {
266     std::lock_guard<std::mutex> lock(this->mtx);
267     if (this->req_list.size() == 0)
268     {
269         req.req_num = current_req;
270     }
271     else
272     {
273         HMI_SEQ_INFO(this->current_req, "add: %d", this->req_list.back().req_num + 1);
274         req.req_num = this->req_list.back().req_num + 1;
275     }
276     this->req_list.push_back(req);
277     return req.req_num;
278 }
279
280 /**
281  * Get trigger which the application requests
282  *
283  * WMTrigger contains which application requests what role and where to put(area) and task.
284  * This is used for input event to Window Policy Manager(state machine).
285  *
286  * @param     unsigned[in] request number
287  * @param     bool[in,out] Check request number of the parameter is valid.
288  * @return    WMTrigger which associates with the request number
289  * @attention If the request number is not valid, parameter "found" is false
290  *            and return value will be meaningless value.
291  *            Caller can check the request parameter is valid.
292  */
293 struct WMTrigger AppList::getRequest(unsigned req_num, bool *found)
294 {
295     *found = false;
296     for (const auto &x : this->req_list)
297     {
298         if (req_num == x.req_num)
299         {
300             *found = true;
301             return x.trigger;
302         }
303     }
304     HMI_SEQ_ERROR(req_num, "Couldn't get request : %d", req_num);
305     return WMTrigger{"", "", "", Task::TASK_INVALID};
306 }
307
308 /**
309  * Get actions which the application requests
310  *
311  * WMAciton contains the information of state transition.
312  * In other words, it contains actions of Window Manager,
313  * which role should be put to the area.
314  *
315  * @param     unsigned[in] request number
316  * @param     bool[in,out] Check request number of the parameter is valid.
317  * @return    WMTrigger which associates with the request number
318  * @attention If the request number is not valid, parameter "found" is false
319  *            and return value will be no reference pointer.
320  *            Caller must check the request parameter is valid.
321  */
322 const vector<struct WMAction> &AppList::getActions(unsigned req_num, bool* found)
323 {
324     *found = false;
325     for (auto &x : this->req_list)
326     {
327         if (req_num == x.req_num)
328         {
329             *found = true;
330             return x.sync_draw_req;
331         }
332     }
333     HMI_SEQ_ERROR(req_num, "Couldn't get action with the request : %d", req_num);
334     {
335       static vector<struct WMAction> empty;
336       return empty;
337     }
338 }
339
340 /**
341  * Set actions to the request.
342  *
343  * Add actions to the request.
344  * This function can be called many times, and actions increase.
345  * This function is used for decision of actions of Window Manager
346  * according to the result of Window Policy Manager.
347  *
348  * @param     unsigned[in] request number
349  * @param     WMAction[in] Action of Window Manager.
350  * @return    WMError If request number is not valid, FAIL will be returned.
351  */
352 WMError AppList::setAction(unsigned req_num, const struct WMAction &action)
353 {
354     std::lock_guard<std::mutex> lock(this->mtx);
355     WMError result = WMError::FAIL;
356     for (auto &x : this->req_list)
357     {
358         if (req_num != x.req_num)
359         {
360             continue;
361         }
362         x.sync_draw_req.push_back(action);
363         result = WMError::SUCCESS;
364         break;
365     }
366     return result;
367 }
368
369 /**
370  * Note:
371  * @note This function set action with parameters.
372  *       If visible is true, it means app should be visible, so enddraw_finished parameter should be false.
373  *       otherwise (visible is false) app should be invisible. Then enddraw_finished param is set to true.
374  *       This function doesn't support actions for focus yet.
375  */
376 /**
377  * Set actions to the request.
378  *
379  * This function is overload function.
380  * The feature is same as other one.
381  *
382  * @param     unsigned[in] request number
383  * @param     string[in]   application id
384  * @param     string[in]   role
385  * @param     string[in]   area
386  * @param     Task[in]     the role should be visible or not.
387  * @return    WMError If request number is not valid, FAIL will be returned.
388  * @attention This function set action with parameters, then caller doesn't need to create WMAction object.
389  *            If visible is true, it means app should be visible, so enddraw_finished parameter will be false.
390  *            otherwise (visible is false) app should be invisible. Then enddraw_finished param is set to true.
391  *            This function doesn't support actions for focus yet.
392  */
393 WMError AppList::setAction(unsigned req_num, shared_ptr<WMClient> client, const string &role, const string &area, TaskVisible visible)
394 {
395     std::lock_guard<std::mutex> lock(this->mtx);
396     WMError result = WMError::FAIL;
397     for (auto &x : req_list)
398     {
399         if (req_num != x.req_num)
400         {
401             continue;
402         }
403         // If visible task is not invisible, redraw is required -> true
404         bool edraw_f = (visible != TaskVisible::INVISIBLE) ? false : true;
405         WMAction action{req_num, client, role, area, visible, edraw_f};
406
407         x.sync_draw_req.push_back(action);
408         result = WMError::SUCCESS;
409         break;
410     }
411     return result;
412 }
413
414 /**
415  * Set end_draw_finished param is true
416  *
417  * This function checks
418  *   - req_num is equal to current request number
419  *   - appid and role are equeal to the appid and role stored in action list
420  * If it is valid, set the action is finished.
421  *
422  * @param  unsigned[in] request number
423  * @param  string[in]   application id
424  * @param  string[in]   role
425  * @return If the parameters are not valid in action list, returns false
426  */
427 bool AppList::setEndDrawFinished(unsigned req_num, const string &appid, const string &role)
428 {
429     std::lock_guard<std::mutex> lock(this->mtx);
430     bool result = false;
431     for (auto &x : req_list)
432     {
433         if (req_num < x.req_num)
434         {
435             break;
436         }
437         if (req_num == x.req_num)
438         {
439             for (auto &y : x.sync_draw_req)
440             {
441                 if (y.client->appID() == appid && y.role == role)
442                 {
443                     HMI_SEQ_INFO(req_num, "Role %s finish redraw", y.role.c_str());
444                     y.end_draw_finished = true;
445                     result = true;
446                 }
447             }
448         }
449     }
450     this->reqDump();
451     return result;
452 }
453
454 /**
455  * Check all actions of the requested sequence is finished
456  *
457  * @param  unsigned[in] request_number
458  * @return true if all action is set.
459  */
460 bool AppList::endDrawFullfilled(unsigned req_num)
461 {
462     bool result = false;
463     for (const auto &x : req_list)
464     {
465         if (req_num < x.req_num)
466         {
467             break;
468         }
469         if (req_num == x.req_num)
470         {
471             result = true;
472             for (const auto &y : x.sync_draw_req)
473             {
474                 result &= y.end_draw_finished;
475                 if (!result)
476                 {
477                     break;
478                 }
479             }
480         }
481     }
482     return result;
483 }
484
485 /**
486  * Finish the request, then remove it.
487  *
488  * @param  unsigned[in] request_number
489  * @return None
490  * @note   Please call next after this function to receive or process next request.
491  */
492 void AppList::removeRequest(unsigned req_num)
493 {
494     std::lock_guard<std::mutex> lock(this->mtx);
495     this->req_list.erase(remove_if(this->req_list.begin(), this->req_list.end(),
496                                    [req_num](WMRequest x) {
497                                        return x.req_num == req_num;
498                                    }));
499 }
500
501 /**
502  * Move the current request to next
503  *
504  * @param  None
505  * @return None
506  */
507 void AppList::next()
508 {
509     std::lock_guard<std::mutex> lock(this->mtx);
510     ++this->current_req;
511     if (0 == this->current_req)
512     {
513         this->current_req = 1;
514     }
515 }
516
517 /**
518  * Check the request exists is in request list
519  *
520  * @param  None
521  * @return true if WMRequest exists in the request list
522  */
523 bool AppList::haveRequest() const
524 {
525     return !this->req_list.empty();
526 }
527
528 void AppList::clientDump()
529 {
530     DUMP("======= client dump =====");
531     for (const auto &x : this->app2client)
532     {
533         const auto &y = x.second;
534         y->dumpInfo();
535     }
536     DUMP("======= client dump end=====");
537 }
538
539 void AppList::reqDump()
540 {
541     DUMP("======= req dump =====");
542     DUMP("current request : %d", current_req);
543     for (const auto &x : req_list)
544     {
545         DUMP("requested       : %d", x.req_num);
546         DUMP("Trigger : (APPID :%s, ROLE :%s, AREA :%s, TASK: %d)",
547              x.trigger.appid.c_str(),
548              x.trigger.role.c_str(),
549              x.trigger.area.c_str(),
550              x.trigger.task);
551
552         for (const auto &y : x.sync_draw_req)
553         {
554             DUMP(
555                 "Action  : (APPID :%s, ROLE :%s, AREA :%s, VISIBLE : %s, END_DRAW_FINISHED: %d)",
556                 y.client->appID().c_str(),
557                 y.role.c_str(),
558                 y.area.c_str(),
559                 (y.visible == TaskVisible::INVISIBLE) ? "invisible" : "visible",
560                 y.end_draw_finished);
561         }
562     }
563     DUMP("======= req dump end =====");
564 }
565 } // namespace wm