ca484a6a37132e68e7540ded5556cc57549c4f42
[profile/tv/apps/native/settings.git] / src / view_need_pwd.c
1 /*
2  * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  * Licensed under the Apache License, Version 2.0 (the License);
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an AS IS BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include <utilX.h>
18
19 #include "dbg.h"
20 #include "def.h"
21 #include "utils.h"
22 #include "settings_provider.h"
23 #include "view_need_pwd.h"
24
25 #define CHNLLOCK_DATA_ID "view_need_passcode_data"
26
27 #define MSGID_TITLE "Passcode"
28 #define MSGID_TEXT "Please enter your passcode"
29 #define MSGID_CANCEL "Cancel"
30 #define MSGID_WRONG_PWD "Wrong passcode, please try again"
31
32 #define CTXPOPUP_WIDTH 688
33 #define CTXPOPUP_HEIGHT 411
34
35 #define KEY_PASSCODE "settings/system/change_passcode"
36 #define VCONF_TYPE_STRING "string"
37
38 #define BOX_PADDING 10
39
40 #define SIG_CLICKED "clicked"
41 #define SIG_DISMISSED "dismissed"
42
43 #define PWD_SYMBOL "*"
44 #define PWD_RANGE "0123456789"
45 #define EMPTY_SYMBOL ""
46
47 enum {
48         PWD_ENTRY_0,
49         PWD_ENTRY_1,
50         PWD_ENTRY_2,
51         PWD_ENTRY_3,
52         PWD_ENTRY_MAX
53 };
54
55 struct _chnllock_data {
56         Evas_Object *win;
57         Evas_Object *bg;
58         Evas_Object *base;
59         Evas_Object *ctxpopup;
60         Evas_Object *cancel_btn;
61         Evas_Object *box;
62
63         Eina_Array *array;
64
65         char passcode[BUF_SIZE];
66
67         struct setting_mgr *mgr;
68         struct settingview_data *view;
69         struct obj_geometry_data gd;
70 };
71
72 static void _free_priv_data(struct _chnllock_data *data);
73 static void _hide(Evas_Object *base);
74
75 /**
76 * Free user data.
77 *
78 * @param[in]: data : the user data of channel lock.
79 *
80 * @return: void.
81 */
82 static void _free_priv_data(struct _chnllock_data *data)
83 {
84         if (!data)
85                 return;
86
87         if (data->bg)
88                 evas_object_del(data->bg);
89
90         if (data->base)
91                 evas_object_del(data->base);
92
93         if (data->ctxpopup)
94                 evas_object_del(data->ctxpopup);
95
96         if (data->array)
97                 eina_array_free(data->array);
98
99         free(data);
100 }
101
102 /**
103 * Create background of channel lock view.
104 *
105 * @param[in]: win : the window this view created on.
106 *
107 * @return: the created view of type evas object.
108 */
109 static Evas_Object *_add_view_bg(Evas_Object *win)
110 {
111         Evas_Object *bg;
112
113         if (!win) {
114                 _ERR("window is null.");
115                 return NULL;
116         }
117
118         bg = utils_add_base(win);
119         if (!bg) {
120                 _ERR("elm layout add failed.");
121                 return NULL;
122         }
123
124         elm_layout_file_set(bg, EDJ_FILE, GRP_PWD_BG);
125
126         return bg;
127 }
128
129 /**
130 * Create the base layout of channel lock view.
131 *
132 * @param[in]: ctxpopup : the ctxpopup which contains channel lock view.
133 *
134 * @return: the created base layout of channel lock view.
135 */
136 static Evas_Object *_add_view_base(Evas_Object *ctxpopup)
137 {
138         Evas_Object *base;
139
140         if (!ctxpopup)
141                 return NULL;
142
143         base = utils_add_base(ctxpopup);
144         if (!base) {
145                 _ERR("elm layout add failed.");
146                 return NULL;
147         }
148
149         elm_layout_file_set(base, EDJ_FILE, GRP_PWD_VIEW);
150
151         elm_object_part_text_set(base, PART_TITLE,
152                         utils_get_translation_str(MSGID_TITLE));
153         elm_object_part_text_set(base, PART_UPTEXT,
154                         utils_get_translation_str(MSGID_TEXT));
155
156         return base;
157 }
158
159 /**
160 * Evas_Smart_Cb type callback for handling click event.
161 *
162 * @param[in]: priv : the user data.
163 * @param[in]: obj : the corresponding object which the click event occurred.
164 * @param[in]: ev : event info.
165 *
166 * @return: void.
167 */
168 static void _cancel_btn_clicked_cb(void *priv, Evas_Object *obj,
169                 void *ev)
170 {
171         struct _chnllock_data *data;
172
173         if (!priv || !obj)
174                 return;
175
176         data = priv;
177
178         settingmgr_view_pop(data->mgr);
179 }
180
181 /**
182 * Create cancel button of channel lock view.
183 *
184 * @param[in]: data : the user data of channel lock view.
185 *
186 * @return: the created cancel button or null if error occurred.
187 */
188 static Evas_Object *_add_view_cancel_btn(struct _chnllock_data *data)
189 {
190         Evas_Object *btn;
191
192         if (!data || !data->base)
193                 return NULL;
194
195         btn = utils_add_btn(data->base, PWD_BASIC_BTN,
196                         utils_get_translation_str(MSGID_CANCEL), EINA_TRUE);
197         if (!btn) {
198                 _ERR("utils add button failed.");
199                 return NULL;
200         }
201
202         evas_object_smart_callback_add(btn, SIG_CLICKED,
203                         _cancel_btn_clicked_cb, data);
204         elm_object_part_content_set(data->base, SWALLOW_CANCEL_BTN, btn);
205
206         return btn;
207 }
208
209 /**
210 * Check if the input passcode is right.
211 *
212 * @param[in]: data : the user data of channel lock view.
213 *
214 * @return: 0 - wrong passcode, 1 - right passcode.
215 */
216 static int _check_passcode(struct _chnllock_data *data)
217 {
218         char *passcode;
219
220         if (!data || !data->passcode || !data->view)
221                 return 0;
222
223         passcode = NULL;
224         provider_get_passcode(KEY_PASSCODE, &passcode);
225
226         if (strncmp(data->passcode, passcode, strlen(passcode))) {
227                 free(passcode);
228                 return 0;
229         }
230
231         free(passcode);
232
233         return 1;
234 }
235
236 /**
237 * Show the ON/OFF sublist of channel lock view.
238 *
239 * @param[in]: data : the user data of channel lock view.
240 *
241 * @return: void.
242 */
243 static void _push_next_view(struct _chnllock_data *data)
244 {
245         struct settingitem *item;
246         Eina_List *list;
247         const char *id;
248
249         if (!data || !data->view)
250                 return;
251
252         list = viewdata_get_childitems_list(data->view);
253         if (!list)
254                 return;
255
256         item = eina_list_nth(list, 0);
257         if (!item)
258                 return;
259
260         id = settingitem_get_id(item);
261         if (!id)
262                 return;
263
264         settingmgr_view_push(data->mgr, id, &data->gd);
265 }
266
267 /**
268 * Evas_Object_Event_Cb type callback for handling key press event.
269 *
270 * @param[in]: priv : the user data.
271 * @param[in]: e : the evas canvas.
272 * @param[in]: obj : the corresponding object which the key press event occurred.
273 * @param[in]: ei : event info.
274 *
275 * @return: void.
276 */
277 static void _key_down_cb(void *priv, Evas *e, Evas_Object *obj,
278                 void *ei)
279 {
280         Evas_Event_Key_Down *event;
281         Eina_Array *array;
282         Evas_Object *entry, *next_entry;
283         struct _chnllock_data *data;
284         const char *keyname;
285         char *text;
286         int btn_num, i;
287
288         if (!priv || !ei || !obj)
289                 return;
290
291         data = priv;
292         array = data->array;
293         if (!array)
294                 return;
295
296         event = ei;
297         keyname = event->keyname;
298         if (!keyname)
299                 return;
300
301         btn_num = -1;
302         for (i = PWD_ENTRY_0; i < PWD_ENTRY_MAX; i++) {
303                 if (obj == eina_array_data_get(array, i)) {
304                         btn_num = i;
305                         break;
306                 }
307         }
308
309         if (btn_num == -1)
310                 return;
311
312         if (!strncmp(keyname, KEY_BACK, strlen(keyname)) || !strncmp(keyname, KEY_BACK_REMOTE, strlen(keyname))) {
313                 settingmgr_view_pop(data->mgr);
314         } else if (!strncmp(keyname, KEY_DOWN, strlen(keyname))) {
315                 elm_object_focus_set(data->cancel_btn, EINA_TRUE);
316         } else if (!strncmp(keyname, KEY_0, strlen(keyname)) ||
317                         !strncmp(keyname, KEY_1, strlen(keyname)) ||
318                         !strncmp(keyname, KEY_2, strlen(keyname)) ||
319                         !strncmp(keyname, KEY_3, strlen(keyname)) ||
320                         !strncmp(keyname, KEY_4, strlen(keyname)) ||
321                         !strncmp(keyname, KEY_5, strlen(keyname)) ||
322                         !strncmp(keyname, KEY_6, strlen(keyname)) ||
323                         !strncmp(keyname, KEY_7, strlen(keyname)) ||
324                         !strncmp(keyname, KEY_8, strlen(keyname)) ||
325                         !strncmp(keyname, KEY_9, strlen(keyname))) {
326                 elm_entry_entry_set(obj, PWD_SYMBOL);
327                 data->passcode[btn_num] = keyname[0];
328
329                 if (btn_num < PWD_ENTRY_3) {
330                         elm_object_focus_next(obj, ELM_FOCUS_NEXT);
331                         next_entry = elm_object_focus_next_object_get(obj,
332                                         ELM_FOCUS_NEXT);
333                         if (!next_entry)
334                                 return;
335
336                         elm_object_focus_next_object_set(data->cancel_btn,
337                                         next_entry, ELM_FOCUS_UP);
338                 } else {
339                         if (_check_passcode(data)) {
340                                 _hide(data->base);
341                                 _push_next_view(data);
342                         } else {
343                                 text = utils_get_translation_str(
344                                                 MSGID_WRONG_PWD);
345                                 elm_object_part_text_set(data->base,
346                                                 PART_UPTEXT, text);
347
348                                 entry = eina_array_data_get(array, PWD_ENTRY_0);
349                                 if (!entry)
350                                         return;
351
352                                 elm_object_focus_set(entry, EINA_TRUE);
353
354                                 for (i = PWD_ENTRY_0; i < PWD_ENTRY_MAX; i++) {
355                                         entry = eina_array_data_get(array, i);
356                                         if (!entry)
357                                                 return;
358
359                                         elm_object_text_set(entry,
360                                                         EMPTY_SYMBOL);
361                                 }
362                         }
363                 }
364         }
365 }
366
367 /**
368 * Set the move directions of focus between entries and cancel button.
369 *
370 * @param[in]: array : eina array containing entries.
371 * @param[in]: cancel_btn : the cancel button.
372 *
373 * @return: void.
374 */
375 static void _set_entry_directions(Eina_Array *array,
376                 Evas_Object *cancel_btn)
377 {
378         Evas_Object *entry;
379         int idx;
380
381         if (!array || !cancel_btn)
382                 return;
383
384         for (idx = PWD_ENTRY_0; idx < PWD_ENTRY_3; idx++) {
385                 entry = eina_array_data_get(array, idx);
386                 if (!entry)
387                         return;
388
389                 elm_object_focus_next_object_set(entry,
390                                 eina_array_data_get(array, idx + 1),
391                                 ELM_FOCUS_NEXT);
392                 elm_object_focus_next_object_set(entry,
393                                 cancel_btn, ELM_FOCUS_DOWN);
394         }
395
396         elm_object_focus_next_object_set(cancel_btn,
397                         eina_array_data_get(array, PWD_ENTRY_0),
398                         ELM_FOCUS_UP);
399 }
400
401 /**
402 * Create entry.
403 *
404 * @param[in]: parent : object the entry will be created on.
405 *
406 * @return: the created entry or null if error occurred.
407 */
408 static Evas_Object *_add_entry(Evas_Object *parent)
409 {
410         Evas_Object *entry;
411         Elm_Entry_Filter_Limit_Size length = {
412                 .max_char_count = 1
413         };
414         Elm_Entry_Filter_Accept_Set type = {
415                 .accepted = PWD_RANGE
416         };
417
418         if (!parent)
419                 return NULL;
420
421         entry = utils_add_entry(parent);
422         if (!entry) {
423                 _ERR("utils add entry failed.");
424                 return NULL;
425         }
426
427         elm_entry_markup_filter_append(entry,
428                         elm_entry_filter_limit_size, &length);
429         elm_entry_markup_filter_append(entry,
430                         elm_entry_filter_accept_set, &type);
431
432         elm_object_style_set(entry, STYLE_PWD_ENTRY);
433
434         elm_entry_text_style_user_push(entry, STYLE_ENTRY_TEXT);
435         elm_object_part_content_set(parent, SWALLOW_ENTRY, entry);
436
437         return entry;
438 }
439
440 /**
441 * Create entries for inputting passcode.
442 *
443 * @param[in]: data : the user data of channel lock view.
444 *
445 * @return: 0 - Success, -1 - Fail.
446 */
447 static int _add_view_entries(struct _chnllock_data *data)
448 {
449         Eina_Array *array;
450         Evas_Object *box;
451         Evas_Object *entry, *base;
452         int idx;
453
454         if (!data || !data->base) {
455                 _ERR("invalid arguments.");
456                 return -1;
457         }
458
459         box = utils_add_box(data->base);
460         if (!box)
461                 return -1;
462
463         elm_box_horizontal_set(box, EINA_TRUE);
464         elm_box_padding_set(box, BOX_PADDING, BOX_PADDING);
465
466         array = eina_array_new(1);
467         if (!array) {
468                 evas_object_del(box);
469                 return -1;
470         }
471
472         for (idx = PWD_ENTRY_0; idx < PWD_ENTRY_MAX; idx++) {
473                 base = utils_add_base(data->base);
474                 if (!base) {
475                         _ERR("utils add base failed.");
476                         evas_object_del(box);
477                         eina_array_free(array);
478                         return -1;
479                 }
480
481                 elm_layout_file_set(base, EDJ_FILE, GRP_PWD_ENTRY);
482
483                 entry = _add_entry(base);
484                 if (!entry) {
485                         _ERR("add entry failed.");
486                         evas_object_del(box);
487                         eina_array_free(array);
488                         evas_object_del(base);
489                         return -1;
490                 }
491
492                 eina_array_push(array, entry);
493                 elm_box_pack_end(box, base);
494
495                 evas_object_event_callback_add(entry, EVAS_CALLBACK_KEY_DOWN,
496                                 _key_down_cb, data);
497         }
498
499         elm_object_focus_allow_set(eina_array_data_get(array, PWD_ENTRY_0),
500                         EINA_TRUE);
501         elm_object_focus_set(eina_array_data_get(array, PWD_ENTRY_0),
502                         EINA_TRUE);
503
504         elm_object_part_content_set(data->base, SWALLOW_CONTENT_AREA, box);
505
506         _set_entry_directions(array, data->cancel_btn);
507
508         data->array = array;
509         data->box = box;
510
511         return 0;
512 }
513
514 /**
515 * Evas_Smart_Cb type callback for handling ctxpopup dismissed event.
516 *
517 * @param[in]: priv : the user data.
518 * @param[in]: obj : the corresponding object which the dismissed event occurred.
519 * @param[in]: ev : event info.
520 *
521 * @return: void.
522 */
523 static void _ctxpopup_dismissed(void *priv, Evas_Object *obj,
524                 void *ev)
525 {
526         struct _chnllock_data *data;
527
528         if (!priv || !obj)
529                 return;
530
531         data = priv;
532         if (!data->base || !data->mgr)
533                 return;
534
535         _hide(data->base);
536
537         settingmgr_view_pop(data->mgr);
538 }
539
540 /**
541 * Create all the UI components of channel lock view.
542 *
543 * @param[in]: mgr : view manager of settings views.
544 * @param[in]: view : data of view.
545 * @prev[in]: prev : the user data.
546 *
547 * @return: the base layout of channel lock view or null
548 *               if error occurred.
549 */
550 static Evas_Object *_create(struct setting_mgr *mgr,
551                 struct settingview_data *view, void *prev)
552 {
553         Evas_Object *win, *base, *bg;
554         Evas_Object *ctxpopup;
555         Evas_Object *cancel_btn;
556         struct _chnllock_data *data;
557         int ret, width, height, xpos, ypos;
558         struct obj_geometry_data *tmp;
559
560         if (!mgr || !view || !prev) {
561                 _ERR("invalid argument.");
562                 return NULL;
563         }
564
565         win = settingmgr_get_win(mgr);
566         if (!win) {
567                 _ERR("settings manager get window failed.");
568                 return NULL;
569         }
570
571         data = calloc(1, sizeof(*data));
572         if (!data) {
573                 _ERR("calloc memory for _priv_data failed.");
574                 return NULL;
575         }
576
577         tmp = prev;
578
579         data->win = win;
580         data->gd = *tmp;
581
582         bg = _add_view_bg(win);
583         if (!bg) {
584                 _ERR("add background failed.");
585                 goto error;
586         }
587
588         data->bg = bg;
589
590         ctxpopup = utils_add_ctxpopup(win, CHANGE_PWD_CTXPOPUP_STYLE);
591         if (!ctxpopup) {
592                 _ERR("add ctxpopup failed.");
593                 goto error;
594         }
595
596         data->ctxpopup = ctxpopup;
597
598         base = _add_view_base(data->ctxpopup);
599         if (!base) {
600                 _ERR("add view base failed.");
601                 goto error;
602         }
603
604         data->base = base;
605
606         elm_object_content_set(ctxpopup, base);
607
608         width = height = 0;
609         ecore_x_window_size_get(ecore_x_window_root_first_get(),
610                         &width, &height);
611
612         xpos = (width - CTXPOPUP_WIDTH) / 2;
613         ypos = (height - CTXPOPUP_HEIGHT) / 2;
614         evas_object_move(data->ctxpopup, xpos * ELM_SCALE,
615                         ypos * ELM_SCALE);
616
617         evas_object_smart_callback_add(data->ctxpopup,
618                         SIG_DISMISSED, _ctxpopup_dismissed, data);
619
620         cancel_btn = _add_view_cancel_btn(data);
621         if (!cancel_btn) {
622                 _ERR("add cancel button faield.");
623                 goto error;
624         }
625
626         data->cancel_btn = cancel_btn;
627
628         ret = _add_view_entries(data);
629         if (ret != 0)
630                 goto error;
631
632         data->mgr = mgr;
633         data->view = view;
634
635         evas_object_data_set(base, CHNLLOCK_DATA_ID, data);
636
637         return base;
638
639 error:
640         _free_priv_data(data);
641         return NULL;
642 }
643
644 /**
645 * Show the channel lock view.
646 *
647 * @param[in]: base : the base layout of channel lock view.
648 *
649 * @return: void.
650 */
651 static void _show(Evas_Object *base)
652 {
653         struct _chnllock_data *data;
654
655         if (!base)
656                 return;
657
658         data = evas_object_data_get(base, CHNLLOCK_DATA_ID);
659         if (!data) {
660                 _ERR("get data from base failed. ID: %s.", CHNLLOCK_DATA_ID);
661                 return;
662         }
663
664         evas_object_show(data->ctxpopup);
665         evas_object_show(data->bg);
666         evas_object_show(data->base);
667 }
668
669 /**
670 * Destroy the channel lock view.
671 *
672 * @param[in]: base : the base layout of channel lock view.
673 *
674 * @return: void.
675 */
676 static void _destroy(Evas_Object *base)
677 {
678         struct _chnllock_data *data;
679
680         if (!base)
681                 return;
682
683         data = evas_object_data_get(base, CHNLLOCK_DATA_ID);
684         if (!data) {
685                 _ERR("get data from base failed. ID: %s.", CHNLLOCK_DATA_ID);
686                 return;
687         }
688
689         _free_priv_data(data);
690 }
691
692 /**
693 * Hide the channel lock view.
694 *
695 * @param[in]: base : the base layout of channel lock view.
696 *
697 * @return: void.
698 */
699 static void _hide(Evas_Object *base)
700 {
701         struct _chnllock_data *data;
702
703         if (!base)
704                 return;
705
706         data = evas_object_data_get(base, CHNLLOCK_DATA_ID);
707         if (!data)
708                 return;
709
710         evas_object_hide(data->base);
711         evas_object_hide(data->ctxpopup);
712         evas_object_hide(data->bg);
713 }
714
715 /**
716 * Refresh ON/OFF text of channel lock item.
717 *
718 * @param[in]: base : the base layout of channel lock view.
719 *
720 * @return: void.
721 */
722 static void _refresh(Evas_Object *base)
723 {
724         struct _chnllock_data *data;
725
726         if (!base)
727                 return;
728
729         data = evas_object_data_get(base, CHNLLOCK_DATA_ID);
730         if (!data)
731                 return;
732
733         settingmgr_view_pop(data->mgr);
734 }
735
736 /**
737 * view class of channel lock view.
738 */
739 struct setting_class _vclass = {
740         .title = VCLASS_TITLE_NEED_PASSCODE,
741         .create = _create,
742         .show = _show,
743         .destroy = _destroy,
744         .hide = _hide,
745         .refresh = _refresh
746 };
747
748 /**
749 * Return view class of channel lock view.
750 *
751 * @param: null.
752 *
753 * @return: the view class of channel lock view.
754 */
755 struct setting_class *view_need_passcode_get_vclass(void)
756 {
757         return &_vclass;
758 }