2014년 4월 17일 목요일

Tizen Multi Proc Service/UI App sample

아래 내용은 Tizen 2.2 기반이라 상위 버전에서는 별 의미 없는 내용입니다.
--------------------------------------------------------------------------- : https://developer.tizen.org/dev-guide/2.2.1/org.tizen.native.appprogramming/html/sample_descriptions/multiprocserviceapp.htm

: https://developer.tizen.org/dev-guide/2.2.1/org.tizen.native.appprogramming/html/sample_descriptions/multiprocserviceapp.htm

Tizen에서 ServiceApp과 UiApp간의 interaction을 알 수 있는 샘플
Timer event를 발생 시키는 ServiceApp과 이 ServiceApp에서 event를 받아 Ui에 표시해주는 application sample.

Service와 app간 통신은 IMessagePortListener를 상속받아서 메세지를 주고 받으며 처리한다.

실행해 보려면 Documentation에 나와 있다 시피
service app의 id와 service name을 manifest.xml에서 확인한 뒤
ui app의 SampleUiApp에서 아래 부분을 수정해 줘야 한다.


String serviceName(L".multiprocserviceapp");
String repAppId(15);

repAppId = L"LVjRUjlONC";

AppId serviceId(repAppId+serviceName);


[Tizen::Io::IMessagePortListener]

: https://developer.tizen.org/dev-guide/2.2.1/org.tizen.native.apireference/classTizen_1_1Io_1_1IMessagePortListener.html


이것 저것 다 빼고 발로 그린 class diagram


[MultiProcServiceApp]


[SampleServiceApp]
Tizen에서 UI feature를 가지지 않고 background에서 실행될 수 있는 ServiceApp을 상속 받는 class이며 background로 실행되어 Timer를 제어하여 상황 변경 시 event를 app으로 보내주는 것임.

초기화 시점에 App과의 통신을 위한 SampleMessagePort class와 Timer를 제어, event를 발생하는 SampleTimer를 생성하며 SampleMessagePort 생성(construct)시 port name으로 사용할 문자열을 전달하여 port를 생성하도록 한다.


[Message Port Communication]

: https://developer.tizen.org/dev-guide/2.2.0/org.tizen.native.appprogramming/html/guide/io/messageport.htm





bool
SampleServiceApp::OnAppInitializing(AppRegistry& appRegistry)
{
AppLog("SampleServiceApp::OnAppInitializing is called.");
result r = E_SUCCESS;

// Initialize ServerChannel
__pMessagePort = new (std::nothrow) SampleMessagePort();
TryReturn(__pMessagePort != null, false, "SampleServiceApp : [E_FAILURE] Failed to create __pMessagePort.");
AppLog("SampleServiceApp : __pMessagePort is created.");

r = __pMessagePort->Construct(LOCAL_MESSAGE_PORT_NAME);
TryReturn(IsFailed(r) != true, r, "SampleServiceApp : [%s] Failed to construct __pMessagePort", GetErrorMessage(r));
AppLog("SampleServiceApp : __pMessagePort is constructed.");

// Initialize Timer
__pTimer = new (std::nothrow) SampleTimer;
TryReturn(__pTimer != null, false, "SampleServiceApp : [E_FAILURE] Failed to create __pTimer.");
AppLog("SampleServiceApp : __pTimer is created.");

r = __pTimer->Construct();
TryReturn(IsFailed(r) != true, r, "SampleServiceApp : [%s] Failed to construct __pTimer", GetErrorMessage(r));
AppLog("SampleServiceApp : __pTimer is constructed.");

return true;
}



아래의 Tizen::Ui::Control의 가상함수인 OnUserEventReceivedN()를 구현 하여
SampleTimer로 부터 전달 받은 event를 App으로 전달한다.

void
SampleServiceApp::OnUserEventReceivedN(RequestId requestId, IList* pArgs)
{
switch (requestId)
{
case TIMER_START :
if (__pTimer != null)
{
__pTimer->Start();
}
break;
case TIMER_STOP :
if (__pTimer != null)
{
__pTimer->Stop();
}
Terminate();
break;
case TIMER_EXPIRED :
if (__pMessagePort != null)
{
HashMap *pMap = new HashMap(SingleObjectDeleter);
pMap->Construct();
pMap->Add(new String(L"ServiceApp"), new String(L"timer expired"));

__pMessagePort->SendMessage(pMap);

delete pMap;
}
break;
case TIMER_EXIT :
Terminate();
break;
default:
break;
}
}


[SampleMessagePort]

SampleMessagePort는 message를 수신받기위해 Tizen::Io::IMessagePortListener를 구현하였음.
위 그림에서와 같이 수신받는 port인 local port, 전달하는 port인 remote port를 멤버 변수로 가지고 있어 메시지 수신 및 발송 까지 처리하는 class 임

local port는 MessagePortManager를 통해서 생성하고 remote port는 listener에서 connect가 되었을때 전달 받음.

result
SampleMessagePort::Construct(const String& localPortName)
{
result r = E_SUCCESS;

__pLocalMessagePort = MessagePortManager::RequestLocalMessagePort(localPortName);
__pLocalMessagePort->AddMessagePortListener(*this);
...
return r;
}

void
SampleMessagePort::OnMessageReceivedN(RemoteMessagePort* pRemoteMessagePort, IMap* pMessage)
{
String *pData = static_cast<String *>(pMessage->GetValue(String(L"UiApp")));

AppLog("SampleServiceApp : Received data : %ls", pData->GetPointer());

HashMap *pMap = new HashMap(SingleObjectDeleter);
pMap->Construct();

if (pData->CompareTo(L"connect") == 0)
{
__pRemoteMessagePort = pRemoteMessagePort;
pMap->Add(new String(L"ServiceApp"), new String(L"ready"));
}
...
}


result
SampleMessagePort::SendMessage(const IMap* pMessage)
{
...
r = __pRemoteMessagePort->SendMessage(__pLocalMessagePort, pMessage);
...
}


[SampleTimer]

Timer event 수신을 위해서 Tizen::Base::Runtime::ITimerEventListener 를 상속 받음.
Timer가 expire 될 경우 SampleServiceApp으로 TIMER_EXPIRED event를 전달함.

void
SampleTimer::OnTimerExpired(Timer& timer)
{
AppLog("SampleServiceApp : __pTimer is expired.");

if (__isRunning)
{
App* pApp = App::GetInstance();
if (pApp != null)
{
ArrayList messageList;
messageList.Construct();

pApp->SendUserEvent(TIMER_EXPIRED, &messageList);

messageList.RemoveAll(true);
}

if (__isRepeatable)
{
timer.Start(TIMER_INTERVAL_RUN);
}
}
else
{
timer.Start(TIMER_INTERVAL_READY);
}
}


-----------------------------------------------------------------------------------------------------

[MultiProcUiApp]

이것 저것 다 빼고 발로 그린 class diagram


[SampleUiApp]

SampleUiApp에서는 GUI 구성에 필요한 frame과 service와 통신을 위해 사용하는 SampleServiceProxy를 생성한다.

AppId(String일 뿐이다.)를 생성한뒤 SampleServiceProxy 생성 후 초기화 때 인자로 넘겨 준다.

bool
SampleUiApp::OnAppInitialized(void)
{
...
String serviceName(L".MultiProcServiceApp");
String repAppId(15);

repAppId = L"qwertzxcvb";

AppId serviceId(repAppId+serviceName);

AppLog("SampleUiApp : Service Id is %ls", serviceId.GetPointer());

// Initialize ServiceProxy.
result r = E_SUCCESS;
__pService = new (std::nothrow) SampleServiceProxy();
r = __pService->Construct(serviceId, REMOTE_PORT_NAME);
if (IsFailed(r))
{
AppLog("SampleUiApp : [%s] SeviceProxy creation is failed.", GetErrorMessage(r));
__pForm->SendUserEvent(STATE_FAIL, null);
}
else
{
__isReady = true;
}

return true;
}


Service로부터 메시지를 수신 받거나 전송하기 위해
Tizen::Base::Runtime::IEventListener를 구현하였음.
requestId에 따라서 명령을 처리하며 위에서 초기화 때 생성한 SampleServiceProxy를 사용하여
메시지 전송


void
SampleUiApp::OnUserEventReceivedN(RequestId requestId, IList* pArgs)
{
AppLog("SampleUiApp : OnUserEventReceivedN is called. requestId is %d", requestId);

result r = E_SUCCESS;

switch (requestId)
{
case STATE_CONNECT_REQUEST :
if (__isReady)
{
HashMap *pMap = new HashMap(SingleObjectDeleter);
pMap->Construct();
pMap->Add(new String(L"UiApp"), new String(L"connect"));

r = __pService->SendMessage(pMap);

delete pMap;

TryReturnVoid(!IsFailed(r), "SampleUiApp : [%s] MessagePort Operation is Failed", GetErrorMessage(r));
}
break;
...
}


[SampleServiceProxy]

Tizen::Io::IMessagePortListener 를 상속 받아 port를 생성, 관리하는 class.

초반에는 Service가 동작하는지를 AppManager를 통해서 확인하고 없다면 Service를 실행한다.
그리고 Service에서는 local port를 반들고 remote port는 connect 때 만들어 졌는 것에 반해
여기서는 local port와 remote port를 명시적으로 생성한다.


result
SampleServiceProxy::Construct(const AppId& appId, const String& remotePortName)
{
...
AppManager* pAppManager = AppManager::GetInstance();
...
for (int i=0; i < 5; ++i)
{
if (pAppManager->IsRunning(__appId))
{
AppLog("SampleUiApp : Service is ready !!!");
break;
}
else
{
AppLog("SampleUiApp : Service is not ready !!! try to launch !!! ");
r = pAppManager->LaunchApplication(__appId, null);
TryReturn(!IsFailed(r), r, "SampleUiApp : [%s]", GetErrorMessage(r));
Thread::Sleep(CHECK_INTERVAL);
}
}

...
__pLocalMessagePort = MessagePortManager::RequestLocalMessagePort(LOCAL_MESSAGE_PORT_NAME);
__pLocalMessagePort->AddMessagePortListener(*this);

__pRemoteMessagePort = MessagePortManager::RequestRemoteMessagePort(appId, remotePortName);

...
}


Form이랑 Frame은 일반적이라 생략...

댓글 없음:

댓글 쓰기