4836caccf7fa291e87804c69c4bdde1b766294c7
[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_plugin_state_do_default_trans(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_plugin_state_do_default_trans(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 static bool is_display_state_valid_for_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 (!is_display_state_valid_for_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
308         return 0;
309 }
310
311 /* FIXME: In this function, extcon checking should be considered after relocating this. */
312 bool display_state_transition_is_possible_to_go_lcdoff(void)
313 {
314         int ret, lock, cradle;
315         int hdmi_state;
316         int dimming;
317
318         if (get_pm_old_state() != S_NORMAL)
319                 return false;
320
321         if (get_pm_cur_state() != S_LCDDIM)
322                 return false;
323
324         display_plugin_config_get_dimming(&dimming);
325         if (!dimming)
326                 return true;
327
328         lock = __get_lock_screen_state();
329         if (lock != VCONFKEY_IDLE_LOCK)
330                 return false;
331
332         hdmi_state = extcon_get_status(EXTCON_CABLE_HDMI);
333         if (hdmi_state)
334                 return false;
335
336         ret = vconf_get_int(VCONFKEY_SYSMAN_CRADLE_STATUS, &cradle);
337         if (ret >= 0 && cradle == DOCK_SOUND)
338                 return false;
339         else if (ret < 0)
340                 _E("Failed to get vconf value for cradle status: %d", vconf_get_ext_errno());
341
342         _D("Goto LCDOFF direct: lock(%d) hdmi(%d) cradle(%d).", lock, hdmi_state, cradle);
343
344         return true;
345 }