display: state-transition: Relocate default_trans()
[platform/core/system/deviced.git] / src / display / display-state-transition.c
1 /*
2  * deviced
3  *
4  * Copyright (c) 2023 Samsung Electronics Co., Ltd.
5  *
6  * Licensed under the Apache License, Version 2.0 (the License);
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18
19 /**
20  * @file        display-state-transition.c
21  * @brief       This file has functions related to display state transition
22  */
23
24 #include "core/udev.h"
25 #include "device-interface.h"
26 #include "display-state-transition.h"
27 #include "display-lock.h"
28 #include "display-plugin.h"
29 #include "extcon/extcon.h"
30 #include "power/power-suspend.h"
31 #include "shared/log.h"
32
33 #define ALWAYS_ON_TIMEOUT               360000000
34
35 static guint state_transition_timer_id;
36 static unsigned int custom_normal_timeout = 0;
37 static unsigned int custom_dim_timeout = 0;
38 static int lock_screen_timeout = LOCK_SCREEN_INPUT_TIMEOUT;
39
40 static int trans_table[S_END][EVENT_END] = {
41         /* Timeout,   Input */
42         { S_START,    S_START    }, /* S_START */
43         { S_LCDDIM,   S_NORMAL   }, /* S_NORMAL */
44         { S_LCDOFF,   S_NORMAL   }, /* S_LCDDIM */
45         { S_SLEEP,    S_NORMAL   }, /* S_LCDOFF */
46         { S_SLEEP,    S_STANDBY  }, /* S_STANDBY */
47         { S_LCDOFF,   S_NORMAL   }, /* S_SLEEP */
48         { S_POWEROFF, S_POWEROFF }, /* S_POWEROFF */
49 };
50
51 static bool is_display_state_valid(enum state_t display_state)
52 {
53         return (display_state >= S_START && display_state < S_END);
54 }
55
56 static bool is_device_event_type_valid(int event_type)
57 {
58         return (event_type >= EVENT_TIMEOUT && event_type < EVENT_END);
59 }
60
61 int display_state_transition_get_next_transition_display_state(enum state_t from_state, enum state_t *to_state, int evt_type)
62 {
63         if (!to_state || !is_display_state_valid(from_state) || !is_device_event_type_valid(evt_type))
64                 return -EINVAL;
65
66         *to_state = trans_table[from_state][evt_type];
67         return 0;
68 }
69
70 int display_state_transition_set_transition_table_display_state(enum state_t display_state, enum state_t set_state, int evt_type)
71 {
72         if (!is_display_state_valid(display_state) || !is_device_event_type_valid(evt_type) || !is_display_state_valid(set_state))
73                 return -EINVAL;
74
75         trans_table[display_state][evt_type] = set_state;
76         return 0;
77 }
78
79 static void remove_state_transition(void)
80 {
81         if (state_transition_timer_id) {
82                 g_source_remove(state_transition_timer_id);
83                 state_transition_timer_id = 0;
84         }
85 }
86
87 static gboolean state_transition_timeout_handler(void *data)
88 {
89         const char *state_name = NULL;
90         display_plugin_state_get_name(get_pm_cur_state(), &state_name);
91         _I("Time out state %s", state_name);
92
93         remove_state_transition();
94
95         display_state_transition_do_state_transition(get_pm_cur_state(), EVENT_TIMEOUT);
96         return G_SOURCE_REMOVE;
97 }
98
99 bool display_state_transition_is_there_state_transition_timer(void)
100 {
101         return (state_transition_timer_id != 0);
102 }
103
104 int display_state_transition_reset_state_transition_timeout(int timeout)
105 {
106         bool timeout_enable;
107         if (!display_plugin_config_get_timeout_enable(&timeout_enable) && (!timeout_enable))
108                 return -EPERM;
109
110         if ((get_pm_cur_state() == S_LCDOFF)
111         && (is_emulator() == true || timeout_sleep_support == false))
112                 return -EPERM;
113
114         _I("Reset timeout(%d ms) pm_cur_state(%d).", timeout, get_pm_cur_state());
115         remove_state_transition();
116
117         if (trans_table[get_pm_cur_state()][EVENT_TIMEOUT] == get_pm_cur_state())
118                 return -EPERM;
119
120         if (timeout > 0)
121                 state_transition_timer_id = g_timeout_add(timeout,
122                         state_transition_timeout_handler, NULL);
123         else if (timeout == 0)
124                 display_state_transition_do_state_transition(get_pm_cur_state(), EVENT_TIMEOUT);
125
126         return 0;
127 }
128
129 int display_state_transition_set_custom_timeout(enum state_t state, unsigned int timeout)
130 {
131         const char *state_name = NULL;
132
133         switch (state) {
134         case S_NORMAL:
135                 custom_normal_timeout = timeout;
136                 break;
137         case S_LCDDIM:
138                 custom_dim_timeout = timeout;
139                 break;
140         default:
141                 display_plugin_state_get_name(state, &state_name);
142                 _W("%s state has no custom timeout", state_name);
143                 return -EPERM;
144         }
145         return 0;
146 }
147
148 int display_state_transition_get_custom_timeout(enum state_t state, unsigned int *timeout)
149 {
150         if (!timeout)
151                 return -EINVAL;
152
153         const char *state_name = NULL;
154
155         switch (state) {
156         case S_NORMAL:
157                 *timeout = custom_normal_timeout;
158                 break;
159         case S_LCDDIM:
160                 *timeout = custom_dim_timeout;
161                 break;
162         default:
163                 *timeout = 0;
164                 display_plugin_state_get_name(state, &state_name);
165                 _W("There is no specific timeout value for %s state", state_name);
166         }
167         return 0;
168 }
169
170
171 int display_state_transition_set_lock_screen_timeout(int timeout)
172 {
173         lock_screen_timeout = timeout;
174         return 0;
175 }
176
177 int display_state_transition_get_lock_screen_timeout(int *timeout)
178 {
179         if (!timeout)
180                 return -EINVAL;
181
182         *timeout = lock_screen_timeout;
183         return 0;
184 }
185
186 void display_state_transition_update_display_state_timeout_by_priority(void)
187 {
188         int run_timeout, val;
189         int lcd_always_on = 0;
190         int normal_state_timeout = 0;
191         int dim_state_timeout = 0;
192
193         /* first priority : custom timeout */
194         if (custom_normal_timeout > 0) {
195                 display_plugin_state_set_timeout(S_NORMAL, custom_normal_timeout);
196                 display_plugin_state_set_timeout(S_LCDDIM, custom_dim_timeout);
197                 _I("CUSTOM : timeout is set by normal(%u ms), dim(%u ms)",
198                     custom_normal_timeout, custom_dim_timeout);
199                 return;
200         }
201
202         /* second priority : lock state */
203         if ((__get_lock_screen_state() == VCONFKEY_IDLE_LOCK) &&
204             !get_lock_screen_bg_state()) {
205                 /* timeout is different according to key or event. */
206                 display_plugin_state_set_timeout(S_NORMAL, lock_screen_timeout);
207                 _I("LOCK: Timeout(%d ms) is set by normal.",
208                     lock_screen_timeout);
209                 return;
210         }
211
212         /* default setting */
213         get_run_timeout(&run_timeout);
214
215         /* for sdk
216          * if the run_timeout is zero, it regards AlwaysOn state
217          */
218         display_plugin_config_get_lcd_always_on(&lcd_always_on);
219         if (run_timeout == 0 || lcd_always_on) {
220                 run_timeout = ALWAYS_ON_TIMEOUT;
221                 _I("LCD always on.");
222         }
223
224         display_plugin_state_set_timeout(S_NORMAL, run_timeout);
225
226         get_dim_timeout(&val);
227         display_plugin_state_set_timeout(S_LCDDIM, val);
228
229         display_plugin_state_get_timeout(S_NORMAL, &normal_state_timeout);
230         display_plugin_state_get_timeout(S_LCDDIM, &dim_state_timeout);
231         _I("Normal: NORMAL timeout is set by %d ms", normal_state_timeout);
232         _I("Normal: DIM timeout is set by %d ms", dim_state_timeout);
233 }
234
235 bool display_state_transition_is_display_state_support_transition(enum state_t state)
236 {
237         switch(state) {
238         case S_NORMAL:
239         case S_LCDDIM:
240         case S_LCDOFF:
241         case S_SLEEP:
242                 return true;
243         default:
244                 return false;
245         }
246
247         return false;
248 }
249
250 int display_state_transition_check_state_transition_condition(enum state_t cur_state, enum state_t next_state)
251 {
252         int trans_cond;
253
254         if (!display_state_transition_is_display_state_support_transition(cur_state))
255                 return -EPERM;
256
257         makeup_trans_condition();
258
259         trans_cond = get_trans_condition() & MASK_BIT;
260
261         if (next_state == S_NORMAL) /* S_NORMAL is exceptional */
262                 return 0;
263
264         switch (cur_state) {
265         case S_NORMAL:
266                 trans_cond = trans_cond & MASK_NORMAL;
267                 break;
268         case S_LCDDIM:
269                 trans_cond = trans_cond & MASK_DIM;
270                 break;
271         case S_LCDOFF:
272                 trans_cond = trans_cond & MASK_OFF;
273                 break;
274         default:
275                 trans_cond = 0;
276                 break;
277         }
278
279         if (trans_cond != 0) {
280                 print_node(cur_state);
281                 return -EPERM;
282         }
283
284         return 0;               /* transitable */
285 }
286
287 int display_state_transition_update_lcdoff_reason(int source)
288 {
289         int ret;
290
291         switch (source) {
292         case VCONFKEY_PM_LCDOFF_BY_TIMEOUT:
293                 _I("LCD OFF by timeout.");
294                 break;
295         case VCONFKEY_PM_LCDOFF_BY_POWERKEY:
296                 _I("LCD OFF by powerkey.");
297                 break;
298         default:
299                 _E("Invalid value(%d).", source);
300                 return -EINVAL;
301         }
302         ret = vconf_set_int(VCONFKEY_PM_LCDOFF_SOURCE, source);
303         if (ret < 0) {
304                 _E("Failed to set vconf value for lcd off source: %d", vconf_get_ext_errno());
305                 return -EPERM;
306         }
307         return 0;
308 }
309
310 /* FIXME: In this function, extcon checking should be considered after relocating this. */
311 bool display_state_transition_is_possible_to_go_lcdoff(void)
312 {
313         int ret, lock, cradle;
314         int hdmi_state;
315         int dimming;
316
317         if (get_pm_old_state() != S_NORMAL)
318                 return false;
319
320         if (get_pm_cur_state() != S_LCDDIM)
321                 return false;
322
323         display_plugin_config_get_dimming(&dimming);
324         if (!dimming)
325                 return true;
326
327         lock = __get_lock_screen_state();
328         if (lock != VCONFKEY_IDLE_LOCK)
329                 return false;
330
331         hdmi_state = extcon_get_status(EXTCON_CABLE_HDMI);
332         if (hdmi_state)
333                 return false;
334
335         ret = vconf_get_int(VCONFKEY_SYSMAN_CRADLE_STATUS, &cradle);
336         if (ret >= 0 && cradle == DOCK_SOUND)
337                 return false;
338         else if (ret < 0)
339                 _E("Failed to get vconf value for cradle status: %d", vconf_get_ext_errno());
340
341         _D("Goto LCDOFF direct: lock(%d) hdmi(%d) cradle(%d).", lock, hdmi_state, cradle);
342
343         return true;
344 }
345
346 /* FXIME: enter action logic should be discussed and considered about better logic */
347 /*
348  * default transition function
349  *   1. call check
350  *   2. transition
351  *   3. call enter action function
352  */
353 int display_state_transition_do_state_transition(enum state_t state, int evt_type)
354 {
355         const char* current_state_name = NULL;
356         const char* next_state_name = NULL;
357         enum state_t next_state;
358         int ret = 0;
359         int timeout = 0;
360
361         if (!display_state_transition_is_display_state_support_transition(state))
362                 return -EPERM;
363
364         if (display_plugin_state_is_there_default_trans(state))
365                 return display_plugin_state_do_default_trans(state, evt_type);
366
367         display_state_transition_get_next_transition_display_state(get_pm_cur_state(), &next_state, evt_type);
368
369         /* check conditions */
370         ret = display_state_transition_check_state_transition_condition(get_pm_cur_state(), next_state);
371         if (ret < 0) {
372                 display_plugin_state_get_name(get_pm_cur_state(), &current_state_name);
373                 display_plugin_state_get_name(next_state, &next_state_name);
374                 /* There is a condition. */
375                 _I("%s locked. Trans to %s failed.", current_state_name, next_state_name);
376                 return -EPERM;
377         }
378
379         /* state transition */
380         set_pm_old_state(get_pm_cur_state());
381         set_pm_cur_state(next_state);
382
383         /* enter action */
384         if (display_plugin_state_is_there_default_action(get_pm_cur_state())) {
385                 if (get_pm_cur_state() == S_LCDOFF)
386                         display_state_transition_update_lcdoff_reason(VCONFKEY_PM_LCDOFF_BY_TIMEOUT);
387
388                 if ((get_pm_cur_state() == S_NORMAL) || (get_pm_cur_state() == S_LCDOFF))
389                         if (set_custom_lcdon_timeout(0) == true)
390                                 display_state_transition_update_display_state_timeout_by_priority();
391
392                 if (display_state_transition_is_possible_to_go_lcdoff()) {
393                         /* enter next state directly */
394                         display_state_transition_do_state_transition(get_pm_cur_state(), EVENT_TIMEOUT);
395                 } else {
396                         if ((get_pm_cur_state() == S_SLEEP) &&
397                         (is_emulator() == true || timeout_sleep_support == false))
398                                 return 0;
399
400                         display_plugin_state_get_timeout(get_pm_cur_state(), &timeout);
401                         display_plugin_state_do_default_action(get_pm_cur_state(), timeout);
402                 }
403         }
404         return 0;
405 }