Add new application for testing the CAPI.
[platform/core/security/askuser.git] / test / apps / capi / PPMTester / src / ppmtester.c
1 /*
2  *  Copyright (c) 2017 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 /**
18  * @file        ppmtester.c
19  * @author      Pawel Kowalski <p.kowalski2@partner.samsung.com>
20  * @brief       The implementation of testing application of the PPM CAPI.
21  */
22
23 #include <app.h>
24 #include <Elementary.h>
25 #include <system_settings.h>
26 #include <efl_extension.h>
27 #include <dlog.h>
28 #include <stdarg.h>
29 #include <privacy_privilege_manager.h>
30
31 #ifdef  LOG_TAG
32 #undef  LOG_TAG
33 #endif
34 #define LOG_TAG "ppmtester"
35
36 #define BUFFER_SIZE 1024
37
38 #if !defined(PACKAGE)
39 #define PACKAGE "org.example.ppmtester"
40 #endif
41
42 typedef struct appdata
43 {
44         Evas_Object *window;
45         Evas_Object *conform;
46         Evas_Object *navi;
47         Evas_Object *msg_box;
48 } appdata_s;
49
50 static void win_delete_request_cb(void *data, Evas_Object *obj, void *event_info)
51 {
52         ui_app_exit();
53 }
54
55 /**
56  * @brief Prints massage into the message box.
57  *
58  * @param[in]   obj     The message box.
59  * @param[in]   msg     The text message that is written to the message box.
60  * @param[in]   ...     Additional arguments declared in the text message.
61  */
62 void print_msg(Evas_Object *obj, const char* msg, ...)
63 {
64         va_list args;
65         va_start(args, msg);
66         char buffer[BUFFER_SIZE];
67         vsnprintf(buffer, BUFFER_SIZE, msg, args);
68         va_end(args);
69
70         Evas_Coord c_y;
71         elm_entry_entry_append(obj, buffer);
72         elm_entry_entry_append(obj, "<br>");
73         elm_entry_cursor_end_set(obj);
74         elm_entry_cursor_geometry_get(obj, NULL, &c_y, NULL, NULL);
75         elm_scroller_region_show(obj, 0, c_y, 0, 0);
76 }
77
78 /**
79  * @brief Clears the message box.
80  *
81  * @param[in]   data          User specific data.
82  * @param[in]   btn           Pointer to the button object.
83  * @param[in]   event_info    Additional event information.
84  */
85 static void _btn_clear_cb(void *data, Evas_Object *btn, void *event_info)
86 {
87         appdata_s *ad = data;
88         elm_entry_entry_set(ad->msg_box, "");
89 }
90
91 /**
92  * @brief Creates the display object.
93  */
94 Evas_Object *_create_new_cd_display(appdata_s *ad, const char *name, void *cb)
95 {
96         // Create a scroller
97         Evas_Object *scroller = elm_scroller_add(ad->window);
98         evas_object_size_hint_weight_set(scroller, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
99
100         // Create a new item
101         Elm_Object_Item *item =
102                 elm_naviframe_item_push(ad->navi, "PPM Tester", NULL, NULL, scroller, NULL);
103         elm_object_item_part_text_set(item, "subtitle", "Test following privileges:");
104
105         if (cb != NULL)
106                 elm_naviframe_item_pop_cb_set(item, (Elm_Naviframe_Item_Pop_Cb) cb, (void *)ad);
107
108         // Create a main box
109         Evas_Object *box = elm_box_add(scroller);
110         elm_object_content_set(scroller, box);
111         elm_box_horizontal_set(box, EINA_FALSE);
112         evas_object_size_hint_align_set(box, EVAS_HINT_FILL, EVAS_HINT_FILL);
113         evas_object_size_hint_weight_set(box, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
114         evas_object_show(box);
115
116         Evas_Object *inner_grid = elm_grid_add(box);
117         elm_object_content_set(box, inner_grid);
118         evas_object_size_hint_align_set(inner_grid, EVAS_HINT_FILL, EVAS_HINT_FILL);
119         evas_object_size_hint_weight_set(inner_grid, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
120         evas_object_show(inner_grid);
121
122         Evas_Object *bbox_scroller = elm_scroller_add(inner_grid);
123         evas_object_size_hint_align_set(bbox_scroller, EVAS_HINT_FILL, EVAS_HINT_FILL);
124         evas_object_size_hint_weight_set(bbox_scroller, EVAS_HINT_EXPAND, 0.0);
125         elm_scroller_policy_set(bbox_scroller, ELM_SCROLLER_POLICY_OFF, ELM_SCROLLER_POLICY_ON);
126         elm_object_style_set(bbox_scroller, "handler");
127         evas_object_show(bbox_scroller);
128
129         // Create a box for adding content
130         Evas_Object *bbox = elm_box_add(bbox_scroller);
131         Evas_Coord padding_between_buttons = 3;
132         elm_box_padding_set(bbox, 0, padding_between_buttons);
133         elm_object_content_set(bbox_scroller, bbox);
134         elm_box_horizontal_set(bbox, EINA_FALSE);
135         evas_object_size_hint_align_set(bbox, EVAS_HINT_FILL, EVAS_HINT_FILL);
136         evas_object_size_hint_weight_set(bbox, EVAS_HINT_EXPAND, 0.0);
137         evas_object_show(bbox);
138
139         // Create "Clear" button
140         Evas_Object *bt = elm_button_add(box);
141         elm_object_text_set(bt, "Clear");
142         evas_object_size_hint_align_set(bt, EVAS_HINT_FILL, EVAS_HINT_FILL);
143         evas_object_size_hint_weight_set(bt, EVAS_HINT_EXPAND, 0.0);
144         evas_object_smart_callback_add(bt, "clicked", _btn_clear_cb, ad);
145         evas_object_show(bt);
146
147         // Create a box for entry
148         Evas_Object *ebox = elm_box_add(inner_grid);
149         elm_box_horizontal_set(ebox, EINA_FALSE);
150         evas_object_size_hint_align_set(ebox, EVAS_HINT_FILL, EVAS_HINT_FILL);
151         evas_object_size_hint_weight_set(ebox, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
152         evas_object_show(ebox);
153
154         // Create a message box
155         Evas_Object *display_window = elm_entry_add(ebox);
156         evas_object_size_hint_align_set(display_window, EVAS_HINT_FILL, EVAS_HINT_FILL);
157         evas_object_size_hint_weight_set(display_window, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
158         evas_object_show(display_window);
159
160         elm_entry_editable_set(display_window, EINA_FALSE);
161         elm_entry_scrollable_set(display_window, EINA_TRUE);
162
163         ad->msg_box = display_window;
164         elm_scroller_policy_set(ad->msg_box, ELM_SCROLLER_POLICY_OFF, ELM_SCROLLER_POLICY_ON);
165         elm_box_pack_end(ebox, display_window);
166
167         elm_grid_pack(inner_grid, bbox_scroller, 0, 0, 100, 35);
168         elm_grid_pack(inner_grid, ebox, 0, 35, 100, 65);
169         elm_box_pack_end(box, inner_grid);
170         elm_box_pack_end(box, bt);
171
172         return bbox;
173 }
174
175 Eina_Bool _pop_cb(void *data, Elm_Object_Item *item)
176 {
177         elm_win_lower(((appdata_s *)data)->window);
178         return EINA_FALSE;
179 }
180
181 /**
182  * @brief Function copied from the Account Manager example.
183  */
184 Evas_Object *_new_button(appdata_s *ad, Evas_Object *display, const char *name, void *cb)
185 {
186         // Create a button
187         Evas_Object *bt = elm_button_add(display);
188         elm_object_text_set(bt, name);
189         evas_object_smart_callback_add(bt, "clicked", (Evas_Smart_Cb) cb, ad);
190         evas_object_size_hint_weight_set(bt, EVAS_HINT_EXPAND, 0.0);
191         evas_object_size_hint_align_set(bt, EVAS_HINT_FILL, EVAS_HINT_FILL);
192         elm_box_pack_end(display, bt);
193         evas_object_show(bt);
194         return bt;
195 }
196
197 /**
198  * @brief Writes text into dlogutil and into GUI.
199  *
200  * @details In order to read a message using dlogutil,
201  * type in the emulator's terminal: dlogutil ppmtester
202  * The 'ppmtester' flag is set using LOG_TAG constant.
203  *
204  * @param[in]   ad          The structure with GUI elements.
205  * @param[in]   privilege   A privilege that is to be logged.
206  * @param[in]   msg         A text that is to be written.
207  */
208 void log_privilege (appdata_s *ad, const char* privilege, const char* msg)
209 {
210         print_msg(ad->msg_box, "----------<br>Privilege: %s<br>Message: %s", privilege, msg);
211         dlog_print(DLOG_INFO, LOG_TAG, "----------\nPrivilege: %s\nMessage: %s", privilege, msg);
212 }
213
214 /**
215  * @brief Based on ppm_popup_response_cb prototype from privacy-privilege-manager.h.
216  *
217  * @param[in]   cause       A value representing the reason why this callback
218  *                          has been called.
219  * @param[in]   result      A result of a response triggered by calling ppm_popup_request().
220  * @param[in]   privilege   A privilege that has been checked.
221  * @param[in]   user_data   User specific data.
222  */
223 void ppm_popup_response_cb_function (ppm_call_cause_e cause, ppm_request_result_e result, const char *privilege, void *user_data)
224 {
225         appdata_s *ad = user_data;
226         switch (cause)
227         {
228                 case PRIVACY_PRIVILEGE_MANAGER_CALL_CAUSE_ANSWER:
229                         log_privilege(ad, privilege, "Callback was called with a valid answer.");
230                         switch (result)
231                         {
232                                 case PRIVACY_PRIVILEGE_MANAGER_REQUEST_RESULT_ALLOW_FOREVER:
233                                         log_privilege(ad, privilege, "A user granted permission to use a privilege for an indefinite period of time.");
234                                         break;
235                                 case PRIVACY_PRIVILEGE_MANAGER_REQUEST_RESULT_DENY_FOREVER:
236                                         log_privilege(ad, privilege, "A user did not grant permission to use a privilege for an indefinite period of time.");
237                                         ui_app_exit();
238                                         break;
239                                 case PRIVACY_PRIVILEGE_MANAGER_REQUEST_RESULT_DENY_ONCE:
240                                         log_privilege(ad, privilege, "A user did not grant permission to use a privilege once.");
241                                         break;
242                                 default:
243                                         break;
244                         }
245                         break;
246                 case PRIVACY_PRIVILEGE_MANAGER_CALL_CAUSE_ERROR:
247                         log_privilege(ad, privilege, "Callback was called because of an error.");
248                         break;
249                 default:
250                 {
251                         char msg[BUFFER_SIZE];
252                         snprintf(msg, BUFFER_SIZE, "Unknown cause: %d", cause);
253                         log_privilege(ad, privilege, msg);
254                         break;
255                 }
256         }
257 }
258
259 /**
260  * @brief Checks the privilege. Writes messages in the bottom part of the main window and
261  * into the shell (in order to read these messages use command: dlogutil ppmtester).
262  *
263  * @param[in]   ad          The structure with GUI elements.
264  * @param[in]   privilege   A privilege that is to be checked.
265  * @param[in]   ret         The code of the error.
266  */
267 void app_log_errors(appdata_s *ad, const char* privilege, ppm_error_e ret)
268 {
269         switch (ret)
270         {
271                 case PRIVACY_PRIVILEGE_MANAGER_ERROR_IO_ERROR:
272                         log_privilege(ad, privilege, "I/O error");
273                         break;
274                 case PRIVACY_PRIVILEGE_MANAGER_ERROR_INVALID_PARAMETER:
275                         log_privilege(ad, privilege, "Invalid parameter");
276                         break;
277                 case PRIVACY_PRIVILEGE_MANAGER_ERROR_ALREADY_IN_PROGRESS:
278                         log_privilege(ad, privilege, "Operation already in progress");
279                         break;
280                 case PRIVACY_PRIVILEGE_MANAGER_ERROR_OUT_OF_MEMORY:
281                         log_privilege(ad, privilege, "Out of memory");
282                         break;
283                 case PRIVACY_PRIVILEGE_MANAGER_ERROR_UNKNOWN:
284                         log_privilege(ad, privilege, "Unknown error");
285                         break;
286                 default:
287                         log_privilege(ad, privilege, "Unknown error");
288                         break;
289         }
290 }
291
292 /**
293  * @brief Checks the privilege. Writes messages in the bottom part of the main window and
294  * into the shell (in order to read these messages use command: dlogutil ppmtester).
295  *
296  * @param[in]   ad          The structure with GUI elements.
297  * @param[in]   privilege   A privilege that is to be checked.
298  */
299 void check_privilege (appdata_s *ad, const char* privilege)
300 {
301         ppm_check_result_e result;
302
303         int ret = ppm_check_permission(privilege, &result);
304
305         if (ret != PRIVACY_PRIVILEGE_MANAGER_ERROR_NONE) // If there is an error, print log.
306         {
307                 app_log_errors(ad, privilege, ret);
308                 return;
309         }
310
311         switch (result) // Alow, deny or ask.
312         {
313                 case PRIVACY_PRIVILEGE_MANAGER_CHECK_RESULT_ALLOW:
314                         log_privilege(ad, privilege, "An application has permission to use a privilege.");
315                         break;
316                 case PRIVACY_PRIVILEGE_MANAGER_CHECK_RESULT_DENY:
317                         log_privilege(ad, privilege, "An application doesn't have permission to use a privilege.");
318                         break;
319                 case PRIVACY_PRIVILEGE_MANAGER_CHECK_RESULT_ASK:
320                 {
321                         log_privilege(ad, privilege, "A user has to be asked whether to grant permission to use a privilege.");
322                         int ret_popup = ppm_request_permission(privilege, ppm_popup_response_cb_function, ad);
323                         if (ret_popup != PRIVACY_PRIVILEGE_MANAGER_ERROR_NONE)
324                         {
325                                 app_log_errors(ad, privilege, ret_popup);
326                                 return;
327                         }
328                         break;
329                 }
330                 default:
331                 {
332                         char msg[BUFFER_SIZE];
333                         snprintf(msg, BUFFER_SIZE, "Unknown result: %d", result);
334                         log_privilege(ad, privilege, msg);
335                         break;
336                 }
337         }
338 }
339
340 /**
341  * @brief Callback for 'camera' button.
342  *
343  * @param[in]   ad          The structure with GUI elements.
344  * @param[in]   obj         Display object.
345  */
346 void _test_privilege_camera(appdata_s *ad, Evas_Object *obj)
347 {
348         check_privilege(ad, "http://tizen.org/privilege/camera");
349 }
350
351 /**
352  * @brief Callback for 'location' button.
353  *
354  * @param[in]   ad          The structure with GUI elements.
355  * @param[in]   obj         Display object.
356  */
357 void _test_privilege_location(appdata_s *ad, Evas_Object *obj)
358 {
359         check_privilege(ad, "http://tizen.org/privilege/location");
360 }
361
362 /**
363  * @brief Callback for 'contact.read' button.
364  *
365  * @param[in]   ad          The structure with GUI elements.
366  * @param[in]   obj         Display object.
367  */
368 void _test_privilege_contact_read(appdata_s *ad, Evas_Object *obj)
369 {
370         check_privilege(ad, "http://tizen.org/privilege/contact.read");
371 }
372
373 /**
374  * @brief Callback for 'contact.write' button.
375  *
376  * @param[in]   ad          The structure with GUI elements.
377  * @param[in]   obj         Display object.
378  */
379 void _test_privilege_contact_write(appdata_s *ad, Evas_Object *obj)
380 {
381         check_privilege(ad, "http://tizen.org/privilege/contact.write");
382 }
383
384 /**
385  * @brief Creates buttons in the main window.
386  *
387  * @param[in]   ad          The structure with GUI elements.
388  */
389 void create_buttons_in_main_window(appdata_s *ad)
390 {
391         Evas_Object *display = _create_new_cd_display(ad, "PPM Tester", _pop_cb);
392
393         _new_button(ad, display, "camera", _test_privilege_camera);
394         _new_button(ad, display, "location", _test_privilege_location);
395         _new_button(ad, display, "contact.read", _test_privilege_contact_read);
396         _new_button(ad, display, "contact.write", _test_privilege_contact_write);
397 }
398
399 /**
400  * @brief Creates base GUI (window, conformant, naviframe and buttons).
401  *
402  * @param[in]   ad     The structure with GUI elements.
403  */
404 static void create_base_gui(appdata_s *ad)
405 {
406         // Setting the window
407         ad->window = elm_win_util_standard_add(PACKAGE, PACKAGE);
408         elm_win_conformant_set(ad->window, EINA_TRUE);
409         elm_win_autodel_set(ad->window, EINA_TRUE);
410         elm_win_indicator_mode_set(ad->window, ELM_WIN_INDICATOR_SHOW);
411         elm_win_indicator_opacity_set(ad->window, ELM_WIN_INDICATOR_OPAQUE);
412         evas_object_smart_callback_add(ad->window, "delete, request", win_delete_request_cb, NULL);
413
414         // Create conformant
415         ad->conform = elm_conformant_add(ad->window);
416         evas_object_size_hint_weight_set(ad->conform, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
417         elm_win_resize_object_add(ad->window, ad->conform);
418         evas_object_show(ad->conform);
419
420         // Create a naviframe
421         ad->navi = elm_naviframe_add(ad->conform);
422         evas_object_size_hint_align_set(ad->navi, EVAS_HINT_FILL, EVAS_HINT_FILL);
423         evas_object_size_hint_weight_set(ad->navi, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
424
425         elm_object_content_set(ad->conform, ad->navi);
426         evas_object_show(ad->navi);
427
428         // Fill the list with items
429         create_buttons_in_main_window(ad);
430
431         eext_object_event_callback_add(ad->navi, EEXT_CALLBACK_BACK, eext_naviframe_back_cb, NULL);
432
433         // Show the window after base gui is set up
434         evas_object_show(ad->window);
435 }
436
437 static bool app_create(void *data)
438 {
439         /*
440          * Hook to take necessary actions before main event loop starts
441          * Initialize UI resources and application's data
442          * If this function returns true, the main loop of application starts
443          * If this function returns false, the application is terminated
444          */
445
446         appdata_s *ad = data;
447
448         create_base_gui(ad);
449
450         return true;
451 }
452
453 static void app_control(app_control_h app_control, void *data)
454 {
455         // Handle the launch request.
456 }
457
458 static void app_pause(void *data)
459 {
460         // Take necessary actions when application becomes invisible.
461 }
462
463 static void app_resume(void *data)
464 {
465         // Take necessary actions when application becomes visible.
466
467         // Checking two example privileges on resume:
468         const char* privileges [] = {"http://tizen.org/privilege/alarm.get", "http://tizen.org/privilege/calendar.read"};
469         for (int i = 0; i < sizeof(privileges)/sizeof(privileges[0]); i++)
470         {
471            check_privilege(data, privileges[i]);
472         }
473 }
474
475 static void app_terminate(void *data)
476 {
477         // Release all resources.
478 }
479
480 int main(int argc, char *argv[])
481 {
482         appdata_s ad = {0,};
483         int ret = 0;
484
485         ui_app_lifecycle_callback_s event_callback = {0,};
486
487         event_callback.create = app_create;
488         event_callback.terminate = app_terminate;
489         event_callback.pause = app_pause;
490         event_callback.resume = app_resume;
491         event_callback.app_control = app_control;
492
493         ret = ui_app_main(argc, argv, &event_callback, &ad);
494         if (ret != APP_ERROR_NONE)
495         {
496                 dlog_print(DLOG_ERROR, LOG_TAG, "app_main() is failed. err = %d", ret);
497         }
498
499         return ret;
500 }