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