0ce48eedaa21ad450b7dcc569485ae8dc5def271
[platform/core/security/askuser.git] / src / notification-daemon / ui / Popupper.cpp
1 /*
2  *  Copyright (c) 2017 - 2018 Samsung Electronics Co.
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  * @file        src/agent/notification-daemon/Popupper.cpp
18  * @author      Zofia Abramowska <z.abramowska@samsung.com>
19  * @author      Ernest Borowski <e.borowski@partner.samsung.com>
20  * @brief       Definition of Popupper class
21  */
22
23 #include "Popupper.h"
24
25 #include "Answerable.h"
26 #include "Po.h"
27 #include "PopupCheckMobile.h"
28 #include "PopupCheckWearable.h"
29
30 #include <exception/ErrnoException.h>
31 #include <exception/Exception.h>
32 #include <log/alog.h>
33 #include <libintl.h>
34 #include <vconf.h>
35 #include <efl_util.h>
36 #include <system_info.h>
37
38 #include <unistd.h>
39
40 namespace AskUser {
41
42 namespace Notification {
43
44 namespace {
45     std::string getProfileName() {
46         char *profileName = nullptr;
47         system_info_get_platform_string("http://tizen.org/feature/profile", &profileName);
48         if (!profileName) {
49             ALOGE("profileName is NULL");
50             throw Exception("get profileName failed");
51         }
52         std::unique_ptr<char, decltype(free)*> profileNamePtr(profileName, free);
53         return std::string(profileName);
54     }
55
56     std::string getHomeKey() {
57         std::string profileName = getProfileName();
58         if (profileName[0] == 'w' || profileName[0] == 'W')
59             return "XF86PowerOff";
60         else
61             return "XF86Home";
62     }
63 }
64
65
66 void Popupper::registerPopupResponseHandler(PopupHandler handler) {
67     m_popupResponseHandler = handler;
68 }
69
70 void Popupper::unfocusedCb(void *data, Evas_Object *, void *)
71 {
72     ALOGD("Unfocused");
73     Popupper *popupper = static_cast<Popupper*>(data);
74
75     if (popupper->m_shouldRaise) {
76         evas_object_show(popupper->m_win);
77     }
78 }
79
80 void Popupper::popupClose()
81 {
82     ALOGD("Window close");
83     m_shouldRaise = false;
84
85     if (!m_elementPtr)
86         ALOGD("Closing non-existing popup");
87
88     m_elementPtr.reset(nullptr);
89     m_answerablePtr.reset(nullptr);
90     m_responses.clear();
91     m_privaciesSequence.setPrivacies({});
92     evas_object_hide(m_win);
93 }
94
95 void Popupper::buttonAnswer(IAnswerable::Button button) {
96     NResponseType answer = m_answerablePtr->getAnswer(button);
97     m_responses.push_back(answer);
98
99     if (m_responses.size() == m_privaciesSequence.size()) {
100         m_popupResponseHandler(m_responses);
101         return;
102     }
103
104     Privacy privacy;
105     if (!m_privaciesSequence.getNextPrivacy(privacy)) {
106         ALOGE("Unable to get next privacy");
107         respondToRest(NResponseType::None);
108         return;
109     }
110
111     if (!m_elementPtr->showNext(Po::createPopupCheckMsg(m_pkgId, privacy))) {
112         ALOGE("unable to show next popup");
113         respondToRest(NResponseType::None);
114     }
115 }
116
117 void Popupper::allowPressedCb(void *data, Evas_Object *, void *)
118 {
119     Popupper *popupper = static_cast<Popupper*>(data);
120     popupper->buttonAnswer(IAnswerable::Button::ALLOW);
121 }
122
123 void Popupper::denyPressedCb(void *data, Evas_Object *, void *)
124 {
125     Popupper *popupper = static_cast<Popupper*>(data);
126     popupper->buttonAnswer(IAnswerable::Button::DENY);
127 }
128
129 Eina_Bool Popupper::hwKeyClickedCb(void *data, int type, void *event)
130 {
131     Ecore_Event_Key *ev = static_cast<Ecore_Event_Key*>(event);
132     Popupper* runner = static_cast<Popupper*>(data);
133     double delay = 0.5;
134     ALOGD("HW button pressed. type <" << type << "> pressed key is <" << ev->key << ">");
135     if ((!strcmp(getHomeKey().c_str(), ev->key) || !strcmp("XF86Back", ev->key)) && runner->m_elementPtr) {
136         ALOGD("Respond as deny once.");
137         if (!strcmp("XF86Back", ev->key))
138             delay = 0;
139         ecore_timer_add(delay,
140             [](void *data) -> Eina_Bool {
141                 Popupper *runner = static_cast<Popupper *>(data);
142                 runner->respondToRest(NResponseType::None);
143                 return ECORE_CALLBACK_CANCEL;
144             },
145             runner);
146     }
147     return EINA_TRUE;
148 }
149
150 Popupper::~Popupper()
151 {}
152
153 void Popupper::initialize()
154 {
155     elm_init(0, NULL);
156     m_win = elm_win_add(NULL, Po::getPopupTitleMsg().c_str(), ELM_WIN_NOTIFICATION);
157     if (!m_win) {
158         ALOGE("EFL : Failed to add window");
159         throw Exception("Elementary failed");
160     }
161     efl_util_set_notification_window_level(m_win, EFL_UTIL_NOTIFICATION_LEVEL_TOP);
162
163     if (elm_win_wm_rotation_supported_get(m_win)) {
164         int rots[4] = { 0, 90, 180, 270 };
165         elm_win_wm_rotation_available_rotations_set(m_win, (const int *)(&rots), 4);
166     }
167
168     elm_win_autodel_set(m_win, EINA_TRUE);
169     elm_win_override_set(m_win, EINA_TRUE);
170     elm_win_alpha_set(m_win, EINA_TRUE);
171
172     // callbacks
173     elm_win_indicator_opacity_set(m_win, ELM_WIN_INDICATOR_OPAQUE);
174     elm_win_indicator_mode_set(m_win, ELM_WIN_INDICATOR_SHOW);
175     evas_object_smart_callback_add(m_win, "unfocused", &Popupper::unfocusedCb, this);
176
177     elm_win_keygrab_set(m_win, getHomeKey().c_str(), 0, 0, 0, ELM_WIN_KEYGRAB_SHARED);
178     elm_win_keygrab_set(m_win, "XF86Back", 0, 0, 0, ELM_WIN_KEYGRAB_TOPMOST);
179     ecore_event_handler_add(ECORE_EVENT_KEY_UP, &Popupper::hwKeyClickedCb, this);
180 }
181
182 void Popupper::show() {
183     evas_object_show(m_win);
184 }
185
186 void Popupper::popupCheck(const std::string &pkgId, const std::vector<Privacy> &privacies) {
187     std::string profileName = getProfileName();
188     PopupCheck *popup;
189     m_responses.clear();
190     m_privaciesSequence.setPrivacies(privacies);
191     m_pkgId = pkgId;
192     try {
193         Privacy currentPrivacy;
194         if (!m_privaciesSequence.getNextPrivacy(currentPrivacy)) {
195             ALOGE("Unable to get next privacy");
196             respondToRest(NResponseType::None);
197             return;
198         }
199         if (profileName[0] != 'w' && profileName[0] != 'W') {
200             // Not wearable
201             popup = new PopupCheckMobile(m_win, Po::createPopupCheckMsg(pkgId, currentPrivacy), m_privaciesSequence.size());
202         } else {
203             // Wearable
204             popup = new PopupCheckWearable(m_win, Po::createPopupCheckMsg(pkgId, currentPrivacy),
205                                            pkgId, currentPrivacy, m_privaciesSequence.size());
206         }
207         popup->create();
208     } catch (const std::exception &e) {
209         ALOGE("Failed to create popup check : " << e.what());
210         respondToRest(NResponseType::None);
211         return;
212     }
213
214     m_answerablePtr.reset(new AnswerablePopupCheck(popup));
215     evas_object_smart_callback_add(popup->getAllowButton(), "clicked", &Popupper::allowPressedCb,
216                                    this);
217     evas_object_smart_callback_add(popup->getDenyButton(), "clicked", &Popupper::denyPressedCb,
218                                    this);
219
220     m_elementPtr.reset(popup);
221     show();
222
223 }
224
225 void Popupper::respondToRest(NResponseType response)
226 {
227     size_t alreadyRespondedCount = m_responses.size();
228     while (alreadyRespondedCount < m_privaciesSequence.size()) {
229         m_responses.push_back(response);
230         alreadyRespondedCount++;
231     }
232     m_popupResponseHandler(m_responses);
233 }
234
235 void Popupper::start()
236 {
237     elm_run();
238 }
239
240 void Popupper::stop()
241 {
242     m_shouldRaise = false;
243     elm_win_keygrab_unset(m_win, getHomeKey().c_str(), 0, 0);
244     elm_win_keygrab_unset(m_win, "XF86Back", 0, 0);
245     m_elementPtr.reset(nullptr);
246     m_answerablePtr.reset(nullptr);
247     m_responses.clear();
248     evas_object_del(m_win);
249     m_win = nullptr;
250     elm_exit();
251 }
252
253 void Popupper::shutdown() {
254     elm_shutdown();
255 }
256
257 } /* namespace Notification */
258
259 } /* namespace AskUser */