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