Re-implement 'create' functions to support dynamic loading
[platform/core/context/context-provider.git] / src / call / Call.cpp
1 /*
2  * Copyright (c) 2015 Samsung Electronics Co., Ltd.
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 <Util.h>
18 #include "Call.h"
19
20 #define TELEPHONY_NOTI_ID_CNT 8
21
22 using namespace ctx;
23
24 static bool __telephonyInitialized = false;
25 static telephony_noti_e __callNotiIds[] =
26 {
27    TELEPHONY_NOTI_VOICE_CALL_STATUS_IDLE,
28    TELEPHONY_NOTI_VOICE_CALL_STATUS_ACTIVE,
29 //   TELEPHONY_NOTI_VOICE_CALL_STATUS_HELD,
30 //   TELEPHONY_NOTI_VOICE_CALL_STATUS_DIALING,
31    TELEPHONY_NOTI_VOICE_CALL_STATUS_ALERTING,
32    TELEPHONY_NOTI_VOICE_CALL_STATUS_INCOMING,
33    TELEPHONY_NOTI_VIDEO_CALL_STATUS_IDLE,
34    TELEPHONY_NOTI_VIDEO_CALL_STATUS_ACTIVE,
35 //   TELEPHONY_NOTI_VIDEO_CALL_STATUS_DIALING,
36    TELEPHONY_NOTI_VIDEO_CALL_STATUS_ALERTING,
37    TELEPHONY_NOTI_VIDEO_CALL_STATUS_INCOMING,
38 };
39 static Json __latest;
40
41 CallStateProvider::CallStateProvider() :
42         BasicProvider(SUBJ_STATE_CALL)
43 {
44         __handleList.count = 0;
45         __handleList.handle = NULL;
46 }
47
48 CallStateProvider::~CallStateProvider()
49 {
50 }
51
52 bool CallStateProvider::isSupported()
53 {
54         return util::getSystemInfoBool("tizen.org/feature/network.telephony");
55 }
56
57 void CallStateProvider::__updateCb(telephony_h handle, telephony_noti_e notiId, void *data, void *userData)
58 {
59         CallStateProvider *instance = static_cast<CallStateProvider*>(userData);
60         instance->__handleUpdate(handle, notiId, data);
61 }
62
63 void CallStateProvider::__handleUpdate(telephony_h handle, telephony_noti_e notiId, void* id)
64 {
65         Json data;
66         unsigned int count;
67         telephony_call_h *callList;
68
69         // Call state
70         switch (notiId) {
71         case TELEPHONY_NOTI_VOICE_CALL_STATUS_IDLE:
72         case TELEPHONY_NOTI_VIDEO_CALL_STATUS_IDLE:
73                 data.set(NULL, KEY_STATE, VAL_IDLE);
74                 break;
75         case TELEPHONY_NOTI_VOICE_CALL_STATUS_ACTIVE:
76         case TELEPHONY_NOTI_VIDEO_CALL_STATUS_ACTIVE:
77                 data.set(NULL, KEY_STATE, VAL_ACTIVE);
78                 break;
79         case TELEPHONY_NOTI_VOICE_CALL_STATUS_ALERTING:
80         case TELEPHONY_NOTI_VIDEO_CALL_STATUS_ALERTING:
81                 data.set(NULL, KEY_STATE, VAL_ALERTING);
82                 break;
83         case TELEPHONY_NOTI_VOICE_CALL_STATUS_INCOMING:
84         case TELEPHONY_NOTI_VIDEO_CALL_STATUS_INCOMING:
85                 data.set(NULL, KEY_STATE, VAL_INCOMING);
86                 break;
87 /*      // Ignore below cases
88         case TELEPHONY_NOTI_VOICE_CALL_STATUS_HELD:
89         case TELEPHONY_NOTI_VOICE_CALL_STATUS_DIALING:
90         case TELEPHONY_NOTI_VIDEO_CALL_STATUS_DIALING:*/
91         default:
92                 _E("Unkown noti id: %d", notiId);
93                 return;
94         }
95
96         // Call type
97         switch (notiId) {
98         case TELEPHONY_NOTI_VOICE_CALL_STATUS_IDLE:
99         case TELEPHONY_NOTI_VOICE_CALL_STATUS_ACTIVE:
100         case TELEPHONY_NOTI_VOICE_CALL_STATUS_ALERTING:
101         case TELEPHONY_NOTI_VOICE_CALL_STATUS_INCOMING:
102                 data.set(NULL, KEY_TYPE, VAL_VOICE);
103                 break;
104         case TELEPHONY_NOTI_VIDEO_CALL_STATUS_IDLE:
105         case TELEPHONY_NOTI_VIDEO_CALL_STATUS_ACTIVE:
106         case TELEPHONY_NOTI_VIDEO_CALL_STATUS_ALERTING:
107         case TELEPHONY_NOTI_VIDEO_CALL_STATUS_INCOMING:
108                 data.set(NULL, KEY_TYPE, VAL_VIDEO);
109                 break;
110 /*      // Ignore below cases
111         case TELEPHONY_NOTI_VOICE_CALL_STATUS_HELD:
112         case TELEPHONY_NOTI_VOICE_CALL_STATUS_DIALING:
113         case TELEPHONY_NOTI_VIDEO_CALL_STATUS_DIALING:*/
114         default:
115                 _E("Unkown noti id: %d", notiId);
116                 return;
117         }
118
119         int err = telephony_call_get_call_list(handle, &count, &callList);
120         IF_FAIL_VOID_TAG(err == TELEPHONY_ERROR_NONE, _E, "Getting call list failed");
121
122         unsigned int callId = *static_cast<unsigned int *>(id);
123         for (unsigned int i = 0; i < count; i++) {
124                 unsigned int tempId;
125                 // Handle id
126                 if (!__getCallHandleId(callList[i], tempId)) {
127                         continue;
128                 }
129
130                 if (callId != tempId) {
131                         continue;
132                 }
133
134                 // Address
135                 std::string address;
136                 if (__getCallAddress(callList[i], address)) {
137                         data.set(NULL, KEY_ADDRESS, address);
138                         break;
139                 }
140         }
141
142         if (__latest != data) {
143                 publish(NULL, ERR_NONE, data);
144                 __latest = data.str();
145         }
146         telephony_call_release_call_list(count, &callList);
147 }
148
149 bool CallStateProvider::__initTelephony()
150 {
151         IF_FAIL_RETURN(!__telephonyInitialized, true);
152
153         int err = telephony_init(&__handleList);
154         IF_FAIL_RETURN_TAG(err == TELEPHONY_ERROR_NONE, false, _E, "Initialization failed");
155
156         __telephonyInitialized = true;
157         return true;
158 }
159
160 void CallStateProvider::__releaseTelephony()
161 {
162         IF_FAIL_VOID(__telephonyInitialized);
163
164         telephony_deinit(&__handleList);
165
166         __telephonyInitialized = false;
167 }
168
169 bool CallStateProvider::__setCallback()
170 {
171         /* TODO: Consider dual-sim devices */
172         IF_FAIL_RETURN_TAG(__initTelephony(), false, _E, "Initialization failed");
173
174         int err;
175
176         for (unsigned int i = 0; i < __handleList.count; i++) {
177                 for (unsigned int j = 0; j < TELEPHONY_NOTI_ID_CNT; j++) {
178                         err = telephony_set_noti_cb(__handleList.handle[i], __callNotiIds[j], __updateCb, this);
179                         IF_FAIL_CATCH(err == TELEPHONY_ERROR_NONE);
180                 }
181         }
182
183         return true;
184
185 CATCH:
186         _E("Initialization failed");
187         __releaseTelephony();
188         return false;
189 }
190
191 void CallStateProvider::__unsetCallback()
192 {
193         for (unsigned int i = 0; i < __handleList.count; i++) {
194                 for (unsigned int j = 0; j < TELEPHONY_NOTI_ID_CNT; j++) {
195                         telephony_unset_noti_cb(__handleList.handle[i], __callNotiIds[j]);
196                 }
197         }
198
199         __releaseTelephony();
200 }
201
202 bool CallStateProvider::__getCallState(telephony_call_h& handle, std::string& state)
203 {
204         state.clear();
205
206         telephony_call_status_e st;
207         int err = telephony_call_get_status(handle, &st);
208         IF_FAIL_RETURN_TAG(err == TELEPHONY_ERROR_NONE, false, _E, "Getting state failed");
209
210         switch (st) {
211         case TELEPHONY_CALL_STATUS_ACTIVE:
212                 state = VAL_ACTIVE;
213                 break;
214         case TELEPHONY_CALL_STATUS_HELD:
215                 state = VAL_HELD;
216                 break;
217         case TELEPHONY_CALL_STATUS_DIALING:
218                 state = VAL_DIALING;
219                 break;
220         case TELEPHONY_CALL_STATUS_ALERTING:
221                 state = VAL_ALERTING;
222                 break;
223         case TELEPHONY_CALL_STATUS_INCOMING:
224                 state = VAL_INCOMING;
225                 break;
226         default:
227                 state = VAL_IDLE;
228         }
229
230         IF_FAIL_RETURN_TAG(!state.empty(), false, _W, "State is empty");
231
232         return true;
233 }
234
235 bool CallStateProvider::__getCallType(telephony_call_h& handle, std::string& type)
236 {
237         type.clear();
238
239         telephony_call_type_e t;
240         int err = telephony_call_get_type(handle, &t);
241         IF_FAIL_RETURN_TAG(err == TELEPHONY_ERROR_NONE, false, _E, "Getting type failed");
242
243         switch (t) {
244         case TELEPHONY_CALL_TYPE_VOICE:
245                 type = VAL_VOICE;
246                 break;
247         case TELEPHONY_CALL_TYPE_VIDEO:
248                 type = VAL_VIDEO;
249                 break;
250         default:
251                 _E("Unknown type: %d", t);
252                 return false;
253         }
254
255         IF_FAIL_RETURN_TAG(!type.empty(), false, _W, "Type is empty");
256
257         return true;
258 }
259
260 bool CallStateProvider::__getCallAddress(telephony_call_h& handle, std::string& address)
261 {
262         address.clear();
263
264         char* number = NULL;
265         int err = telephony_call_get_number(handle, &number);
266         IF_FAIL_RETURN_TAG(err == TELEPHONY_ERROR_NONE, false, _E, "Getting address failed");
267
268         if (number) {
269                 address = number;
270                 g_free(number);
271                 number = NULL;
272         }
273
274         IF_FAIL_RETURN_TAG(!address.empty(), false, _W, "Address is empty");
275
276         return true;
277 }
278
279 bool CallStateProvider::__getCallHandleId(telephony_call_h& handle, unsigned int& id)
280 {
281         int err = telephony_call_get_handle_id(handle, &id);
282         IF_FAIL_RETURN_TAG(err == TELEPHONY_ERROR_NONE, false, _E, "Getting handle id failed");
283
284         return true;
285 }
286
287 int CallStateProvider::subscribe()
288 {
289         bool ret = __setCallback();
290         IF_FAIL_RETURN(ret, ERR_OPERATION_FAILED);
291         return ERR_NONE;
292 }
293
294 int CallStateProvider::unsubscribe()
295 {
296         __unsetCallback();
297         return ERR_NONE;
298 }
299
300 bool CallStateProvider::__readCurrentStatus(telephony_h& handle, Json* data)
301 {
302         unsigned int count = 0;
303         telephony_call_h *callList = NULL;
304         telephony_call_get_call_list(handle, &count, &callList);
305
306         // Default data
307         data->set(NULL, KEY_STATE, VAL_IDLE);
308
309         // Held & Dialing are ignored
310         for (unsigned int i = 0; i < count; i++) {
311                 // Call state
312                 std::string state;
313                 if (__getCallState(callList[i], state)) {
314                         // Skip Held & Dialing
315                         if (state.compare(VAL_HELD) == 0 || state.compare(VAL_DIALING) == 0)
316                                 continue;
317
318                         data->set(NULL, KEY_STATE, state);
319                 }
320
321                 // Call type
322                 std::string type;
323                 if (__getCallType(callList[i], type)) {
324                         data->set(NULL, KEY_MEDIUM, type);
325                 }
326
327                 // Address
328                 std::string address;
329                 if (__getCallAddress(callList[i], address)) {
330                         data->set(NULL, KEY_ADDRESS, address);
331                 }
332
333                 if (state == VAL_ACTIVE) {
334                         break;
335                 }
336         }
337
338         telephony_call_release_call_list(count, &callList);
339         return true;
340 }
341
342 int CallStateProvider::read()
343 {
344         bool temporaryHandle = false;
345         if (!__telephonyInitialized) {
346                 IF_FAIL_RETURN(__initTelephony(), ERR_OPERATION_FAILED);
347                 temporaryHandle = true;
348         }
349
350         bool ret = true;
351         Json data;
352         data.set(NULL, KEY_STATE, VAL_IDLE);
353
354         for (unsigned int i = 0; i < __handleList.count; i++) {
355                 telephony_sim_state_e state;
356                 int err = telephony_sim_get_state(__handleList.handle[i], &state);
357                 IF_FAIL_RETURN_TAG(err == TELEPHONY_ERROR_NONE, ERR_OPERATION_FAILED, _E, "Getting SIM status failed");
358
359                 if (state != TELEPHONY_SIM_STATE_AVAILABLE)
360                         continue;
361
362                 ret = __readCurrentStatus(__handleList.handle[i], &data);
363                 break;
364         }
365
366         if (temporaryHandle)
367                 __releaseTelephony();
368
369         if (ret) {
370                 replyToRead(NULL, ERR_NONE, data);
371                 return ERR_NONE;
372         }
373
374         return ERR_OPERATION_FAILED;
375 }