Merge "[CallManager] Test app implementation and framework issue fixes." preview1-00254
authorShinhui Kang <sinikang@samsung.com>
Tue, 26 Sep 2017 21:36:17 +0000 (21:36 +0000)
committerGerrit Code Review <gerrit@review.ap-northeast-2.compute.internal>
Tue, 26 Sep 2017 21:36:17 +0000 (21:36 +0000)
src/Tizen.CallManager/Interop/Interop.CallManager.cs
src/Tizen.CallManager/Interop/Interop.GsList.cs [new file with mode: 0755]
src/Tizen.CallManager/Tizen.CallManager/CmClientHandle.cs
src/Tizen.CallManager/Tizen.CallManager/CmUtility.cs
test/Tizen.CallManager.Test/MainPage.cs [new file with mode: 0755]
test/Tizen.CallManager.Test/Program.cs [new file with mode: 0755]
test/Tizen.CallManager.Test/Tizen.CallManager.Test.csproj [new file with mode: 0755]
test/Tizen.CallManager.Test/Tizen.CallManager.Test.sln [new file with mode: 0755]
test/Tizen.CallManager.Test/shared/res/Tizen.CallManager.Test.png [new file with mode: 0755]
test/Tizen.CallManager.Test/tizen-manifest.xml [new file with mode: 0755]

index f4d3c4b..393efa5 100755 (executable)
@@ -29,7 +29,7 @@ internal static partial class Interop
     internal static partial class CallManager
     {
         [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
-        internal delegate void CallStatusChangedCallback(CallStatus callStatus, string number, IntPtr userData);
+        internal delegate void CallStatusChangedCallback(CallStatus callStatus, IntPtr number, IntPtr userData);
         [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
         internal delegate void CallMuteStatusChangedCallback(CallMuteStatus muteStatus, IntPtr userData);
         [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
diff --git a/src/Tizen.CallManager/Interop/Interop.GsList.cs b/src/Tizen.CallManager/Interop/Interop.GsList.cs
new file mode 100755 (executable)
index 0000000..661b514
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+using System;
+using System.Runtime.InteropServices;
+
+/// <summary>
+/// Interop class for GSList
+/// </summary>
+internal static partial class Interop
+{
+    internal static partial class GsList
+    {
+        [DllImport(Libraries.Glib, EntryPoint = "g_slist_length")]
+        internal static extern int GetLength(IntPtr list);
+        [DllImport(Libraries.Glib, EntryPoint = "g_slist_nth_data")]
+        internal static extern IntPtr GetDataByIndex(IntPtr list, int index);
+    }
+}
index c41dc82..38b4292 100755 (executable)
@@ -17,6 +17,7 @@
 using System;
 using System.Collections.Generic;
 using System.Runtime.InteropServices;
+using System.Linq;
 
 namespace Tizen.CallManager
 {
@@ -251,9 +252,9 @@ namespace Tizen.CallManager
 
         private void RegisterCallStatusChangedEvent()
         {
-            _callStatusChangedCb = (CallStatus status, string number, IntPtr userData) =>
+            _callStatusChangedCb = (CallStatus status, IntPtr number, IntPtr userData) =>
             {
-                _callStatusChanged?.Invoke(null, new CallStatusChangedEventArgs(status, number));
+                _callStatusChanged?.Invoke(null, new CallStatusChangedEventArgs(status, Marshal.PtrToStringAnsi(number)));
             };
             int ret = Interop.CallManager.SetCallStatusCallback(_handle, _callStatusChangedCb, IntPtr.Zero);
             if (ret != (int)CmError.None)
@@ -301,7 +302,7 @@ namespace Tizen.CallManager
         {
             _callEventCb = (CallEvent callEvent, IntPtr eventData, IntPtr userData) =>
             {
-                _callEvent?.Invoke(null, new CallEventEventArgs(callEvent, CmUtility.GetCallEventData(eventData)));
+                _callEvent?.Invoke(null, new CallEventEventArgs(callEvent, CmUtility.GetCallEventData(callEvent, eventData)));
             };
             int ret = Interop.CallManager.SetCallEventCb(_handle, _callEventCb, IntPtr.Zero);
             if (ret != (int)CmError.None)
@@ -506,20 +507,22 @@ namespace Tizen.CallManager
                     return null;
                 }
 
+                int length = Interop.GsList.GetLength(list);
+                if (length == 0)
+                {
+                    Log.Debug(CmUtility.LogTag, "Call list is empty");
+                    return Enumerable.Empty<CallData>();
+                }
+
                 List<CallData> callList = new List<CallData>();
-                int offset = 0;
-                IntPtr data = Marshal.ReadIntPtr(list, offset);
-                if (data != IntPtr.Zero)
+                IntPtr callData = IntPtr.Zero;
+                for (int index = 0; index < length; index++)
                 {
-                    do
+                    callData = Interop.GsList.GetDataByIndex(list, index);
+                    if (callData != IntPtr.Zero)
                     {
-                        offset += Marshal.SizeOf(data);
-                        callList.Add(CmUtility.GetCallData(data));
-                        Interop.CallManager.FreeCallData(data);
-                        data = IntPtr.Zero;
+                        callList.Add(CmUtility.GetCallData(callData));
                     }
-
-                    while ((data = Marshal.ReadIntPtr(list, offset)) != IntPtr.Zero);
                 }
 
                 return callList;
@@ -540,20 +543,21 @@ namespace Tizen.CallManager
                     return null;
                 }
 
+                int length = Interop.GsList.GetLength(list);
+                if (length == 0)
+                {
+                    Log.Debug(CmUtility.LogTag, "Conf call list is empty");
+                    return Enumerable.Empty<ConferenceCallData>();
+                }
                 List<ConferenceCallData> confList = new List<ConferenceCallData>();
-                int offset = 0;
-                IntPtr data = Marshal.ReadIntPtr(list, offset);
-                if (data != IntPtr.Zero)
+                IntPtr confData = IntPtr.Zero;
+                for (int index = 0; index < length; index++)
                 {
-                    do
+                    confData = Interop.GsList.GetDataByIndex(list, index);
+                    if (confData != IntPtr.Zero)
                     {
-                        offset += Marshal.SizeOf(data);
-                        confList.Add(CmUtility.GetConfCallData(data));
-                        Interop.CallManager.FreeConfCallData(data);
-                        data = IntPtr.Zero;
+                        confList.Add(CmUtility.GetConfCallData(confData));
                     }
-
-                    while ((data = Marshal.ReadIntPtr(list, offset)) != IntPtr.Zero);
                 }
 
                 return confList;
index 91d2c49..e37be1a 100755 (executable)
@@ -38,6 +38,11 @@ namespace Tizen.CallManager
 
         internal static CallData GetCallData(IntPtr handle)
         {
+            if (handle == IntPtr.Zero)
+            {
+                return null;
+            }
+
             CallData data = new CallData();
             int ret = Interop.CallManager.GetCallId(handle, out uint id);
             if (ret != (int)CmError.None)
@@ -264,6 +269,11 @@ namespace Tizen.CallManager
 
         internal static ConferenceCallData GetConfCallData(IntPtr handle)
         {
+            if (handle == IntPtr.Zero)
+            {
+                return null;
+            }
+
             ConferenceCallData confData = new ConferenceCallData();
             int ret = Interop.CallManager.GetConfCallId(handle, out uint callId);
             if (ret != (int)CmError.None)
@@ -312,73 +322,115 @@ namespace Tizen.CallManager
             return confData;
         }
 
-        internal static CallEventData GetCallEventData(IntPtr handle)
+        internal static CallEventData GetCallEventData(CallEvent callEvent, IntPtr handle)
         {
-            CallEventData eventData = new CallEventData();
-            int ret = Interop.CallManager.GetEventDataCallId(handle, out uint id);
-            if (ret != (int)CmError.None)
+            if (handle == IntPtr.Zero)
             {
-                Log.Error(CmUtility.LogTag, "Failed to get event data call ID, Error: " + (CmError)ret);
+                return null;
             }
 
-            else
-            {
-                eventData.EventId = id;
-            }
+            CallEventData eventData = new CallEventData();
 
-            ret = Interop.CallManager.GetSimSlot(handle, out MultiSimSlot simSlot);
-            if (ret != (int)CmError.None)
-            {
-                Log.Error(CmUtility.LogTag, "Failed to get event data sim slot, Error: " + (CmError)ret);
-            }
+            if (callEvent == CallEvent.Active)
+            {
+                int ret = Interop.CallManager.GetEventDataCallId(handle, out uint id);
+                if (ret != (int)CmError.None)
+                {
+                    Log.Error(CmUtility.LogTag, "Failed to get event data call ID, Error: " + (CmError)ret);
+                }
+
+                else
+                {
+                    eventData.EventId = id;
+                }
+
+                ret = Interop.CallManager.GetSimSlot(handle, out MultiSimSlot simSlot);
+                if (ret != (int)CmError.None)
+                {
+                    Log.Error(CmUtility.LogTag, "Failed to get event data sim slot, Error: " + (CmError)ret);
+                }
+
+                else
+                {
+                    eventData.Slot = simSlot;
+                }
+
+                ret = Interop.CallManager.GetIncomingCallData(handle, out IntPtr incoming);
+                if (ret != (int)CmError.None)
+                {
+                    Log.Error(CmUtility.LogTag, "Failed to get incoming call data, Error: " + (CmError)ret);
+                }
+
+                else
+                {
+                    CallData incomingData = GetCallData(incoming);
+                    if (incomingData != null)
+                    {
+                        ret = Interop.CallManager.FreeCallData(incoming);
+                        if (ret != (int)CmError.None)
+                        {
+                            Log.Error(CmUtility.LogTag, "Failed to free incoming call data, Error: " + (CmError)ret);
+                        }
+                    }
 
-            else
-            {
-                eventData.Slot = simSlot;
-            }
+                    eventData.Incoming = incomingData;
+                }
 
-            ret = Interop.CallManager.GetEndCause(handle, out CallEndCause endCause);
-            if (ret != (int)CmError.None)
-            {
-                Log.Error(CmUtility.LogTag, "Failed to get end cause, Error: " + (CmError)ret);
-            }
+                ret = Interop.CallManager.GetActiveCall(handle, out IntPtr active);
+                if (ret != (int)CmError.None)
+                {
+                    Log.Error(CmUtility.LogTag, "Failed to get active call data, Error: " + (CmError)ret);
+                }
 
-            else
-            {
-                eventData.Cause = endCause;
-            }
+                else
+                {
+                    CallData activeData = GetCallData(active);
+                    if (activeData != null)
+                    {
+                        ret = Interop.CallManager.FreeCallData(active);
+                        if (ret != (int)CmError.None)
+                        {
+                            Log.Error(CmUtility.LogTag, "Failed to free active call data, Error: " + (CmError)ret);
+                        }
+                    }
 
-            ret = Interop.CallManager.GetIncomingCallData(handle, out IntPtr incoming);
-            if (ret != (int)CmError.None)
-            {
-                Log.Error(CmUtility.LogTag, "Failed to get incoming call data, Error: " + (CmError)ret);
-            }
+                    eventData.Active = activeData;
+                }
 
-            else
-            {
-                eventData.Incoming = GetCallData(incoming);
-            }
+                ret = Interop.CallManager.GetHeldCall(handle, out IntPtr held);
+                if (ret != (int)CmError.None)
+                {
+                    Log.Error(CmUtility.LogTag, "Failed to get held call data, Error: " + (CmError)ret);
+                }
 
-            ret = Interop.CallManager.GetActiveCall(handle, out IntPtr active);
-            if (ret != (int)CmError.None)
-            {
-                Log.Error(CmUtility.LogTag, "Failed to get active call data, Error: " + (CmError)ret);
-            }
+                else
+                {
+                    CallData heldData = GetCallData(held);
+                    if (heldData != null)
+                    {
+                        ret = Interop.CallManager.FreeCallData(held);
+                        if (ret != (int)CmError.None)
+                        {
+                            Log.Error(CmUtility.LogTag, "Failed to free held call data, Error: " + (CmError)ret);
+                        }
+                    }
 
-            else
-            {
-                eventData.Active = GetCallData(active);
+                    eventData.Held = heldData;
+                }
             }
 
-            ret = Interop.CallManager.GetHeldCall(handle, out IntPtr held);
-            if (ret != (int)CmError.None)
+            else if (callEvent == CallEvent.Idle)
             {
-                Log.Error(CmUtility.LogTag, "Failed to get held call data, Error: " + (CmError)ret);
-            }
+                int ret = Interop.CallManager.GetEndCause(handle, out CallEndCause endCause);
+                if (ret != (int)CmError.None)
+                {
+                    Log.Error(CmUtility.LogTag, "Failed to get end cause, Error: " + (CmError)ret);
+                }
 
-            else
-            {
-                eventData.Held = GetCallData(held);
+                else
+                {
+                    eventData.Cause = endCause;
+                }
             }
 
             return eventData;
diff --git a/test/Tizen.CallManager.Test/MainPage.cs b/test/Tizen.CallManager.Test/MainPage.cs
new file mode 100755 (executable)
index 0000000..d832250
--- /dev/null
@@ -0,0 +1,538 @@
+using System;
+using System.Threading.Tasks;
+using System.Collections.Generic;
+using System.Linq;
+using Xamarin.Forms;
+using Tizen;
+using Tizen.CallManager;
+
+namespace XamarinForTizen.Tizen
+{
+    public class MainPage : ContentPage
+    {
+        public MainPage()
+        {
+            var initBtn = new Button
+            {
+                Text = "Initialize",
+                VerticalOptions = LayoutOptions.Start,
+                HorizontalOptions = LayoutOptions.FillAndExpand
+            };
+            initBtn.Clicked += initBtn_Clicked;
+
+            var dialBtn = new Button
+            {
+                Text = "Dial & end voice call",
+                VerticalOptions = LayoutOptions.Start,
+                HorizontalOptions = LayoutOptions.FillAndExpand
+            };
+            dialBtn.Clicked += dialBtn_Clicked;
+
+            var holdBtn = new Button
+            {
+                Text = "Hold & unhold voice call",
+                VerticalOptions = LayoutOptions.Start,
+                HorizontalOptions = LayoutOptions.FillAndExpand
+            };
+            holdBtn.Clicked += holdBtn_Clicked;
+
+            var answerBtn = new Button
+            {
+                Text = "Answer incoming call",
+                VerticalOptions = LayoutOptions.Start,
+                HorizontalOptions = LayoutOptions.FillAndExpand
+            };
+            answerBtn.Clicked += answerBtn_Clicked;
+
+            var alertBtn = new Button
+            {
+                Text = "Start & Stop alert",
+                VerticalOptions = LayoutOptions.Start,
+                HorizontalOptions = LayoutOptions.FillAndExpand
+            };
+            alertBtn.Clicked += alertBtn_Clicked;
+
+            var rejectBtn = new Button
+            {
+                Text = "Reject incoming call",
+                VerticalOptions = LayoutOptions.Start,
+                HorizontalOptions = LayoutOptions.FillAndExpand
+            };
+            rejectBtn.Clicked += rejectBtn_Clicked;
+
+            var swapBtn = new Button
+            {
+                Text = "Swap call",
+                VerticalOptions = LayoutOptions.Start,
+                HorizontalOptions = LayoutOptions.FillAndExpand
+            };
+            swapBtn.Clicked += swapBtn_Clicked;
+
+            var joinBtn = new Button
+            {
+                Text = "Join calls",
+                VerticalOptions = LayoutOptions.Start,
+                HorizontalOptions = LayoutOptions.FillAndExpand
+            };
+            joinBtn.Clicked += joinBtn_Clicked;
+
+            var splitBtn = new Button
+            {
+                Text = "Split call",
+                VerticalOptions = LayoutOptions.Start,
+                HorizontalOptions = LayoutOptions.FillAndExpand
+            };
+            splitBtn.Clicked += splitBtn_Clicked;
+
+            var getAllCallListBtn = new Button
+            {
+                Text = "Get all call list",
+                VerticalOptions = LayoutOptions.Start,
+                HorizontalOptions = LayoutOptions.FillAndExpand
+            };
+            getAllCallListBtn.Clicked += getAllCallListBtn_Clicked;
+
+            var getConfCallListBtn = new Button
+            {
+                Text = "Get conf call list",
+                VerticalOptions = LayoutOptions.Start,
+                HorizontalOptions = LayoutOptions.FillAndExpand
+            };
+            getConfCallListBtn.Clicked += getConfCallListBtn_Clicked;
+
+            var getCallDataBtn = new Button
+            {
+                Text = "Get all call data",
+                VerticalOptions = LayoutOptions.Start,
+                HorizontalOptions = LayoutOptions.FillAndExpand
+            };
+            getCallDataBtn.Clicked += getCallDataBtn_Clicked;
+
+            var statusBtn = new Button
+            {
+                Text = "Get call status",
+                VerticalOptions = LayoutOptions.Start,
+                HorizontalOptions = LayoutOptions.FillAndExpand
+            };
+            statusBtn.Clicked += statusBtn_Clicked;
+
+            var deinitBtn = new Button
+            {
+                Text = "Deinitialize",
+                VerticalOptions = LayoutOptions.Start,
+                HorizontalOptions = LayoutOptions.FillAndExpand
+            };
+            deinitBtn.Clicked += deinitBtn_Clicked;
+
+            Content = new StackLayout
+            {
+                VerticalOptions = LayoutOptions.Center,
+                Children = {
+                        initBtn, dialBtn, holdBtn, answerBtn, alertBtn, rejectBtn, swapBtn, joinBtn, splitBtn,
+                        getAllCallListBtn, getConfCallListBtn, getCallDataBtn, statusBtn, deinitBtn
+                    }
+            };
+        }
+
+        private void getCallDataBtn_Clicked(object sender, EventArgs e)
+        {
+            try
+            {
+                if (Globals.cmHandle == null)
+                {
+                    Log.Debug(Globals.LogTag, "Not initialized!!!!!");
+                    return;
+                }
+
+                Globals.cmHandle.GetAllCallData(out CallData incoming, out CallData active, out CallData held);
+                if (incoming == null)
+                {
+                    Log.Debug(Globals.LogTag, "No incoming call");
+                }
+
+                else
+                {
+                    Log.Debug(Globals.LogTag, "Incoming call Id: " + incoming.Id);
+                    Log.Debug(Globals.LogTag, "Incoming call number: " + incoming.CallNumber);
+                }
+
+                if (active == null)
+                {
+                    Log.Debug(Globals.LogTag, "No active calls");
+                }
+
+                else
+                {
+                    Log.Debug(Globals.LogTag, "Active call Id: " + active.Id);
+                    Log.Debug(Globals.LogTag, "Active call number: " + active.CallNumber);
+                }
+
+                if (held == null)
+                {
+                    Log.Debug(Globals.LogTag, "No held calls");
+                }
+
+                else
+                {
+                    Log.Debug(Globals.LogTag, "Held call Id: " + held.Id);
+                    Log.Debug(Globals.LogTag, "Held call number: " + held.CallNumber);
+                }
+            }
+
+            catch (Exception ex)
+            {
+                Log.Debug(Globals.LogTag, "Get all call data exception: " + ex.ToString());
+            }
+        }
+
+        private void getConfCallListBtn_Clicked(object sender, EventArgs e)
+        {
+            try
+            {
+                if (Globals.cmHandle == null)
+                {
+                    Log.Debug(Globals.LogTag, "Not initialized!!!!!");
+                    return;
+                }
+
+                List<ConferenceCallData> confCallList = Globals.cmHandle.AllConferenceCalls.ToList();
+                if (confCallList.Count == 0)
+                {
+                    Log.Debug(Globals.LogTag, "Conf call list is empty");
+                    return;
+                }
+
+                for (int i = 0; i < confCallList.Count; i++)
+                {
+                    Log.Debug(Globals.LogTag, "ID[" + i + "]: " + confCallList[i].Id);
+                    Log.Debug(Globals.LogTag, "Number[" + i + "]: " + confCallList[i].CallNumber);
+                    Log.Debug(Globals.LogTag, "PersonId[" + i + "]: " + confCallList[i].PersonId);
+                    Log.Debug(Globals.LogTag, "Mode[" + i + "]: " + confCallList[i].Mode);
+                }
+            }
+
+            catch (Exception ex)
+            {
+                Log.Debug(Globals.LogTag, "Get all conf call list exception: " + ex.ToString());
+            }
+        }
+
+        private void getAllCallListBtn_Clicked(object sender, EventArgs e)
+        {
+            try
+            {
+                if (Globals.cmHandle == null)
+                {
+                    Log.Debug(Globals.LogTag, "Not initialized!!!!!");
+                    return;
+                }
+
+                List<CallData> callDataList = Globals.cmHandle.AllCalls.ToList();
+                if (callDataList.Count == 0)
+                {
+                    Log.Debug(Globals.LogTag, "Call data list is empty");
+                    return;
+                }
+
+                for (int i = 0; i < callDataList.Count; i++)
+                {
+                    Log.Debug(Globals.LogTag, "Call ID[" + i +"]: " + callDataList[i].Id);
+                    Log.Debug(Globals.LogTag, "Number[" + i + "]: " + callDataList[i].CallNumber);
+                    Log.Debug(Globals.LogTag, "Call direction[" + i + "]: " + callDataList[i].Direction);
+                    Log.Debug(Globals.LogTag, "Name[" + i + "]: " + callDataList[i].CallingName);
+                    Log.Debug(Globals.LogTag, "Call type[" + i + "]: " + callDataList[i].Type);
+                    Log.Debug(Globals.LogTag, "Call state[" + i + "]: " + callDataList[i].State);
+                    Log.Debug(Globals.LogTag, "Member count[" + i + "]: " + callDataList[i].MemberCount);
+                    Log.Debug(Globals.LogTag, "Is Ecc[" + i + "]: " + callDataList[i].IsEmergency);
+                    Log.Debug(Globals.LogTag, "Call domain[" + i + "]: " + callDataList[i].Domain);
+                    Log.Debug(Globals.LogTag, "Start time[" + i + "]: " + callDataList[i].StartTime);
+                }
+            }
+
+            catch (Exception ex)
+            {
+                Log.Debug(Globals.LogTag, "Get all call list exception: " + ex.ToString());
+            }
+        }
+
+        private void splitBtn_Clicked(object sender, EventArgs e)
+        {
+            try
+            {
+                if (Globals.cmHandle == null)
+                {
+                    Log.Debug(Globals.LogTag, "Not initialized!!!!!");
+                    return;
+                }
+
+                Globals.cmHandle.SplitCall(1);
+            }
+
+            catch (Exception ex)
+            {
+                Log.Debug(Globals.LogTag, "Split call exception: " + ex.ToString());
+            }
+        }
+
+        private void joinBtn_Clicked(object sender, EventArgs e)
+        {
+            try
+            {
+                if (Globals.cmHandle == null)
+                {
+                    Log.Debug(Globals.LogTag, "Not initialized!!!!!");
+                    return;
+                }
+
+                Globals.cmHandle.JoinCall();
+            }
+
+            catch (Exception ex)
+            {
+                Log.Debug(Globals.LogTag, "Join call exception: " + ex.ToString());
+            }
+        }
+
+        private void swapBtn_Clicked(object sender, EventArgs e)
+        {
+            try
+            {
+                if (Globals.cmHandle == null)
+                {
+                    Log.Debug(Globals.LogTag, "Not initialized!!!!!");
+                    return;
+                }
+
+                Globals.cmHandle.SwapCall();
+            }
+
+            catch (Exception ex)
+            {
+                Log.Debug(Globals.LogTag, "Swap call exception: " + ex.ToString());
+            }
+        }
+
+        private void statusBtn_Clicked(object sender, EventArgs e)
+        {
+            try
+            {
+                if (Globals.cmHandle == null)
+                {
+                    Log.Debug(Globals.LogTag, "Not initialized!!!!!");
+                    return;
+                }
+
+                Log.Debug(Globals.LogTag, "Call status: " + Globals.cmHandle.CallStatus);
+            }
+
+            catch (Exception ex)
+            {
+                Log.Debug(Globals.LogTag, "Get call status exception: " + ex.ToString());
+            }
+        }
+
+        private void rejectBtn_Clicked(object sender, EventArgs e)
+        {
+            try
+            {
+                if (Globals.cmHandle == null)
+                {
+                    Log.Debug(Globals.LogTag, "Not initialized!!!!!");
+                    return;
+                }
+
+                Globals.cmHandle.RejectCall();
+            }
+
+            catch (Exception ex)
+            {
+                Log.Debug(Globals.LogTag, "Reject call exception: " + ex.ToString());
+            }
+        }
+
+        private async void alertBtn_Clicked(object sender, EventArgs e)
+        {
+            try
+            {
+                if (Globals.cmHandle == null)
+                {
+                    Log.Debug(Globals.LogTag, "Not initialized!!!!!");
+                    return;
+                }
+
+                Globals.cmHandle.CallStatusChanged += CmHandle_CallStatusChanged;
+                Globals.cmHandle.StopAlert();
+                await Task.Delay(5000);
+                Globals.cmHandle.StartAlert();
+            }
+
+            catch (Exception ex)
+            {
+                Log.Debug(Globals.LogTag, "Call alert exception: " + ex.ToString());
+            }
+        }
+
+        private void CmHandle_CallStatusChanged(object sender, CallStatusChangedEventArgs e)
+        {
+            Log.Debug(Globals.LogTag, "Call status changed: " + e.CallNumber + e.Status);
+        }
+
+        private void answerBtn_Clicked(object sender, EventArgs e)
+        {
+            try
+            {
+                if (Globals.cmHandle == null)
+                {
+                    Log.Debug(Globals.LogTag, "Not initialized!!!!!");
+                    return;
+                }
+
+                Globals.cmHandle.AnswerCall(CallAnswerType.Normal);
+            }
+
+            catch (Exception ex)
+            {
+                Log.Debug(Globals.LogTag, "Answer call exception: " + ex.ToString());
+            }
+        }
+
+        private async void holdBtn_Clicked(object sender, EventArgs e)
+        {
+            try
+            {
+                if (Globals.cmHandle == null)
+                {
+                    Log.Debug(Globals.LogTag, "Not initialized!!!!!");
+                    return;
+                }
+
+                Globals.HoldTest = true;
+                Globals.cmHandle.DialCall(Globals.Number, CallType.Voice, MultiSimSlot.Default);
+                await Task.Delay(20000);
+                Globals.cmHandle.HoldCall();
+                await Task.Delay(8000);
+                Globals.cmHandle.UnholdCall();
+                await Task.Delay(8000);
+                Globals.cmHandle.EndCall(1, CallReleaseType.AllActiveCalls);
+            }
+
+            catch (Exception ex)
+            {
+                Log.Debug(Globals.LogTag, "Hold call exception: " + ex.ToString());
+            }
+        }
+
+        private async void dialBtn_Clicked(object sender, EventArgs e)
+        {
+            try
+            {
+                if (Globals.cmHandle == null)
+                {
+                    Log.Debug(Globals.LogTag, "Not initialized!!!!!");
+                    return;
+                }
+
+                Globals.cmHandle.DialCall(Globals.Number, CallType.Voice, MultiSimSlot.Default);
+                await Task.Delay(20000);
+                Globals.cmHandle.EndCall(1, CallReleaseType.AllCalls);
+            }
+
+            catch (Exception ex)
+            {
+                Log.Debug(Globals.LogTag, "Dial call exception: " + ex.ToString());
+            }
+        }
+
+        private void deinitBtn_Clicked(object sender, EventArgs e)
+        {
+            try
+            {
+                if (Globals.cmHandle == null)
+                {
+                    Log.Debug(Globals.LogTag, "Not initialized!!!!!");
+                    return;
+                }
+
+                CallManager.DeinitCm(Globals.cmHandle);
+                Globals.cmHandle = null;
+                Log.Debug(Globals.LogTag, "Callmanager deinitialized successfully");
+            }
+
+            catch (Exception ex)
+            {
+                Log.Debug(Globals.LogTag, "Callmanager deinit exception: " + ex.ToString());
+            }
+        }
+
+        private void initBtn_Clicked(object sender, EventArgs e)
+        {
+            try
+            {
+                if (Globals.cmHandle != null)
+                {
+                    Log.Debug(Globals.LogTag, "Already initialized!!!!!");
+                    return;
+                }
+
+                Globals.cmHandle = CallManager.InitCm();
+                Globals.cmHandle.EnableRecovery("Tizen.CallManager.Test");
+                Log.Debug(Globals.LogTag, "Callmanager initialization is successful");
+            }
+
+            catch(Exception ex)
+            {
+                Log.Debug(Globals.LogTag, "Callmanager init exception: " + ex.ToString());
+            }
+        }
+
+        private async void CmHandle_CallEventChangedAsync(object sender, CallEventEventArgs e)
+        {
+            try
+            {
+                Log.Debug(Globals.LogTag, "Call event changed handler, CallEvent: " + e.Event);
+                if (e.EventData != null)
+                {
+                    Log.Debug(Globals.LogTag, "Call ID: " + e.EventData.Id);
+                    Log.Debug(Globals.LogTag, "Sim slot: " + e.EventData.SimSlot);
+                    Log.Debug(Globals.LogTag, "Call end cause: " + e.EventData.EndCause);
+                }
+
+                if (Globals.DialTest && e.Event == CallEvent.Active)
+                {
+                    Globals.DialTest = false;
+                    await Task.Delay(3000);
+                    Globals.cmHandle.EndCall(e.EventData.Id, CallReleaseType.ByCallHandle);
+                }
+
+                if (Globals.HoldTest && e.Event == CallEvent.Active)
+                {
+                    await Task.Delay(3000);
+                    Globals.cmHandle.HoldCall();
+                }
+
+                if (Globals.HoldTest && e.Event == CallEvent.Held)
+                {
+                    Globals.HoldTest = false;
+                    await Task.Delay(8000);
+                    Globals.cmHandle.UnholdCall();
+                    await Task.Delay(8000);
+                    Globals.cmHandle.EndCall(e.EventData.Id, CallReleaseType.AllActiveCalls);
+                }
+            }
+
+            catch (Exception ex)
+            {
+                Log.Debug(Globals.LogTag, "End call exception: " + ex.ToString());
+            }
+        }
+
+        ~MainPage()
+        {
+            if (Globals.cmHandle != null)
+            {
+                CallManager.DeinitCm(Globals.cmHandle);
+                Globals.cmHandle = null;
+            }
+        }
+    }
+}
diff --git a/test/Tizen.CallManager.Test/Program.cs b/test/Tizen.CallManager.Test/Program.cs
new file mode 100755 (executable)
index 0000000..6896494
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ *  Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+
+using Xamarin.Forms;
+using Tizen;
+using Tizen.System;
+using Tizen.CallManager;
+
+namespace XamarinForTizen.Tizen
+{
+    internal static class Globals
+    {
+        internal static string LogTag = "CallManagerTest";
+        internal static CmClientHandle cmHandle = null;
+        internal static string Number = "9900816947";
+        internal static bool DialTest = false;
+        internal static bool HoldTest = false;
+    }
+    public class App : Application
+    {
+        private static bool s_isTelephonySupported = false;
+        public App()
+        {
+            SystemInfo.TryGetValue("http://tizen.org/feature/network.telephony", out s_isTelephonySupported);
+            if (s_isTelephonySupported)
+            {
+                Log.Debug(Globals.LogTag, "Telephony feature check = " + s_isTelephonySupported);
+                MainPage = new NavigationPage(new MainPage());
+            }
+
+            else
+            {
+                Log.Debug(Globals.LogTag, "Telephony feature is not supported");
+            }
+        }
+
+        protected override void OnStart()
+        {
+            // Handle when your app starts
+        }
+
+        protected override void OnSleep()
+        {
+            // Handle when your app sleeps
+        }
+
+        protected override void OnResume()
+        {
+            // Handle when your app resumes
+        }
+    }
+
+    class Program : global::Xamarin.Forms.Platform.Tizen.FormsApplication
+    {
+        private static App _app;
+        protected override void OnCreate()
+        {
+            base.OnCreate();
+
+            Log.Debug(Globals.LogTag, "OnCreate()");
+            _app = new App();
+            LoadApplication(_app);
+        }
+
+        public static App getApp()
+        {
+            return _app;
+        }
+        static void Main(string[] args)
+        {
+            var app = new Program();
+            global::Xamarin.Forms.Platform.Tizen.Forms.Init(app);
+            app.Run(args);
+        }
+    }
+}
\ No newline at end of file
diff --git a/test/Tizen.CallManager.Test/Tizen.CallManager.Test.csproj b/test/Tizen.CallManager.Test/Tizen.CallManager.Test.csproj
new file mode 100755 (executable)
index 0000000..783e8a8
--- /dev/null
@@ -0,0 +1,63 @@
+<Project>
+  <Import Project="Sdk.props" Sdk="Microsoft.NET.Sdk" />
+
+  <PropertyGroup Label="Globals">
+    <TizenProjectExtensionsPath>$(MSBuildExtensionsPath)\Tizen\VisualStudio\</TizenProjectExtensionsPath>
+  </PropertyGroup>
+
+  <Import Project="$(TizenProjectExtensionsPath)Tizen.NET.ProjectType.props" Condition="Exists('$(TizenProjectExtensionsPath)Tizen.NET.ProjectType.props')" />
+
+  <PropertyGroup>
+    <OutputType>Exe</OutputType>
+    <TargetFramework>netcoreapp1.1</TargetFramework>
+  </PropertyGroup>
+
+  <!-- Property Group for Tizen Project -->
+  <PropertyGroup>
+    <TizenCreateTpkOnBuild>true</TizenCreateTpkOnBuild>
+    <PackageTargetFallback>$(PackageTargetFallback);portable-net45+wp80+win81+wpa81</PackageTargetFallback>
+  </PropertyGroup>
+
+  <!--
+  This Property Group for msbuild command line.
+  If project build on Visual Studio, it would be set automatically through the certificate manager.
+  <PropertyGroup>
+    <AuthorPath>author_test.p12</AuthorPath>
+    <AuthorPass>author_test</AuthorPass>
+    <DistributorPath>tizen-distributor-signer.p12</DistributorPath>
+    <DistributorPass>tizenpkcs12passfordsigner</DistributorPass>
+  </PropertyGroup>
+  -->
+
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugType>portable</DebugType>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>None</DebugType>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <Folder Include="lib\" />
+    <Folder Include="res\" />
+  </ItemGroup>
+
+  <ItemGroup>
+    <PackageReference Include="Tizen.NET.Sdk" Version="0.9.18-pre1" />
+    <PackageReference Include="Xamarin.Forms" Version="2.4.0.275-pre3" />
+    <PackageReference Include="Xamarin.Forms.Platform.Tizen" Version="2.3.5-r256-001" />
+  </ItemGroup>
+
+  <ItemGroup>
+    <ProjectReference Include="..\..\src\Tizen.CallManager\Tizen.CallManager.csproj" />
+  </ItemGroup>
+
+  <Import Project="Sdk.targets" Sdk="Microsoft.NET.Sdk" />
+  <Import Project="$(TizenProjectExtensionsPath)Tizen.NET.ProjectType.targets" Condition="Exists('$(TizenProjectExtensionsPath)Tizen.NET.ProjectType.targets')" />
+
+  <!-- Install Check 'Visual Studio for Tizen' for developing on Visual Studio -->
+  <Target Name="TizenVsixInstallCheck" BeforeTargets="CompileDesignTime">
+    <Warning Condition="!Exists('$(TizenProjectExtensionsPath)Tizen.NET.ProjectType.props')" Text="$(TizenProjectExtensionsPath)Tizen.NET.ProjectType.props is not exist.&#xA; you need to check if 'Visual Studio for Tizen' is installed" />
+    <Warning Condition="!Exists('$(TizenProjectExtensionsPath)Tizen.NET.ProjectType.targets')" Text="$(TizenProjectExtensionsPath)Tizen.NET.ProjectType.targets is not exist.\&#xA; you need to check if 'Visual Studio for Tizen' is installed" />
+  </Target>
+</Project>
+
diff --git a/test/Tizen.CallManager.Test/Tizen.CallManager.Test.sln b/test/Tizen.CallManager.Test/Tizen.CallManager.Test.sln
new file mode 100755 (executable)
index 0000000..1119daf
--- /dev/null
@@ -0,0 +1,28 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 15
+VisualStudioVersion = 15.0.26430.13
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tizen.CallManager.Test", "Tizen.CallManager.Test.csproj", "{404DDD6F-0734-4F16-A70F-EB384C247669}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tizen.CallManager", "..\..\src\Tizen.CallManager\Tizen.CallManager.csproj", "{4067DC7E-6F41-415B-950A-934CC0CEAFE5}"
+EndProject
+Global
+       GlobalSection(SolutionConfigurationPlatforms) = preSolution
+               Debug|Any CPU = Debug|Any CPU
+               Release|Any CPU = Release|Any CPU
+       EndGlobalSection
+       GlobalSection(ProjectConfigurationPlatforms) = postSolution
+               {404DDD6F-0734-4F16-A70F-EB384C247669}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+               {404DDD6F-0734-4F16-A70F-EB384C247669}.Debug|Any CPU.Build.0 = Debug|Any CPU
+               {404DDD6F-0734-4F16-A70F-EB384C247669}.Release|Any CPU.ActiveCfg = Release|Any CPU
+               {404DDD6F-0734-4F16-A70F-EB384C247669}.Release|Any CPU.Build.0 = Release|Any CPU
+               {4067DC7E-6F41-415B-950A-934CC0CEAFE5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+               {4067DC7E-6F41-415B-950A-934CC0CEAFE5}.Debug|Any CPU.Build.0 = Debug|Any CPU
+               {4067DC7E-6F41-415B-950A-934CC0CEAFE5}.Release|Any CPU.ActiveCfg = Release|Any CPU
+               {4067DC7E-6F41-415B-950A-934CC0CEAFE5}.Release|Any CPU.Build.0 = Release|Any CPU
+       EndGlobalSection
+       GlobalSection(SolutionProperties) = preSolution
+               HideSolutionNode = FALSE
+       EndGlobalSection
+EndGlobal
diff --git a/test/Tizen.CallManager.Test/shared/res/Tizen.CallManager.Test.png b/test/Tizen.CallManager.Test/shared/res/Tizen.CallManager.Test.png
new file mode 100755 (executable)
index 0000000..9f3cb98
Binary files /dev/null and b/test/Tizen.CallManager.Test/shared/res/Tizen.CallManager.Test.png differ
diff --git a/test/Tizen.CallManager.Test/tizen-manifest.xml b/test/Tizen.CallManager.Test/tizen-manifest.xml
new file mode 100755 (executable)
index 0000000..ed05adc
--- /dev/null
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns="http://tizen.org/ns/packages" api-version="4" package="Tizen.CallManager.Test" version="1.0.0">
+  <profile name="common" />
+  <ui-application appid="org.tizen.example.Tizen.CallManager.Test"
+                                       exec="Tizen.CallManager.Test.dll"
+                                       type="dotnet"
+                                       multiple="false"
+                                       taskmanage="true"
+                                       nodisplay="false"
+                                       launch_mode="single">
+    <label>Tizen.CallManager.Test</label>
+    <icon>Tizen.CallManager.Test.png</icon>
+  </ui-application>
+</manifest>