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 "display-state-transition.h"
30 #include "shared/device-notifier.h"
31 #include "shared/devices.h"
32 #include "shared/plugin.h"
37 #define SIGNAL_HOMESCREEN "HomeScreen"
39 #define SIGNAL_ALPMLCDOFF "ALPMLCDOff"
40 #define SIGNAL_ALPM_ON "ALPMOn"
41 #define SIGNAL_ALPM_OFF "ALPMOff"
43 #define CLOCK_START "clockstart"
44 #define CLOCK_END "clockend"
45 #define CLOCK_CHANGED "clockchanged"
46 #define TIMEOUT_NONE (-1)
47 #define AMBIENT_CLOCK_WAITING_TIME 5000 /* ms */
49 static struct display_plugin *disp_plgn;
50 static int ambient_state;
51 static int ambient_condition; /* Setting Value */
52 static pid_t ambient_pid; /* Ambient Clock pid */
53 static unsigned int update_count;
55 void broadcast_ambient_state(int state)
60 signal = (state == true ? SIGNAL_ALPM_ON : SIGNAL_ALPM_OFF);
61 ret = gdbus_signal_emit(NULL,
63 DEVICED_INTERFACE_DISPLAY,
67 _E("Failed to send dbus signal(%s).", signal);
70 int ambient_get_condition(void)
72 return ambient_condition;
75 int ambient_get_state(void)
80 static void ambient_set_condition(keynode_t *key_nodes, void *data)
84 if (key_nodes == NULL) {
85 _E("Wrong parameter, key_nodes is null.");
89 val = vconf_keynode_get_bool(key_nodes);
90 if (val != ambient_condition) {
91 if (display_panel_get_dpms_cached_state() != DPMS_ON)
92 if (disp_plgn->pm_lock_internal)
93 disp_plgn->pm_change_internal(INTERNAL_LOCK_PM, LCD_NORMAL);
96 ambient_condition = val;
97 _I("Ambient mode condition is %d.", ambient_condition);
99 state = (ambient_condition == 0 ? 0 : 1);
100 device_notify(DEVICE_NOTIFIER_DISPLAY_AMBIENT_CONDITION, (void *)&state);
102 set_dim_state(state);
105 int ambient_set_state(int on)
107 if (!ambient_condition)
110 broadcast_ambient_state(on);
115 * When display is turned off before going to AOD, Generally pm receives
116 * clock signal or ALPMLCDOFF signal and decides to go to AOD or not.
117 * But a specific case, the signal is not received.
118 * So at that time deviced should turn off display to match the pair.
121 if (disp_plgn->pm_lock_internal)
122 disp_plgn->pm_lock_internal(INTERNAL_LOCK_AMBIENT,
123 LCD_OFF, STAY_CUR_STATE, AMBIENT_CLOCK_WAITING_TIME);
127 _D("AMBIENT is %s.", (on ? ON : OFF));
131 device_notify(DEVICE_NOTIFIER_DISPLAY_AMBIENT_STATE, (void *)&ambient_state);
136 void ambient_check_invalid_state(pid_t pid)
138 if (pid != INTERNAL_LOCK_AMBIENT)
142 /* In emulator, deviced does not turn off the display. */
143 if (display_panel_get_dpms_cached_state() == DPMS_ON)
147 if (ambient_get_state() == false)
150 _I("Invalid state. Ambient state is change to off.");
152 /* If lcd_power is on and ambient state is true
153 * when pm state is changed to sleep,
154 * deviced doesn't get the clock signal.
155 * deviced just turns off lcd in this case.
158 display_state_transition_reset_state_transition_timeout(TIMEOUT_NONE);
159 lcd_direct_control(DPMS_OFF, NORMAL_MODE);
161 broadcast_lcd_off_late(LCD_OFF_LATE_MODE);
164 static void ambient_start_clock(void)
166 if ((get_pm_cur_state() == S_NORMAL) ||
167 (get_pm_cur_state() == S_LCDDIM) ||
168 (ambient_state == false))
171 if (disp_plgn->pm_lock_internal)
172 disp_plgn->pm_lock_internal(INTERNAL_LOCK_AMBIENT, LCD_OFF, STAY_CUR_STATE,
173 AMBIENT_CLOCK_WAITING_TIME);
176 static void ambient_end_clock(pid_t pid)
178 if ((get_pm_cur_state() == S_NORMAL) ||
179 (get_pm_cur_state() == S_LCDDIM) ||
180 (ambient_state == false))
183 if (update_count == 0) {
186 display_panel_set_panel_state_by_off_state(NORMAL_MODE);
187 broadcast_lcd_off_late(LCD_OFF_LATE_MODE);
188 if (disp_plgn->pm_unlock_internal)
189 disp_plgn->pm_unlock_internal(INTERNAL_LOCK_AMBIENT, LCD_OFF, PM_SLEEP_MARGIN);
193 if (update_count == UINT_MAX)
197 _I("Enter real ambient state by process(%d).",
201 static void homescreen_signal_handler(GDBusConnection *conn,
212 if (!g_variant_get_safe(param, "(s)", &screen)) {
213 _E("failed to get params from gvariant. expected:%s, type:%s", "(s)", g_variant_get_type_string(param));
217 if (screen == NULL) {
218 _E("screen is null.");
221 _D("screen : %s", screen);
223 pid = gdbus_connection_get_sender_pid(conn, sender);
225 if (!strncmp(screen, CLOCK_START, strlen(CLOCK_START)))
226 ambient_start_clock();
227 else if (!strncmp(screen, CLOCK_END, strlen(CLOCK_END)))
228 ambient_end_clock(pid);
235 static void ambient_lcdoff_signal_handler(GDBusConnection *conn,
243 if (ambient_state == false) {
244 _E("It is not alpm mode.");
248 if (disp_plgn->pm_lock_internal)
249 disp_plgn->pm_lock_internal(INTERNAL_LOCK_AMBIENT, LCD_OFF, GOTO_STATE_NOW, 0);
251 _I("Display off in suspend state.");
253 ambient_set_state(false);
254 lcd_direct_control(DPMS_OFF, NORMAL_MODE);
256 broadcast_lcd_off_late(LCD_OFF_LATE_MODE);
257 if (disp_plgn->pm_unlock_internal)
258 disp_plgn->pm_unlock_internal(INTERNAL_LOCK_AMBIENT, LCD_OFF, PM_SLEEP_MARGIN);
261 static void ambient_init(void *data)
265 ret = vconf_get_bool("db/starter/always_on_display", &ambient_condition);
267 _E("Failed to get initial AOD condition. AOD is not going to work.");
270 _I("Ambient mode condition is %d.", ambient_condition);
272 vconf_notify_key_changed("db/starter/always_on_display",
273 ambient_set_condition, NULL);
275 ret = gdbus_signal_subscribe(NULL,
277 DEVICED_INTERFACE_NAME,
279 homescreen_signal_handler,
282 _E("Failed to register signal handler: %d", ret);
284 ret = gdbus_signal_subscribe(NULL,
286 DEVICED_INTERFACE_NAME,
288 ambient_lcdoff_signal_handler,
291 _E("Failed to register signal handler: %d", ret);
294 static void ambient_exit(void *data)
296 ambient_set_state(false);
297 vconf_ignore_key_changed("db/starter/always_on_display", ambient_set_condition);
300 static const struct display_ops ambient_ops = {
302 .init = ambient_init,
303 .exit = ambient_exit,
306 DISPLAY_OPS_REGISTER(&ambient_ops)
308 static void __CONSTRUCTOR__ initialize(void)
310 disp_plgn = get_var_display_plugin();
312 _E("Failed to get display plugin variable.");