4 * Copyright (c) 2012 - 2017 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.
22 #include <libsyscommon/libgdbus.h>
23 #include <libsyscommon/common.h>
24 #include <system/syscommon-plugin-deviced-common-interface.h>
28 #include "display-lock.h"
29 #include "display-ops.h"
30 #include "display-panel.h"
31 #include "display-plugin.h"
32 #include "display-state-transition.h"
33 #include "shared/log.h"
34 #include "shared/device-notifier.h"
35 #include "shared/devices.h"
36 #include "shared/plugin.h"
41 #define SIGNAL_HOMESCREEN "HomeScreen"
43 #define SIGNAL_ALPMLCDOFF "ALPMLCDOff"
44 #define SIGNAL_ALPM_ON "ALPMOn"
45 #define SIGNAL_ALPM_OFF "ALPMOff"
47 #define CLOCK_START "clockstart"
48 #define CLOCK_END "clockend"
49 #define CLOCK_CHANGED "clockchanged"
50 #define AMBIENT_CLOCK_WAITING_TIME 5000 /* ms */
52 static struct display_plugin *disp_plgn;
53 static int ambient_state;
54 static int ambient_condition; /* Setting Value */
55 static pid_t ambient_pid; /* Ambient Clock pid */
56 static unsigned int update_count;
58 void broadcast_ambient_state(int state)
63 signal = (state == true ? SIGNAL_ALPM_ON : SIGNAL_ALPM_OFF);
64 ret = gdbus_signal_emit(NULL,
66 DEVICED_INTERFACE_DISPLAY,
70 _E("Failed to send dbus signal(%s).", signal);
73 int ambient_get_condition(void)
75 return ambient_condition;
78 int ambient_get_state(void)
83 static void ambient_set_condition(keynode_t *key_nodes, void *data)
87 if (key_nodes == NULL) {
88 _E("Wrong parameter, key_nodes is null.");
92 val = vconf_keynode_get_bool(key_nodes);
93 if (val != ambient_condition) {
94 if (display_panel_get_dpms_cached_state() != DPMS_ON)
95 display_state_transition_request_state_transition_with_option(DEVICED_EVENT_DISPLAY_AMBIENT, LCD_NORMAL);
98 ambient_condition = val;
99 _I("Ambient mode condition is %d.", ambient_condition);
101 state = (ambient_condition == 0 ? 0 : 1);
102 syscommon_notifier_emit_notify(DEVICED_NOTIFIER_DISPLAY_AMBIENT_CONDITION, (void *)&state);
104 display_plugin_set_dim_state(state);
107 int ambient_set_state(int on)
109 if (!ambient_condition)
112 broadcast_ambient_state(on);
117 * When display is turned off before going to AOD, Generally pm receives
118 * clock signal or ALPMLCDOFF signal and decides to go to AOD or not.
119 * But a specific case, the signal is not received.
120 * So at that time deviced should turn off display to match the pair.
123 display_lock_request_lock_with_option(DEVICED_EVENT_DISPLAY_AMBIENT,
124 LCD_OFF, STAY_CUR_STATE, AMBIENT_CLOCK_WAITING_TIME);
128 _D("AMBIENT is %s.", (on ? ON : OFF));
132 syscommon_notifier_emit_notify(DEVICED_NOTIFIER_DISPLAY_AMBIENT_STATE, (void *)&ambient_state);
137 void ambient_check_invalid_state(pid_t pid)
139 if (pid != DEVICED_EVENT_DISPLAY_AMBIENT)
142 if (syscommon_is_emulator()) {
143 /* In emulator, deviced does not turn off the display. */
144 if (display_panel_get_dpms_cached_state() == DPMS_ON)
148 if (ambient_get_state() == false)
151 _I("Invalid state. Ambient state is change to off.");
153 /* If lcd_power is on and ambient state is true
154 * when pm state is changed to sleep,
155 * deviced doesn't get the clock signal.
156 * deviced just turns off lcd in this case.
159 display_state_transition_reset_state_transition_timeout(TIMEOUT_NONE);
160 lcd_direct_control(DPMS_OFF, NORMAL_MODE);
162 broadcast_lcd_off_late(LCD_OFF_LATE_MODE);
165 static void ambient_start_clock(void)
168 enum deviced_display_state current;
170 ret = display_state_get_current(¤t);
174 if ((current == DEVICED_DISPLAY_STATE_ON) ||
175 (current == DEVICED_DISPLAY_STATE_DIM) ||
176 (ambient_state == false))
179 display_lock_request_lock_with_option(DEVICED_EVENT_DISPLAY_AMBIENT, LCD_OFF, STAY_CUR_STATE,
180 AMBIENT_CLOCK_WAITING_TIME);
183 static void ambient_end_clock(pid_t pid)
186 enum deviced_display_state current;
188 ret = display_state_get_current(¤t);
192 if ((current == DEVICED_DISPLAY_STATE_ON) ||
193 (current == DEVICED_DISPLAY_STATE_DIM) ||
194 (ambient_state == false))
197 if (update_count == 0) {
200 display_panel_set_panel_state_by_off_state(NORMAL_MODE);
201 broadcast_lcd_off_late(LCD_OFF_LATE_MODE);
202 display_lock_request_unlock_with_option(DEVICED_EVENT_DISPLAY_AMBIENT, LCD_OFF, PM_SLEEP_MARGIN);
206 if (update_count == UINT_MAX)
210 _I("Enter real ambient state by process(%d).",
214 static void homescreen_signal_handler(GDBusConnection *conn,
225 if (!g_variant_get_safe(param, "(s)", &screen)) {
226 _E("failed to get params from gvariant. expected:%s, type:%s", "(s)", g_variant_get_type_string(param));
230 if (screen == NULL) {
231 _E("screen is null.");
234 _D("screen : %s", screen);
236 pid = gdbus_connection_get_sender_pid(conn, sender);
238 if (!strncmp(screen, CLOCK_START, strlen(CLOCK_START)))
239 ambient_start_clock();
240 else if (!strncmp(screen, CLOCK_END, strlen(CLOCK_END)))
241 ambient_end_clock(pid);
248 static void ambient_lcdoff_signal_handler(GDBusConnection *conn,
256 if (ambient_state == false) {
257 _E("It is not alpm mode.");
261 display_lock_request_lock_with_option(DEVICED_EVENT_DISPLAY_AMBIENT, LCD_OFF, GOTO_STATE_NOW, 0);
263 _I("Display off in suspend state.");
265 ambient_set_state(false);
266 lcd_direct_control(DPMS_OFF, NORMAL_MODE);
268 broadcast_lcd_off_late(LCD_OFF_LATE_MODE);
269 display_lock_request_unlock_with_option(DEVICED_EVENT_DISPLAY_AMBIENT, LCD_OFF, PM_SLEEP_MARGIN);
272 static void ambient_init(void *data)
276 ret = vconf_get_bool("db/starter/always_on_display", &ambient_condition);
278 _E("Failed to get initial AOD condition. AOD is not going to work.");
281 _I("Ambient mode condition is %d.", ambient_condition);
283 vconf_notify_key_changed("db/starter/always_on_display",
284 ambient_set_condition, NULL);
286 ret = gdbus_signal_subscribe(NULL,
288 DEVICED_INTERFACE_NAME,
290 homescreen_signal_handler,
293 _E("Failed to register signal handler: %d", ret);
295 ret = gdbus_signal_subscribe(NULL,
297 DEVICED_INTERFACE_NAME,
299 ambient_lcdoff_signal_handler,
302 _E("Failed to register signal handler: %d", ret);
305 static void ambient_exit(void *data)
307 ambient_set_state(false);
308 vconf_ignore_key_changed("db/starter/always_on_display", ambient_set_condition);
311 static const struct display_ops ambient_ops = {
313 .init = ambient_init,
314 .exit = ambient_exit,
317 DISPLAY_OPS_REGISTER(&ambient_ops)
319 static void __CONSTRUCTOR__ initialize(void)
321 disp_plgn = get_var_display_plugin();
323 _E("Failed to get display plugin variable.");