e790d96fc779e99f6ff0893cf2c6baa198ceab00
[apps/osp/Call.git] / src / CallApp.cpp
1 //
2 // Copyright (c) 2012 Samsung Electronics Co., Ltd.
3 //
4 // Licensed under the Flora License, Version 1.1 (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://floralicense.org/license/
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  * Name        : CallApp
18  * Version     :
19  * Vendor      :
20  * Description :
21  */
22
23 #include <FUi.h>
24 #include <FShell.h>
25 #include "CallApp.h"
26 #include "CallAppFrame.h"
27 #include "CallPresentationModel.h"
28 #include "CallTypes.h"
29 #include "CallAppUtility.h"
30 #include "CallIAppStateChangeListner.h"
31
32 using namespace Tizen::App;
33 using namespace Tizen::Base;
34 using namespace Tizen::System;
35 using namespace Tizen::Ui;
36 using namespace Tizen::Ui::Controls;
37 using namespace Tizen::Ui::Scenes;
38 using namespace Tizen::Base::Utility;
39 using namespace Tizen::Base::Collection;
40 using namespace Tizen::Base::Utility;
41 using namespace Tizen::Shell;
42
43
44 CallApp::CallApp(void):__initialSceneId(L""), __pLaunchArgs(null)
45 {
46         __listenerList.Construct();
47 }
48
49 CallApp::~CallApp(void)
50 {
51 }
52
53 UiApp*
54 CallApp::CreateInstance(void)
55 {
56         // Create the instance through the constructor.
57         return new CallApp();
58 }
59
60 bool
61 CallApp::OnAppInitializing(AppRegistry& appRegistry)
62 {
63         AppControlProviderManager* pProviderMgr = AppControlProviderManager::GetInstance();
64         pProviderMgr->SetAppControlProviderEventListener(this);
65         PowerManager::AddScreenEventListener(*this);
66         return true;
67 }
68
69 bool
70 CallApp::OnAppInitialized(void)
71 {
72         // TODO:
73         // Comment.
74
75         // Create a Frame
76         CallAppFrame* pCallAppFrame = new CallAppFrame();
77         pCallAppFrame->Construct();
78         pCallAppFrame->SetName(L"CallApp");
79         AddFrame(*pCallAppFrame);
80
81         //Check if there is no initial scene, then exit application.
82         //This case will normally come when invalid AppControl request has come,
83         //or incoming call is coming from unknown number and "reject unknown number" settings is enabled.
84         if (GetInitialScene().IsEmpty() == true)
85         {
86                 return false;
87         }
88
89         return true;
90 }
91
92 bool
93 CallApp::OnAppWillTerminate(void)
94 {
95         // TODO:
96         // Comment.
97         return true;
98 }
99
100 bool
101 CallApp::OnAppTerminating(AppRegistry& appRegistry, bool forcedTermination)
102 {
103         // TODO:
104         // Deallocate resources allocated by this App for termination.
105         // The App's permanent data and context can be saved via appRegistry.
106         PowerManager::RemoveScreenEventListener(*this);
107         return true;
108 }
109
110 void
111 CallApp::OnForeground(void)
112 {
113         IEnumerator* pEnum = __listenerList.GetEnumeratorN();
114         while (pEnum->MoveNext() == E_SUCCESS)
115         {
116                 IAppStateChangeListener* pInterface = static_cast<IAppStateChangeListener*>(pEnum->GetCurrent());
117                 if (pInterface == null)
118                 {
119                         delete pEnum;
120
121                         return;
122                 }
123                 pInterface->OnForeground();
124         }
125         delete pEnum;
126 }
127
128 void
129 CallApp::OnBackground(void)
130 {
131         // TODO:
132         // Stop drawing when the application is moved to the background.
133 }
134
135 void
136 CallApp::OnLowMemory(void)
137 {
138         // TODO:
139         // Free unused resources or close the application.
140 }
141
142 void
143 CallApp::OnBatteryLevelChanged(BatteryLevel batteryLevel)
144 {
145         // TODO:
146         // Handle any changes in battery level here.
147         // Stop using multimedia features(camera, mp3 etc.) if the battery level is CRITICAL.
148 }
149
150 void
151 CallApp::OnScreenOn(void)
152 {
153         // TODO:
154         // Get the released resources or resume the operations that were paused or stopped in OnScreenOff().
155 }
156
157 void
158 CallApp::OnScreenOff(void)
159 {
160         AppLogDebug("Enter");
161         IEnumerator* pEnum = __listenerList.GetEnumeratorN();
162         while (pEnum->MoveNext() == E_SUCCESS)
163         {
164                 IAppStateChangeListener* pInterface = static_cast<IAppStateChangeListener*>(pEnum->GetCurrent());
165                 if (pInterface == null)
166                 {
167                         delete pEnum;
168
169                         return;
170                 }
171                 pInterface->OnScreenOff();
172         }
173         delete pEnum;
174
175 }
176
177 SceneId
178 CallApp::GetInitialScene(void)
179 {
180         return __initialSceneId;
181 }
182
183 IList*
184 CallApp::GetAppLaunchArguments(void)
185 {
186         return __pLaunchArgs;
187 }
188
189 void
190 CallApp::AddAppStateChangeListener(const IAppStateChangeListener& listener)
191 {
192         __listenerList.Add(listener);
193
194 }
195 void
196 CallApp::RemoveAppStateChangeListener(const IAppStateChangeListener& listener)
197 {
198         __listenerList.Remove(listener);
199 }
200
201 void
202 CallApp::OnAppControlRequestReceived(RequestId reqId, const String& operationId, const String* pUriData,
203                 const String* pMimeType, const IMap* pExtraData)
204 {
205         AppLogDebug("Enter ");
206         if(pUriData != null)
207         {
208                 AppLogDebug("%ls ",pUriData->GetPointer());
209         }
210
211         if(pExtraData == null && pUriData != null)
212         {
213                 //The request is from web app
214                 AppLogDebug("%ls",pUriData->GetPointer());
215                 ProcessWebAppControlRequest(reqId, operationId, pUriData);
216         }
217         else
218         {
219                 //process AppControl parameters
220                 ProcessAppControlRequest(reqId, operationId, pExtraData,pUriData);
221         }
222         AppLogDebug("EXIT");
223 }
224
225 void
226 CallApp::ProcessWebAppControlRequest(RequestId reqId, const String& operationId,const String* pUriData)
227 {
228         //Construct map from string
229         String delim(DELIMITER);
230         StringTokenizer st(*pUriData,delim);
231         String token;
232         HashMap extraData;
233         extraData.Construct();
234         while(st.HasMoreTokens())
235         {
236                 String key=L"";
237                 String value=L"";
238                 st.GetNextToken(token);
239                 token.Trim();
240                 key.Append(token);
241                 if(st.HasMoreTokens())
242                 {
243                         token.Clear();
244                         st.GetNextToken(token);
245                         token.Trim();
246                         value.Append(token);
247                 }
248                 extraData.Add(new (std::nothrow) String(key), new (std::nothrow) String(value));
249         }
250
251         //Adding this explicitly as there no other way to invoke call from webapp
252         extraData.Add(new (std::nothrow) String(PARAM_CALL_TYPE), new (std::nothrow) String(PARAM_CALL_VALUE_VOICE));
253
254         ProcessAppControlRequest(reqId,operationId,&extraData);
255
256         extraData.RemoveAll(true);
257 }
258
259 void
260 CallApp::ProcessAppControlRequest(RequestId reqId, const String& operationId,const IMap* pArgsMap,const String* pUriData)
261 {
262         AppLogDebug("Enter %ls",operationId.GetPointer());
263         __pLaunchArgs = null;
264         if(operationId.Equals(OPERATION_ID_CALL,true) == true)
265         {
266                 AppLogDebug("OPERATION_ID_CALL");
267                 if(pArgsMap != null)
268                 {
269                         bool isIncomingCallRequest = false;
270                         String* pKey = new (std::nothrow) String(LAUNCHTYPE);
271                         if (pArgsMap->ContainsKey(*pKey) == true)
272                         {
273                                 const String* pValue = static_cast<const String*>(pArgsMap->GetValue(*pKey));
274                                 if ((pValue != null) && (pValue->Equals(PARAM_ORIGIN_MT, true) == true))
275                                 {
276                                         isIncomingCallRequest = true;
277                                 }
278                         }
279                         //Check if incoming call request or outgoing call request
280                         if(isIncomingCallRequest == true)
281                         {
282                                 HandleIncomingCallAppControlRequest(reqId, pArgsMap);
283                         }
284                         else
285                         {
286                                 HandleDialCallAppControlRequest(reqId, pArgsMap,pUriData);
287                         }
288                 }
289                 else
290                 {
291                         AppLogDebug("pArgsMap == null");
292                 }
293         }
294 }
295
296 void
297 CallApp::HandleIncomingCallAppControlRequest(RequestId reqId,const IMap* pArgsMap)
298 {
299         AppLogDebug("Enter");
300         SceneManager* pSceneManager = SceneManager::GetInstance();
301         //response message
302         AppCtrlResult appControlResult = APP_CTRL_RESULT_FAILED;
303
304         //call handle
305         String callHandle(L"");
306         String* pKey = new (std::nothrow) String(CALL_HANDLE);
307         if (pArgsMap->ContainsKey(*pKey) == true)
308         {
309                 const String* pValue = static_cast<const String*>(pArgsMap->GetValue(*pKey));
310                 if (pValue != null)
311                 {
312                         callHandle.Append(*pValue);
313                 }
314         }
315         delete pKey;
316         //contact number
317         String contactNumber(L"");
318         pKey = new (std::nothrow) String(CONTACT_NUMBER);
319         if (pArgsMap->ContainsKey(*pKey) == true)
320         {
321                 const String* pContactValue = static_cast<const String*>(pArgsMap->GetValue(*pKey));
322                 if (pContactValue != null)
323                 {
324                         contactNumber.Append(*pContactValue);
325                         AppLogDebug("%ls",contactNumber.GetPointer());
326                 }
327         }
328         delete pKey;
329         pKey = null;
330
331         //Fetch incoming call details
332         CallPresentationModel* pCallPresentor = CallPresentationModel::GetInstance();
333         //Check if there is already a dial call present .This can happen in some
334         //race conditions N_SE-39531
335         if(pCallPresentor->IsIncomingorDialingCallPresent())
336         {
337                 int incomingHandle;
338                 Integer::Parse(callHandle,incomingHandle);
339                 pCallPresentor->RejectCall(incomingHandle,false,contactNumber);
340                 AppLog("Cancelled already an incoming call present");
341                 appControlResult = APP_CTRL_RESULT_CANCELED;
342                 AppControlProviderManager::GetInstance()->SendAppControlResult(reqId, appControlResult, null);
343                 return;
344         }
345
346         AppCallInfo* pIncomingCall = pCallPresentor->FetchIncomingCallDetailsN(callHandle, contactNumber);
347         if(pIncomingCall != null)
348         {
349                 bool isCallRejected = pCallPresentor->CheckIncomingCallToBeRejected(pIncomingCall);
350                 if(isCallRejected == false)
351                 {
352                         //save app launch argument list
353                         __pLaunchArgs = new (std::nothrow) ArrayList(SingleObjectDeleter);
354                         __pLaunchArgs->Construct(1);
355                         __pLaunchArgs->Add(pIncomingCall);
356                         if(__initialSceneId.IsEmpty() == true)
357                         {
358                                 __initialSceneId = IDSCN_SCENE_INCOMINGCALL;
359                         }
360                         else
361                         {
362                                 //App already initialized, goto incoming call form
363                                 pSceneManager->GoForward(ForwardSceneTransition(IDSCN_SCENE_INCOMINGCALL, SCENE_TRANSITION_ANIMATION_TYPE_NONE,
364                                                  SCENE_HISTORY_OPTION_NO_HISTORY, SCENE_DESTROY_OPTION_DESTROY), __pLaunchArgs);
365                                 __pLaunchArgs = null;
366                         }
367
368
369                 }
370                 else
371                 {
372                         //Show messageBox showing automatic call rejection
373                         /*MessageBox callRejectedInoMsgBox;
374                         String msg(L"Call From ");
375                         msg.Append(contactNumber);
376                         msg.Append(L" Rejected.");
377                         callRejectedInoMsgBox.Construct(L"Call Rejected", msg, MSGBOX_STYLE_NONE,1000);
378                         int modalResult = 0;
379                         // Calls ShowAndWait() : Draws and Shows itself and processes events
380                         callRejectedInoMsgBox.ShowAndWait(modalResult);*/
381
382                         //go back to previous scene if App was already running, else exit application.
383                         if(__initialSceneId.IsEmpty() == true)
384                         {
385                                 //KEEP "__initialSceneId" as empty and return false from "OnAppInitialized()"
386                                 AppLog("Terminate Phone Application");
387                                 Terminate();
388                         }
389                 }
390                 //set success message
391                 appControlResult = APP_CTRL_RESULT_SUCCEEDED;
392         }
393         else
394         {
395                 appControlResult = APP_CTRL_RESULT_FAILED;
396         }
397         AppLogDebug("Exiting %d",appControlResult);
398         AppControlProviderManager::GetInstance()->SendAppControlResult(reqId, appControlResult, null);
399 }
400
401 void
402 CallApp::HandleDialCallAppControlRequest(RequestId reqId,const IMap* pArgsMap,const String* pUriData)
403 {
404         //response message
405         AppCtrlResult appControlResult = APP_CTRL_RESULT_FAILED;
406
407         if (pArgsMap != null)
408         {
409                 String callType(L"");
410                 String phoneNumber(L"");
411                 //phone number
412                 String* pKey = new (std::nothrow) String(PARAM_PHONE_NUMBER);
413                 if(pArgsMap->ContainsKey(*pKey) == true)
414                 {
415                         const String* pPhoneValue = static_cast<const String*>(pArgsMap->GetValue(*pKey));
416                         if(pPhoneValue != null)
417                         {
418                                 AppLogDebug("%ls",pPhoneValue->GetPointer());
419                                 phoneNumber.Append(*pPhoneValue);
420                         }
421                 }
422                 else
423                 {
424                         AppLogDebug("PARAM_PHONE_NUMBER not present");
425                         //Now check if tel uri is present
426                         if(pUriData != null)
427                         {
428                                 AppLogDebug("pUriData is present %ls",pUriData->GetPointer());
429                                 phoneNumber.Append(*pUriData);
430                                 if(phoneNumber.Contains(PARAM_PHONE_NUMBER))
431                                 {
432                                         phoneNumber.Replace(PARAM_PHONE_NUMBER,L"");
433                                         if(phoneNumber.Contains(DELIMITER))
434                                         {
435                                                 phoneNumber.Replace(DELIMITER,L"");
436                                                 AppLogDebug("%ls",phoneNumber.GetPointer());
437                                         }
438                                 }
439                                 AppLogDebug("%ls",phoneNumber.GetPointer());
440                         }
441                 }
442                 delete pKey;
443                 //Check if its a valid number
444                 if(CheckNumberIsValid(phoneNumber) == false)
445                 {
446                         //go back to previous scene if App was already running, else exit application.
447                         if(__initialSceneId.IsEmpty() == true)
448                         {
449                                 //KEEP "__initialSceneId" as empty and return false from "OnAppInitialized()"
450                                 AppLog("Terminate Phone Application");
451                                 AppControlProviderManager::GetInstance()->SendAppControlResult(reqId, appControlResult, null);
452                                 Terminate();
453                                 return;
454                         }
455                         else
456                         {
457                                 //invalid phone number.always return, but App will come to foreground
458                                 //and show current screen, if any calls is present.
459                                 return;
460                         }
461                 }
462                 //call type
463                 pKey = new (std::nothrow) String(PARAM_CALL_TYPE);
464                 if(pArgsMap->ContainsKey(*pKey) == true)
465                 {
466                         const String* pCallTypeValue = static_cast<const String*>(pArgsMap->GetValue(*pKey));
467                         if(pCallTypeValue != null)
468                         {
469                                 callType.Append(*pCallTypeValue);
470                         }
471                 }
472                 delete pKey;
473                 pKey = null;
474
475                 //Fetch currently active call count
476                 if (callType.IsEmpty() == false
477                                 && callType.Equals(PARAM_CALL_VALUE_VOICE, false) == true
478                                 && phoneNumber.IsEmpty() == false)
479                 {
480                         SceneManager* pSceneManager = SceneManager::GetInstance();
481                         //check if there is already a call in dialing mode, then dont accept any other dialing request.
482                         if (pSceneManager->GetCurrentSceneId() == IDSCN_SCENE_OUTCALL
483                                         || pSceneManager->GetCurrentSceneId()
484                                                         == IDSCN_SCENE_OUT_EMERGENCYCALL)
485                         {
486                                 AppLog("Cancelled");
487                                 appControlResult = APP_CTRL_RESULT_CANCELED;
488                                 AppControlProviderManager::GetInstance()->SendAppControlResult(reqId, appControlResult, null);
489                                 return;
490                         }
491
492                         CallPresentationModel* pCallPresentor = CallPresentationModel::GetInstance();
493                         //Check if there is already an incoming call
494                         //this can  happen in some race conditions N_SE-39531
495                         if(pCallPresentor->IsIncomingorDialingCallPresent() == true)
496                         {
497                                 AppLog("Cancelled already an incoming call present");
498                                 appControlResult = APP_CTRL_RESULT_CANCELED;
499                                 AppControlProviderManager::GetInstance()->SendAppControlResult(reqId, appControlResult, null);
500                                 return;
501                         }
502                         int currentActiveCallCount = pCallPresentor->GetCurrentCallCount();
503                         if(currentActiveCallCount <= 1)
504                         {
505                                 //Abort any AppControl Request running already to show incoming call screen
506                                 if (pCallPresentor->IsAppControlRunning() == true)
507                                 {
508                                         pCallPresentor->AbortAppControlRequest();
509                                 }
510                                 //make an outgoing call with given number
511                                 String* contactTxt = new (std::nothrow) String(phoneNumber);
512                                 __pLaunchArgs =  new (std::nothrow) ArrayList(SingleObjectDeleter);
513                                 __pLaunchArgs->Construct();
514                                 __pLaunchArgs->Add(contactTxt);
515                                 bool isEmergencyCall = pCallPresentor->IsEmergencyNumber(*contactTxt, true);
516
517                                 SceneId nextScene = IDSCN_SCENE_OUTCALL;
518                                 if (isEmergencyCall)
519                                 {
520                                         nextScene = IDSCN_SCENE_OUT_EMERGENCYCALL;
521                                 }
522                                 //Check if app was already running
523                                 if(__initialSceneId.IsEmpty() == true)
524                                 {
525                                         //phone App is not already launched
526                                         __initialSceneId = nextScene;
527                                 }
528                                 else
529                                 {
530                                         AppLog("Outgoing call");
531                                         pSceneManager->GoForward( ForwardSceneTransition( nextScene, SCENE_TRANSITION_ANIMATION_TYPE_NONE,
532                                                          SCENE_HISTORY_OPTION_NO_HISTORY, SCENE_DESTROY_OPTION_DESTROY), __pLaunchArgs);
533                                 }
534                                 appControlResult = APP_CTRL_RESULT_SUCCEEDED;
535                         }
536                         else
537                         {
538                                 //already 2 active calls, 3rd call not allowed
539                                 appControlResult = APP_CTRL_RESULT_CANCELED;
540                         }
541                 }
542                 else
543                 {
544                         appControlResult = APP_CTRL_RESULT_FAILED;
545                 }
546         }
547         //send response message
548         AppControlProviderManager::GetInstance()->SendAppControlResult(reqId, appControlResult, null);
549 }
550
551 bool
552 CallApp::CheckNumberIsValid(String phoneNumber)
553 {
554         //Pattern to compare all characters except 0-9 * # P ; , +
555         String phoneNumberPattern(L"[^0-9*#P,p+;]");
556         RegularExpression checkPhoneNumber;
557         checkPhoneNumber.Construct(phoneNumberPattern);
558         //If there is any character other than these listed above then display invalid number
559         bool resultMatch = checkPhoneNumber.Match(phoneNumber,false);
560         //return false for patterns other than 0-9 * # P ; , +
561         if(resultMatch == true)
562         {
563                 //return phone number is invalid
564                 return false;
565         }
566
567         return true;
568
569 }
570
571 void
572 CallApp::SetTopMostWindow(bool bTopMost)
573 {
574         AppLogDebug("bTopMost = %d",bTopMost);
575         result res = E_FAILURE;
576         //ToDO: Need to see if there is better way to handle
577         //this case
578
579         if(bTopMost == true)
580         {
581                 GetAppFrame()->GetFrame()->SetZOrderGroup(WINDOW_Z_ORDER_GROUP_HIGHEST);
582                 AppManager::GetInstance()->AddActiveAppEventListener(*this);
583                 /*if(PowerManager::IsScreenOn() == false)
584                 {
585                         AppLogDebug("TurnScreenOn");
586                         res = PowerManager::TurnScreenOn();
587                         AppLogDebug("TurnScreenOn %d",res);
588                 }*/
589
590         }
591         else
592         {
593                 GetAppFrame()->GetFrame()->SetZOrderGroup(WINDOW_Z_ORDER_GROUP_NORMAL);
594                 PowerManager::KeepScreenOnState(false);
595                 AppManager::GetInstance()->RemoveActiveAppEventListener(*this);
596         }
597
598         if(LockManager::GetInstance()->IsLocked())
599         {
600                 AppLogDebug("Phone Locked");
601                 LockManager::GetInstance()->Unlock();
602         }
603
604 }
605 void
606 CallApp::OnActiveAppChanged(const String& appId)
607 {
608         AppLogDebug("Enter %ls",appId.GetPointer());
609         if(GetAppId().Equals(appId) == true)
610         {
611                 result res = PowerManager::KeepScreenOnState(true,false);
612                 AppLogDebug("KeepScreenOnState %d",res);
613
614         }
615
616 }