4 * Copyright (c) 2023 Samsung Electronics Co., Ltd.
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
10 * http://www.apache.org/licenses/LICENSE-2.0
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.
20 * @file display-state-transition.c
21 * @brief This file has functions related to display state transition
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"
33 #define ALWAYS_ON_TIMEOUT 360000000
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;
40 static int trans_table[S_END][EVENT_END] = {
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 */
51 static bool is_display_state_valid(enum state_t display_state)
53 return (display_state >= S_START && display_state < S_END);
56 static bool is_device_event_type_valid(int event_type)
58 return (event_type >= EVENT_TIMEOUT && event_type < EVENT_END);
61 int display_state_transition_get_next_transition_display_state(enum state_t from_state, enum state_t *to_state, int evt_type)
63 if (!to_state || !is_display_state_valid(from_state) || !is_device_event_type_valid(evt_type))
66 *to_state = trans_table[from_state][evt_type];
70 int display_state_transition_set_transition_table_display_state(enum state_t display_state, enum state_t set_state, int evt_type)
72 if (!is_display_state_valid(display_state) || !is_device_event_type_valid(evt_type) || !is_display_state_valid(set_state))
75 trans_table[display_state][evt_type] = set_state;
79 static void remove_state_transition(void)
81 if (state_transition_timer_id) {
82 g_source_remove(state_transition_timer_id);
83 state_transition_timer_id = 0;
87 static gboolean state_transition_timeout_handler(void *data)
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);
93 remove_state_transition();
95 display_state_transition_do_state_transition(get_pm_cur_state(), EVENT_TIMEOUT);
96 return G_SOURCE_REMOVE;
99 bool display_state_transition_is_there_state_transition_timer(void)
101 return (state_transition_timer_id != 0);
104 int display_state_transition_reset_state_transition_timeout(int timeout)
107 if (!display_plugin_config_get_timeout_enable(&timeout_enable) && (!timeout_enable))
110 if ((get_pm_cur_state() == S_LCDOFF)
111 && (is_emulator() == true || timeout_sleep_support == false))
114 _I("Reset timeout(%d ms) pm_cur_state(%d).", timeout, get_pm_cur_state());
115 remove_state_transition();
117 if (trans_table[get_pm_cur_state()][EVENT_TIMEOUT] == get_pm_cur_state())
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);
129 int display_state_transition_set_custom_timeout(enum state_t state, unsigned int timeout)
131 const char *state_name = NULL;
135 custom_normal_timeout = timeout;
138 custom_dim_timeout = timeout;
141 display_plugin_state_get_name(state, &state_name);
142 _W("%s state has no custom timeout", state_name);
148 int display_state_transition_get_custom_timeout(enum state_t state, unsigned int *timeout)
153 const char *state_name = NULL;
157 *timeout = custom_normal_timeout;
160 *timeout = custom_dim_timeout;
164 display_plugin_state_get_name(state, &state_name);
165 _W("There is no specific timeout value for %s state", state_name);
171 int display_state_transition_set_lock_screen_timeout(int timeout)
173 lock_screen_timeout = timeout;
177 int display_state_transition_get_lock_screen_timeout(int *timeout)
182 *timeout = lock_screen_timeout;
186 void display_state_transition_update_display_state_timeout_by_priority(void)
188 int run_timeout, val;
189 int lcd_always_on = 0;
190 int normal_state_timeout = 0;
191 int dim_state_timeout = 0;
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);
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);
212 /* default setting */
213 get_run_timeout(&run_timeout);
216 * if the run_timeout is zero, it regards AlwaysOn state
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.");
224 display_plugin_state_set_timeout(S_NORMAL, run_timeout);
226 get_dim_timeout(&val);
227 display_plugin_state_set_timeout(S_LCDDIM, val);
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);
235 bool display_state_transition_is_display_state_support_transition(enum state_t state)
250 int display_state_transition_check_state_transition_condition(enum state_t cur_state, enum state_t next_state)
254 if (!display_state_transition_is_display_state_support_transition(cur_state))
257 makeup_trans_condition();
259 trans_cond = get_trans_condition() & MASK_BIT;
261 if (next_state == S_NORMAL) /* S_NORMAL is exceptional */
266 trans_cond = trans_cond & MASK_NORMAL;
269 trans_cond = trans_cond & MASK_DIM;
272 trans_cond = trans_cond & MASK_OFF;
279 if (trans_cond != 0) {
280 print_node(cur_state);
284 return 0; /* transitable */
287 int display_state_transition_update_lcdoff_reason(int source)
292 case VCONFKEY_PM_LCDOFF_BY_TIMEOUT:
293 _I("LCD OFF by timeout.");
295 case VCONFKEY_PM_LCDOFF_BY_POWERKEY:
296 _I("LCD OFF by powerkey.");
299 _E("Invalid value(%d).", source);
302 ret = vconf_set_int(VCONFKEY_PM_LCDOFF_SOURCE, source);
304 _E("Failed to set vconf value for lcd off source: %d", vconf_get_ext_errno());
310 /* FIXME: In this function, extcon checking should be considered after relocating this. */
311 bool display_state_transition_is_possible_to_go_lcdoff(void)
313 int ret, lock, cradle;
317 if (get_pm_old_state() != S_NORMAL)
320 if (get_pm_cur_state() != S_LCDDIM)
323 display_plugin_config_get_dimming(&dimming);
327 lock = __get_lock_screen_state();
328 if (lock != VCONFKEY_IDLE_LOCK)
331 hdmi_state = extcon_get_status(EXTCON_CABLE_HDMI);
335 ret = vconf_get_int(VCONFKEY_SYSMAN_CRADLE_STATUS, &cradle);
336 if (ret >= 0 && cradle == DOCK_SOUND)
339 _E("Failed to get vconf value for cradle status: %d", vconf_get_ext_errno());
341 _D("Goto LCDOFF direct: lock(%d) hdmi(%d) cradle(%d).", lock, hdmi_state, cradle);
346 /* FXIME: enter action logic should be discussed and considered about better logic */
348 * default transition function
351 * 3. call enter action function
353 int display_state_transition_do_state_transition(enum state_t state, int evt_type)
355 const char* current_state_name = NULL;
356 const char* next_state_name = NULL;
357 enum state_t next_state;
361 if (!display_state_transition_is_display_state_support_transition(state))
364 if (display_plugin_state_is_there_default_trans(state))
365 return display_plugin_state_do_default_trans(state, evt_type);
367 display_state_transition_get_next_transition_display_state(get_pm_cur_state(), &next_state, evt_type);
369 /* check conditions */
370 ret = display_state_transition_check_state_transition_condition(get_pm_cur_state(), next_state);
372 display_plugin_state_get_name(get_pm_cur_state(), ¤t_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);
379 /* state transition */
380 set_pm_old_state(get_pm_cur_state());
381 set_pm_cur_state(next_state);
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);
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();
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);
396 if ((get_pm_cur_state() == S_SLEEP) &&
397 (is_emulator() == true || timeout_sleep_support == false))
400 display_plugin_state_get_timeout(get_pm_cur_state(), &timeout);
401 display_plugin_state_do_default_action(get_pm_cur_state(), timeout);