Add initialize constructor for variable init.
[platform/core/system/deviced.git] / src / display / ambient-mode.c
1 /*
2  * deviced
3  *
4  * Copyright (c) 2012 - 2017 Samsung Electronics Co., Ltd.
5  *
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
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
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.
17  */
18
19
20 #include <stdbool.h>
21 #include <fcntl.h>
22 #include <libsyscommon/dbus-system.h>
23
24 #include "util.h"
25 #include "core.h"
26 #include "display.h"
27 #include "display-ops.h"
28 #include "core/device-notifier.h"
29 #include "core/devices.h"
30 #include "shared/plugin.h"
31
32 #define ON              "on"
33 #define OFF             "off"
34
35 #define SIGNAL_HOMESCREEN       "HomeScreen"
36
37 #define SIGNAL_ALPMLCDOFF               "ALPMLCDOff"
38 #define SIGNAL_ALPM_ON                  "ALPMOn"
39 #define SIGNAL_ALPM_OFF                 "ALPMOff"
40
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 */
46
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;
52
53 void broadcast_ambient_state(int state)
54 {
55         int ret;
56         char *signal;
57
58         signal = (state == true ? SIGNAL_ALPM_ON : SIGNAL_ALPM_OFF);
59         ret = dbus_handle_emit_dbus_signal(NULL,
60                                                 DEVICED_PATH_DISPLAY,
61                                                 DEVICED_INTERFACE_DISPLAY,
62                                                 signal,
63                                                 NULL);
64         if (ret < 0)
65                 _E("Failed to send dbus signal(%s).", signal);
66 }
67
68 int ambient_get_condition(void)
69 {
70         return ambient_condition;
71 }
72
73 int ambient_get_state(void)
74 {
75         return ambient_state;
76 }
77
78 static void ambient_set_condition(keynode_t *key_nodes, void *data)
79 {
80         int state, val;
81
82         if (key_nodes == NULL) {
83                 _E("Wrong parameter, key_nodes is null.");
84                 return;
85         }
86
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);
92         }
93
94         ambient_condition = val;
95         _I("Ambient mode condition is %d.", ambient_condition);
96
97         state = (ambient_condition == 0 ? 0 : 1);
98         device_notify(DEVICE_NOTIFIER_DISPLAY_AMBIENT_CONDITION, (void *)&state);
99
100         set_dim_state(state);
101 }
102
103 int ambient_set_state(int on)
104 {
105         if (!ambient_condition)
106                 return 0;
107
108         broadcast_ambient_state(on);
109
110         update_count = 0;
111
112         /**
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.
117          */
118         if (on) {
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);
122         } else
123                 ambient_pid = 0;
124
125         _D("AMBIENT is %s.", (on ? ON : OFF));
126
127         ambient_state = on;
128
129         device_notify(DEVICE_NOTIFIER_DISPLAY_AMBIENT_STATE, (void *)&ambient_state);
130
131         return 0;
132 }
133
134 void ambient_check_invalid_state(pid_t pid)
135 {
136         if (pid != INTERNAL_LOCK_AMBIENT)
137                 return;
138
139         if (is_emulator()) {
140                 /* In emulator, deviced does not turn off the display. */
141                 if (backlight_ops.get_lcd_power() == DPMS_ON)
142                         return;
143         }
144
145         if (ambient_get_state() == false)
146                 return;
147
148         _I("Invalid state. Ambient state is change to off.");
149
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.
154          */
155
156         reset_timeout(TIMEOUT_NONE);
157         ambient_set_state(false);
158         lcd_direct_control(DPMS_OFF, NORMAL_MODE);
159
160         broadcast_lcd_off_late(LCD_OFF_LATE_MODE);
161 }
162
163 static void ambient_start_clock(void)
164 {
165         if ((get_pm_cur_state() == S_NORMAL) ||
166             (get_pm_cur_state() == S_LCDDIM) ||
167             (ambient_state == false))
168                 return;
169
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);
173 }
174
175 static void ambient_end_clock(pid_t pid)
176 {
177         if ((get_pm_cur_state() == S_NORMAL) ||
178             (get_pm_cur_state() == S_LCDDIM) ||
179             (ambient_state == false))
180                 return;
181
182         if (update_count == 0) {
183                 _D("lcd off");
184
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);
189         }
190
191         update_count++;
192         if (update_count == UINT_MAX)
193                 update_count = 1;
194         ambient_pid = pid;
195
196         _I("Enter real ambient state by process(%d).",
197             ambient_pid);
198 }
199
200 static void homescreen_signal_handler(GDBusConnection  *conn,
201         const gchar      *sender,
202         const gchar      *path,
203         const gchar      *iface,
204         const gchar      *name,
205         GVariant         *param,
206         gpointer          data)
207 {
208         char *screen = NULL;
209         pid_t pid;
210
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));
213                 goto out;
214         }
215
216         if (screen == NULL) {
217                 _E("screen is null.");
218                 goto out;
219         }
220         _D("screen : %s", screen);
221
222         pid = dbus_connection_get_sender_pid(conn, sender);
223
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);
228
229 out:
230         if (screen)
231                 g_free(screen);
232 }
233
234 static void ambient_lcdoff_signal_handler(GDBusConnection  *conn,
235         const gchar      *sender,
236         const gchar      *path,
237         const gchar      *iface,
238         const gchar      *name,
239         GVariant         *param,
240         gpointer          data)
241 {
242         if (ambient_state == false) {
243                 _E("It is not alpm mode.");
244                 return;
245         }
246
247         if (disp_plgn->pm_lock_internal)
248                 disp_plgn->pm_lock_internal(INTERNAL_LOCK_AMBIENT, LCD_OFF, GOTO_STATE_NOW, 0);
249
250         _I("Display off in suspend state.");
251
252         ambient_set_state(false);
253         lcd_direct_control(DPMS_OFF, NORMAL_MODE);
254
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);
258 }
259
260 static void ambient_init(void *data)
261 {
262         int ret;
263
264         ret = vconf_get_bool("db/starter/always_on_display", &ambient_condition);
265         if (ret < 0) {
266                 _E("Failed to get initial AOD condition. AOD is not going to work.");
267                 return;
268         } else {
269                 _I("Ambient mode condition is %d.", ambient_condition);
270
271                 vconf_notify_key_changed("db/starter/always_on_display",
272                         ambient_set_condition, NULL);
273         }
274         ret = subscribe_dbus_signal(NULL,
275                                 DEVICED_OBJECT_PATH,
276                                 DEVICED_INTERFACE_NAME,
277                                 SIGNAL_HOMESCREEN,
278                                 homescreen_signal_handler,
279                                 NULL, NULL);
280         if (ret <= 0)
281                 _E("Failed to register signal handler: %d", ret);
282
283         ret = subscribe_dbus_signal(NULL,
284                                 DEVICED_OBJECT_PATH,
285                                 DEVICED_INTERFACE_NAME,
286                                 SIGNAL_ALPMLCDOFF,
287                                 ambient_lcdoff_signal_handler,
288                                 NULL, NULL);
289         if (ret <= 0)
290                 _E("Failed to register signal handler: %d", ret);
291 }
292
293 static void ambient_exit(void *data)
294 {
295         ambient_set_state(false);
296         vconf_ignore_key_changed("db/starter/always_on_display", ambient_set_condition);
297 }
298
299 static const struct display_ops ambient_ops = {
300         .name     = "ambient",
301         .init     = ambient_init,
302         .exit     = ambient_exit,
303 };
304
305 DISPLAY_OPS_REGISTER(&ambient_ops)
306
307 static void __CONSTRUCTOR__ initialize(void)
308 {
309         disp_plgn = get_display_plugin();
310         if (!disp_plgn) {
311                 _E("Failed to get display plugin.");
312         }
313 }