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/dbus-system.h>
27 #include "display-ops.h"
28 #include "core/device-notifier.h"
29 #include "core/devices.h"
30 #include "shared/plugin.h"
35 #define SIGNAL_HOMESCREEN "HomeScreen"
37 #define SIGNAL_ALPMLCDOFF "ALPMLCDOff"
38 #define SIGNAL_ALPM_ON "ALPMOn"
39 #define SIGNAL_ALPM_OFF "ALPMOff"
41 #define CLOCK_START "clockstart"
42 #define CLOCK_END "clockend"
43 #define CLOCK_CHANGED "clockchanged"
44 #define TIMEOUT_NONE (-1)
45 #define AMBIENT_CLOCK_WAITING_TIME 5000 /* ms */
47 static struct display_plugin *disp_plgn;
48 static int ambient_state;
49 static int ambient_condition; /* Setting Value */
50 static pid_t ambient_pid; /* Ambient Clock pid */
51 static unsigned int update_count;
53 void broadcast_ambient_state(int state)
58 signal = (state == true ? SIGNAL_ALPM_ON : SIGNAL_ALPM_OFF);
59 ret = dbus_handle_emit_dbus_signal(NULL,
61 DEVICED_INTERFACE_DISPLAY,
65 _E("Failed to send dbus signal(%s).", signal);
68 int ambient_get_condition(void)
70 return ambient_condition;
73 int ambient_get_state(void)
78 static void ambient_set_condition(keynode_t *key_nodes, void *data)
82 if (key_nodes == NULL) {
83 _E("Wrong parameter, key_nodes is null.");
87 val = vconf_keynode_get_bool(key_nodes);
88 if (val != ambient_condition) {
89 if (backlight_ops.get_lcd_power() != DPMS_ON)
90 if (disp_plgn->pm_lock_internal)
91 disp_plgn->pm_change_internal(INTERNAL_LOCK_PM, LCD_NORMAL);
94 ambient_condition = val;
95 _I("Ambient mode condition is %d.", ambient_condition);
97 state = (ambient_condition == 0 ? 0 : 1);
98 device_notify(DEVICE_NOTIFIER_DISPLAY_AMBIENT_CONDITION, (void *)&state);
100 set_dim_state(state);
103 int ambient_set_state(int on)
105 if (!ambient_condition)
108 broadcast_ambient_state(on);
113 * When display is turned off before going to AOD, Generally pm receives
114 * clock signal or ALPMLCDOFF signal and decides to go to AOD or not.
115 * But a specific case, the signal is not received.
116 * So at that time deviced should turn off display to match the pair.
119 if (disp_plgn->pm_lock_internal)
120 disp_plgn->pm_lock_internal(INTERNAL_LOCK_AMBIENT,
121 LCD_OFF, STAY_CUR_STATE, AMBIENT_CLOCK_WAITING_TIME);
125 _D("AMBIENT is %s.", (on ? ON : OFF));
129 device_notify(DEVICE_NOTIFIER_DISPLAY_AMBIENT_STATE, (void *)&ambient_state);
134 void ambient_check_invalid_state(pid_t pid)
136 if (pid != INTERNAL_LOCK_AMBIENT)
140 /* In emulator, deviced does not turn off the display. */
141 if (backlight_ops.get_lcd_power() == DPMS_ON)
145 if (ambient_get_state() == false)
148 _I("Invalid state. Ambient state is change to off.");
150 /* If lcd_power is on and ambient state is true
151 * when pm state is changed to sleep,
152 * deviced doesn't get the clock signal.
153 * deviced just turns off lcd in this case.
156 reset_timeout(TIMEOUT_NONE);
157 ambient_set_state(false);
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 backlight_ops.off(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 (!dh_get_param_from_var(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 = dbus_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 = subscribe_dbus_signal(NULL,
276 DEVICED_INTERFACE_NAME,
278 homescreen_signal_handler,
281 _E("Failed to register signal handler: %d", ret);
283 ret = subscribe_dbus_signal(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_display_plugin();
311 _E("Failed to get display plugin.");