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