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