9ff5cbc0bc5ecb17557c2a02e7920e7f63dc9949
[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 <FBaseSysLog.h>
47
48 #include <FBase_StringConverter.h>
49 #include <FIo_DataControlResultSetImpl.h>
50
51 #include "FApp_AppArg.h"
52 #include "FApp_AppControlEventArg.h"
53 #include "FApp_AppControlRegistry.h"
54 #include "FApp_AppControlImpl.h"
55 #include "FApp_AppImpl.h"
56 #include "FApp_AppInfo.h"
57 #include "FApp_Aul.h"
58 #include "FApp_AppControlManager.h"
59 #include "FApp_AppManagerProxy.h"
60 #include "FApp_ConditionManagerProxy.h"
61 #include "FApp_MapDataControlImpl.h"
62 #include "FApp_SqlDataControlImpl.h"
63 #include "FAppPkg_PackageManagerImpl.h"
64 #include "FAppPkg_PackageInfoImpl.h"
65 #include "FApp_AppMessageImpl.h"
66 #include "FApp_AppManagerImpl.h"
67 #include "FApp_AppControlResponseEvent.h"
68 #include "FApp_IAppControlPluginProvider.h"
69
70
71 using namespace Tizen::App::Package;
72 using namespace Tizen::Base;
73 using namespace Tizen::Base::Collection;
74 using namespace Tizen::Base::Runtime;
75 using namespace Tizen::Base::Utility;
76 using namespace Tizen::Io;
77
78
79 namespace Tizen { namespace App
80 {
81
82 const wchar_t TIZEN_OPERATION_PICK[] = L"http://tizen.org/appcontrol/operation/pick";
83 const wchar_t TIZEN_OPERATION_MAIN[] = L"http://tizen.org/appcontrol/operation/main";
84 const wchar_t LEGACY_OPERATION_MAIN[] = L"osp.operation.MAIN";
85 const char TIZEN_NOTIFICATION_DATA[] = "http://tizen.org/appcontrol/data/notification";
86
87 _AppControlManager::_AppControlManager(void)
88 {
89         SysLog(NID_APP, "");
90
91         // AppControl event handling is expected to be performed in the main thread.
92         __appControlEvent.Construct();
93         __appControlEvent.AddListener(*dynamic_cast<_IAppControlSysEventListener*>(this));
94         __appControlResponseEventContainer.Construct();
95         __appControlResponseEventList.Construct();
96 }
97
98 _AppControlManager::~_AppControlManager(void)
99 {
100         SysLog(NID_APP, "");
101         __appControlEvent.RemoveListener(*dynamic_cast<_IAppControlSysEventListener*>(this));
102         IEnumeratorT<int>* pEnum = __appControlResponseEventList.GetEnumeratorN();
103
104         if (pEnum != null)
105         {
106                 while(pEnum->MoveNext() == E_SUCCESS)
107                 {
108                         int reqId;
109                         pEnum->GetCurrent(reqId);
110                         _AppControlResponseEvent* pResponseEvent = null;
111                         __appControlResponseEventContainer.GetValue(reqId, pResponseEvent);
112                         delete pResponseEvent;
113
114                         __appControlResponseEventContainer.Remove(reqId);
115                         SysLog(NID_APP, "pResponseEvent gets deleted. reqId(%d)", reqId);
116                 }
117         }
118         delete pEnum;
119 }
120
121 _AppControlManager*
122 _AppControlManager::GetInstance(void)
123 {
124         static _AppControlManager inst;
125
126         return &inst;
127 }
128
129 result
130 _AppControlManager::GetMimeFromExt(const String& ext, String& out)
131 {
132         std::unique_ptr<char[]> pExtension(_StringConverter::CopyToCharArrayN(ext));
133         SysTryReturnResult(NID_APP, pExtension != null, E_OUT_OF_MEMORY, "String allocation failure.");
134
135         char* mime = NULL;
136         mime_type_get_mime_type(pExtension.get(), &mime);
137
138         SysTryReturnResult(NID_APP, mime != NULL, E_UNSUPPORTED_FORMAT, "MIME type conversion failure for %ls.", ext.GetPointer());
139
140         out = mime;
141         free(mime);
142
143         return E_SUCCESS;
144 }
145
146 void
147 _AppControlManager::OnAppControlEventReceivedN(int reqId, _AppArg* pAppArg, int res)
148 {
149         SysLog(NID_APP, "Received request Id %d, arg 0x%x", reqId, pAppArg);
150
151         //_AppArg::Print(b);
152         // get launch info from request Id
153         _DataControlInfo* pInfo = __launchManager.FindItem(reqId);
154         SysTryReturnVoidResult(NID_APP, pInfo != null, E_OBJ_NOT_FOUND, "[E_OBJ_NOT_FOUND] request Id %d not found with response %d", reqId,
155                                         res);
156
157         // invoke callback
158         if (pInfo->launchCb)
159         {
160                 if (pInfo->magic == LAUNCH_INFO_MAGIC)
161                 {
162                         SysLog(NID_APP, "Invoking callback 0x%x", pInfo->launchCb);
163                         //pAppArg->Print();
164
165                         if (pInfo->pUserData)
166                         {
167                                 (*pInfo->launchCb)(pInfo->pUserData, pInfo->pArg, pAppArg, static_cast<service_result_e>(res), pInfo->property, reqId);
168                         }
169                 }
170                 else
171                 {
172                         SysLogException(NID_APP, E_SYSTEM, "Corrupted data structure.");
173                 }
174         }
175
176         // clean up argument
177         __launchManager.RemoveItem(reqId);
178 }
179
180
181 // callback for AppControl start event
182 void
183 _AppControlManager::OnAppControlEventReceivedN(int reqId, const AppId& appId, const String& operationId)
184 {
185         SysLog(NID_APP, "Received request Id %d, app %ls, operationId %ls", reqId, appId.GetPointer(), operationId.GetPointer());
186
187         // get launch info from request Id
188         _InProcessInfo* pInfo = __inAppManager.FindItem(reqId);
189         SysTryReturnVoidResult(NID_APP, pInfo != null, E_OBJ_NOT_FOUND, "[E_OBJ_NOT_FOUND] request Id %d not found.", reqId);
190
191         // at least listener
192         IAppControlResponseListener* pListener = dynamic_cast<IAppControlResponseListener*>(pInfo->pListener);
193         SysTryReturnVoidResult(NID_APP, pListener != null, E_SYSTEM, "[E_SYSTEM] Invalid result callback for req %d, app %ls.", reqId, appId.GetPointer());
194
195         result r = E_SUCCESS;
196
197         if (pListener)
198         {
199                 AppId actualAppId = appId;
200                 if (appId == L'c')
201                 {
202                         actualAppId.Clear();
203                         r = E_OPERATION_CANCELED;
204                 }
205                 SysLog(NID_APP, "Invoking callback 0x%x.", pListener);
206
207                 _AppControlResponseEvent* pResponseEvent = null;
208                 __appControlResponseEventContainer.GetValue(reqId, pResponseEvent);
209                 SysLog(NID_APP, "StartResponseReceived Request Id(%d), ResponseEvent 0x%x.", reqId, pResponseEvent);
210                 if (pResponseEvent != null)
211                 {
212                         String oId(operationId);
213                         _AppControlResponseEventArg* pResponseEventArg = new (std::nothrow) _AppControlResponseEventArg(pListener, _APPCONTROL_RESPONSETYPE_START, actualAppId, oId, r, APP_CTRL_RESULT_SUCCEEDED, null, reqId, false);
214
215                         if (pResponseEventArg != null)
216                         {
217                                 pResponseEvent->Fire(*pResponseEventArg);
218                                 SysLog(NID_APP, "pResponseEvent is Fired");
219                         }
220                 }
221                 else
222                 {
223                         pListener->OnAppControlStartResponseReceived(actualAppId, operationId, r);
224                         SysLog(NID_APP, "OnAppControlStartResponseReceived called directly");
225                 }
226         }
227         else
228         {
229                 SysLog(NID_APP, "No listener registered.");
230         }
231
232         if (r == E_OPERATION_CANCELED)
233         {
234                 SysLog(NID_APP, "Removed start listener as operation is canceled.");
235                 __inAppManager.RemoveItem(reqId);
236         }
237 }
238
239
240 void
241 _AppControlManager::InvokeAppControlCompleteListener(IAppControlResponseListener& listener, const AppId& appId, const String& op, AppCtrlResult res, const IMap* pExtraData, bool noRaise)
242 {
243         listener.OnAppControlCompleteResponseReceived(appId, op, res, pExtraData);
244
245         if (!noRaise)
246         {
247                 _AppImpl::GetInstance()->SendUserEvent(_APP_EVENT_RAISE, null, false);
248         }
249
250         SysLog(NID_APP, "AppControl response finished.");
251 }
252
253
254 void
255 _AppControlManager::InvokeLegacyAppControlCompleteListener(IAppControlEventListener& listener, const AppId& appId, const String& op, const IList* pList, bool noRaise)
256 {
257         listener.OnAppControlCompleted(appId, op, pList);
258
259         if (!noRaise)
260         {
261                 _AppImpl::GetInstance()->SendUserEvent(_APP_EVENT_RAISE, null, false);
262         }
263
264         SysLog(NID_APP, "Legacy AppControl response finished.");
265 }
266
267
268 // callback for in-process event handling
269 void
270 _AppControlManager::OnAppControlPluginEventReceivedN(int reqId, int res, const AppId& optAppId, const String& optOperation, const IMap* pArgs, int property)
271 {
272         SysLog(NID_APP, "Received request Id %d, res %d, args 0x%x", reqId, res, pArgs);
273
274         // process proper callback
275         _InProcessInfo* pInfo = __inAppManager.FindItem(reqId);
276         SysTryReturnVoidResult(NID_APP, pInfo != null, E_OBJ_NOT_FOUND, "[E_OBJ_NOT_FOUND] request Id %d not found with args 0x%x", reqId,
277                                         pArgs);
278
279         if (pInfo->pListener)
280         {
281                 String aId;
282                 String oId;
283
284                 if (optAppId.IsEmpty())
285                 {
286                         aId = pInfo->providerId;
287                         oId = pInfo->operationId;
288                 }
289                 else
290                 {
291                         // implicit launch only
292                         aId = optAppId;
293                         oId = optOperation;
294
295                         SysLog(NID_APP, "Changing appId/operation for implicit launch.");
296                 }
297
298                 SysLog(NID_APP, "Invoking callback 0x%x for (%ls, %ls).", pInfo->pListener, aId.GetPointer(), oId.GetPointer());
299
300                 const bool isSubMode = (property & _APPCONTROL_PROPERTY_SUBMODE);
301                 const bool isServiceCallee = (property & _APPCONTROL_PROPERTY_SERVICE_CALLEE);
302
303                 if (pInfo->isLegacy)
304                 {
305                         IAppControlEventListener* pListener = dynamic_cast<IAppControlEventListener*>(pInfo->pListener);
306                         if (pListener)
307                         {
308                                 ArrayList list(SingleObjectDeleter);
309                                 _AppArg::FillLegacyAppControlResult(list, res, pArgs, aId);
310
311                                 InvokeLegacyAppControlCompleteListener(*pListener, aId, oId, &list, isSubMode | isServiceCallee);
312                         }
313                         else
314                         {
315                                 SysLog(NID_APP, "Wrong AppControl listener type.");
316                         }
317                 }
318                 else
319                 {
320                         IAppControlResponseListener* pListener = dynamic_cast<IAppControlResponseListener*>(pInfo->pListener);
321                         if (pListener)
322                         {
323                                 _AppControlResponseEvent* pResponseEvent = null;
324                                 int responseEventRequestId = RESPONSE_EVENT_REQID_MAGIC + reqId;
325                                 __appControlResponseEventContainer.GetValue(responseEventRequestId, pResponseEvent);
326
327                                 if (pResponseEvent != null)
328                                 {
329                                         _AppControlResponseEventArg* pResponseEventArg = new (std::nothrow) _AppControlResponseEventArg(pListener, _APPCONTROL_RESPONSETYPE_COMPLETE, aId, oId, E_SUCCESS, static_cast<AppCtrlResult>(res), const_cast<IMap*> (pArgs), responseEventRequestId, isSubMode);
330                                         if (pResponseEventArg != null)
331                                         {
332                                                 pResponseEvent->Fire(*pResponseEventArg);
333                                                 SysLog(NID_APP, "pResponseEvent is Fired");
334                                         }
335                                 }
336                                 else
337                                 {
338                                         InvokeAppControlCompleteListener(*pListener, aId, oId, ConvertAppControlResultCode(res), pArgs, isSubMode | isServiceCallee);
339                                         SysLog(NID_APP, "Listener called directly");
340                                         delete pArgs;
341                                 }
342                         }
343                         else
344                         {
345                                 SysLog(NID_APP, "Wrong AppControl listener type.");
346                         }
347                 }
348         }
349         else
350         {
351                 SysLogException(NID_APP, E_SYSTEM, "Invalid AppControl listener.");
352         }
353
354 #if 0
355         // [FIXME] following logic is not needed.
356         // call TerminateAppControl
357         if (pInfo->pProvider)
358         {
359                 pInfo->pProvider->StopAppControlPlugin(pInfo->reqId);
360                 SysLog(NID_APP, "AppControl stopped for req %d.", pInfo->reqId);
361         }
362 #endif
363
364         // remove from list and unload dll
365         __inAppManager.RemoveItem(reqId);
366 }
367
368
369 result
370 _AppControlManager::SendAppControlEvent(IEventArg& arg)
371 {
372         return __appControlEvent.FireAsync(arg);
373 }
374
375 Tizen::Base::Collection::IMapT<int,_AppControlResponseEvent*>*
376 _AppControlManager::GetAppControlResponseEventContainer(void)
377 {
378         return &__appControlResponseEventContainer;
379 }
380
381
382 static bool
383 IsMatchingProcListener(const _InProcessInfo& info, IEventListener* pListener)
384 {
385         return (info.pListener == pListener);
386 }
387
388
389 void
390 _AppControlManager::StopAppControlResponseListener(IAppControlResponseListener* pListener)
391 {
392         // __inAppManager, __launchManager
393         _InProcessInfo* pProcInfo = __inAppManager.FindItemWithListener(IsMatchingProcListener, pListener);
394         if (pProcInfo)
395         {
396                 __inAppManager.RemoveItem(pProcInfo);
397                 SysLog(NID_APP, "Listener 0x%x is removed from in-process stub list.", pListener);
398         }
399 }
400
401
402 // generic launch callback
403 static void
404 LaunchResultCb(bundle* b, int request_code, appsvc_result_val res, void* data)
405 {
406         SysLog(NID_APP, "SLP callee result: %d", res);
407
408         _AppControlManager* pImpl = static_cast<_AppControlManager*>(data);
409         if (pImpl == null)
410         {
411                 return;
412         }
413
414         _AppArg* pAppArg = new (std::nothrow) _AppArg;
415         SysTryReturnVoidResult(NID_APP, pAppArg != null, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] AppControl event argument creation failure.");
416
417         _AppControlEventArg* pArg = null;
418         result r = pAppArg->Construct(b);
419         SysTryCatch(NID_APP, !IsFailed(r), , r, "[%s] AppControl event argument creation failure.", GetErrorMessage(r));
420
421         pArg = new (std::nothrow) _AppControlEventArg(request_code, pAppArg, res);
422         SysTryCatch(NID_APP, pArg != null, r = E_OUT_OF_MEMORY, r, "[E_OUT_OF_MEMORY] AppControl event argument creation failure.");
423
424         //_AppArg::Print(b);
425         pImpl->SendAppControlEvent(*pArg);
426
427         return;
428
429 CATCH:
430         delete pAppArg;
431 }
432
433
434 result
435 _AppControlManager::SendAppControlStartResponse(int req, const char* pValue, const char* pOp)
436 {
437         _AppControlStartEventArg* pArg = new (std::nothrow) _AppControlStartEventArg(req, AppId(pValue), String(pOp));
438         SysTryReturnResult(NID_APP, pArg != null, E_OUT_OF_MEMORY, "AppControl start event creation failure.");
439
440         SendAppControlEvent(*pArg);
441
442         return E_SUCCESS;
443 }
444
445
446 result
447 _AppControlManager::LaunchPkg(_AppMessageImpl& msg, const char* pkg_name, const char* op, const char* mime, const char* uri, AppSvcResFn pCb, void* data)
448 {
449         bundle* kb = msg.GetBundle();
450
451         if (pkg_name)
452         {
453                 appsvc_set_pkgname(kb, pkg_name);
454         }
455
456         appsvc_set_operation(kb, (op) ? op : APPSVC_OPERATION_DEFAULT);
457
458         if (mime)
459         {
460                 appsvc_set_mime(kb, mime);
461         }
462
463         if (uri)
464         {
465                 appsvc_set_uri(kb, uri);
466         }
467
468         int pid = LaunchPkg(msg, pCb, data);
469
470         result r = E_SUCCESS;
471         if (pid < 0)
472         {
473                 r = GetLastResult();
474         }
475
476         return r;
477 }
478
479
480 int
481 _AppControlManager::Launch(_AppMessageImpl& msg, const char* pkg_name, const char* op, const char* mime, const char* uri, AppSvcResFn pCb, void* data)
482 {
483         bundle* kb = msg.GetBundle();
484         SysTryReturn(NID_APP, kb != NULL, -1, E_OUT_OF_MEMORY, "Bundle allocation failure.");
485
486         if (pkg_name)
487         {
488                 appsvc_set_pkgname(kb, pkg_name);
489         }
490
491         appsvc_set_operation(kb, (op) ? op : APPSVC_OPERATION_DEFAULT);
492
493         if (mime)
494         {
495                 appsvc_set_mime(kb, mime);
496         }
497
498         if (uri)
499         {
500                 appsvc_set_uri(kb, uri);
501         }
502
503         if (_AppImpl::GetInstance() != null)
504         {
505                 const long handle = _AppImpl::GetInstance()->GetWindowHandle();
506                 _AppArg::UpdateWindowHandle(kb, handle);
507         }
508
509         SysLog(NID_APP, "MIME(%s), URI(%s).", appsvc_get_mime(kb), appsvc_get_uri(kb));
510         int pid = appsvc_run_service(kb, 0, reinterpret_cast<appsvc_res_fn>(pCb), this);
511
512         result r = E_SUCCESS;
513         if (pid < 0)
514         {
515                 switch (pid)
516                 {
517                 case APPSVC_RET_EILLACC:
518                         r = E_ILLEGAL_ACCESS;
519                         break;
520                 case APPSVC_RET_EINVAL:
521                         r = E_MAX_EXCEEDED;
522                         break;
523                 default:
524                         r = E_SYSTEM;
525                         break;
526                 }
527                 SysLog(NID_APP, "[%s]Launching service %s failure", GetErrorMessage(r), pkg_name);
528         }
529         SetLastResult(r);
530
531         return pid;
532 }
533
534
535 int
536 _AppControlManager::LaunchPkg(_AppMessageImpl& msg, AppSvcResFn pCb, void* data)
537 {
538         bundle* kb = msg.GetBundle();
539         SysTryReturn(NID_APP, kb != NULL, -1, E_OUT_OF_MEMORY, "Bundle allocation failure.");
540
541         if (_AppImpl::GetInstance() != null)
542         {
543                 const long handle = _AppImpl::GetInstance()->GetWindowHandle();
544                 _AppArg::UpdateWindowHandle(kb, handle);
545         }
546
547         int pid = appsvc_run_service(kb, 0, reinterpret_cast<appsvc_res_fn>(pCb), this);
548
549         result r = E_SUCCESS;
550         if (pid < 0)
551         {
552                 switch (pid)
553                 {
554                 case APPSVC_RET_EILLACC:
555                         r = E_ILLEGAL_ACCESS;
556                         break;
557                 case APPSVC_RET_EINVAL:
558                         r = E_MAX_EXCEEDED;
559                         break;
560                 default:
561                         r = E_SYSTEM;
562                         break;
563                 }
564                 SysLog(NID_APP, "[%s] Launching service %s failure", GetErrorMessage(r), appsvc_get_appid(kb));
565         }
566         SetLastResult(r);
567
568         return pid;
569 }
570
571
572 result
573 _AppControlManager::LaunchPkg(const char* pkg_name, const char* op, const char* mime, const char* uri, AppSvcResFn pCb, void* data)
574 {
575         _AppMessageImpl msg;
576
577         return LaunchPkg(msg, pkg_name, op, mime, uri, pCb, data);
578 }
579
580 result
581 _AppControlManager::LaunchAppWithCondition(const AppId& appId, const String& condition, IList* pArrayArgs)
582 {
583         result r = E_SUCCESS;
584         _AppArg * pArg = new (std::nothrow) _AppArg();
585         SysTryCatch(NID_APP, pArg != null, r = E_OUT_OF_MEMORY, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY]");
586
587         r = pArg->ConstructForAppLaunchCondition(condition, pArrayArgs);
588         SysTryCatch(NID_APP, !IsFailed(r), , r, "[%s] ConstructForAppLaunchCondition(%ls, .. ) fails", GetErrorMessage(r), condition.GetPointer());
589
590         r = _AppControlManager::LaunchApp(appId, pArg);
591 CATCH:
592         delete pArg;
593         return r;
594 }
595
596 result
597 _AppControlManager::LaunchApp(const AppId& appId, _AppArg* pArg, int req)
598 {
599         SysTryReturnResult(NID_APP, pArg != null, E_INVALID_ARG, "Invalid launch argument");
600         SysLog(NID_APP, "App: %ls.", appId.GetPointer());
601
602         String actualAppId = appId;
603         if (appId.GetLength() == 10)
604         {
605                 const String& name = _PackageManagerImpl::GetInstance()->GetDefaultAppExecutableName(appId);
606
607                 if (!name.IsEmpty())
608                 {
609                         actualAppId.Append(L'.');
610                         actualAppId.Append(name);
611                 }
612         }
613
614         pArg->UpdateRequestId(req);
615
616         if (_AppImpl::GetInstance() != null)
617         {
618                 const long handle = _AppImpl::GetInstance()->GetWindowHandle();
619                 pArg->UpdateWindowHandle(handle);
620         }
621
622         int pid = -1;
623         bundle* kb = NULL;
624         String tempId;
625         actualAppId.SubString(0, 10, tempId);
626         tempId += L'.';
627         tempId += L"_AppControl";
628
629         // [INFO] Ugly solution for submode support
630         pArg->UpdateAppId(tempId);
631         kb = pArg->GetBundle();
632         
633         pid = appsvc_run_service(kb, req, LaunchResultCb, this);
634         if (pid >= 0)
635         {
636                 SysLog(NID_APP, "Submode launch successful");
637                 return E_SUCCESS;
638         }
639         else if (pid == APPSVC_RET_EINVAL)
640         {
641                 SysLog(NID_APP, "Argument overflow");
642                 return E_MAX_EXCEEDED;
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 += L"_AppControl";
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