아래 내용은 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은 일반적이라 생략...
2014년 4월 17일 목요일
Tizen BasicApp sample
아래 내용은 Tizen 2.2 기반이라 상위 버전에서는 별 의미 없는 내용입니다.
--------------------------------------------------------------------------- : https://developer.tizen.org/dev-guide/2.2.1/org.tizen.native.appprogramming/html/sample_descriptions/basicapp.htm
https://developer.tizen.org/dev-guide/2.2.1/org.tizen.native.appprogramming/html/tutorials/ui_tutorial/task_basicapp_panels.htm
Tizen sample 중 가장 기본 앱인 basic app을 대충 훑어봄...
간단하게 Tab header를 통해 Button, Orientation, Image panel에 있는
button, image, orientation 변경을 확인할 수 있음.

이것저것 다 생략하고 발로 그린 class diagram.
[BasicAppEntry.cpp]
Tizen에서는 memory에 필요 library들과 application executable을 load하고
application executable의 OspMain() 함수를 호출하여 실행.
OspMain()함수에서는 BasicApp의 instance 생성을 함
int
OspMain(int argc, char* pArgv[])
{
...
result r = Tizen::App::Application::Execute(BasicApp::CreateInstance, &args);
...
}
[BasicApp.cpp]
BasicApp에서는 app을 system에 등록하고 app UI 표시를 위해 BasicAppFram을 생성하여 등록함.
BasicApp은 Application(UiApp)을 상속 받고 Back key 처리를 위해서 IScreenEventListener를 구현함.
Tizen::App::Application(UiApp), Tizen::App::ServiceApp
: https://developer.tizen.org/dev-guide/2.2.1/org.tizen.native.appprogramming/html/guide/app/service_app_fundamentals.htm
문서에서 나와 있듯이 일반적인 application은 Application을 상속받아 구현하면 되며
UI를 가지지 않고 background로 동작하는 app을 ServiceApp을 상속받아서 만들 수 있음.
AppRegistry
: https://developer.tizen.org/dev-guide/2.2.1/org.tizen.native.apireference/classTizen_1_1App_1_1AppRegistry.html
: 설명에서는 app의 preference들을 저장하고 사용하기 위해 사용하는 class라고 하는데 아무래도 system에서 app 관리를 위해서도 사용되는 class일 것 같다... (tizen 소스를 보면 알겠지만...귀찮음)
bool
BasicApp::OnAppInitializing(AppRegistry& appRegistry)
{
int lastPanelId = 0;
String lastPanelName(L"");
String panelIDkey(L"AppLastPanelId");
String panelNamekey(L"AppLastPanelName");
result r = appRegistry.Get(panelIDkey, lastPanelId);
if (r == E_KEY_NOT_FOUND)
{
lastPanelId = 0;
appRegistry.Add(panelIDkey, lastPanelId);
}
r = appRegistry.Get(panelNamekey, lastPanelName);
if (r == E_KEY_NOT_FOUND)
{
appRegistry.Add(panelNamekey, L"Panel1");
}
// Create a Frame
BasicAppFrame* pBasicAppFrame = new (std::nothrow) BasicAppFrame();
pBasicAppFrame->Initialize(lastPanelId);
pBasicAppFrame->SetName(L"BasicApp");
AddFrame(*pBasicAppFrame);
return true;
}
[BasicAppFrame]
Tizen GUI 구성에 기본이 되는 Frame class을 상속 받은 class로 실제 App에서 사용될 MainForm을 생성&등록하는 역할을 한다.
Tizen User Interface
: https://developer.tizen.org/dev-guide/2.2.0/org.tizen.native.appprogramming/html/guide/ui/ui_namespace.htm
result
BasicAppFrame::OnInitializing(void)
{
// Create a form
MainForm* pMainForm = new (std::nothrow) MainForm();
result r = pMainForm->Initialize(__panelId);
// Add the form to the frame
AddControl(pMainForm);
// Set the current form
SetCurrentForm(pMainForm);
// Draw the form
pMainForm->Invalidate(true);
return r;
}
[MainForm]
BasicApp의 기본 GUI를 구성하는 class
기본으로 Tizen::Ui::Controls::Form을 상속 받고 Action event handling을 위해 IActionEventListener와
Back key 처리를 위해 IFormBackEventListener를 구현 한다.
class MainForm
: public Tizen::Ui::Controls::Form
, public Tizen::Ui::IActionEventListener
, public Tizen::Ui::Controls::IFormBackEventListener
{
...
private:
Tizen::Ui::Controls::Panel* __pPanel[3];
Tizen::Ui::Controls::Button* __pButtonOrientation;
Tizen::Ui::Orientation __status;
int __panelId;
};
초기화 시점에서 GUI를 구성하는 위쪽 Tab들, ButtonPannel을 구성하고
tab들의 상태를 초기화 하기 위한 코드가 있음.
이전 실행 종료 시점에 저장해 둔 tab 위치(__panelId)에 따라서 보여지게 하기 위한 코드
좀 다른 얘기이지만 SceneManager를 사용하지 않지만 SceneManager에는 FormFactory와 PanelFactory를 등록하여 id를 사용해서 생성하게 하는 부분이 있음.. 좀 이대로 해보려고 했으나 Form 생성은 되지만 Panel 생성은 안되는 것 같다.. 나중에 좀 더 봐야 할듯.
: https://developer.tizen.org/dev-guide/2.2.1/org.tizen.native.appprogramming/html/tutorials/ui_tutorial/registering_scenes.htm
result
MainForm::OnInitializing(void)
{
result r = E_SUCCESS;
Rectangle clientRect = GetClientAreaBounds();
Rectangle rect(0, 0, clientRect.width, clientRect.height);
// Create header
Header* pHeader = GetHeader();
if (pHeader != null)
{
pHeader->SetStyle(HEADER_STYLE_TAB);
HeaderItem headerItem1;
headerItem1.Construct(ID_HEADER_ITEM1);
headerItem1.SetText(L"Button");
pHeader->AddItem(headerItem1);
...
pHeader->AddActionEventListener(*this);
}
SetFormBackEventListener(this);
// Create the Button panel
ButtonPanel* pButtonPanel = new (std::nothrow) ButtonPanel();
pButtonPanel->Initialize(rect);
AddControl(pButtonPanel);
__pPanel[0] = pButtonPanel;
// Orientation panel was created with UI Builder,
// so only its button events must be defined here
__pPanel[1] = static_cast<Panel *>(GetControl(IDC_ORIENTATIONPANEL));
if (__pPanel[1] != null)
{
__pButtonOrientation = static_cast<Button *>(GetControl(IDC_BUTTON_ORIENTATION, true));
if (__pButtonOrientation != null)
{
__pButtonOrientation->SetActionId(ID_ORIENTATION);
__pButtonOrientation->AddActionEventListener(*this);
}
}
// Set the current panel as selected in the header and display it on the form
if (pHeader)
{
pHeader->SetItemSelected(__panelId);
if(__panelId == 2)
{
if (__pPanel[2] == null)
{
CreateImagePanel();
}
SetOrientation(ORIENTATION_AUTOMATIC);
}
if (__pPanel[0] != null)
{
__pPanel[0]->SetShowState(false);
}
if (__pPanel[1] != null)
{
__pPanel[1]->SetShowState(false);
}
__pPanel[__panelId]->SetShowState(true);
}
Invalidate(true);
return r;
}
Action event 처리를 위한 IActionEventListener 구현 부
Tab 처리를 위한 코드는 좀 노가다 같다..
사실 tab widget을 system에서 제공해 주면 이런 코드는 안봐도 될것 같은데..
void
MainForm::OnActionPerformed(const Tizen::Ui::Control& source, int actionId)
{
switch(actionId)
{
case ID_HEADER_ITEM1:
{
if (__pPanel[0] != null)
{
__pPanel[0]->SetShowState(true);
}
if (__pPanel[1] != null)
{
__pPanel[1]->SetShowState(false);
}
if (__pPanel[2] != null)
{
__pPanel[2]->SetShowState(false);
}
SetOrientation(ORIENTATION_PORTRAIT);
}
break;
case ID_HEADER_ITEM2:
...
case ID_HEADER_ITEM3:
...
case ID_ORIENTATION:
{
if (__pPanel[1]->GetShowState())
{
OrientationStatus status = GetOrientationStatus();
if (status == ORIENTATION_STATUS_PORTRAIT)
{
__status = ORIENTATION_LANDSCAPE;
}
else if (status == ORIENTATION_STATUS_LANDSCAPE)
{
__status = ORIENTATION_PORTRAIT;
}
SetOrientation(__status);
}
}
break;
default:
break;
}
Invalidate(true);
}
종료 시점에는 AppRegistry를 통해 선택된 tab index를 저장해 둔다..
근데 왜 panelIDkey와 panelNamekey 두개로 저장하는 걸까?
result
MainForm::OnTerminating(void)
{
AppRegistry *appRegistry = Application::GetInstance()->GetAppRegistry();
String panelIDkey(L"AppLastPanelId");
String panelNamekey(L"AppLastPanelName");
Header* pHeader = GetHeader();
result r = appRegistry->Set(panelIDkey,pHeader->GetSelectedItemIndex());
if (IsFailed(r))
{
//error condition
}
String panel;
panel.Format(50, L"Panel%d", pHeader->GetSelectedItemIndex());
r = appRegistry->Set(panelNamekey, panel);
if (IsFailed(r))
{
//error condition
}
r = appRegistry->Save();
if (IsFailed(r))
{
//failed to save data to registry.
}
return r;
}
그리고 아래 Tutorial 괜찮음
: http://tizenschools.com/?p=557
--------------------------------------------------------------------------- : https://developer.tizen.org/dev-guide/2.2.1/org.tizen.native.appprogramming/html/sample_descriptions/basicapp.htm
https://developer.tizen.org/dev-guide/2.2.1/org.tizen.native.appprogramming/html/tutorials/ui_tutorial/task_basicapp_panels.htm
Tizen sample 중 가장 기본 앱인 basic app을 대충 훑어봄...
간단하게 Tab header를 통해 Button, Orientation, Image panel에 있는
button, image, orientation 변경을 확인할 수 있음.

이것저것 다 생략하고 발로 그린 class diagram.
[BasicAppEntry.cpp]
Tizen에서는 memory에 필요 library들과 application executable을 load하고
application executable의 OspMain() 함수를 호출하여 실행.
OspMain()함수에서는 BasicApp의 instance 생성을 함
int
OspMain(int argc, char* pArgv[])
{
...
result r = Tizen::App::Application::Execute(BasicApp::CreateInstance, &args);
...
}
[BasicApp.cpp]
BasicApp에서는 app을 system에 등록하고 app UI 표시를 위해 BasicAppFram을 생성하여 등록함.
BasicApp은 Application(UiApp)을 상속 받고 Back key 처리를 위해서 IScreenEventListener를 구현함.
Tizen::App::Application(UiApp), Tizen::App::ServiceApp
: https://developer.tizen.org/dev-guide/2.2.1/org.tizen.native.appprogramming/html/guide/app/service_app_fundamentals.htm
문서에서 나와 있듯이 일반적인 application은 Application을 상속받아 구현하면 되며
UI를 가지지 않고 background로 동작하는 app을 ServiceApp을 상속받아서 만들 수 있음.
AppRegistry
: https://developer.tizen.org/dev-guide/2.2.1/org.tizen.native.apireference/classTizen_1_1App_1_1AppRegistry.html
: 설명에서는 app의 preference들을 저장하고 사용하기 위해 사용하는 class라고 하는데 아무래도 system에서 app 관리를 위해서도 사용되는 class일 것 같다... (tizen 소스를 보면 알겠지만...귀찮음)
bool
BasicApp::OnAppInitializing(AppRegistry& appRegistry)
{
int lastPanelId = 0;
String lastPanelName(L"");
String panelIDkey(L"AppLastPanelId");
String panelNamekey(L"AppLastPanelName");
result r = appRegistry.Get(panelIDkey, lastPanelId);
if (r == E_KEY_NOT_FOUND)
{
lastPanelId = 0;
appRegistry.Add(panelIDkey, lastPanelId);
}
r = appRegistry.Get(panelNamekey, lastPanelName);
if (r == E_KEY_NOT_FOUND)
{
appRegistry.Add(panelNamekey, L"Panel1");
}
// Create a Frame
BasicAppFrame* pBasicAppFrame = new (std::nothrow) BasicAppFrame();
pBasicAppFrame->Initialize(lastPanelId);
pBasicAppFrame->SetName(L"BasicApp");
AddFrame(*pBasicAppFrame);
return true;
}
[BasicAppFrame]
Tizen GUI 구성에 기본이 되는 Frame class을 상속 받은 class로 실제 App에서 사용될 MainForm을 생성&등록하는 역할을 한다.
Tizen User Interface
: https://developer.tizen.org/dev-guide/2.2.0/org.tizen.native.appprogramming/html/guide/ui/ui_namespace.htm
result
BasicAppFrame::OnInitializing(void)
{
// Create a form
MainForm* pMainForm = new (std::nothrow) MainForm();
result r = pMainForm->Initialize(__panelId);
// Add the form to the frame
AddControl(pMainForm);
// Set the current form
SetCurrentForm(pMainForm);
// Draw the form
pMainForm->Invalidate(true);
return r;
}
[MainForm]
BasicApp의 기본 GUI를 구성하는 class
기본으로 Tizen::Ui::Controls::Form을 상속 받고 Action event handling을 위해 IActionEventListener와
Back key 처리를 위해 IFormBackEventListener를 구현 한다.
class MainForm
: public Tizen::Ui::Controls::Form
, public Tizen::Ui::IActionEventListener
, public Tizen::Ui::Controls::IFormBackEventListener
{
...
private:
Tizen::Ui::Controls::Panel* __pPanel[3];
Tizen::Ui::Controls::Button* __pButtonOrientation;
Tizen::Ui::Orientation __status;
int __panelId;
};
초기화 시점에서 GUI를 구성하는 위쪽 Tab들, ButtonPannel을 구성하고
tab들의 상태를 초기화 하기 위한 코드가 있음.
이전 실행 종료 시점에 저장해 둔 tab 위치(__panelId)에 따라서 보여지게 하기 위한 코드
좀 다른 얘기이지만 SceneManager를 사용하지 않지만 SceneManager에는 FormFactory와 PanelFactory를 등록하여 id를 사용해서 생성하게 하는 부분이 있음.. 좀 이대로 해보려고 했으나 Form 생성은 되지만 Panel 생성은 안되는 것 같다.. 나중에 좀 더 봐야 할듯.
: https://developer.tizen.org/dev-guide/2.2.1/org.tizen.native.appprogramming/html/tutorials/ui_tutorial/registering_scenes.htm
result
MainForm::OnInitializing(void)
{
result r = E_SUCCESS;
Rectangle clientRect = GetClientAreaBounds();
Rectangle rect(0, 0, clientRect.width, clientRect.height);
// Create header
Header* pHeader = GetHeader();
if (pHeader != null)
{
pHeader->SetStyle(HEADER_STYLE_TAB);
HeaderItem headerItem1;
headerItem1.Construct(ID_HEADER_ITEM1);
headerItem1.SetText(L"Button");
pHeader->AddItem(headerItem1);
...
pHeader->AddActionEventListener(*this);
}
SetFormBackEventListener(this);
// Create the Button panel
ButtonPanel* pButtonPanel = new (std::nothrow) ButtonPanel();
pButtonPanel->Initialize(rect);
AddControl(pButtonPanel);
__pPanel[0] = pButtonPanel;
// Orientation panel was created with UI Builder,
// so only its button events must be defined here
__pPanel[1] = static_cast<Panel *>(GetControl(IDC_ORIENTATIONPANEL));
if (__pPanel[1] != null)
{
__pButtonOrientation = static_cast<Button *>(GetControl(IDC_BUTTON_ORIENTATION, true));
if (__pButtonOrientation != null)
{
__pButtonOrientation->SetActionId(ID_ORIENTATION);
__pButtonOrientation->AddActionEventListener(*this);
}
}
// Set the current panel as selected in the header and display it on the form
if (pHeader)
{
pHeader->SetItemSelected(__panelId);
if(__panelId == 2)
{
if (__pPanel[2] == null)
{
CreateImagePanel();
}
SetOrientation(ORIENTATION_AUTOMATIC);
}
if (__pPanel[0] != null)
{
__pPanel[0]->SetShowState(false);
}
if (__pPanel[1] != null)
{
__pPanel[1]->SetShowState(false);
}
__pPanel[__panelId]->SetShowState(true);
}
Invalidate(true);
return r;
}
Action event 처리를 위한 IActionEventListener 구현 부
Tab 처리를 위한 코드는 좀 노가다 같다..
사실 tab widget을 system에서 제공해 주면 이런 코드는 안봐도 될것 같은데..
void
MainForm::OnActionPerformed(const Tizen::Ui::Control& source, int actionId)
{
switch(actionId)
{
case ID_HEADER_ITEM1:
{
if (__pPanel[0] != null)
{
__pPanel[0]->SetShowState(true);
}
if (__pPanel[1] != null)
{
__pPanel[1]->SetShowState(false);
}
if (__pPanel[2] != null)
{
__pPanel[2]->SetShowState(false);
}
SetOrientation(ORIENTATION_PORTRAIT);
}
break;
case ID_HEADER_ITEM2:
...
case ID_HEADER_ITEM3:
...
case ID_ORIENTATION:
{
if (__pPanel[1]->GetShowState())
{
OrientationStatus status = GetOrientationStatus();
if (status == ORIENTATION_STATUS_PORTRAIT)
{
__status = ORIENTATION_LANDSCAPE;
}
else if (status == ORIENTATION_STATUS_LANDSCAPE)
{
__status = ORIENTATION_PORTRAIT;
}
SetOrientation(__status);
}
}
break;
default:
break;
}
Invalidate(true);
}
종료 시점에는 AppRegistry를 통해 선택된 tab index를 저장해 둔다..
근데 왜 panelIDkey와 panelNamekey 두개로 저장하는 걸까?
result
MainForm::OnTerminating(void)
{
AppRegistry *appRegistry = Application::GetInstance()->GetAppRegistry();
String panelIDkey(L"AppLastPanelId");
String panelNamekey(L"AppLastPanelName");
Header* pHeader = GetHeader();
result r = appRegistry->Set(panelIDkey,pHeader->GetSelectedItemIndex());
if (IsFailed(r))
{
//error condition
}
String panel;
panel.Format(50, L"Panel%d", pHeader->GetSelectedItemIndex());
r = appRegistry->Set(panelNamekey, panel);
if (IsFailed(r))
{
//error condition
}
r = appRegistry->Save();
if (IsFailed(r))
{
//failed to save data to registry.
}
return r;
}
그리고 아래 Tutorial 괜찮음
: http://tizenschools.com/?p=557
2013년 4월 28일 일요일
Sample chat with Smack library
이전 블로그에서 이전 함 (원본 글 2013/04/28 작성)
* Smack library로 sample chat을 실행 해 봄.
* Server는 OpenFire 설치 후 계정 설정 후 테스트
* Android상에서 테스트 하려면 아래의 경로의 asmack.jar를 사용해야 한다.
* XMPP의 id는 email과 비슷하다는 것을 꼭 유념하고 상대 id에 domain이 포함되도록 해야한다.
포함되지 않으면 메세지 전송 시 remote server not found (404) error를 리턴한다.
Smack library의 simple sample은 아래에서 보여주고 있음.
// Create a connection to the igniterealtime.org XMPP server. Connection con = new XMPPConnection("igniterealtime.org");
// Connect to the server con.connect(); // Most servers require you to login before performing other tasks. con.login("jsmith", "mypass"); // Start a new conversation with John Doe and send him a message. Chat chat = connection.getChatManager().createChat("jdoe@igniterealtime.org", new MessageListener() { |
XMPP기반 서버에 연결하기 위해 XMPPConnection을 사용하여 host name을 명시하고 connect하는 코드
혹시 IP, port base로 연결을 위해서는 ConnectionConfiguration을 사용해야 함.
// Create a connection to the igniterealtime.org XMPP server.
Connection con = new XMPPConnection("igniterealtime.org");
// Connect to the server
con.connect();
|
서버에서 Authentication이 필요하다면 계정 정보를 입력
// Most servers require you to login before performing other tasks.
con.login("jsmith", "mypass");
|
1:1 chatting에서는 상대방 계정(jdoe@igniterealtime.org)을 명시 필요.
Group chatting을 위해서는 MultiUserChat을 사용해야 함.. 관련 내용은 아래 링크를 참고
(MultiUserChat 다다: http://www.igniterealtime.org/builds/smack/docs/latest/documentation/extensions/muc.html)
// Start a new conversation with John Doe and send him a message.
Chat chat = connection.getChatManager().createChat("jdoe@igniterealtime.org", new MessageListener() { |
Message는 다음과 같은 Type을 가지고 각 Type별 mandatory, optional field는 다음과 같다.
Represents XMPP message packets. A message can be one of several types:
| ||||||||||||||||||||||||||||||||||||
뭐 message를 전달하고 connection을 close하는 코드...
chat.sendMessage("Howdy!");
// Disconnect from the server
con.disconnect(); |
사실 상 XMPP spec를 모르는 상태에서도 library를 사용하는데는 별 무리가 없을 정도로 쉽고 일관적이다.
Documentation이나 web 상에서 관련 질문이나 답변도 쉽게 찾을 수 있고..
아래는 작성해서 테스트 해본 샘플 코드...
Smack library에서 제공하는 것과 별 차이 없다.
* 다만 OpenFire의 default port는 5222
ChatRoom c1 = new ChatRoom("localhost", 5222);
c1.setAuthInfo("h@c-portable", "1234");
c1.talkWith("c@c-portable", new MessageListener() {
public void processMessage(Chat chat, Message message) {
System.out.print("h is received message => ");
if(message.getSubject() != null)
{
System.out.println(message.getSubject() + " : ");
}
System.out.println(message.getBody());
}
});
ChatRoom c2 = new ChatRoom("localhost", 5222);
c2.setAuthInfo("c@c-portable", "1234");
c2.talkWith("h@c-portable", new MessageListener() {
public void processMessage(Chat chat, Message message) {
System.out.print("c is received message => ");
if(message.getSubject() != null)
{
System.out.println(message.getSubject() + " : ");
}
System.out.println(message.getBody());
}
});
class ChatRoom {
private Connection connection;
private Chat chat;
private String accountID;
private String accountPW;
ChatRoom(String host, int port) {
connection = new XMPPConnection(new ConnectionConfiguration(host, port));
}
void setAuthInfo(String id, String pw) {
accountID = id;
accountPW = pw;
}
void talkWith(String NameOfPersonTalkWith, MessageListener messageListener) {
try {
connection.connect();
connection.login(accountID, accountPW);
chat = connection.getChatManager().createChat(NameOfPersonTalkWith,
messageListener);
chat.sendMessage("Entered!");
} catch (XMPPException e) {
e.printStackTrace();
}
}
void send(String msg) {
if (chat != null) {
try {
chat.sendMessage(msg);
} catch (XMPPException e) {
e.printStackTrace();
}과
}
}
void close() {
connection.disconnect();
}
}
|
실행 결과
h is received message => Entered!
c is received message => Entered!
h is received message => msg send 2
c is received message => msg send 3
h is received message => msg send 4
c is received message => msg send 5
h is received message => msg send 6
c is received message => msg send 7
h is received message => msg send 8
c is received message => msg send 9
h is received message => msg send 10
|
피드 구독하기:
글 (Atom)




