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>
27 #include "display-ops.h"
28 #include "display-panel.h"
29 #include "shared/device-notifier.h"
30 #include "shared/devices.h"
31 #include "shared/plugin.h"
36 #define SIGNAL_HOMESCREEN "HomeScreen"
38 #define SIGNAL_ALPMLCDOFF "ALPMLCDOff"
39 #define SIGNAL_ALPM_ON "ALPMOn"
40 #define SIGNAL_ALPM_OFF "ALPMOff"
42 #define CLOCK_START "clockstart"
43 #define CLOCK_END "clockend"
44 #define CLOCK_CHANGED "clockchanged"
45 #define TIMEOUT_NONE (-1)
46 #define AMBIENT_CLOCK_WAITING_TIME 5000 /* ms */
48 static struct display_plugin *disp_plgn;
49 static int ambient_state;
50 static int ambient_condition; /* Setting Value */
51 static pid_t ambient_pid; /* Ambient Clock pid */
52 static unsigned int update_count;
54 void broadcast_ambient_state(int state)
59 signal = (state == true ? SIGNAL_ALPM_ON : SIGNAL_ALPM_OFF);
60 ret = gdbus_signal_emit(NULL,
62 DEVICED_INTERFACE_DISPLAY,
66 _E("Failed to send dbus signal(%s).", signal);
69 int ambient_get_condition(void)
71 return ambient_condition;
74 int ambient_get_state(void)
79 static void ambient_set_condition(keynode_t *key_nodes, void *data)
83 if (key_nodes == NULL) {
84 _E("Wrong parameter, key_nodes is null.");
88 val = vconf_keynode_get_bool(key_nodes);
89 if (val != ambient_condition) {
90 if (display_panel_get_dpms_cached_state() != DPMS_ON)
91 if (disp_plgn->pm_lock_internal)
92 disp_plgn->pm_change_internal(INTERNAL_LOCK_PM, LCD_NORMAL);
95 ambient_condition = val;
96 _I("Ambient mode condition is %d.", ambient_condition);
98 state = (ambient_condition == 0 ? 0 : 1);
99 device_notify(DEVICE_NOTIFIER_DISPLAY_AMBIENT_CONDITION, (void *)&state);
101 set_dim_state(state);
104 int ambient_set_state(int on)
106 if (!ambient_condition)
109 broadcast_ambient_state(on);
114 * When display is turned off before going to AOD, Generally pm receives
115 * clock signal or ALPMLCDOFF signal and decides to go to AOD or not.
116 * But a specific case, the signal is not received.
117 * So at that time deviced should turn off display to match the pair.
120 if (disp_plgn->pm_lock_internal)
121 disp_plgn->pm_lock_internal(INTERNAL_LOCK_AMBIENT,
122 LCD_OFF, STAY_CUR_STATE, AMBIENT_CLOCK_WAITING_TIME);
126 _D("AMBIENT is %s.", (on ? ON : OFF));
130 device_notify(DEVICE_NOTIFIER_DISPLAY_AMBIENT_STATE, (void *)&ambient_state);
135 void ambient_check_invalid_state(pid_t pid)
137 if (pid != INTERNAL_LOCK_AMBIENT)
141 /* In emulator, deviced does not turn off the display. */
142 if (display_panel_get_dpms_cached_state() == DPMS_ON)
146 if (ambient_get_state() == false)
149 _I("Invalid state. Ambient state is change to off.");
151 /* If lcd_power is on and ambient state is true
152 * when pm state is changed to sleep,
153 * deviced doesn't get the clock signal.
154 * deviced just turns off lcd in this case.
157 reset_timeout(TIMEOUT_NONE);
158 lcd_direct_control(DPMS_OFF, NORMAL_MODE);
160 broadcast_lcd_off_late(LCD_OFF_LATE_MODE);
163 static void ambient_start_clock(void)
165 if ((get_pm_cur_state() == S_NORMAL) ||
166 (get_pm_cur_state() == S_LCDDIM) ||
167 (ambient_state == false))
170 if (disp_plgn->pm_lock_internal)
171 disp_plgn->pm_lock_internal(INTERNAL_LOCK_AMBIENT, LCD_OFF, STAY_CUR_STATE,
172 AMBIENT_CLOCK_WAITING_TIME);
175 static void ambient_end_clock(pid_t pid)
177 if ((get_pm_cur_state() == S_NORMAL) ||
178 (get_pm_cur_state() == S_LCDDIM) ||
179 (ambient_state == false))
182 if (update_count == 0) {
185 display_panel_set_panel_state_by_off_state(NORMAL_MODE);
186 broadcast_lcd_off_late(LCD_OFF_LATE_MODE);
187 if (disp_plgn->pm_unlock_internal)
188 disp_plgn->pm_unlock_internal(INTERNAL_LOCK_AMBIENT, LCD_OFF, PM_SLEEP_MARGIN);
192 if (update_count == UINT_MAX)
196 _I("Enter real ambient state by process(%d).",
200 static void homescreen_signal_handler(GDBusConnection *conn,
211 if (!g_variant_get_safe(param, "(s)", &screen)) {
212 _E("failed to get params from gvariant. expected:%s, type:%s", "(s)", g_variant_get_type_string(param));
216 if (screen == NULL) {
217 _E("screen is null.");
220 _D("screen : %s", screen);
222 pid = gdbus_connection_get_sender_pid(conn, sender);
224 if (!strncmp(screen, CLOCK_START, strlen(CLOCK_START)))
225 ambient_start_clock();
226 else if (!strncmp(screen, CLOCK_END, strlen(CLOCK_END)))
227 ambient_end_clock(pid);
234 static void ambient_lcdoff_signal_handler(GDBusConnection *conn,
242 if (ambient_state == false) {
243 _E("It is not alpm mode.");
247 if (disp_plgn->pm_lock_internal)
248 disp_plgn->pm_lock_internal(INTERNAL_LOCK_AMBIENT, LCD_OFF, GOTO_STATE_NOW, 0);
250 _I("Display off in suspend state.");
252 ambient_set_state(false);
253 lcd_direct_control(DPMS_OFF, NORMAL_MODE);
255 broadcast_lcd_off_late(LCD_OFF_LATE_MODE);
256 if (disp_plgn->pm_unlock_internal)
257 disp_plgn->pm_unlock_internal(INTERNAL_LOCK_AMBIENT, LCD_OFF, PM_SLEEP_MARGIN);
260 static void ambient_init(void *data)
264 ret = vconf_get_bool("db/starter/always_on_display", &ambient_condition);
266 _E("Failed to get initial AOD condition. AOD is not going to work.");
269 _I("Ambient mode condition is %d.", ambient_condition);
271 vconf_notify_key_changed("db/starter/always_on_display",
272 ambient_set_condition, NULL);
274 ret = gdbus_signal_subscribe(NULL,
276 DEVICED_INTERFACE_NAME,
278 homescreen_signal_handler,
281 _E("Failed to register signal handler: %d", ret);
283 ret = gdbus_signal_subscribe(NULL,
285 DEVICED_INTERFACE_NAME,
287 ambient_lcdoff_signal_handler,
290 _E("Failed to register signal handler: %d", ret);
293 static void ambient_exit(void *data)
295 ambient_set_state(false);
296 vconf_ignore_key_changed("db/starter/always_on_display", ambient_set_condition);
299 static const struct display_ops ambient_ops = {
301 .init = ambient_init,
302 .exit = ambient_exit,
305 DISPLAY_OPS_REGISTER(&ambient_ops)
307 static void __CONSTRUCTOR__ initialize(void)
309 disp_plgn = get_var_display_plugin();
311 _E("Failed to get display plugin variable.");