tizen 2.4 release
[framework/uifw/e17-mod-tizen-devicemgr.git] / src / rotation_devicemgr.c
1 /*
2  * Copyright (c) 2013 Samsung Electronics Co., Ltd. All rights reserved.
3  *
4  * This file is a modified version of BSD licensed file and
5  * licensed under the Flora License, Version 1.1 (the License);
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *     http://floralicense.org/license/
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an AS IS BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  * Please, see the COPYING file for the original copyright owner and
18  * license.
19  */
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <errno.h>
23 #include <stdlib.h>
24 #include <unistd.h>
25
26 #include <e.h>
27 #include <sensor_internal_deprecated.h>
28 #include <sensor_auto_rotation.h>
29 #include <vconf.h>
30 #include <X11/Xlib.h>
31 #include "e_devicemgr_privates.h"
32 #include "rotation_devicemgr.h"
33
34 #include "dlog.h"
35 #undef LOG_TAG
36 #define LOG_TAG "E17_EXTRA_MODULES"
37
38 typedef struct _E_DM_Sensor_Rotation E_DM_Sensor_Rotation;
39
40 struct _E_DM_Sensor_Rotation
41 {
42    int                             handle;
43    Eina_Bool                       started;
44    enum auto_rotation_state        state;
45    Ecore_Timer                    *retry_timer;
46    int                             retry_count;
47    Eina_Bool                       lock;
48    Eina_Bool                       connected;
49 };
50
51 /* static global variables */
52 static E_DM_Sensor_Rotation rot;
53 static Ecore_X_Atom ATOM_DEVICE_ROTATION_ANGLE = 0;
54
55 /* local subsystem functions */
56 static Eina_Bool _sensor_connect(void);
57 static Eina_Bool _sensor_disconnect(void);
58 static Eina_Bool _sensor_connect_retry_timeout(void *data);
59 static void      _sensor_rotation_changed_cb(unsigned int event_type, sensor_event_data_t *event, void *data);
60 static void      _vconf_cb_lock_change(keynode_t *node, void *data);
61 static void      _sensor_rotation_set(int ang);
62 static int       _ang_get(enum auto_rotation_state state);
63
64 /* externally accessible functions */
65 Eina_Bool 
66 e_mod_sf_rotation_init(void)
67 {
68    int r = 0, lock = 0;
69    Eina_Bool res = EINA_FALSE;
70
71    rot.connected = EINA_FALSE;
72    rot.retry_count = 0;
73    res = _sensor_connect();
74    if (res)
75      {
76         r = vconf_get_bool(VCONFKEY_SETAPPL_AUTO_ROTATE_SCREEN_BOOL, &lock);
77         if (r)
78           {
79              ELBF(ELBT_ROT, 0, 0,
80                   "ERR! AUTO_ROTATE_SCREEN_BOOL get failed. "
81                   "r:%d lock:%d", r, lock);
82           }
83         else
84           {
85              rot.lock = !lock;
86              vconf_notify_key_changed(VCONFKEY_SETAPPL_AUTO_ROTATE_SCREEN_BOOL,
87                                       _vconf_cb_lock_change,
88                                       NULL);
89              ELBF(ELBT_ROT, 0, 0,
90                   "AUTO_ROTATE_SCREEN_BOOL get succeeded. "
91                   "lock:%d rot.locK%d", lock, rot.lock);
92           }
93      }
94    _sensor_rotation_set(0);
95    return EINA_TRUE;
96 }
97
98 Eina_Bool 
99 e_mod_sf_rotation_deinit(void)
100 {
101    vconf_ignore_key_changed(VCONFKEY_SETAPPL_AUTO_ROTATE_SCREEN_BOOL, _vconf_cb_lock_change);
102    _sensor_disconnect();
103    return EINA_TRUE;
104 }
105
106 /* local subsystem functions */
107 static Eina_Bool
108 _sensor_connect(void)
109 {
110    int h, r, lock = 0;
111    if (rot.connected) return EINA_TRUE;
112
113    if (rot.retry_timer)
114      {
115         ecore_timer_del(rot.retry_timer);
116         rot.retry_timer = NULL;
117      }
118
119    rot.handle = -1;
120    rot.started = EINA_FALSE;
121
122    h = sf_connect(AUTO_ROTATION_SENSOR);
123    if (h < 0)
124      {
125         ELB(ELBT_ROT, "ERR! sf_connect failed", h);
126         goto error;
127      }
128
129    r = sf_register_event(h, AUTO_ROTATION_EVENT_CHANGE_STATE,
130                          NULL, _sensor_rotation_changed_cb, NULL);
131    if (r < 0)
132      {
133         ELB(ELBT_ROT, "ERR! sf_register_event failed", r);
134         sf_disconnect(h);
135         goto error;
136      }
137
138    r = sf_start(h, 0);
139    if (r < 0)
140      {
141         ELB(ELBT_ROT, "ERR! sf_start failed", r);
142         sf_unregister_event(h, AUTO_ROTATION_EVENT_CHANGE_STATE);
143         sf_disconnect(h);
144         goto error;
145      }
146
147    rot.handle = h;
148    rot.started = EINA_TRUE;
149    rot.retry_count = 0;
150    rot.lock = EINA_FALSE;
151    rot.connected = EINA_TRUE;
152
153    ELB(ELBT_ROT, "sf_connect succeeded", h);
154    return EINA_TRUE;
155
156 error:
157    if (rot.retry_count <= 20)
158      {
159         rot.retry_timer = ecore_timer_add(10.0f,
160                                           _sensor_connect_retry_timeout,
161                                           NULL);
162      }
163    return EINA_FALSE;
164 }
165
166 static Eina_Bool
167 _sensor_disconnect(void)
168 {
169    int r;
170    if (!rot.connected) return EINA_TRUE;
171
172    rot.lock = EINA_FALSE;
173
174    if (rot.retry_timer)
175      {
176         ecore_timer_del(rot.retry_timer);
177         rot.retry_timer = NULL;
178      }
179
180    rot.retry_count = 0;
181
182    if (rot.handle < 0)
183      {
184         ELB(ELBT_ROT, "ERR! invalid handle", rot.handle);
185         goto error;
186      }
187
188    if (rot.started)
189      {
190         r = sf_unregister_event(rot.handle,
191                                 AUTO_ROTATION_EVENT_CHANGE_STATE);
192         if (r < 0)
193           {
194              ELB(ELBT_ROT, "ERR! sf_unregister_event failed", r);
195              goto error;
196           }
197         r = sf_stop(rot.handle);
198         if (r < 0)
199           {
200              ELB(ELBT_ROT, "ERR! sf_stop failed", r);
201              goto error;
202           }
203         rot.started = EINA_TRUE;
204      }
205
206    r = sf_disconnect(rot.handle);
207    if (r < 0)
208      {
209         ELB(ELBT_ROT, "ERR! sf_disconnect failed", r);
210         goto error;
211      }
212
213    rot.handle = -1;
214    rot.connected = EINA_FALSE;
215    ELB(ELBT_ROT, "sf_disconnect succeeded", NULL);
216    return EINA_TRUE;
217 error:
218    return EINA_FALSE;
219 }
220
221 static Eina_Bool
222 _sensor_connect_retry_timeout(void *data)
223 {
224    int r = 0, lock = 0;
225    Eina_Bool res = EINA_FALSE;
226
227    if (rot.retry_timer)
228      {
229         ecore_timer_del(rot.retry_timer);
230         rot.retry_timer = NULL;
231      }
232    rot.retry_count++;
233    ELB(ELBT_ROT, "retrying to connect sensor", rot.retry_count);
234    res = _sensor_connect();
235    if (res)
236      {
237         r = vconf_get_bool(VCONFKEY_SETAPPL_AUTO_ROTATE_SCREEN_BOOL, &lock);
238         if (r)
239           {
240              ELBF(ELBT_ROT, 0, 0,
241                   "ERR! AUTO_ROTATE_SCREEN_BOOL get failed. "
242                   "r:%d lock:%d", r, lock);
243           }
244         else
245           {
246              rot.lock = !lock;
247              vconf_notify_key_changed(VCONFKEY_SETAPPL_AUTO_ROTATE_SCREEN_BOOL,
248                                       _vconf_cb_lock_change,
249                                       NULL);
250              ELBF(ELBT_ROT, 0, 0,
251                   "AUTO_ROTATE_SCREEN_BOOL get succeeded. "
252                   "lock:%d rot.locK%d", lock, rot.lock);
253           }
254      }
255
256    return ECORE_CALLBACK_CANCEL;
257 }
258
259 static int
260 _ang_get(enum auto_rotation_state state)
261 {
262    E_Devicemgr_Config_Rotation *cr = NULL;
263    Eina_List *l = NULL;
264    int ang = -1, res = -1;
265
266    /* change CW (SensorFW) to CCW(EFL) */
267    switch (state)
268      {
269       case AUTO_ROTATION_DEGREE_0:     ang = 0; break;
270       case AUTO_ROTATION_DEGREE_90:    ang = 270; break;
271       case AUTO_ROTATION_DEGREE_180:   ang = 180; break;
272       case AUTO_ROTATION_DEGREE_270:   ang = 90; break;
273       default:
274          ELB(ELBT_ROT, "Unknown state", state);
275         break;
276      }
277
278    EINA_LIST_FOREACH(_e_devicemgr_cfg->rotation, l, cr)
279      {
280         if (!cr) continue;
281         if (cr->angle == ang)
282           {
283              if (cr->enable)
284                res = ang;
285              break;
286           }
287      }
288
289    return res;
290 }
291
292 enum auto_rotation_state
293 _state_get(int ang)
294 {
295    switch (ang)
296      {
297       case 0:
298          return AUTO_ROTATION_DEGREE_0;
299       case 270:
300          return AUTO_ROTATION_DEGREE_90;
301       case 180:
302          return AUTO_ROTATION_DEGREE_180;
303       case 90:
304          return AUTO_ROTATION_DEGREE_270;
305       default:
306          return AUTO_ROTATION_DEGREE_UNKNOWN;
307      }
308 }
309
310 static void
311 _sensor_rotation_changed_cb(unsigned int         event_type,
312                             sensor_event_data_t *event,
313                             void                *data)
314 {
315     enum auto_rotation_state state;
316     E_Manager *m = e_manager_current_get();
317     E_Zone *zone = e_util_zone_current_get(m);
318     int ang = 0;
319
320     if (rot.lock) return;
321     if (!zone) return;
322     if (event_type != AUTO_ROTATION_EVENT_CHANGE_STATE) return;
323     if (!event) return;
324
325     state = *((enum auto_rotation_state*)(event->event_data));
326
327     ang = _ang_get(state);
328
329     SECURE_SLOGD("[ROTATION] SENSOR ROT_CHANGE, state:%d angle:%d", state, ang);
330     ELBF(ELBT_ROT, 0, 0, "ROT_EV state:%d angle:%d", state, ang);
331
332     e_zone_rotation_set(zone, ang);
333
334     rot.state = state;
335     _sensor_rotation_set(ang);
336 }
337
338 static void
339 _vconf_cb_lock_change(keynode_t *node,
340                       void      *data)
341 {
342    E_Manager *m = NULL;
343    E_Zone *zone = NULL;
344    int lock = 0, z_ang = -1, ang = -1;
345    Eina_Bool res = EINA_FALSE;
346    if (!node)
347      {
348         ELB(ELBT_ROT, "ERR! node is NULL", 0);
349         return;
350      }
351
352    m = e_manager_current_get();
353    if (m) zone = e_util_zone_current_get(m);
354
355    lock = !vconf_keynode_get_bool(node);
356    ELBF(ELBT_ROT, 0, 0, "ROT LOCK: %d->%d", rot.lock, lock);
357
358    if (lock)
359      {
360         // disconnect sensor for reducing the current sinking.
361         _sensor_disconnect();
362         if (zone) e_zone_rotation_set(zone, 0);
363         rot.state = AUTO_ROTATION_DEGREE_0;
364      }
365    else
366      {
367         // connect sensor for auto rotation.
368         res = _sensor_connect();
369         ELB(ELBT_ROT, "_sensor_connect() res", res);
370         if (res)
371           {
372              sensor_data_t data;
373              if (sf_get_data(rot.handle, AUTO_ROTATION_BASE_DATA_SET, &data) < 0)
374                {
375                   ELB(ELBT_ROT, "ERR! getting rotation failed", NULL);
376                }
377              else
378                {
379                   ang = _ang_get(data.values[0]);
380                   if (zone) z_ang = e_zone_rotation_get(zone);
381                   if ((ang != -1) && (ang != z_ang))
382                     {
383                        if (zone) e_zone_rotation_set(zone, ang);
384                        rot.state = _state_get(ang);
385                        _sensor_rotation_set(ang);
386                     }
387                }
388           }
389      }
390
391    rot.lock = lock;
392 }
393
394 static void
395 _sensor_rotation_set(int ang)
396 {
397    Ecore_X_Window root = ecore_x_window_root_first_get();
398    unsigned int val = (unsigned int)ang;
399
400    if (!ATOM_DEVICE_ROTATION_ANGLE)
401      ATOM_DEVICE_ROTATION_ANGLE = ecore_x_atom_get("_E_DEVICE_ROTATION_ANGLE");
402
403    ecore_x_window_prop_card32_set(root,
404                                   ATOM_DEVICE_ROTATION_ANGLE,
405                                   &val, 1);
406 }