removed redundant code
[platform/framework/native/appfw.git] / src / app / FApp_AppControlManager.cpp
1 //
2 // Copyright (c) 2012 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 /**
18  * @file        FApp_AppControlManager.cpp
19  * @brief       This is the implementation for the _AppControlManager class.
20  */
21
22 #include <stdint.h>
23 #include <cstdio>
24 #include <unique_ptr.h>
25
26 #include <appsvc/appsvc.h>
27 #include <aul/aul.h>
28 #include <bundle.h>
29 #include <content/mime_type.h>
30 #include <appinfo.h>
31
32 #include <FBaseInteger.h>
33 #include <FBaseObject.h>
34 #include <FBaseString.h>
35 #include <FBaseColIListT.h>
36 #include <FBaseColArrayList.h>
37 #include <FBaseErrors.h>
38 #include <FAppAppControl.h>
39 #include <FAppAppManager.h>
40 #include <FAppIAppControlListener.h>
41 #include <FAppIAppControlResponseListener.h>
42 #include <FAppIAppFrame.h>
43 #include <FAppSqlDataControl.h>
44 #include <FAppMapDataControl.h>
45 #include <FAppPkgPackageInfo.h>
46 #include <FAppPkgPackageAppInfo.h>
47 #include <FBaseSysLog.h>
48
49 #include <FBase_StringConverter.h>
50 #include <FIo_DataControlResultSetImpl.h>
51
52 #include "FApp_AppArg.h"
53 #include "FApp_AppControlEventArg.h"
54 #include "FApp_AppControlRegistry.h"
55 #include "FApp_AppControlImpl.h"
56 #include "FApp_AppImpl.h"
57 #include "FApp_AppInfo.h"
58 #include "FApp_Aul.h"
59 #include "FApp_AppControlManager.h"
60 #include "FApp_AppManagerProxy.h"
61 #include "FApp_ConditionManagerProxy.h"
62 #include "FApp_MapDataControlImpl.h"
63 #include "FApp_SqlDataControlImpl.h"
64 #include "FAppPkg_PackageManagerImpl.h"
65 #include "FAppPkg_PackageInfoImpl.h"
66 #include "FApp_AppMessageImpl.h"
67 #include "FApp_AppManagerImpl.h"
68 #include "FApp_AppControlResponseEvent.h"
69 #include "FApp_IAppControlPluginProvider.h"
70
71
72 using namespace Tizen::App::Package;
73 using namespace Tizen::Base;
74 using namespace Tizen::Base::Collection;
75 using namespace Tizen::Base::Runtime;
76 using namespace Tizen::Base::Utility;
77 using namespace Tizen::Io;
78
79
80 namespace Tizen { namespace App
81 {
82
83 const wchar_t TIZEN_OPERATION_PICK[] = L"http://tizen.org/appcontrol/operation/pick";
84 const wchar_t TIZEN_OPERATION_MAIN[] = L"http://tizen.org/appcontrol/operation/main";
85 const wchar_t LEGACY_OPERATION_MAIN[] = L"osp.operation.MAIN";
86 const char TIZEN_NOTIFICATION_DATA[] = "http://tizen.org/appcontrol/data/notification";
87
88 _AppControlManager::_AppControlManager(void)
89 {
90         SysLog(NID_APP, "");
91
92         // AppControl event handling is expected to be performed in the main thread.
93         __appControlEvent.Construct();
94         __appControlEvent.AddListener(*dynamic_cast<_IAppControlSysEventListener*>(this));
95         __appControlResponseEventContainer.Construct();
96         __appControlResponseEventList.Construct();
97 }
98
99 _AppControlManager::~_AppControlManager(void)
100 {
101         SysLog(NID_APP, "");
102         __appControlEvent.RemoveListener(*dynamic_cast<_IAppControlSysEventListener*>(this));
103         IEnumeratorT<int>* pEnum = __appControlResponseEventList.GetEnumeratorN();
104
105         if (pEnum != null)
106         {
107                 while(pEnum->MoveNext() == E_SUCCESS)
108                 {
109                         int reqId;
110                         pEnum->GetCurrent(reqId);
111                         _AppControlResponseEvent* pResponseEvent = null;
112                         __appControlResponseEventContainer.GetValue(reqId, pResponseEvent);
113                         delete pResponseEvent;
114
115                         __appControlResponseEventContainer.Remove(reqId);
116                         SysLog(NID_APP, "pResponseEvent gets deleted. reqId(%d)", reqId);
117                 }
118         }
119         delete pEnum;
120 }
121
122 _AppControlManager*
123 _AppControlManager::GetInstance(void)
124 {
125         static _AppControlManager inst;
126
127         return &inst;
128 }
129
130 result
131 _AppControlManager::GetMimeFromExt(const String& ext, String& out)
132 {
133         std::unique_ptr<char[]> pExtension(_StringConverter::CopyToCharArrayN(ext));
134         SysTryReturnResult(NID_APP, pExtension != null, E_OUT_OF_MEMORY, "String allocation failure.");
135
136         char* mime = NULL;
137         mime_type_get_mime_type(pExtension.get(), &mime);
138
139         SysTryReturnResult(NID_APP, mime != NULL, E_UNSUPPORTED_FORMAT, "MIME type conversion failure for %ls.", ext.GetPointer());
140
141         out = mime;
142         free(mime);
143
144         return E_SUCCESS;
145 }
146
147
148 String
149 _AppControlManager::GetMimeTypeFromDataType(const String& data)
150 {
151         // Data type is either MIME type or .[extension]
152
153         if (data.IsEmpty() || data[0] != L'.')
154         {
155                 return data;
156         }
157
158         // .[extension]
159         String ext;
160         data.SubString(1, ext);
161
162         String res;
163         result r = _AppControlManager::GetMimeFromExt(ext, res);
164         SysTryReturn(NID_APP, !IsFailed(r), L"", r, "[%s] MIME type conversion failed for %ls.", GetErrorMessage(r), ext.GetPointer());
165
166         SysLog(NID_APP, "Conversion from %ls into %ls.", data.GetPointer(), res.GetPointer());
167         return res;
168 }
169
170
171 void
172 _AppControlManager::OnAppControlEventReceivedN(int reqId, _AppArg* pAppArg, int res)
173 {
174         SysLog(NID_APP, "Received request Id %d, arg 0x%x", reqId, pAppArg);
175
176         //_AppArg::Print(b);
177         // get launch info from request Id
178         _DataControlInfo* pInfo = __launchManager.FindItem(reqId);
179         SysTryReturnVoidResult(NID_APP, pInfo != null, E_OBJ_NOT_FOUND, "[E_OBJ_NOT_FOUND] request Id %d not found with response %d", reqId,
180                                         res);
181
182         // invoke callback
183         if (pInfo->launchCb)
184         {
185                 if (pInfo->magic == LAUNCH_INFO_MAGIC)
186                 {
187                         SysLog(NID_APP, "Invoking callback 0x%x", pInfo->launchCb);
188                         //pAppArg->Print();
189
190                         if (pInfo->pUserData)
191                         {
192                                 (*pInfo->launchCb)(pInfo->pUserData, pInfo->pArg, pAppArg, static_cast<service_result_e>(res), pInfo->property, reqId);
193                         }
194                 }
195                 else
196                 {
197                         SysLogException(NID_APP, E_SYSTEM, "Corrupted data structure.");
198                 }
199         }
200
201         // clean up argument
202         __launchManager.RemoveItem(reqId);
203 }
204
205
206 // callback for AppControl start event
207 void
208 _AppControlManager::OnAppControlEventReceivedN(int reqId, const AppId& appId, const String& operationId)
209 {
210         SysLog(NID_APP, "Received request Id %d, app %ls, operationId %ls", reqId, appId.GetPointer(), operationId.GetPointer());
211
212         // get launch info from request Id
213         _InProcessInfo* pInfo = __inAppManager.FindItem(reqId);
214         SysTryReturnVoidResult(NID_APP, pInfo != null, E_OBJ_NOT_FOUND, "[E_OBJ_NOT_FOUND] request Id %d not found.", reqId);
215
216         IAppControlResponseListener* pListener = dynamic_cast<IAppControlResponseListener*>(pInfo->pListener);
217         if (pListener == null)
218         {
219                 SysLog(NID_APP, "Empty AppControl listener callback for req %d, app %ls.", reqId, appId.GetPointer());
220                 return;
221         }
222
223         result r = E_SUCCESS;
224
225         AppId actualAppId = appId;
226         if (appId == L'c')
227         {
228                 actualAppId.Clear();
229                 r = E_OPERATION_CANCELED;
230         }
231         SysLog(NID_APP, "Invoking callback 0x%x.", pListener);
232
233         _AppControlResponseEvent* pResponseEvent = null;
234         __appControlResponseEventContainer.GetValue(reqId, pResponseEvent);
235         SysLog(NID_APP, "StartResponseReceived Request Id(%d), ResponseEvent 0x%x.", reqId, pResponseEvent);
236         if (pResponseEvent != null)
237         {
238                 String oId(operationId);
239                 _AppControlResponseEventArg* pResponseEventArg = new (std::nothrow) _AppControlResponseEventArg(pListener, _APPCONTROL_RESPONSETYPE_START, actualAppId, oId, r, APP_CTRL_RESULT_SUCCEEDED, null, reqId, false);
240
241                 if (pResponseEventArg != null)
242                 {
243                         pResponseEvent->Fire(*pResponseEventArg);
244                         SysLog(NID_APP, "pResponseEvent is Fired");
245                 }
246         }
247         else
248         {
249                 pListener->OnAppControlStartResponseReceived(actualAppId, operationId, r);
250                 SysLog(NID_APP, "OnAppControlStartResponseReceived called directly");
251         }
252
253         if (r == E_OPERATION_CANCELED)
254         {
255                 SysLog(NID_APP, "Removed start listener as operation is canceled.");
256                 __inAppManager.RemoveItem(reqId);
257         }
258 }
259
260
261 void
262 _AppControlManager::InvokeAppControlCompleteListener(IAppControlResponseListener& listener, const AppId& appId, const String& op, AppCtrlResult res, const IMap* pExtraData, bool noRaise)
263 {
264         listener.OnAppControlCompleteResponseReceived(appId, op, res, pExtraData);
265
266         if (!noRaise)
267         {
268                 _AppImpl::GetInstance()->SendUserEvent(_APP_EVENT_RAISE, null, false);
269         }
270
271         SysLog(NID_APP, "AppControl response finished.");
272 }
273
274
275 void
276 _AppControlManager::InvokeLegacyAppControlCompleteListener(IAppControlEventListener& listener, const AppId& appId, const String& op, const IList* pList, bool noRaise)
277 {
278         listener.OnAppControlCompleted(appId, op, pList);
279
280         if (!noRaise)
281         {
282                 _AppImpl::GetInstance()->SendUserEvent(_APP_EVENT_RAISE, null, false);
283         }
284
285         SysLog(NID_APP, "Legacy AppControl response finished.");
286 }
287
288
289 // callback for in-process event handling
290 void
291 _AppControlManager::OnAppControlPluginEventReceivedN(int reqId, int res, const AppId& optAppId, const String& optOperation, const IMap* pArgs, int property)
292 {
293         SysLog(NID_APP, "Received request Id %d, res %d, args 0x%x", reqId, res, pArgs);
294
295         // process proper callback
296         _InProcessInfo* pInfo = __inAppManager.FindItem(reqId);
297         SysTryReturnVoidResult(NID_APP, pInfo != null, E_OBJ_NOT_FOUND, "[E_OBJ_NOT_FOUND] request Id %d not found with args 0x%x", reqId,
298                                         pArgs);
299
300         if (pInfo->pListener)
301         {
302                 String aId;
303                 String oId;
304
305                 if (optAppId.IsEmpty())
306                 {
307                         aId = pInfo->providerId;
308                         oId = pInfo->operationId;
309                 }
310                 else
311                 {
312                         // implicit launch only
313                         aId = optAppId;
314                         oId = optOperation;
315
316                         SysLog(NID_APP, "Changing appId/operation for implicit launch.");
317                 }
318
319                 SysLog(NID_APP, "Invoking callback 0x%x for (%ls, %ls).", pInfo->pListener, aId.GetPointer(), oId.GetPointer());
320
321                 const bool isSubMode = (property & _APPCONTROL_PROPERTY_SUBMODE);
322                 const bool isServiceCallee = (property & _APPCONTROL_PROPERTY_SERVICE_CALLEE);
323
324                 if (pInfo->isLegacy)
325                 {
326                         IAppControlEventListener* pListener = dynamic_cast<IAppControlEventListener*>(pInfo->pListener);
327                         if (pListener)
328                         {
329                                 ArrayList list(SingleObjectDeleter);
330                                 _AppArg::FillLegacyAppControlResult(list, res, pArgs, aId);
331
332                                 InvokeLegacyAppControlCompleteListener(*pListener, aId, oId, &list, isSubMode | isServiceCallee);
333                         }
334                         else
335                         {
336                                 SysLog(NID_APP, "Wrong AppControl listener type.");
337                         }
338                 }
339                 else
340                 {
341                         IAppControlResponseListener* pListener = dynamic_cast<IAppControlResponseListener*>(pInfo->pListener);
342                         if (pListener)
343                         {
344                                 _AppControlResponseEvent* pResponseEvent = null;
345                                 int responseEventRequestId = RESPONSE_EVENT_REQID_MAGIC + reqId;
346                                 __appControlResponseEventContainer.GetValue(responseEventRequestId, pResponseEvent);
347
348                                 if (pResponseEvent != null)
349                                 {
350                                         _AppControlResponseEventArg* pResponseEventArg = new (std::nothrow) _AppControlResponseEventArg(pListener, _APPCONTROL_RESPONSETYPE_COMPLETE, aId, oId, E_SUCCESS, static_cast<AppCtrlResult>(res), const_cast<IMap*> (pArgs), responseEventRequestId, isSubMode);
351                                         if (pResponseEventArg != null)
352                                         {
353                                                 pResponseEvent->Fire(*pResponseEventArg);
354                                                 SysLog(NID_APP, "pResponseEvent is Fired");
355                                         }
356                                 }
357                                 else
358                                 {
359                                         InvokeAppControlCompleteListener(*pListener, aId, oId, ConvertAppControlResultCode(res), pArgs, isSubMode | isServiceCallee);
360                                         SysLog(NID_APP, "Listener called directly");
361                                         delete pArgs;
362                                 }
363                         }
364                         else
365                         {
366                                 SysLog(NID_APP, "Wrong AppControl listener type.");
367                         }
368                 }
369         }
370         else
371         {
372                 SysLog(NID_APP, "Empty AppControl listener.");
373         }
374
375
376         // remove from list and unload dll
377         __inAppManager.RemoveItem(reqId);
378 }
379
380
381 result
382 _AppControlManager::SendAppControlEvent(IEventArg& arg)
383 {
384         return __appControlEvent.FireAsync(arg);
385 }
386
387 Tizen::Base::Collection::IMapT<int,_AppControlResponseEvent*>*
388 _AppControlManager::GetAppControlResponseEventContainer(void)
389 {
390         return &__appControlResponseEventContainer;
391 }
392
393
394 static bool
395 IsMatchingProcListener(const _InProcessInfo& info, IEventListener* pListener)
396 {
397         return (info.pListener == pListener);
398 }
399
400
401 void
402 _AppControlManager::StopAppControlResponseListener(IAppControlResponseListener* pListener)
403 {
404         // __inAppManager, __launchManager
405         _InProcessInfo* pProcInfo = __inAppManager.FindItemWithListener(IsMatchingProcListener, pListener);
406         if (pProcInfo)
407         {
408                 pProcInfo->pListener = null;
409                 SysLog(NID_APP, "Listener 0x%x is removed from in-process stub list.", pListener);
410         }
411 }
412
413
414 // generic launch callback
415 static void
416 LaunchResultCb(bundle* b, int request_code, appsvc_result_val res, void* data)
417 {
418         SysLog(NID_APP, "SLP callee result: %d", res);
419
420         _AppControlManager* pImpl = static_cast<_AppControlManager*>(data);
421         if (pImpl == null)
422         {
423                 return;
424         }
425
426         _AppArg* pAppArg = new (std::nothrow) _AppArg;
427         SysTryReturnVoidResult(NID_APP, pAppArg != null, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] AppControl event argument creation failure.");
428
429         _AppControlEventArg* pArg = null;
430         result r = pAppArg->Construct(b);
431         SysTryCatch(NID_APP, !IsFailed(r), , r, "[%s] AppControl event argument creation failure.", GetErrorMessage(r));
432
433         pArg = new (std::nothrow) _AppControlEventArg(request_code, pAppArg, res);
434         SysTryCatch(NID_APP, pArg != null, r = E_OUT_OF_MEMORY, r, "[E_OUT_OF_MEMORY] AppControl event argument creation failure.");
435
436         //_AppArg::Print(b);
437         pImpl->SendAppControlEvent(*pArg);
438
439         return;
440
441 CATCH:
442         delete pAppArg;
443 }
444
445
446 result
447 _AppControlManager::SendAppControlStartResponse(int req, const char* pValue, const char* pOp)
448 {
449         _AppControlStartEventArg* pArg = new (std::nothrow) _AppControlStartEventArg(req, AppId(pValue), String(pOp));
450         SysTryReturnResult(NID_APP, pArg != null, E_OUT_OF_MEMORY, "AppControl start event creation failure.");
451
452         SendAppControlEvent(*pArg);
453
454         return E_SUCCESS;
455 }
456
457
458 result
459 _AppControlManager::LaunchPkg(_AppMessageImpl& msg, const char* pkg_name, const char* op, const char* mime, const char* uri, AppSvcResFn pCb, void* data)
460 {
461         bundle* kb = msg.GetBundle();
462
463         if (pkg_name)
464         {
465                 appsvc_set_pkgname(kb, pkg_name);
466         }
467
468         appsvc_set_operation(kb, (op) ? op : APPSVC_OPERATION_DEFAULT);
469
470         if (mime)
471         {
472                 appsvc_set_mime(kb, mime);
473         }
474
475         if (uri)
476         {
477                 appsvc_set_uri(kb, uri);
478         }
479
480         int pid = LaunchPkg(msg, pCb, data);
481
482         result r = E_SUCCESS;
483         if (pid < 0)
484         {
485                 r = GetLastResult();
486         }
487
488         return r;
489 }
490
491
492 int
493 _AppControlManager::Launch(_AppMessageImpl& msg, const char* pkg_name, const char* op, const char* mime, const char* uri, AppSvcResFn pCb, void* data)
494 {
495         bundle* kb = msg.GetBundle();
496         SysTryReturn(NID_APP, kb != NULL, -1, E_OUT_OF_MEMORY, "Bundle allocation failure.");
497
498         if (pkg_name)
499         {
500                 appsvc_set_pkgname(kb, pkg_name);
501         }
502
503         appsvc_set_operation(kb, (op) ? op : APPSVC_OPERATION_DEFAULT);
504
505         if (mime)
506         {
507                 appsvc_set_mime(kb, mime);
508         }
509
510         if (uri)
511         {
512                 appsvc_set_uri(kb, uri);
513         }
514
515         if (_AppImpl::GetInstance() != null)
516         {
517                 const long handle = _AppImpl::GetInstance()->GetWindowHandle();
518                 _AppArg::UpdateWindowHandle(kb, handle);
519         }
520
521         SysLog(NID_APP, "MIME(%s), URI(%s).", appsvc_get_mime(kb), appsvc_get_uri(kb));
522         int pid = appsvc_run_service(kb, 0, reinterpret_cast<appsvc_res_fn>(pCb), this);
523
524         result r = E_SUCCESS;
525         if (pid < 0)
526         {
527                 switch (pid)
528                 {
529                 case APPSVC_RET_EILLACC:
530                         r = E_ILLEGAL_ACCESS;
531                         break;
532                 case APPSVC_RET_EINVAL:
533                         r = E_MAX_EXCEEDED;
534                         break;
535                 default:
536                         r = E_SYSTEM;
537                         break;
538                 }
539                 SysLog(NID_APP, "[%s]Launching service %s failure", GetErrorMessage(r), pkg_name);
540         }
541         SetLastResult(r);
542
543         return pid;
544 }
545
546
547 int
548 _AppControlManager::LaunchPkg(_AppMessageImpl& msg, AppSvcResFn pCb, void* data)
549 {
550         bundle* kb = msg.GetBundle();
551         SysTryReturn(NID_APP, kb != NULL, -1, E_OUT_OF_MEMORY, "Bundle allocation failure.");
552
553         if (_AppImpl::GetInstance() != null)
554         {
555                 const long handle = _AppImpl::GetInstance()->GetWindowHandle();
556                 _AppArg::UpdateWindowHandle(kb, handle);
557         }
558
559         int pid = appsvc_run_service(kb, 0, reinterpret_cast<appsvc_res_fn>(pCb), this);
560
561         result r = E_SUCCESS;
562         if (pid < 0)
563         {
564                 switch (pid)
565                 {
566                 case APPSVC_RET_EILLACC:
567                         r = E_ILLEGAL_ACCESS;
568                         break;
569                 case APPSVC_RET_EINVAL:
570                         r = E_MAX_EXCEEDED;
571                         break;
572                 default:
573                         r = E_SYSTEM;
574                         break;
575                 }
576                 SysLog(NID_APP, "[%s] Launching service %s failure", GetErrorMessage(r), appsvc_get_appid(kb));
577         }
578         SetLastResult(r);
579
580         return pid;
581 }
582
583
584 result
585 _AppControlManager::LaunchApp(const AppId& appId, _AppArg* pArg, int req)
586 {
587         SysTryReturnResult(NID_APP, pArg != null, E_INVALID_ARG, "Invalid launch argument");
588         SysLog(NID_APP, "App: %ls.", appId.GetPointer());
589
590         String actualAppId = appId;
591 #if 0
592         // This logic is only for very old legacy code to support "pkgid" launch and should be removed
593         if (appId.GetLength() == 10)
594         {
595                 const String& name = _PackageManagerImpl::GetInstance()->GetDefaultAppExecutableName(appId);
596
597                 if (!name.IsEmpty())
598                 {
599                         actualAppId.Append(L'.');
600                         actualAppId.Append(name);
601                 }
602         }
603 #endif
604
605         pArg->UpdateRequestId(req);
606
607         if (_AppImpl::GetInstance() != null)
608         {
609                 const long handle = _AppImpl::GetInstance()->GetWindowHandle();
610                 pArg->UpdateWindowHandle(handle);
611         }
612
613         int pid = -1;
614         bundle* kb = NULL;
615
616         std::unique_ptr< PackageAppInfo > pAppInfo(_PackageManagerImpl::GetInstance()->GetPackageAppInfoN(appId));
617         SysTryReturn(NID_APP, pAppInfo != null, E_SYSTEM, GetLastResult(), "[%s] Getting AppInfo failed.", GetErrorMessage(GetLastResult()));
618         _PackageAppInfoImpl* pAppInfoImpl = _PackageAppInfoImpl::GetInstance(pAppInfo.get());
619         SysTryReturnResult(NID_APP, pAppInfoImpl != null , E_SYSTEM, "Severe system error");
620
621         if (pAppInfoImpl->IsServiceApp() == false)
622         {
623                 String tempId;
624                 actualAppId.SubString(0, 10, tempId);
625                 tempId += L'.';
626                 tempId += String(SUBMODE_NAME);
627
628                 // [INFO] Ugly solution for submode support
629                 pArg->UpdateAppId(tempId);
630                 kb = pArg->GetBundle();
631
632                 pid = appsvc_run_service(kb, req, LaunchResultCb, this);
633                 if (pid >= 0)
634                 {
635                         SysLog(NID_APP, "Submode launch successful");
636                         return E_SUCCESS;
637                 }
638                 else if (pid == APPSVC_RET_EINVAL)
639                 {
640                         SysLog(NID_APP, "Argument overflow");
641                         return E_MAX_EXCEEDED;
642                 }
643         }
644
645         pArg->UpdateAppId(actualAppId);
646
647         // retry for possible failure
648         int count = 0;
649         const int TRY_COUNT = 3;
650         const int TRY_SLEEP_TIME = 65;
651         do
652         {
653                 kb = pArg->GetBundle();
654                 pid = appsvc_run_service(kb, req, LaunchResultCb, this);
655                 if (pid >= 0)
656                 {
657                         SysLog(NID_APP, "Application(%d) launched with reqId(%d) and arg(0x%x).", pid, req, pArg);
658                         return E_SUCCESS;
659                 }
660                 else if (pid == APPSVC_RET_EINVAL)
661                 {
662                         SysLog(NID_APP, "Argument overflow");
663                         return E_MAX_EXCEEDED;
664                 }
665
666                 count++;
667                 SysLog(NID_APP, "Waiting %dth time.", count);
668                 Thread::Sleep(TRY_SLEEP_TIME);
669         }
670         while (count < TRY_COUNT);
671
672         result r = E_SUCCESS;
673         switch (pid)
674         {
675         case APPSVC_RET_EILLACC:
676                 r = E_ILLEGAL_ACCESS;
677                 break;
678         default:
679                 r = E_SYSTEM;
680                 break;
681         }
682
683         SysLogException(NID_APP, r, "[%s] Launching service failure for %ls", GetErrorMessage(r), appId.GetPointer());
684
685         return r;
686 }
687
688 static bool
689 _IsDefaultApplication(const AppId& packageId, const String& appId)
690 {
691         const String& execName = _PackageManagerImpl::GetInstance()->GetDefaultAppExecutableName(packageId);
692
693         int index = -1;
694         result r = appId.IndexOf(L'.', 0, index);
695         if (r != E_SUCCESS)
696         {
697                 return false;
698         }
699
700         String tmp;
701         appId.SubString(index + 1, tmp);
702         if (tmp == execName)
703         {
704                 SysLog(NID_APP, "Default application %ls", tmp.GetPointer());
705                 return true;
706         }
707
708         return false;
709 }
710
711
712 int
713 _AppControlManager::Launch(const AppId& appId, _AppArg* pArg, int req)
714 {
715         return Launch(appId, pArg, reinterpret_cast<AppSvcResFn>(LaunchResultCb), this, req);
716 }
717
718
719 int
720 _AppControlManager::Launch(const _AppMessageImpl& msg, AppSvcResFn pCb, void* pData, int req)
721 {
722         const bundle* pBundle = msg.GetBundle();
723
724         _AppArg arg;
725         arg.Construct(pBundle);
726
727         return Launch(_AppMessageImpl::GetApplicationId(pBundle), &arg, pCb, pData, req);
728 }
729
730
731 int
732 _AppControlManager::Launch(const AppId& appId, _AppArg* pArg, AppSvcResFn pCb, void* pData, int req)
733 {
734         SysTryReturn(NID_APP, pArg != null, -1, E_INVALID_ARG, "[E_INVALID_ARG] Invalid launch argument");
735         SysLog(NID_APP, "App: %ls.", appId.GetPointer());
736
737         String actualAppId = appId;
738
739         pArg->UpdateRequestId(req);
740
741         if (_AppImpl::GetInstance() != null)
742         {
743                 const long handle = _AppImpl::GetInstance()->GetWindowHandle();
744                 pArg->UpdateWindowHandle(handle);
745         }
746
747         int pid = -1;
748         bundle* kb = NULL;
749         String tempId;
750
751         actualAppId.SubString(0, 10, tempId);
752
753         const int type = _AppInfo::GetAppType();
754         if ((!(type & _APP_TYPE_SERVICE_APP)) && _IsDefaultApplication(tempId, appId))
755         {
756                 tempId += L'.';
757                 tempId += String(SUBMODE_NAME);
758
759                 // [INFO] Ugly solution for submode support
760                 pArg->UpdateAppId(tempId);
761                 kb = pArg->GetBundle();
762
763                 pid = appsvc_run_service(kb, req, reinterpret_cast<appsvc_res_fn>(pCb), pData);
764                 if (pid >= 0)
765                 {
766                         SysLog(NID_APP, "Submode launch successful");
767                         SetLastResult(E_SUCCESS);
768                         return pid;
769                 }
770                 else if (pid == APPSVC_RET_EINVAL)
771                 {
772                         SetLastResult(E_MAX_EXCEEDED);
773                         return pid;
774                 }
775         }
776
777         pArg->UpdateAppId(actualAppId);
778
779         // retry for possible failure
780         int count = 0;
781         const int TRY_COUNT = 3;
782         const int TRY_SLEEP_TIME = 65;
783         do
784         {
785                 kb = pArg->GetBundle();
786                 pid = appsvc_run_service(kb, req, reinterpret_cast<appsvc_res_fn>(pCb), pData);
787                 if (pid >= 0)
788                 {
789                         SysLog(NID_APP, "Application(%d) launched with reqId(%d) and arg(0x%x).", pid, req, pArg);
790                         SetLastResult(E_SUCCESS);
791                         return pid;
792                 }
793                 else if (pid == APPSVC_RET_EINVAL)
794                 {
795                         SetLastResult(E_MAX_EXCEEDED);
796                         return pid;
797                 }
798
799                 count++;
800                 SysLog(NID_APP, "Waiting %dth time with %d.", count, pid);
801                 Thread::Sleep(TRY_SLEEP_TIME);
802         }
803         while (count < TRY_COUNT);
804
805         result r = E_SUCCESS;
806         switch (pid)
807         {
808         case APPSVC_RET_EILLACC:
809                 r = E_ILLEGAL_ACCESS;
810                 break;
811         default:
812                 r = E_SYSTEM;
813                 break;
814         }
815
816         SysLogException(NID_APP, r, "[%s] Launching service failure for %ls", GetErrorMessage(r), appId.GetPointer());
817
818         SetLastResult(r);
819
820         return pid;
821 }
822
823
824 void
825 _AppControlManager::FinishAppControl(int reqId, int res, IMap* pMap)
826 {
827         SysLog(NID_APP, "req %d, res %d.", reqId, res);
828         _NativeAppControlEventArg* pArg = new (std::nothrow) _NativeAppControlEventArg(reqId, res, pMap, _APPCONTROL_PROPERTY_SUBMODE);
829         SysTryReturnVoidResult(NID_APP, pArg != null, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Return argument allocation failure.");
830
831         SendAppControlEvent(*pArg);
832 }
833
834
835         void
836 _AppControlManager::FinishAppControl(int reqId, int res, const AppId& appId, const String& oId, IMap* pMap, int prop)
837 {
838         SysLog(NID_APP, "req %d, res %d, appId(%ls), oId(%ls).", reqId, res, appId.GetPointer(), oId.GetPointer());
839         _NativeAppControlEventArg* pArg = new (std::nothrow) _NativeAppControlEventArg(reqId, res, appId, oId, pMap, prop);
840         SysTryReturnVoidResult(NID_APP, pArg != null, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Return argument allocation failure.");
841
842         SendAppControlEvent(*pArg);
843 }
844
845
846 void
847 _AppControlManager::RemoveResultRequest(int reqId)
848 {
849         __resultManager.RemoveItem(reqId);
850 }
851
852 const _AppArg*
853 _AppControlManager::FindResultRequest(int reqId) const
854 {
855         const _ResultInfo* pInfo = __resultManager.FindItem(reqId);
856         return (pInfo) ? &(pInfo->arg) : null;
857 }
858
859 int
860 _AppControlManager::AddLaunchRequest(_AppArg* pArg, LaunchCbType pCb, void* pData, int prop)
861 {
862         SysTryReturn(NID_APP, pArg != null, -1, E_INVALID_ARG, "[E_INVALID_ARG] Empty argument.");
863
864         _DataControlInfo* pItem = new (std::nothrow) _DataControlInfo(pArg, pCb, pData, prop);
865         SysTryReturn(NID_APP, pItem != null, -1, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Empty argument.");
866
867         SysLog(NID_APP, "Registering callback 0x%x, 0x%x", pCb, pData);
868
869         return __launchManager.InsertItem(pItem);
870 }
871
872 void
873 _AppControlManager::RemoveLaunchRequest(int req)
874 {
875         __launchManager.RemoveItem(req);
876 }
877
878 result
879 _AppControlManager::RegisterRequest(service_s* service, int& req, _AppHandler& handler)
880 {
881         bundle* b = _AppArg::GetBundleFromSvc(service);
882
883         _AppArg* pArg = new (std::nothrow) _AppArg();
884         SysTryReturnResult(NID_APP, pArg != null, E_OUT_OF_MEMORY, "ArrayList creation failure.");
885         pArg->Construct(b);
886
887         result r = E_SUCCESS;
888
889         // ownership is transfered to RequestManager
890         _ResultInfo* pItem = new (std::nothrow) _ResultInfo(*pArg);
891         SysTryCatch(NID_APP, pItem != null, , r = E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Empty argument.");
892
893         req = __resultManager.InsertItem(pItem);
894         SysTryCatch(NID_APP, req != -1, , r = E_INVALID_STATE, "[E_INVALID_STATE] Invalid argument handling state.");
895
896         handler = _AppArg::GetHandler(b);
897
898         return E_SUCCESS;
899
900 CATCH:
901         delete pArg;
902
903         return r;
904 }
905
906
907 AppCtrlResult
908 _AppControlManager::ConvertAppControlResultCode(int resCode)
909 {
910         AppCtrlResult ret = APP_CTRL_RESULT_FAILED;
911
912         switch(resCode)
913         {
914                 case SERVICE_RESULT_SUCCEEDED:
915                         ret = APP_CTRL_RESULT_SUCCEEDED;
916                         break;
917                 case SERVICE_RESULT_FAILED:
918                         ret = APP_CTRL_RESULT_CANCELED;
919                         break;
920                 case SERVICE_RESULT_CANCELED:
921                         ret = APP_CTRL_RESULT_ABORTED;
922                         break;
923                 case APPSVC_OSP_RES_FAIL:
924                         ret = APP_CTRL_RESULT_FAILED;
925                         break;
926                 case APPSVC_OSP_RES_TERMINATE:
927                         ret = APP_CTRL_RESULT_TERMINATED;
928                         break;
929                 default:
930                         ret = APP_CTRL_RESULT_FAILED;
931                         break;
932         }
933
934         return ret;
935 }
936
937
938 void
939 _AppControlManager::OnAppControlResponseEventReceivedN(const Tizen::Base::Runtime::IEventArg* arg)
940 {
941         const _AppControlResponseEventArg* pEventArg = dynamic_cast<const _AppControlResponseEventArg*>(arg);
942
943         if (pEventArg != null)
944         {
945                 IAppControlResponseListener* pResponseListener = pEventArg->GetListener();
946
947                 if(pResponseListener != null)
948                 {
949                         if(pEventArg->GetType() == _APPCONTROL_RESPONSETYPE_START)
950                         {
951                                 pResponseListener->OnAppControlStartResponseReceived(pEventArg->GetAppId(), pEventArg->GetOperationId(), pEventArg->GetResult());
952                                 SysLog(NID_APP, "OnAppControlStartResponseReceived called");
953                         }
954                         else
955                         {
956                                 InvokeAppControlCompleteListener(*pResponseListener, pEventArg->GetAppId(), pEventArg->GetOperationId(), pEventArg->GetAppControlResult(), pEventArg->GetExtraData(), pEventArg->IsSubMode());
957                                 SysLog(NID_APP, "Listener called");
958
959                                 _AppControlResponseEvent* pResponseEvent = null;
960                                 _AppControlManager::GetInstance()->GetAppControlResponseEventContainer()->GetValue(pEventArg->GetRequestId(), pResponseEvent);
961                                 _AppControlManager::GetInstance()->GetAppControlResponseEventContainer()->Remove(pEventArg->GetRequestId());
962
963                                 delete pResponseEvent;
964                                 SysLog(NID_APP, "pResponseEvent gets deleted, reqId(%d)", pEventArg->GetRequestId());
965                         }
966                 }
967                 else
968                 {
969                         SysLog(NID_APP, "Invalid ResponseListener");
970                 }
971         }
972         else
973         {
974                 SysLog(NID_APP, "Invalid AppControl arguments : arg(0x%x)", &arg);
975         }
976 }
977
978 }} // Tizen::App