4 * Copyright (c) 2016 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.
19 #include <sys/types.h>
25 #include "auto-brightness-sensorhub.h"
26 #include "shared/device-notifier.h"
28 #include "device-interface.h"
30 #include "shared/common.h"
31 #include "shared/devices.h"
32 #include "shared/log.h"
33 #include "display-actor.h"
34 #include "display-info.h"
35 #include "display-panel.h"
36 #include "display-backlight.h"
37 #include "display-ops.h"
38 #include "display-info.h"
40 #define CHARGER_LCD_NODE "/sys/class/power_supply/battery/lcd"
41 #define SIGNAL_HOMESCREEN "HomeScreen"
42 #define CLOCK_CHANGED "clockchanged"
43 #define CLOCK_END "clockend"
45 enum charging_lcd_state {
50 static struct display_backlight_ops *backlight_ops;
51 static guint autobrt_timer;
52 static int autobrtlevel;
54 static bool aod_clock_displayed; /* True while AOD screen is displayed */
56 static gboolean lcdon_from_aod_cb(gpointer data)
58 int level = (int)(intptr_t) data;
62 /* If it is still not turned on, do not apply auto brightness */
63 if (display_panel_get_dpms_cached_state() != DPMS_ON)
64 return G_SOURCE_REMOVE;
66 display_backlight_change_brightness_by_dpms_state(DPMS_ON);
67 set_brightness_level(level);
69 /* lcdon is completed, aod disappered */
70 aod_clock_displayed = false;
72 return G_SOURCE_REMOVE;
75 /* For AOD state, there is race condition between
76 * HomeScreen dbus signal and AutoBrightnessChanged dbus method call.
77 * Cannot decide which one arrives first */
78 static GVariant *dbus_autobrightnesschanged(GDBusConnection *conn,
79 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
80 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
85 g_variant_get(param, "(i)", &level);
87 /* If received level is identical to autobrt timer reserved level, ignore it. */
88 if (autobrt_timer && autobrtlevel == level) {
89 _D("Ignore autobrightness change request as same request(%d) is pending.", level);
90 return g_variant_new("(i)", ret);
94 g_source_remove(autobrt_timer);
98 syscommon_notifier_emit_notify(DEVICE_NOTIFIER_LCD_AUTOBRT_SENSING, NULL);
100 /* When display state changes from AOD to LCDON, brightness change
101 * effect seems sluggish because of heavy load of jobs for turning on
102 * display. So delay this brightness change a bit to avoid this
103 * heavy loaded time and therefore make it change smoothly. */
104 if (aod_clock_displayed) {
105 autobrtlevel = level; /* reserve the level, defer applying */
106 autobrt_timer = g_timeout_add(200, lcdon_from_aod_cb, (gpointer)(intptr_t) level);
107 } else { /* DEVICED_DISPLAY_STATE_ON state or LCDON from usual OFF state, not from AOD */
108 set_brightness_level(level);
111 return g_variant_new("(i)", ret);
114 static void aod_change_signal(GDBusConnection *conn,
125 if (!g_variant_get_safe(param, "(s)", &screen)) {
126 _E("failed to get params from gvariant. expected:%s, type:%s", "(s)", g_variant_get_type_string(param));
130 if (screen == NULL) {
131 _E("screen is null.");
135 /* clock-viewer sends "clockchanged" as signal parameter when AOD->LCDON.
136 * On catching this signal, do change brightness immediately. */
137 if (!strcmp(screen, CLOCK_CHANGED)) {
138 /* aod_clock_displayed can be false if this clockchanged siganl arrives after 200ms timeout.
139 * In this situation, there is noting to do because all the
140 * brightness-related task, which should have been done in this routine,
141 * have been performed by timeout callback, lcdon_from_aod_cb(). */
142 if (!aod_clock_displayed)
145 display_backlight_change_brightness_by_dpms_state(DPMS_ON);
146 if (autobrt_timer) { /* if there is reserved level, apply it */
147 g_source_remove(autobrt_timer);
149 set_brightness_level(autobrtlevel);
151 /* lcdon is completed, aod disappered */
152 aod_clock_displayed = false;
153 } else if (!strcmp(screen, CLOCK_END)) {
154 /* lcdoff is completed, aod showed up */
155 aod_clock_displayed = true;
163 static const dbus_method_s dbus_methods[] = {
164 { "AutoBrightnessChanged", "i", "i", dbus_autobrightnesschanged },
167 static const dbus_interface_u dbus_interface = {
169 .name = DEVICED_INTERFACE_DISPLAY,
170 .methods = dbus_methods,
171 .nr_methods = ARRAY_SIZE(dbus_methods),
174 static int display_state_changed(void *data)
176 enum deviced_display_state state;
179 state = DATA_VALUE_INT(data);
181 if (state == DEVICED_DISPLAY_STATE_ON)
182 ret = sys_set_int(CHARGER_LCD_NODE, CHARGING_LCD_ON);
184 ret = sys_set_int(CHARGER_LCD_NODE, CHARGING_LCD_OFF);
187 _E("Can't write %s node %d.", CHARGER_LCD_NODE, state);
192 static void display_handler_init(void *data)
196 prepare_level_handler();
197 syscommon_notifier_subscribe_notify(DEVICE_NOTIFIER_LCD, display_state_changed);
199 aod_clock_displayed = false;
200 ret = gdbus_signal_subscribe(NULL,
202 DEVICED_INTERFACE_NAME,
207 _E("Failed to register signal handler: %d", ret);
209 ret = sys_set_int(CHARGER_LCD_NODE, CHARGING_LCD_ON);
211 _E("Can't write %s node.", CHARGER_LCD_NODE);
213 ret = gdbus_add_object(NULL, DEVICED_PATH_DISPLAY, &dbus_interface);
215 _E("Failed to register dbus object.");
218 static const struct display_ops display_handler_ops = {
219 .name = "dislay-handler",
220 .init = display_handler_init,
223 DISPLAY_OPS_REGISTER(&display_handler_ops)
225 static void __CONSTRUCTOR__ initialize(void)
227 backlight_ops = get_var_backlight_ops();
229 _E("Failed to get backlight operator variable.");