Add Voicememo app (#142)
author안주원/Common Platform Lab(SR)/Staff Engineer/삼성전자 <juwon.ahn@samsung.com>
Mon, 20 Jan 2020 04:38:25 +0000 (13:38 +0900)
committer부정균/Common Platform Lab(SR)/Staff Engineer/삼성전자 <jk.pu@samsung.com>
Mon, 20 Jan 2020 04:38:25 +0000 (13:38 +0900)
162 files changed:
Test/Voicememo2020/README.md [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo.sln [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/App.xaml [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/App.xaml.cs [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/Converters/CountryCodeToNameConverter.cs [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/Converters/DurationToRemainingTimeConverter.cs [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/Converters/RecordImageSourceColorConverter.cs [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/Converters/RecordsCountToViewVisibilityConverter.cs [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/Converters/SttToPropertyConverter.cs [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/Data/RecordDatabase.cs [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/EffectRenderers/BlendColorEffect.cs [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/EffectRenderers/TizenEventPropagationEffect.cs [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/EffectRenderers/TizenItemLongPressEffect.cs [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/EffectRenderers/TizenStyleEffect.cs [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/Effects/ImageAttributes.cs [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/Effects/ImageBlendEffect.cs [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/Effects/InternalExtension.cs [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/Effects/ItemLongPressEffect.cs [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/Effects/TizenEventPropagationEffect.cs [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/Effects/TizenStyleEffect.cs [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/Effects/VisualAttributes.cs [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/Interop/Interop.Libraries.cs [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/Interop/Interop.SystemCall.cs [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/Models/LatestRecord.cs [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/Models/Record.cs [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/Models/SttLanguage.cs [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/Renderers/GraphicPopUpRenderer.cs [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/Renderers/ProgressbarPopupRenderer.cs [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/Resx/AppResources.Designer.cs [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/Resx/AppResources.hi.resx [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/Resx/AppResources.ko.resx [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/Resx/AppResources.resx [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/Services/AppDataService.cs [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/Services/AppTerminator.cs [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/Services/AudioPlayService.cs [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/Services/AudioRecordService.cs [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/Services/DeviceInformationService.cs [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/Services/LocaleService.cs [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/Services/MediaContentService.cs [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/Services/SpeechToTextService.cs [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/Services/UserPermission.cs [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/Settings.StyleCop [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/Utility.cs [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/Utility/ColorConverter.cs [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/Utility/LogInformation.cs [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/Utility/PrivilegeInformation.cs [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/ViewModels/BasePageModel.cs [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/ViewModels/DetailsPageModel.cs [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/ViewModels/MainPageModel.cs [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/ViewModels/MessageKeys.cs [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/ViewModels/PlayBackPageModel.cs [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/ViewModels/RecordingPageModel.cs [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/Views/BindableToolbarItem.cs [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/Views/CancelPage.xaml [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/Views/CancelPage.xaml.cs [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/Views/CirclePageEx.xaml [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/Views/CirclePageEx.xaml.cs [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/Views/DetailsPage.xaml [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/Views/DetailsPage.xaml.cs [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/Views/GraphicPopup.cs [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/Views/IGraphicPopup.cs [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/Views/IProgressbarPopup.cs [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/Views/LanguageSelectionPage.xaml [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/Views/LanguageSelectionPage.xaml.cs [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/Views/MainPage.xaml [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/Views/MainPage.xaml.cs [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/Views/PageFactory.cs [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/Views/PlayBackPage.xaml [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/Views/PlayBackPage.xaml.cs [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/Views/ProgressbarPopup.cs [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/Views/RecordListPage.xaml [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/Views/RecordListPage.xaml.cs [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/Views/RecordingPage.xaml [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/Views/RecordingPage.xaml.cs [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/Views/SttLanguageViewCell.xaml [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/Views/SttLanguageViewCell.xaml.cs [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/Views/ViewExtensions.cs [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/VoiceMemo.cs [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/VoiceMemo.csproj [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/res/2019/details_playback_icon.png [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/res/2019/recording_stt_icon.png [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/res/2019/voice_mamo_slider_btn_bg.png [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/res/2019/voicememo_effect.png [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/res/2019/voicememo_volume_control_cover_bg.png [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/res/2019/voicerecorder_effect_bg.png [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/res/2019_custom_button/details_vol_icon_off.png [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/res/2019_custom_button/details_vol_icon_on.png [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/res/2019_custom_button/record_controller_bg.png [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/res/2019_custom_button/recording_icon_cancel.png [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/res/2019_custom_button/recording_icon_stop.png [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/res/2019_custom_button/voicerecorder_btn_bg.png [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/res/2019_custom_button/voicerecorder_btn_pause.png [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/res/2019_custom_button/voicerecorder_btn_play.png [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/res/2019_custom_button/voicerecorder_playback_btn_pause.png [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/res/2019_custom_button/voicerecorder_stop_icon.png [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/res/2019_images_icons/b_icon_voicememo.png [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/res/2019_images_icons/b_slider_icon_minus.png [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/res/2019_images_icons/b_slider_icon_plus.png [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/res/2019_images_icons/details_playback_icon.png [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/res/2019_images_icons/more_option_icon_delete.png [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/res/2019_images_icons/more_option_icon_language.png [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/res/2019_images_icons/more_option_icon_stt_off.png [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/res/2019_images_icons/more_option_icon_stt_on.png [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/res/2019_images_icons/more_option_icon_stt_recording.png [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/res/2019_images_icons/play_volume_slider_ic.png [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/res/2019_images_icons/tw_ic_menu_delete_holo_dark.png [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/res/2019_images_icons/tw_ic_menu_selectall_holo_dark.png [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/res/2019_images_icons/tw_ic_popup_btn_check.png [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/res/2019_images_icons/tw_ic_popup_btn_delete.png [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/res/2019_images_icons/tw_toast_popup_memory_full_gear.png [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/res/2019_images_icons/tw_toast_popup_memory_full_mobile.png [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/res/2019_images_icons/voice_mamo_slider_mute.png [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/res/2019_images_icons/voice_mamo_slider_volume_on.png [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/res/2019_images_icons/voice_memo_slash.png [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/res/2019_images_icons/voicememo_effect.png [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/res/2019_images_icons/voicerecorder_bt_headset_image.png [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/res/2019_images_icons/voicerecorder_bt_mobile_image.png [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/res/2019_images_icons/voicerecorder_btn_pause.png [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/res/2019_images_icons/voicerecorder_btn_play.png [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/res/2019_images_icons/voicerecorder_effect_bg.png [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/res/2019_images_icons/voicerecorder_icon_stt.png [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/res/2019_images_icons/weather_toast_popup_show_on_divice.png [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/res/b_icon_voicememo.png [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/res/button/details_vol_icon_off.png [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/res/button/details_vol_icon_on.png [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/res/details_playback_icon.png [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/res/details_vol_icon_off.png [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/res/details_vol_icon_on.png [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/res/icons/b_slider_icon_minus.png [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/res/icons/b_slider_icon_plus.png [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/res/more_option_icon_delete.png [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/res/more_option_icon_language.png [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/res/more_option_icon_stt_list.png [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/res/more_option_icon_stt_off.png [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/res/more_option_icon_stt_on.png [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/res/record_controller_bg.png [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/res/record_stop_icon.png [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/res/recording_icon_cancel.png [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/res/recording_icon_pause.png [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/res/recording_stt_icon.png [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/res/tw_ic_popup_btn_check.png [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/res/tw_ic_popup_btn_delete.png [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/res/tw_no_item_bg.png [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/res/voice_mamo_slider_btn_bg.png [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/res/voice_mamo_slider_mute.png [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/res/voice_mamo_slider_volume_on.png [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/res/voicememo_effect.png [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/res/voicerecorder_btn_bg.png [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/res/voicerecorder_btn_pause.png [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/res/voicerecorder_btn_play.png [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/res/voicerecorder_btn_stop.png [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/res/voicerecorder_icon_stt.png [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/res/voicerecorder_icon_stt_off.png [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/res/voicerecorder_stop_bg.png [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/res/voicerecorder_stop_icon.png [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/res/xml/accessoryservices.xml [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/shared/res/VoiceMemo.png [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/shared/res/splash.png [new file with mode: 0755]
Test/Voicememo2020/VoiceMemo/tizen-manifest.xml [new file with mode: 0755]
Tizen.CircularUI/Tizen.Wearable.CircularUI.Forms.Renderer/CircleScrollViewRenderer.cs [changed mode: 0644->0755]
XSF.sln [changed mode: 0644->0755]
Xamarin.Forms/Xamarin.Forms.Platform.Tizen/Forms.cs [changed mode: 0644->0755]

diff --git a/Test/Voicememo2020/README.md b/Test/Voicememo2020/README.md
new file mode 100755 (executable)
index 0000000..7d0db81
--- /dev/null
@@ -0,0 +1,3 @@
+# Voicememo2020
+
+This is the Voicememo application for Galaxy Watch product in C#. 
diff --git a/Test/Voicememo2020/VoiceMemo.sln b/Test/Voicememo2020/VoiceMemo.sln
new file mode 100755 (executable)
index 0000000..a463c94
--- /dev/null
@@ -0,0 +1,25 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.29215.179
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VoiceMemo", "VoiceMemo\VoiceMemo.csproj", "{E85DA711-1972-4A14-B80F-D354415A0F09}"
+EndProject
+Global
+       GlobalSection(SolutionConfigurationPlatforms) = preSolution
+               Debug|Any CPU = Debug|Any CPU
+               Release|Any CPU = Release|Any CPU
+       EndGlobalSection
+       GlobalSection(ProjectConfigurationPlatforms) = postSolution
+               {E85DA711-1972-4A14-B80F-D354415A0F09}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+               {E85DA711-1972-4A14-B80F-D354415A0F09}.Debug|Any CPU.Build.0 = Debug|Any CPU
+               {E85DA711-1972-4A14-B80F-D354415A0F09}.Release|Any CPU.ActiveCfg = Release|Any CPU
+               {E85DA711-1972-4A14-B80F-D354415A0F09}.Release|Any CPU.Build.0 = Release|Any CPU
+       EndGlobalSection
+       GlobalSection(SolutionProperties) = preSolution
+               HideSolutionNode = FALSE
+       EndGlobalSection
+       GlobalSection(ExtensibilityGlobals) = postSolution
+               SolutionGuid = {C4DF83AB-49AF-4F12-8BF5-22D1A7A720C8}
+       EndGlobalSection
+EndGlobal
diff --git a/Test/Voicememo2020/VoiceMemo/App.xaml b/Test/Voicememo2020/VoiceMemo/App.xaml
new file mode 100755 (executable)
index 0000000..84d1246
--- /dev/null
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<Application xmlns="http://xamarin.com/schemas/2014/forms"
+             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
+             x:Class="VoiceMemo.App">
+       <Application.Resources>
+               <!-- Application resource dictionary -->
+        <ResourceDictionary>
+            <Style x:Key="LabelStyle-Base" TargetType="Label">
+                <Setter Property="HorizontalTextAlignment" Value="Center" />
+                <Setter Property="VerticalTextAlignment" Value="Center" />
+                <Setter Property="TextColor" Value="White" />
+            </Style>
+            <Style x:Key="BaseLabelStyle" TargetType="Label">
+                <Setter Property="HorizontalOptions" Value="Center" />
+                <Setter Property="VerticalOptions" Value="Center" />
+                <Setter Property="VerticalTextAlignment" Value="Center" />
+                <Setter Property="HorizontalTextAlignment" Value="Center" />
+                <Setter Property="TextColor" Value="White" />
+            </Style>
+        </ResourceDictionary>
+    </Application.Resources>
+</Application>
\ No newline at end of file
diff --git a/Test/Voicememo2020/VoiceMemo/App.xaml.cs b/Test/Voicememo2020/VoiceMemo/App.xaml.cs
new file mode 100755 (executable)
index 0000000..d60c756
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://floralicense.org/license/
+ *
+ * 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.Globalization;
+using System.Threading;
+using VoiceMemo.Data;
+using VoiceMemo.Services;
+using VoiceMemo.ViewModels;
+using VoiceMemo.Views;
+using Xamarin.Forms;
+using Xamarin.Forms.Xaml;
+
+[assembly: XamlCompilation(XamlCompilationOptions.Compile)]
+namespace VoiceMemo
+{
+    /// <summary>
+    /// VoiceMemo Application class
+    /// </summary>
+    public partial class App : Application
+    {
+        MainPage firstPage;
+        //MainPageCS firstPageCS;
+        public MainPageModel mainPageModel;
+        public App()
+        {
+            // Get locale information
+            UpdateLocale();
+            InitializeComponent();
+
+            firstPage = (MainPage)PageFactory.GetInstance(Pages.StandBy);
+            MainPage = new NavigationPage(firstPage);
+            mainPageModel = (MainPageModel)firstPage.BindingContext;
+
+            //firstPageCS = (MainPageCS)PageFactory.GetInstance(Pages.StandByCS);
+            //MainPage = new NavigationPage(firstPageCS);
+
+            //mainPageModel = (MainPageModel)firstPageCS.BindingContext;
+        }
+
+        // database for voice records
+        static RecordDatabase database;
+        public static RecordDatabase Database
+        {
+            get
+            {
+                if (database == null)
+                {
+                    database = new RecordDatabase(DeviceInformationService.Instance.GetLocalDBFilePath("DotnetVoiceMemo.db3"));
+                }
+
+                return database;
+            }
+        }
+
+        protected override void OnStart()
+        {
+
+        }
+
+        protected override void OnSleep()
+        {
+            // Handle when your app sleeps
+        }
+
+        protected override void OnResume()
+        {
+            // Handle when your app resumes
+        }
+
+        /// <summary>
+        /// Get the current locale and apply it.
+        /// </summary>
+        public void UpdateLocale()
+        {
+            // determine the correct, supported .NET culture
+            var ci = LocaleService.Instance.CurrentCultureInfo;
+            SetCultureInfo(ci);
+
+            // Whenever language has been changed, CurrentCulture will be updated.
+            //MessagingCenter.Subscribe<LocaleService, CultureInfo>(this, MessageKeys.LanguageChanged, (obj, culture) =>
+            //{
+            //    SetCultureInfo(culture);
+            //    MessagingCenter.Send<App>(this, MessageKeys.UpdateByLanguageChange);
+            //});
+            //Trace.End();
+        }
+
+        // Set the current culture
+        // It will be used by the Resource Manager
+        void SetCultureInfo(CultureInfo info)
+        {
+            Resx.AppResources.Culture = info; // set the RESX for resource localization
+            Thread.CurrentThread.CurrentCulture = info;
+            Thread.CurrentThread.CurrentUICulture = info;
+        }
+
+        public void Terminate()
+        {
+            MessagingCenter.Unsubscribe<LocaleService, CultureInfo>(this, MessageKeys.LanguageChanged);
+            //((MainPageModel)firstPage?.BindingContext).Dispose();
+            PageFactory.DestoryPage();
+        }
+    }
+}
diff --git a/Test/Voicememo2020/VoiceMemo/Converters/CountryCodeToNameConverter.cs b/Test/Voicememo2020/VoiceMemo/Converters/CountryCodeToNameConverter.cs
new file mode 100755 (executable)
index 0000000..037f521
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://floralicense.org/license/
+ *
+ * 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.Globalization;
+using Xamarin.Forms;
+
+namespace VoiceMemo.Converters
+{
+    /// <summary>
+    /// NameType enum
+    /// </summary>
+    public enum NameType
+    {
+        /// <summary>
+        /// The name of Cultural Region
+        /// </summary>
+        RegionName,
+        /// <summary>
+        /// English Name
+        /// </summary>
+        EnglishName,
+    }
+
+    /// <summary>
+    /// Class CountryCodeToNameConverter
+    /// It converts country code to name.
+    /// </summary>
+    class CountryCodeToNameConverter : IValueConverter
+    {
+        /// <summary>
+        /// Converting source value to target value
+        /// </summary>
+        /// <param name="value">Source object</param>
+        /// <param name="targetType">The target type to convert</param>
+        /// <param name="parameter">parameter object</param>
+        /// <param name="culture">The culture info</param>
+        /// <returns>Returns converted bool to decide UI widget's visibility</returns>
+        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
+        {
+            string countryCode = (string)value;
+            if (countryCode == null)
+            {
+                return null;
+            }
+
+            var type = (NameType)parameter;
+            
+            switch (type)
+            {
+                case NameType.EnglishName:
+                    CultureInfo cultureInfo = new CultureInfo(countryCode);
+                    return cultureInfo.DisplayName;
+                case NameType.RegionName:
+                    RegionInfo regionInfo = new RegionInfo(countryCode.Replace("_", "-"));
+                    return regionInfo.EnglishName;
+                default:
+                    return null;
+            }
+        }
+
+        /// <summary>
+        /// Converting back source value to target value
+        /// This method is not being used in this app.
+        /// </summary>
+        /// <param name="value">Source object</param>
+        /// <seealso cref="System.object">
+        /// <param name="targetType">The target type to convert</param>
+        /// <seealso cref="Type">
+        /// <param name="CultureInfo">The culture info</param>
+        /// <seealso cref="CultureInfo">
+        /// <returns>Returns null</returns>
+        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
+        {
+            return null;
+        }
+    }
+}
diff --git a/Test/Voicememo2020/VoiceMemo/Converters/DurationToRemainingTimeConverter.cs b/Test/Voicememo2020/VoiceMemo/Converters/DurationToRemainingTimeConverter.cs
new file mode 100755 (executable)
index 0000000..7944565
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://floralicense.org/license/
+ *
+ * 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.Globalization;
+using Xamarin.Forms;
+
+namespace VoiceMemo.Converters
+{
+    public enum RemainingTimeType
+    {
+        TimeText,
+    }
+
+    /// <summary>
+    /// Class DurationToRemainingTimeConverter
+    /// It converts duration information to remaining time.
+    /// format - minutes:seconds
+    /// </summary>
+    public class DurationToRemainingTimeConverter : IValueConverter
+    {
+        /// <summary>
+        /// Converting source value to target value
+        /// </summary>
+        /// <param name="value">Source object</param>
+        /// <param name="targetType">The target type to convert</param>
+        /// <param name="parameter">parameter object</param>
+        /// <param name="culture">The culture info</param>
+        /// <returns>Returns converted bool to decide UI widget's visibility</returns>
+        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
+        {
+            int remains = System.Convert.ToInt32(value);
+            RemainingTimeType type = (RemainingTimeType)parameter;
+            switch (type)
+            {
+                case RemainingTimeType.TimeText:
+                    int minutes = remains / 60000;
+                    int seconds = (remains - minutes * 60000) / 1000;
+                    //Console.WriteLine("[DurationToRemainingTimeConverter  -  TimeText] remaining time : " + remains);
+                    // return the remaining time, formatted as {minutes}:{seconds}
+                    return String.Format("{0:00}:{1:00}", minutes, seconds);
+                default:
+                    return null;
+            }
+        }
+
+        /// <summary>
+        /// Converting back source value to target value
+        /// This method is not being used in this app.
+        /// </summary>
+        /// <param name="value">Source object</param>
+        /// <seealso cref="System.object">
+        /// <param name="targetType">The target type to convert</param>
+        /// <seealso cref="Type">
+        /// <param name="CultureInfo">The culture info</param>
+        /// <seealso cref="CultureInfo">
+        /// <returns>Returns null</returns>
+        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
+        {
+            return null;
+        }
+    }
+}
diff --git a/Test/Voicememo2020/VoiceMemo/Converters/RecordImageSourceColorConverter.cs b/Test/Voicememo2020/VoiceMemo/Converters/RecordImageSourceColorConverter.cs
new file mode 100755 (executable)
index 0000000..d8662f1
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://floralicense.org/license/
+ *
+ * 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.Globalization;
+using VoiceMemo.Effects;
+using Xamarin.Forms;
+
+namespace VoiceMemo.Converters
+{
+    class RecordImageSourceColorConverter : IValueConverter
+    {
+        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
+        {
+            string source = (string)value;
+            Image imageOjb = (Image)parameter;
+
+            if (source == "record_stop_icon.png")
+            {
+                ImageAttributes.SetBlendColor(imageOjb, Color.Red);
+            }
+            else if (source == "recording_icon_pause.png")
+            {
+                ImageAttributes.SetBlendColor(imageOjb, Color.FromHex("#FF4F4F4F"));
+            }
+
+            return source;
+        }
+
+        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
+        {
+            throw new NotImplementedException();
+        }
+    }
+}
diff --git a/Test/Voicememo2020/VoiceMemo/Converters/RecordsCountToViewVisibilityConverter.cs b/Test/Voicememo2020/VoiceMemo/Converters/RecordsCountToViewVisibilityConverter.cs
new file mode 100755 (executable)
index 0000000..2e1a4b0
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://floralicense.org/license/
+ *
+ * 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.Globalization;
+using Xamarin.Forms;
+
+namespace VoiceMemo.Converters
+{
+    /// <summary>
+    /// The type of view
+    /// </summary>
+    public enum ViewType
+    {
+        /// <summary>
+        /// View which is shown when there is no record
+        /// </summary>
+        NoRecordView,
+        /// <summary>
+        /// List view when there are some records
+        /// </summary>
+        RecordListView,
+        RecordCheckView,
+    }
+
+    /// <summary>
+    /// converter class
+    /// Change the visibility of view based on the number of voice records
+    /// </summary>
+    public class RecordsCountToViewVisibilityConverter : IValueConverter
+    {
+        /// <summary>
+        /// Converting source value to target value
+        /// </summary>
+        /// <param name="value">Source object</param>
+        /// <param name="targetType">The target type to convert</param>
+        /// <param name="parameter">parameter object</param>
+        /// <param name="culture">The culture info</param>
+        /// <returns>Returns converted bool to decide UI widget's visibility</returns>
+        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
+        {
+            int RecordsCnt = System.Convert.ToInt32(value);
+            ViewType viewType = (ViewType)parameter;
+            //Console.WriteLine("[RecordsCountToViewVisibilityConverter] RecordsCount = " + RecordsCnt + ", viewType :" + viewType);
+
+            switch (viewType)
+            {
+                case ViewType.NoRecordView:
+                    return RecordsCnt == 0 ? true : false;
+                case ViewType.RecordListView:
+                    return RecordsCnt == 0 ? false : true;
+                case ViewType.RecordCheckView:
+                    return RecordsCnt == 0 ? false : true;
+                default:
+                    return true;
+            }
+        }
+
+        /// <summary>
+        /// Converting back source value to target value
+        /// This method is not being used in this app.
+        /// </summary>
+        /// <param name="value">Source object</param>
+        /// <seealso cref="System.object">
+        /// <param name="targetType">The target type to convert</param>
+        /// <seealso cref="Type">
+        /// <param name="CultureInfo">The culture info</param>
+        /// <seealso cref="CultureInfo">
+        /// <returns>Returns null</returns>
+        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
+        {
+            return null;
+        }
+    }
+}
diff --git a/Test/Voicememo2020/VoiceMemo/Converters/SttToPropertyConverter.cs b/Test/Voicememo2020/VoiceMemo/Converters/SttToPropertyConverter.cs
new file mode 100755 (executable)
index 0000000..76ebb80
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://floralicense.org/license/
+ *
+ * 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.Globalization;
+using VoiceMemo.Resx;
+using Xamarin.Forms;
+
+namespace VoiceMemo.Converters
+{
+    public enum SttPropertyType
+    {
+        // Text : "On", "Off"
+        TextString,
+        // Image
+        ImageSource,
+        RecordImageSource,
+    }
+
+    /// <summary>
+    /// Converter class
+    /// According to whether or not STT feature usability is on,
+    /// this converter class will provider the proper text and the path of image file .
+    /// </summary>
+    public class SttToPropertyConverter : IValueConverter
+    {
+        /// <summary>
+        /// Converting source value to target value
+        /// </summary>
+        /// <param name="value">Source object</param>
+        /// <param name="targetType">The target type to convert</param>
+        /// <param name="parameter">parameter object</param>
+        /// <param name="culture">The culture info</param>
+        /// <returns>Returns converted bool to decide UI widget's visibility</returns>
+        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
+        {
+            bool isSttOn = (bool)System.Convert.ToBoolean(value);
+            SttPropertyType type = (SttPropertyType)parameter;
+            //Console.WriteLine("[SttToPropertyConverter] isSttOn: " + isSttOn + ", type:" + type);
+            switch (type)
+            {
+                case SttPropertyType.TextString:
+                    return isSttOn ? AppResources.SttOn : AppResources.SttOff;
+                case SttPropertyType.ImageSource:
+                    return isSttOn ? "more_option_icon_stt_on.png" : "more_option_icon_stt_off.png";
+                case SttPropertyType.RecordImageSource:
+                    return isSttOn ? "voicerecorder_icon_stt.png" : "voicerecorder_icon_stt_off.png";
+                default:
+                    return null;
+            }
+        }
+
+        /// <summary>
+        /// Converting back source value to target value
+        /// This method is not being used in this app.
+        /// </summary>
+        /// <param name="value">Source object</param>
+        /// <seealso cref="System.object">
+        /// <param name="targetType">The target type to convert</param>
+        /// <seealso cref="Type">
+        /// <param name="CultureInfo">The culture info</param>
+        /// <seealso cref="CultureInfo">
+        /// <returns>Returns null</returns>
+        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
+        {
+            return null;
+        }
+    }
+}
diff --git a/Test/Voicememo2020/VoiceMemo/Data/RecordDatabase.cs b/Test/Voicememo2020/VoiceMemo/Data/RecordDatabase.cs
new file mode 100755 (executable)
index 0000000..2e3f1e1
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://floralicense.org/license/
+ *
+ * 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 SQLite;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using VoiceMemo.Models;
+
+namespace VoiceMemo.Data
+{
+    /// <summary>
+    /// Database class
+    /// It stores collection of records
+    /// </summary>
+    public class RecordDatabase
+    {
+        // SQLite connection
+        readonly SQLiteAsyncConnection database;
+
+        public RecordDatabase(string dbPath)
+        {
+            database = new SQLiteAsyncConnection(dbPath);
+            database.CreateTableAsync<Record>().Wait();
+        }
+
+        /// <summary>
+        /// Get list or records in database
+        /// </summary>
+        /// <returns>Task<List<Record>></returns>
+        public Task<List<Record>> GetItemsAsync()
+        {
+            return database.Table<Record>().ToListAsync();
+        }
+
+        /// <summary>
+        /// Save record in database
+        /// </summary>
+        /// <param name="item">Record</param>
+        /// <returns>Task<int></returns>
+        public Task<int> SaveItemAsync(Record item)
+        {
+            if (item.ID != 0)
+            {
+                // in case that item already exists in database
+                return database.UpdateAsync(item);
+            }
+            else
+            {
+                // for the first time item will be added in database
+                return database.InsertAsync(item);
+            }
+        }
+
+        /// <summary>
+        /// Delete record from database
+        /// </summary>
+        /// <param name="item">Record</param>
+        /// <returns>Task<int></returns>
+        public Task<int> DeleteItemAsync(Record item)
+        {
+            return database.DeleteAsync(item);
+        }
+    }
+}
diff --git a/Test/Voicememo2020/VoiceMemo/EffectRenderers/BlendColorEffect.cs b/Test/Voicememo2020/VoiceMemo/EffectRenderers/BlendColorEffect.cs
new file mode 100755 (executable)
index 0000000..f1dfb18
--- /dev/null
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://floralicense.org/license/
+ *
+ * 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 EColor = ElmSharp.Color;
+using EImage = ElmSharp.Image;
+using System;
+using System.ComponentModel;
+using VoiceMemo.EffectRenderers;
+using Xamarin.Forms;
+using Xamarin.Forms.Platform.Tizen;
+using VoiceMemo.Effects;
+
+[assembly: ResolutionGroupName("SEC")]
+[assembly: ExportEffect(typeof(BlendColorEffect), "BlendColorEffect")]
+
+namespace VoiceMemo.EffectRenderers
+{
+    internal class BlendColorEffect : PlatformEffect
+    {
+        static readonly EColor DefaultBlendColor = EColor.Default;
+
+        public object ImageAtctributes { get; private set; }
+
+        protected override void OnAttached()
+        {
+            try
+            {
+                if (Control is EImage nativeControl)
+                {
+                    nativeControl.LoadingCompleted += OnNativeImageLoadingCompleted;
+                }
+
+                UpdateBlendColor();
+            }
+            catch (Exception e)
+            {
+                Log.Error("Cannot set property on attached control. Error: ", e.Message);
+            }
+        }
+
+        protected override void OnDetached()
+        {
+            if (Control is EImage nativeControl)
+            {
+                nativeControl.LoadingCompleted -= OnNativeImageLoadingCompleted;
+                nativeControl.Color = DefaultBlendColor;
+            }
+        }
+
+        protected override void OnElementPropertyChanged(PropertyChangedEventArgs args)
+        {
+            try
+            {
+                if (args.PropertyName == ImageAttributes.BlendColorProperty.PropertyName)
+                {
+                    UpdateBlendColor();
+                }
+            }
+            catch (Exception e)
+            {
+                Log.Error("Cannot set property on attached control. Error : ", e.Message);
+            }
+
+            base.OnElementPropertyChanged(args);
+        }
+
+        void OnNativeImageLoadingCompleted(object sender, EventArgs e)
+        {
+            UpdateBlendColor();
+        }
+
+        void UpdateBlendColor()
+        {
+            if ((Element as Image).IsLoading)
+            {
+                Device.StartTimer(TimeSpan.Zero, () =>
+                {
+                    InternalBlendColorUpdate();
+                    return false;
+                });
+            }
+            else
+            {
+                InternalBlendColorUpdate();
+            }
+        }
+
+        void InternalBlendColorUpdate()
+        {
+            if (Control is EImage image)
+            {
+                var blendColor = (Color)Element.GetValue(ImageAttributes.BlendColorProperty);
+                image.Color = blendColor == Color.Default ? DefaultBlendColor : blendColor.ToNative();
+            }
+        }
+    }
+}
diff --git a/Test/Voicememo2020/VoiceMemo/EffectRenderers/TizenEventPropagationEffect.cs b/Test/Voicememo2020/VoiceMemo/EffectRenderers/TizenEventPropagationEffect.cs
new file mode 100755 (executable)
index 0000000..7b766d5
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://floralicense.org/license/
+ *
+ * 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.ComponentModel;
+using VoiceMemo.EffectRenderers;
+using Xamarin.Forms;
+using Xamarin.Forms.Platform.Tizen;
+
+[assembly: ExportEffect(typeof(TizenEventPropagationEffect), "TizenEventPropagationEffect")]
+
+namespace VoiceMemo.EffectRenderers
+{
+    class TizenEventPropagationEffect : PlatformEffect
+    {
+        protected override void OnAttached()
+        {
+            DoEnable();
+        }
+
+        protected override void OnDetached()
+        {
+            DoEnable(false);
+        }
+
+        protected override void OnElementPropertyChanged(PropertyChangedEventArgs args)
+        {
+            base.OnElementPropertyChanged(args);
+            if (args.PropertyName == VoiceMemo.Effects.TizenEventPropagationEffect.EnablePropagationProperty.PropertyName)
+            {
+                DoEnable();
+            }
+        }
+
+        void DoEnable()
+        {
+            var enablePropagation = VoiceMemo.Effects.TizenEventPropagationEffect.GetEnablePropagation(Element);
+            DoEnable(enablePropagation);
+        }
+
+        void DoEnable(bool enablePropagation)
+        {
+            Control.RepeatEvents = enablePropagation;
+            Control.PropagateEvents = enablePropagation;
+        }
+    }
+}
diff --git a/Test/Voicememo2020/VoiceMemo/EffectRenderers/TizenItemLongPressEffect.cs b/Test/Voicememo2020/VoiceMemo/EffectRenderers/TizenItemLongPressEffect.cs
new file mode 100755 (executable)
index 0000000..fbeff52
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://floralicense.org/license/
+ *
+ * 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 VoiceMemo.EffectRenderers;
+using Xamarin.Forms;
+using Xamarin.Forms.Platform.Tizen;
+
+[assembly: ExportEffect(typeof(TizenItemLongPressEffect), "ItemLongPressEffect")]
+
+namespace VoiceMemo.EffectRenderers
+{
+    public class TizenItemLongPressEffect : PlatformEffect
+    {
+        protected override void OnAttached()
+        {
+            var genlist = Control as ElmSharp.GenList;
+            if (genlist != null)
+            {
+                genlist.ItemLongPressed += ItemLongPressed;
+            }
+        }
+
+        protected override void OnDetached()
+        {
+            var genlist = this.Control as ElmSharp.GenList;
+            if (genlist != null)
+            {
+                genlist.ItemLongPressed -= ItemLongPressed;
+            }
+        }
+
+        void ItemLongPressed(object sender, ElmSharp.GenListItemEventArgs e)
+        {
+            var command = VoiceMemo.Effects.ItemLongPressEffect.GetCommand(Element);
+            command?.Execute(VoiceMemo.Effects.ItemLongPressEffect.GetCommandParameter(Element));
+        }
+    }
+}
diff --git a/Test/Voicememo2020/VoiceMemo/EffectRenderers/TizenStyleEffect.cs b/Test/Voicememo2020/VoiceMemo/EffectRenderers/TizenStyleEffect.cs
new file mode 100755 (executable)
index 0000000..6ef8c60
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://floralicense.org/license/
+ *
+ * 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.ComponentModel;
+using VoiceMemo.EffectRenderers;
+using Xamarin.Forms;
+using Xamarin.Forms.Platform.Tizen;
+
+[assembly: ExportEffect(typeof(TizenStyleEffect), "TizenStyleEffect")]
+
+namespace VoiceMemo.EffectRenderers
+{
+    public class TizenStyleEffect : PlatformEffect
+    {
+        string oldStyle;
+
+        protected override void OnAttached()
+        {
+            DoSetStyle();
+        }
+
+        protected override void OnDetached()
+        {
+            var view = Control as ElmSharp.Widget;
+            if (view != null)
+            {
+                view.Style = oldStyle;
+            }
+        }
+
+        protected override void OnElementPropertyChanged(PropertyChangedEventArgs args)
+        {
+            base.OnElementPropertyChanged(args);
+            if (args.PropertyName == VoiceMemo.Effects.TizenStyleEffect.StyleProperty.PropertyName)
+            {
+                DoSetStyle();
+            }
+        }
+
+        void DoSetStyle()
+        {
+            var view = Control as ElmSharp.Widget;
+            if (view != null)
+            {
+                var style = VoiceMemo.Effects.TizenStyleEffect.GetStyle(Element);
+                oldStyle = view.Style;
+                view.Style = style;
+            }
+        }
+    }
+}
diff --git a/Test/Voicememo2020/VoiceMemo/Effects/ImageAttributes.cs b/Test/Voicememo2020/VoiceMemo/Effects/ImageAttributes.cs
new file mode 100755 (executable)
index 0000000..0f1ad9f
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://floralicense.org/license/
+ *
+ * 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.Collections.Generic;
+using Xamarin.Forms;
+
+namespace VoiceMemo.Effects
+{
+    public static class ImageAttributes
+    {
+        public static readonly BindableProperty BlendColorProperty = BindableProperty.CreateAttached("BlendColor", typeof(Color), typeof(ImageAttributes), Color.Default, propertyChanged: OnBlendColorPropertyChanged);
+        /// <summary>
+        /// Get blending color
+        /// </summary>
+        /// <param name="element">Image object</param>
+        /// <returns>Color</returns>
+        public static Color GetBlendColor(BindableObject element)
+        {
+            return (Color)element.GetValue(BlendColorProperty);
+        }
+
+        /// <summary>
+        /// Set blending color
+        /// </summary>
+        /// <param name="element">Image object</param>
+        /// <param name="color">Color</param>
+        public static void SetBlendColor(BindableObject element, Color color)
+        {
+            element.SetValue(BlendColorProperty, color);
+        }
+
+        static void OnBlendColorPropertyChanged(BindableObject bindable, object oldValue, object newValue)
+        {
+            InternalExtension.InternalPropertyChanged(bindable, BlendColorProperty, () => (Color)newValue == Color.Default, new List<Type> { typeof(Image) });
+        }
+    }
+}
diff --git a/Test/Voicememo2020/VoiceMemo/Effects/ImageBlendEffect.cs b/Test/Voicememo2020/VoiceMemo/Effects/ImageBlendEffect.cs
new file mode 100755 (executable)
index 0000000..8a622ec
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://floralicense.org/license/
+ *
+ * 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.Collections.Generic;
+using Xamarin.Forms;
+
+namespace VoiceMemo.Effects
+{
+    public class ImageBlendEffect : RoutingEffect
+    {
+        public static readonly BindableProperty BlendColorProperty =
+            BindableProperty.CreateAttached("Color", typeof(Color), typeof(ImageBlendEffect), Color.Default);
+
+        public static Color GetBlendColor(BindableObject element)
+        {
+            return (Color)element.GetValue(BlendColorProperty);
+        }
+
+        public static void SetBlendColor(BindableObject element, Color color)
+        {
+            element.SetValue(BlendColorProperty, color);
+        }
+
+        static void OnBlendColorPropertyChanged(BindableObject bindable, object oldValue, object newValue)
+        {
+            InternalExtension.InternalPropertyChanged(bindable, BlendColorProperty, () => (Color)newValue == Color.Default, new List<Type> { typeof(Image) });
+        }
+
+        public ImageBlendEffect() : base("SEC.BlendColorEffect")
+        {
+        }
+    }
+}
diff --git a/Test/Voicememo2020/VoiceMemo/Effects/InternalExtension.cs b/Test/Voicememo2020/VoiceMemo/Effects/InternalExtension.cs
new file mode 100755 (executable)
index 0000000..f53b3ae
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://floralicense.org/license/
+ *
+ * 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.Collections.Generic;
+using Xamarin.Forms;
+
+namespace VoiceMemo.Effects
+{
+    internal static class InternalExtension
+    {
+        internal static void InternalPropertyChanged(BindableObject bindable, BindableProperty property, Func<bool> removalConditionFunc, IList<Type> supportedTypes = null)
+        {
+            if (supportedTypes != null && !supportedTypes.Contains(bindable.GetType()))
+            {
+                return;
+            }
+
+            var element = bindable as Element;
+            string effectName = GetEffectName(property.PropertyName);
+            Effect toRemove = null;
+
+            foreach (var effect in element.Effects)
+            {
+                if (effect.ResolveId == effectName)
+                {
+                    toRemove = effect;
+                    break;
+                }
+            }
+
+            if (toRemove == null)
+            {
+                element.Effects.Add(Effect.Resolve(effectName));
+            }
+            else
+            {
+                if (removalConditionFunc())
+                {
+                    element.Effects.Remove(toRemove);
+                }
+            }
+        }
+
+        internal static string GetEffectName(string propertyName)
+        {
+            return string.Format("SEC.{0}Effect", propertyName);
+        }
+    }
+}
diff --git a/Test/Voicememo2020/VoiceMemo/Effects/ItemLongPressEffect.cs b/Test/Voicememo2020/VoiceMemo/Effects/ItemLongPressEffect.cs
new file mode 100755 (executable)
index 0000000..8d11a1a
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://floralicense.org/license/
+ *
+ * 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.Windows.Input;
+using Xamarin.Forms;
+
+namespace VoiceMemo.Effects
+{
+    /// <summary>
+    /// ItemLongPressEffect class
+    /// </summary>
+    public class ItemLongPressEffect : RoutingEffect
+    {
+        public static readonly BindableProperty CommandProperty = BindableProperty.CreateAttached("Command", typeof(ICommand), typeof(ItemLongPressEffect), null);
+        public static readonly BindableProperty CommandParameterProperty = BindableProperty.CreateAttached("CommandParameter", typeof(object), typeof(ItemLongPressEffect), null);
+
+        public static Command GetCommand(BindableObject view) => (Command)view.GetValue(CommandProperty);
+        public static void SetCommand(BindableObject view, ICommand value) => view.SetValue(CommandProperty, value);
+
+        public static object GetCommandParameter(BindableObject view) => view.GetValue(CommandParameterProperty);
+        public static void SetCommandParameter(BindableObject view, object value) => view.SetValue(CommandParameterProperty, value);
+
+        public ItemLongPressEffect() : base("SEC.ItemLongPressEffect")
+        {
+        }
+    }
+}
diff --git a/Test/Voicememo2020/VoiceMemo/Effects/TizenEventPropagationEffect.cs b/Test/Voicememo2020/VoiceMemo/Effects/TizenEventPropagationEffect.cs
new file mode 100755 (executable)
index 0000000..526551c
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://floralicense.org/license/
+ *
+ * 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;
+
+namespace VoiceMemo.Effects
+{
+    public class TizenEventPropagationEffect : RoutingEffect
+    {
+        public static BindableProperty EnablePropagationProperty = BindableProperty.CreateAttached("EnablePropagation", typeof(bool), typeof(TizenEventPropagationEffect), false);
+
+        public static bool GetEnablePropagation(BindableObject view) => (bool)view.GetValue(EnablePropagationProperty);
+        public static void SetEnablePropagation(BindableObject view, bool value) => view.SetValue(EnablePropagationProperty, value);
+
+        public TizenEventPropagationEffect() : base("SEC.TizenEventPropagationEffect")
+        {
+        }
+    }
+}
diff --git a/Test/Voicememo2020/VoiceMemo/Effects/TizenStyleEffect.cs b/Test/Voicememo2020/VoiceMemo/Effects/TizenStyleEffect.cs
new file mode 100755 (executable)
index 0000000..14c5d5d
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://floralicense.org/license/
+ *
+ * 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;
+
+namespace VoiceMemo.Effects
+{
+    public class TizenStyleEffect : RoutingEffect
+    {
+        public static readonly BindableProperty StyleProperty = BindableProperty.CreateAttached("Style", typeof(string), typeof(TizenStyleEffect), null);
+
+        public static string GetStyle(BindableObject velement) => (string)velement.GetValue(StyleProperty);
+        public static void SetStyle(BindableObject velement, string value) => velement.SetValue(StyleProperty, value);
+
+        public TizenStyleEffect() : base("SEC.TizenStyleEffect")
+        {
+        }
+    }
+}
diff --git a/Test/Voicememo2020/VoiceMemo/Effects/VisualAttributes.cs b/Test/Voicememo2020/VoiceMemo/Effects/VisualAttributes.cs
new file mode 100755 (executable)
index 0000000..298c1b5
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://floralicense.org/license/
+ *
+ * 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;
+
+namespace VoiceMemo.Effects
+{
+    public static class VisualAttributes
+    {
+        public static readonly BindableProperty ThemeStyleProperty = BindableProperty.CreateAttached("ThemeStyle", typeof(string), typeof(VisualAttributes), string.Empty, propertyChanged: OnThemeStylePropertyChanged);
+        public static readonly BindableProperty TooltipProperty = BindableProperty.CreateAttached("Tooltip", typeof(string), typeof(VisualAttributes), string.Empty, propertyChanged: OnTooltipPropertyChanged);
+
+        public static string GetThemeStyle(BindableObject element)
+        {
+            return (string)element.GetValue(ThemeStyleProperty);
+        }
+
+        public static void SetThemeStyle(BindableObject element, string themeStyle)
+        {
+            element.SetValue(ThemeStyleProperty, themeStyle);
+        }
+
+        public static string GetTooltip(BindableObject element)
+        {
+            return (string)element.GetValue(TooltipProperty);
+        }
+
+        public static void SetTooltip(BindableObject element, string tooltipText)
+        {
+            element.SetValue(TooltipProperty, tooltipText);
+        }
+
+        static void OnTooltipPropertyChanged(BindableObject bindable, object oldValue, object newValue)
+        {
+            InternalExtension.InternalPropertyChanged(bindable, TooltipProperty, () => (string)newValue == string.Empty);
+        }
+
+        static void OnThemeStylePropertyChanged(BindableObject bindable, object oldValue, object newValue)
+        {
+            InternalExtension.InternalPropertyChanged(bindable, ThemeStyleProperty, () => (string)newValue == string.Empty);
+        }
+    }
+}
diff --git a/Test/Voicememo2020/VoiceMemo/Interop/Interop.Libraries.cs b/Test/Voicememo2020/VoiceMemo/Interop/Interop.Libraries.cs
new file mode 100755 (executable)
index 0000000..1ea8a02
--- /dev/null
@@ -0,0 +1,14 @@
+using System;
+using System.Runtime.InteropServices;
+
+namespace VoiceMemo.Interop
+{
+    internal static partial class Interop
+    {
+        internal static partial class Libraries
+        {
+            internal const string Libc = "libc.so.6";
+        }
+    }
+}
+
diff --git a/Test/Voicememo2020/VoiceMemo/Interop/Interop.SystemCall.cs b/Test/Voicememo2020/VoiceMemo/Interop/Interop.SystemCall.cs
new file mode 100755 (executable)
index 0000000..60a0778
--- /dev/null
@@ -0,0 +1,25 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Runtime.InteropServices;
+using System.Text;
+
+namespace VoiceMemo.Interop
+{
+    internal static partial class Interop
+    {
+        internal static partial class SystemCall
+        {
+            [DllImport(Libraries.Libc, EntryPoint = "getenv")]
+            internal static extern IntPtr GetEnvInteral(string name);
+
+            internal static string GetEnv(string name)
+            {
+                return Marshal.PtrToStringAnsi(GetEnvInteral(name));
+            }
+
+            [DllImport(Libraries.Libc, EntryPoint = "setenv")]
+            internal static extern int SetEnv(string name, string value, int overwrite);
+        }
+    }
+}
diff --git a/Test/Voicememo2020/VoiceMemo/Models/LatestRecord.cs b/Test/Voicememo2020/VoiceMemo/Models/LatestRecord.cs
new file mode 100755 (executable)
index 0000000..6059375
--- /dev/null
@@ -0,0 +1,20 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace VoiceMemo.Models
+{
+    public class LatestRecord : Record
+    {
+        public Record Record
+        {
+            get;
+            set;
+        }
+
+        public LatestRecord(Record record) : base()
+        {
+            Record = record;
+        }
+    }
+}
diff --git a/Test/Voicememo2020/VoiceMemo/Models/Record.cs b/Test/Voicememo2020/VoiceMemo/Models/Record.cs
new file mode 100755 (executable)
index 0000000..945697a
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://floralicense.org/license/
+ *
+ * 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 SQLite;
+using System;
+using System.ComponentModel;
+using System.Runtime.CompilerServices;
+
+namespace VoiceMemo.Models
+{
+    /// <summary>
+    /// Record class
+    /// It presents information about voice recording file
+    /// </summary>
+    public class Record : INotifyPropertyChanged
+    {
+        [PrimaryKey, AutoIncrement]
+        public int ID { get; set; }
+        public int _id { get; set; }
+        // the title of audio file
+        public string Title { get; set; }
+        // the date of audio file creation
+        public string Date { get; set; }
+        // the duration of recorded file
+        public int Duration { get; set; }
+        // the file path
+        public string Path { get; set; }
+        // indicate that speech-to-text service is enabled or not when recording the audio file
+        public bool SttEnabled { get; set; }
+
+        string _Text;
+        // Text converted by Speech-to-text service
+        public string Text
+        {
+            get
+            {
+                return _Text;
+            }
+
+            set
+            {
+                SetProperty(ref _Text, value, "Text");
+            }
+        }
+
+        bool _Checked;
+        /// <summary>
+        /// Indicate that it's selected or not to delete
+        /// If it's true, it will be deleted.
+        /// It's not stored in database
+        /// </summary>
+        [Ignore]
+        public bool Checked
+        {
+            get { return _Checked; }
+            set
+            {
+                bool changed = SetProperty(ref _Checked, value, "Checked");
+                if (changed)
+                {
+                    //Console.WriteLine("Record.Checked : " + Checked + " --> CheckedNamesCount changed..");
+                    ((App)App.Current).mainPageModel.CheckedNamesCount += Checked ? 1 : -1;
+                }
+            }
+        }
+
+        public override string ToString()
+        {
+            return "Record[" + ID + "," + _id + "] " + Title + ", " + Path + ", " + Date + ", Stt(" + SttEnabled + ") " + "(" + Text + ")";
+        }
+
+        public event PropertyChangedEventHandler PropertyChanged;
+
+        protected bool SetProperty<T>(ref T storage, T value,
+                                      [CallerMemberName] string propertyName = null)
+        {
+            if (Object.Equals(storage, value))
+            {
+                return false;
+            }
+
+            storage = value;
+            OnPropertyChanged(propertyName);
+            return true;
+        }
+
+        /// <summary>
+        /// Called to notify that a change of property happened
+        /// </summary>
+        /// <param name="propertyName">The name of the property that changed</param>
+        protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
+        {
+            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
+        }
+    }
+}
diff --git a/Test/Voicememo2020/VoiceMemo/Models/SttLanguage.cs b/Test/Voicememo2020/VoiceMemo/Models/SttLanguage.cs
new file mode 100755 (executable)
index 0000000..fcb16f1
--- /dev/null
@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://floralicense.org/license/
+ *
+ * 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.ComponentModel;
+using System.Runtime.CompilerServices;
+
+namespace VoiceMemo.Models
+{
+    /// <summary>
+    /// Class SttLanguage
+    /// It presents language (locale) information for Speech-to-Text service
+    /// </summary>
+    public class SttLanguage : INotifyPropertyChanged
+    {
+        bool _isOn;
+        string _lang, _combo, _name, _country;
+
+        public SttLanguage(string lang, string name, string country)
+        {
+            Lang = lang;
+            Name = name;
+            Country = country;
+            Combo = name + "----" + country;
+            IsOn = false;
+        }
+
+        /// <summary>
+        /// Language
+        /// </summary>
+        public string Lang
+        {
+            set { SetProperty(ref _lang, value, "Lang"); }
+            get { return _lang; }
+        }
+
+        /// <summary>
+        /// combination of the full localized culture name and the full name of the country/region in English
+        /// It's used to figure out which language is selected for Speech-to-Text service 
+        /// </summary>
+        public string Combo
+        {
+            set { SetProperty(ref _combo, value, "Combo"); }
+            get { return _combo; }
+        }
+
+        /// <summary>
+        /// Name
+        /// It's CultureInfo.DisplayName property and the full localized culture name
+        /// </summary>
+        public string Name
+        {
+            set { SetProperty(ref _name, value, "Name"); }
+            get { return _name; }
+        }
+
+        /// <summary>
+        /// Country name
+        /// It's RegionInfo.EnglishName property and the full name of the country/region in English.
+        /// </summary>
+        public string Country
+        {
+            set
+            {
+                SetProperty(ref _country, value, "Country");
+            }
+
+            get { return _country; }
+        }
+
+        // Indicate that this language is set for Stt service.
+        public bool IsOn
+        {
+            get { return _isOn; }
+            set
+            {
+                SetProperty(ref _isOn, value, "IsOn");
+            }
+        }
+
+        public override string ToString()
+        {
+            return "SttLanguage Name:" + Name + ", Country:" + Country + ", IsOn: " + IsOn;
+        }
+
+        public event PropertyChangedEventHandler PropertyChanged;
+
+        protected bool SetProperty<T>(ref T storage, T value,
+                                      [CallerMemberName] string propertyName = null)
+        {
+            if (Object.Equals(storage, value))
+            {
+                return false;
+            }
+
+            storage = value;
+            OnPropertyChanged(propertyName);
+            return true;
+        }
+
+        /// <summary>
+        /// Called to notify that a change of property happened
+        /// </summary>
+        /// <param name="propertyName">The name of the property that changed</param>
+        protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
+        {
+            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
+        }
+    }
+}
diff --git a/Test/Voicememo2020/VoiceMemo/Renderers/GraphicPopUpRenderer.cs b/Test/Voicememo2020/VoiceMemo/Renderers/GraphicPopUpRenderer.cs
new file mode 100755 (executable)
index 0000000..363c8fb
--- /dev/null
@@ -0,0 +1,147 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://floralicense.org/license/
+ *
+ * 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 ElmSharp;
+using System;
+using VoiceMemo.Tizen.Wearable.Renderers;
+using VoiceMemo.Views;
+using Xamarin.Forms.Platform.Tizen;
+// @OLD VERSION OF XAMARIN.FORMS
+//using TForms = Xamarin.Forms.Platform.Tizen.Forms;
+using TForms = Xamarin.Forms.Forms;
+using XForms = Xamarin.Forms;
+
+namespace VoiceMemo.Tizen.Wearable.Renderers
+{
+    class GraphicPopUpRenderer : IGraphicPopup, IDisposable
+    {
+        Popup _popUp;
+        bool _isDisposed = false;
+        public event EventHandler BackButtonPressed;
+        public event EventHandler TimedOut;
+
+        public GraphicPopUpRenderer()
+        {
+            Console.WriteLine("GraphicPopUpRenderer()  GetHashCode:" + this.GetHashCode());
+            _popUp = new Popup(TForms.NativeParent)
+            {
+                Style = "toast/circle",
+                Orientation = PopupOrientation.Center,
+                AllowEvents = true,
+            };
+            var path = ResourcePath.GetPath("tw_ic_popup_btn_check.png");
+            var image = new Image(_popUp);
+            image.LoadAsync(path);
+            image.Show();
+            _popUp.SetPartContent("toast,icon", image);
+            _popUp.BackButtonPressed += BackButtonPressedHandler;
+            _popUp.TimedOut += TimedOutHandler;
+            _popUp.Dismissed += _popUp_Dismissed;
+        }
+
+        private void _popUp_Dismissed(object sender, EventArgs e)
+        {
+            Console.WriteLine("[GraphicPopUpRenderer._popUp_Dismissed] ");
+        }
+
+        private void TimedOutHandler(object sender, EventArgs e)
+        {
+            Console.WriteLine("[GraphicPopUpRenderer.TimedOutHandler] ");
+            TimedOut?.Invoke(this, EventArgs.Empty);
+            _popUp.Dismiss();
+        }
+
+        private void BackButtonPressedHandler(object sender, EventArgs e)
+        {
+            Console.WriteLine("[GraphicPopUpRenderer.BackButtonPressedHandler] ");
+            BackButtonPressed?.Invoke(this, EventArgs.Empty);
+            _popUp.Dismiss();
+        }
+
+        string _Text;
+        public string Text
+        {
+            get
+            {
+                return _Text;
+            }
+
+            set
+            {
+                if (_Text != value)
+                {
+                    _Text = value;
+                    Console.WriteLine("[GraphicPopUpRenderer--Update] Text (" + Text + ")");
+                    _popUp.SetPartText("elm.text", Text);
+                }
+            }
+        }
+
+        double _Duration;
+        public double Duration
+        {
+            get
+            {
+                return _Duration;
+            }
+
+            set
+            {
+                if (_Duration != value)
+                {
+                    _Duration = value;
+                    Console.WriteLine("[GraphicPopUpRenderer--Update] Duration (" + Duration + ")");
+                    _popUp.Timeout = Duration;
+                }
+            }
+        }
+
+
+        public void Dispose()
+        {
+            Dispose(true);
+            GC.SuppressFinalize(this);
+        }
+
+        protected virtual void Dispose(bool disposing)
+        {
+            if (_isDisposed)
+            {
+                return;
+            }
+
+            Console.WriteLine("[GraphicPopUpRenderer.Dispose] ");
+            if (disposing)
+            {
+                if (_popUp != null)
+                {
+                    _popUp.BackButtonPressed -= BackButtonPressedHandler;
+                    _popUp.TimedOut -= TimedOutHandler;
+                    _popUp.Unrealize();
+                    _popUp = null;
+                }
+            }
+
+            _isDisposed = true;
+        }
+
+        public void Show()
+        {
+            Console.WriteLine("[GraphicPopUpRenderer.Show] ");
+            _popUp.Show();
+        }
+    }
+}
diff --git a/Test/Voicememo2020/VoiceMemo/Renderers/ProgressbarPopupRenderer.cs b/Test/Voicememo2020/VoiceMemo/Renderers/ProgressbarPopupRenderer.cs
new file mode 100755 (executable)
index 0000000..2f6bca8
--- /dev/null
@@ -0,0 +1,258 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://floralicense.org/license/
+ *
+ * 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 ElmSharp;
+using System;
+using VoiceMemo.Views;
+using TForms = Xamarin.Forms.Forms;
+// @OLD VERSION OF XAMARIN.FORMS
+//using TForms = Xamarin.Forms.Platform.Tizen.Forms;
+
+namespace VoiceMemo.Tizen.Wearable.Renderers
+{
+    class ProgressbarPopupRenderer : IProgressbarPopup, IDisposable
+    {
+        Popup _popUp;
+        Popup _popUp2;
+        Layout _layout;
+        ProgressBar _progressbar;
+        bool _isDisposed = false;
+        public event EventHandler BackButtonPressed;
+        public event EventHandler TimedOut;
+
+        public ProgressbarPopupRenderer()
+        {
+            _popUp = new Popup(TForms.NativeParent)
+            {
+                Style = "circle",
+                Orientation = PopupOrientation.Center,
+            };
+            _popUp.BackButtonPressed += BackButtonPressedHandler;
+            _popUp.TimedOut += ProgressbarPopup_TimedOutHandler;
+            _popUp.Dismissed += _popUp_Dismissed;
+            _popUp.ShowAnimationFinished += _popUp_ShowAnimationFinished;
+
+            _layout = new Layout(_popUp);
+            _layout.SetTheme("layout", "popup", "content/circle");
+            _popUp.SetContent(_layout);
+
+            _progressbar = new ProgressBar(TForms.NativeParent)
+            {
+                Color = Color.FromRgb(77, 207, 255),
+                //BackgroundColor = Color.FromRgb(100, 255, 0),
+                //SpanSize = 50,
+                Style = "process",
+                IsPulseMode = true,
+            };
+            _progressbar.Deleted += _progressbar_Deleted;
+            _popUp.SetPartContent("elm.swallow.progress", _progressbar);
+
+            ///////////////
+            _popUp2 = new Popup(TForms.NativeParent)
+            {
+                Style = "toast/circle/check",
+                Orientation = PopupOrientation.Bottom,
+                //Timeout = Duration,
+            };
+            //_popUp2.SetPartText("elm.text", Text);
+            _popUp2.TimedOut += TimedOutHandler;
+            _popUp2.Dismissed += _popUp2_Dismissed;
+        }
+
+        private void _popUp_ShowAnimationFinished(object sender, EventArgs e)
+        {
+            Console.WriteLine("[ProgressbarPopupRenderer._popUp_ShowAnimationFinished] ");
+        }
+
+        private void _popUp_Resized(object sender, EventArgs e)
+        {
+            Console.WriteLine("[ProgressbarPopupRenderer._popUp_Resized] ");
+        }
+
+        private void _popUp_RenderPost(object sender, EventArgs e)
+        {
+            Console.WriteLine("[ProgressbarPopupRenderer._popUp_RenderPost] ");
+        }
+
+        private void _popUp_Moved(object sender, EventArgs e)
+        {
+            Console.WriteLine("[ProgressbarPopupRenderer._popUp_Moved] ");
+        }
+
+        private void _popUp2_Dismissed(object sender, EventArgs e)
+        {
+            Console.WriteLine("[ProgressbarPopupRenderer._popUp2_Dismissed] ");
+        }
+
+        private void _popUp_Dismissed(object sender, EventArgs e)
+        {
+            Console.WriteLine("[ProgressbarPopupRenderer._popUp_Dismissed] ");
+        }
+
+        /// <summary>
+        /// Invoked when progressbar is removed from Popup
+        /// </summary>
+        /// <param name="sender">sender object</param>
+        /// <param name="e">EventArgs</param>
+        private void _progressbar_Deleted(object sender, EventArgs e)
+        {
+            Console.WriteLine("[ProgressbarPopupRenderer._progressbar_Deleted] ");
+            _popUp2.Show();
+        }
+
+        private void ProgressbarPopup_TimedOutHandler(object sender, EventArgs e)
+        {
+            Console.WriteLine("[ProgressbarPopupRenderer.ProgressbarPopup_TimedOutHandler] ");
+            // Remove Progressbar from Popup when doing progressbar is done
+            _popUp.SetPartContent("elm.swallow.progress", null);
+        }
+
+        private void TimedOutHandler(object sender, EventArgs e)
+        {
+            Console.WriteLine("[ProgressbarPopupRenderer.TimedOutHandler] 0");
+            TimedOut?.Invoke(this, EventArgs.Empty);
+            _popUp.Dismiss();
+        }
+
+        private void BackButtonPressedHandler(object sender, EventArgs e)
+        {
+            Console.WriteLine("[ProgressbarPopupRenderer.BackButtonPressedHandler] ");
+            BackButtonPressed?.Invoke(this, EventArgs.Empty);
+            _popUp.Dismiss();
+        }
+
+        string _Text;
+        public string Text
+        {
+            get
+            {
+                return _Text;
+            }
+
+            set
+            {
+                if (_Text != value)
+                {
+                    _Text = value;
+                    Console.WriteLine("[Update] Text (" + _Text + ")");
+                    _popUp2.SetPartText("elm.text", _Text);
+                }
+            }
+        }
+
+        double _Duration;
+        public double Duration
+        {
+            get
+            {
+                return _Duration;
+            }
+
+            set
+            {
+                if (_Duration != value)
+                {
+                    _Duration = value;
+                    Console.WriteLine("[Update] Duration (" + Duration + ")");
+                    _popUp2.Timeout = _Duration;
+                }
+            }
+        }
+
+        string _ProgressbarText;
+        public string ProgressbarText
+        {
+            get
+            {
+                return _ProgressbarText;
+            }
+
+            set
+            {
+                if (_ProgressbarText != value)
+                {
+                    _ProgressbarText = value;
+                    Console.WriteLine("[Update & Apply] ProgressbarText (" + _ProgressbarText + ")");
+                    _layout.SetPartText("elm.text", _ProgressbarText);
+                }
+            }
+        }
+
+        double _ProgressbarDuration;
+        public double ProgressbarDuration
+        {
+            get
+            {
+                return _ProgressbarDuration;
+            }
+
+            set
+            {
+                if (_ProgressbarDuration != value)
+                {
+                    _ProgressbarDuration = value;
+                    Console.WriteLine("[Update & Apply] ProgressbarDuration (" + _ProgressbarDuration + ")");
+                    _popUp.Timeout = _ProgressbarDuration;
+                }
+            }
+        }
+
+        public void Dispose()
+        {
+            Dispose(true);
+            GC.SuppressFinalize(this);
+        }
+
+        protected virtual void Dispose(bool disposing)
+        {
+            if (_isDisposed)
+            {
+                return;
+            }
+
+            Console.WriteLine("[ProgressbarPopupRenderer.Dispose] ");
+            if (disposing)
+            {
+                if (_popUp != null)
+                {
+                    _layout.Unrealize();
+                    _layout = null;
+                    _popUp.BackButtonPressed -= BackButtonPressedHandler;
+                    _popUp.TimedOut -= TimedOutHandler;
+                    _popUp.Unrealize();
+                    _popUp = null;
+                }
+
+                if (_popUp2 != null)
+                {
+                    _popUp2.TimedOut -= TimedOutHandler;
+                    _popUp2.Unrealize();
+                    _popUp2 = null;
+                }
+            }
+
+            _isDisposed = true;
+        }
+
+        public void Show()
+        {
+            Console.WriteLine("[ProgressbarPopupRenderer.Show] ");
+            _progressbar.Value = 0;
+            _popUp.Show();
+            _progressbar.PlayPulse();
+        }
+    }
+}
diff --git a/Test/Voicememo2020/VoiceMemo/Resx/AppResources.Designer.cs b/Test/Voicememo2020/VoiceMemo/Resx/AppResources.Designer.cs
new file mode 100755 (executable)
index 0000000..0c96117
--- /dev/null
@@ -0,0 +1,180 @@
+//------------------------------------------------------------------------------
+// <auto-generated>
+//     This code was generated by a tool.
+//     Runtime Version:4.0.30319.42000
+//
+//     Changes to this file may cause incorrect behavior and will be lost if
+//     the code is regenerated.
+// </auto-generated>
+//------------------------------------------------------------------------------
+
+namespace VoiceMemo.Resx {
+    using System;
+    
+    
+    /// <summary>
+    ///   A strongly-typed resource class, for looking up localized strings, etc.
+    /// </summary>
+    // This class was auto-generated by the StronglyTypedResourceBuilder
+    // class via a tool like ResGen or Visual Studio.
+    // To add or remove a member, edit your .ResX file then rerun ResGen
+    // with the /str option, or rebuild your VS project.
+    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")]
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+    [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+    public class AppResources {
+        
+        private static global::System.Resources.ResourceManager resourceMan;
+        
+        private static global::System.Globalization.CultureInfo resourceCulture;
+        
+        [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+        internal AppResources() {
+        }
+        
+        /// <summary>
+        ///   Returns the cached ResourceManager instance used by this class.
+        /// </summary>
+        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+        public static global::System.Resources.ResourceManager ResourceManager {
+            get {
+                if (object.ReferenceEquals(resourceMan, null)) {
+                    global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("VoiceMemo.Resx.AppResources", typeof(AppResources).Assembly);
+                    resourceMan = temp;
+                }
+                return resourceMan;
+            }
+        }
+        
+        /// <summary>
+        ///   Overrides the current thread's CurrentUICulture property for all
+        ///   resource lookups using this strongly typed resource class.
+        /// </summary>
+        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+        public static global::System.Globalization.CultureInfo Culture {
+            get {
+                return resourceCulture;
+            }
+            set {
+                resourceCulture = value;
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Recording will be cancelled..
+        /// </summary>
+        public static string CancelRecording {
+            get {
+                return ResourceManager.GetString("CancelRecording", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to DELETE.
+        /// </summary>
+        public static string DELETE {
+            get {
+                return ResourceManager.GetString("DELETE", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Deleted..
+        /// </summary>
+        public static string Deleted {
+            get {
+                return ResourceManager.GetString("Deleted", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Deleting....
+        /// </summary>
+        public static string Deleting {
+            get {
+                return ResourceManager.GetString("Deleting", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Languages.
+        /// </summary>
+        public static string Languages {
+            get {
+                return ResourceManager.GetString("Languages", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to No Recordings.
+        /// </summary>
+        public static string NoRecordings {
+            get {
+                return ResourceManager.GetString("NoRecordings", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Recognition failed.
+        /// </summary>
+        public static string RecognitionFailed {
+            get {
+                return ResourceManager.GetString("RecognitionFailed", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Recordings.
+        /// </summary>
+        public static string Recordings {
+            get {
+                return ResourceManager.GetString("Recordings", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Speech-to-text:.
+        /// </summary>
+        public static string SpeechToText {
+            get {
+                return ResourceManager.GetString("SpeechToText", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Voice memo.
+        /// </summary>
+        public static string StandByTitleMemo {
+            get {
+                return ResourceManager.GetString("StandByTitleMemo", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Voice recorder.
+        /// </summary>
+        public static string StandByTitleRecorder {
+            get {
+                return ResourceManager.GetString("StandByTitleRecorder", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Off.
+        /// </summary>
+        public static string SttOff {
+            get {
+                return ResourceManager.GetString("SttOff", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to On.
+        /// </summary>
+        public static string SttOn {
+            get {
+                return ResourceManager.GetString("SttOn", resourceCulture);
+            }
+        }
+    }
+}
diff --git a/Test/Voicememo2020/VoiceMemo/Resx/AppResources.hi.resx b/Test/Voicememo2020/VoiceMemo/Resx/AppResources.hi.resx
new file mode 100755 (executable)
index 0000000..5c868e2
--- /dev/null
@@ -0,0 +1,159 @@
+<?xml version="1.0" encoding="utf-8"?>
+<root>
+  <!-- 
+    Microsoft ResX Schema 
+    
+    Version 2.0
+    
+    The primary goals of this format is to allow a simple XML format 
+    that is mostly human readable. The generation and parsing of the 
+    various data types are done through the TypeConverter classes 
+    associated with the data types.
+    
+    Example:
+    
+    ... ado.net/XML headers & schema ...
+    <resheader name="resmimetype">text/microsoft-resx</resheader>
+    <resheader name="version">2.0</resheader>
+    <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
+    <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
+    <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
+    <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
+    <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
+        <value>[base64 mime encoded serialized .NET Framework object]</value>
+    </data>
+    <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
+        <comment>This is a comment</comment>
+    </data>
+                
+    There are any number of "resheader" rows that contain simple 
+    name/value pairs.
+    
+    Each data row contains a name, and value. The row also contains a 
+    type or mimetype. Type corresponds to a .NET class that support 
+    text/value conversion through the TypeConverter architecture. 
+    Classes that don't support this are serialized and stored with the 
+    mimetype set.
+    
+    The mimetype is used for serialized objects, and tells the 
+    ResXResourceReader how to depersist the object. This is currently not 
+    extensible. For a given mimetype the value must be set accordingly:
+    
+    Note - application/x-microsoft.net.object.binary.base64 is the format 
+    that the ResXResourceWriter will generate, however the reader can 
+    read any of the formats listed below.
+    
+    mimetype: application/x-microsoft.net.object.binary.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
+            : and then encoded with base64 encoding.
+    
+    mimetype: application/x-microsoft.net.object.soap.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
+            : and then encoded with base64 encoding.
+
+    mimetype: application/x-microsoft.net.object.bytearray.base64
+    value   : The object must be serialized into a byte array 
+            : using a System.ComponentModel.TypeConverter
+            : and then encoded with base64 encoding.
+    -->
+  <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+    <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
+    <xsd:element name="root" msdata:IsDataSet="true">
+      <xsd:complexType>
+        <xsd:choice maxOccurs="unbounded">
+          <xsd:element name="metadata">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" />
+              </xsd:sequence>
+              <xsd:attribute name="name" use="required" type="xsd:string" />
+              <xsd:attribute name="type" type="xsd:string" />
+              <xsd:attribute name="mimetype" type="xsd:string" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="assembly">
+            <xsd:complexType>
+              <xsd:attribute name="alias" type="xsd:string" />
+              <xsd:attribute name="name" type="xsd:string" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="data">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
+              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="resheader">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" />
+            </xsd:complexType>
+          </xsd:element>
+        </xsd:choice>
+      </xsd:complexType>
+    </xsd:element>
+  </xsd:schema>
+  <resheader name="resmimetype">
+    <value>text/microsoft-resx</value>
+  </resheader>
+  <resheader name="version">
+    <value>2.0</value>
+  </resheader>
+  <resheader name="reader">
+    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <resheader name="writer">
+    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <data name="CancelRecording" xml:space="preserve">
+    <value>रिकॉर्डिंग रद्द की जाएगी।</value>
+  </data>
+  <data name="DELETE" xml:space="preserve">
+    <value>हटाएँ</value>
+  </data>
+  <data name="Deleted" xml:space="preserve">
+    <value>हटाया गया।</value>
+  </data>
+  <data name="Deleting" xml:space="preserve">
+    <value>हटाया जा रहा है...</value>
+  </data>
+  <data name="Languages" xml:space="preserve">
+    <value>भाषा</value>
+  </data>
+  <data name="NoRecordings" xml:space="preserve">
+    <value>कोई रिकॉर्डिंग्स नहीं हैं</value>
+  </data>
+  <data name="RecognitionFailed" xml:space="preserve">
+    <value>पहचान विफल रही</value>
+  </data>
+  <data name="Recordings" xml:space="preserve">
+    <value>रिकॉर्डिंग्‍स</value>
+  </data>
+  <data name="SpeechToText" xml:space="preserve">
+    <value>स्पीच-टू-टेक्‍स्‍ट:</value>
+  </data>
+  <data name="StandByTitleMemo" xml:space="preserve">
+    <value>वॉइस मेमो</value>
+  </data>
+  <data name="StandByTitleRecorder" xml:space="preserve">
+    <value>वॉइस रिकॉर्डर</value>
+  </data>
+  <data name="SttOff" xml:space="preserve">
+    <value>बंद</value>
+  </data>
+  <data name="SttOn" xml:space="preserve">
+    <value>चालू</value>
+  </data>
+</root>
\ No newline at end of file
diff --git a/Test/Voicememo2020/VoiceMemo/Resx/AppResources.ko.resx b/Test/Voicememo2020/VoiceMemo/Resx/AppResources.ko.resx
new file mode 100755 (executable)
index 0000000..3435ce2
--- /dev/null
@@ -0,0 +1,159 @@
+<?xml version="1.0" encoding="utf-8"?>
+<root>
+  <!-- 
+    Microsoft ResX Schema 
+    
+    Version 2.0
+    
+    The primary goals of this format is to allow a simple XML format 
+    that is mostly human readable. The generation and parsing of the 
+    various data types are done through the TypeConverter classes 
+    associated with the data types.
+    
+    Example:
+    
+    ... ado.net/XML headers & schema ...
+    <resheader name="resmimetype">text/microsoft-resx</resheader>
+    <resheader name="version">2.0</resheader>
+    <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
+    <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
+    <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
+    <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
+    <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
+        <value>[base64 mime encoded serialized .NET Framework object]</value>
+    </data>
+    <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
+        <comment>This is a comment</comment>
+    </data>
+                
+    There are any number of "resheader" rows that contain simple 
+    name/value pairs.
+    
+    Each data row contains a name, and value. The row also contains a 
+    type or mimetype. Type corresponds to a .NET class that support 
+    text/value conversion through the TypeConverter architecture. 
+    Classes that don't support this are serialized and stored with the 
+    mimetype set.
+    
+    The mimetype is used for serialized objects, and tells the 
+    ResXResourceReader how to depersist the object. This is currently not 
+    extensible. For a given mimetype the value must be set accordingly:
+    
+    Note - application/x-microsoft.net.object.binary.base64 is the format 
+    that the ResXResourceWriter will generate, however the reader can 
+    read any of the formats listed below.
+    
+    mimetype: application/x-microsoft.net.object.binary.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
+            : and then encoded with base64 encoding.
+    
+    mimetype: application/x-microsoft.net.object.soap.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
+            : and then encoded with base64 encoding.
+
+    mimetype: application/x-microsoft.net.object.bytearray.base64
+    value   : The object must be serialized into a byte array 
+            : using a System.ComponentModel.TypeConverter
+            : and then encoded with base64 encoding.
+    -->
+  <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+    <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
+    <xsd:element name="root" msdata:IsDataSet="true">
+      <xsd:complexType>
+        <xsd:choice maxOccurs="unbounded">
+          <xsd:element name="metadata">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" />
+              </xsd:sequence>
+              <xsd:attribute name="name" use="required" type="xsd:string" />
+              <xsd:attribute name="type" type="xsd:string" />
+              <xsd:attribute name="mimetype" type="xsd:string" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="assembly">
+            <xsd:complexType>
+              <xsd:attribute name="alias" type="xsd:string" />
+              <xsd:attribute name="name" type="xsd:string" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="data">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
+              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="resheader">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" />
+            </xsd:complexType>
+          </xsd:element>
+        </xsd:choice>
+      </xsd:complexType>
+    </xsd:element>
+  </xsd:schema>
+  <resheader name="resmimetype">
+    <value>text/microsoft-resx</value>
+  </resheader>
+  <resheader name="version">
+    <value>2.0</value>
+  </resheader>
+  <resheader name="reader">
+    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <resheader name="writer">
+    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <data name="CancelRecording" xml:space="preserve">
+    <value>녹음을 취소합니다.</value>
+  </data>
+  <data name="DELETE" xml:space="preserve">
+    <value>삭제</value>
+  </data>
+  <data name="Deleted" xml:space="preserve">
+    <value>삭제했습니다.</value>
+  </data>
+  <data name="Deleting" xml:space="preserve">
+    <value>삭제 중...</value>
+  </data>
+  <data name="Languages" xml:space="preserve">
+    <value>언어</value>
+  </data>
+  <data name="NoRecordings" xml:space="preserve">
+    <value>녹음 파일 없음</value>
+  </data>
+  <data name="RecognitionFailed" xml:space="preserve">
+    <value>인식하지 못했습니다</value>
+  </data>
+  <data name="Recordings" xml:space="preserve">
+    <value>녹음 목록</value>
+  </data>
+  <data name="SpeechToText" xml:space="preserve">
+    <value>음성을 문자로 변환:</value>
+  </data>
+  <data name="StandByTitleMemo" xml:space="preserve">
+    <value>음성 메모</value>
+  </data>
+  <data name="StandByTitleRecorder" xml:space="preserve">
+    <value>음성 녹음</value>
+  </data>
+  <data name="SttOff" xml:space="preserve">
+    <value>사용 안 함</value>
+  </data>
+  <data name="SttOn" xml:space="preserve">
+    <value>사용 중</value>
+  </data>
+</root>
\ No newline at end of file
diff --git a/Test/Voicememo2020/VoiceMemo/Resx/AppResources.resx b/Test/Voicememo2020/VoiceMemo/Resx/AppResources.resx
new file mode 100755 (executable)
index 0000000..2bde49c
--- /dev/null
@@ -0,0 +1,160 @@
+<?xml version="1.0" encoding="utf-8"?>
+<root>
+  <!-- 
+    Microsoft ResX Schema 
+    
+    Version 2.0
+    
+    The primary goals of this format is to allow a simple XML format 
+    that is mostly human readable. The generation and parsing of the 
+    various data types are done through the TypeConverter classes 
+    associated with the data types.
+    
+    Example:
+    
+    ... ado.net/XML headers & schema ...
+    <resheader name="resmimetype">text/microsoft-resx</resheader>
+    <resheader name="version">2.0</resheader>
+    <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
+    <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
+    <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
+    <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
+    <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
+        <value>[base64 mime encoded serialized .NET Framework object]</value>
+    </data>
+    <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
+        <comment>This is a comment</comment>
+    </data>
+                
+    There are any number of "resheader" rows that contain simple 
+    name/value pairs.
+    
+    Each data row contains a name, and value. The row also contains a 
+    type or mimetype. Type corresponds to a .NET class that support 
+    text/value conversion through the TypeConverter architecture. 
+    Classes that don't support this are serialized and stored with the 
+    mimetype set.
+    
+    The mimetype is used for serialized objects, and tells the 
+    ResXResourceReader how to depersist the object. This is currently not 
+    extensible. For a given mimetype the value must be set accordingly:
+    
+    Note - application/x-microsoft.net.object.binary.base64 is the format 
+    that the ResXResourceWriter will generate, however the reader can 
+    read any of the formats listed below.
+    
+    mimetype: application/x-microsoft.net.object.binary.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
+            : and then encoded with base64 encoding.
+    
+    mimetype: application/x-microsoft.net.object.soap.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
+            : and then encoded with base64 encoding.
+
+    mimetype: application/x-microsoft.net.object.bytearray.base64
+    value   : The object must be serialized into a byte array 
+            : using a System.ComponentModel.TypeConverter
+            : and then encoded with base64 encoding.
+    -->
+  <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+    <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
+    <xsd:element name="root" msdata:IsDataSet="true">
+      <xsd:complexType>
+        <xsd:choice maxOccurs="unbounded">
+          <xsd:element name="metadata">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" />
+              </xsd:sequence>
+              <xsd:attribute name="name" use="required" type="xsd:string" />
+              <xsd:attribute name="type" type="xsd:string" />
+              <xsd:attribute name="mimetype" type="xsd:string" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="assembly">
+            <xsd:complexType>
+              <xsd:attribute name="alias" type="xsd:string" />
+              <xsd:attribute name="name" type="xsd:string" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="data">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
+              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="resheader">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" />
+            </xsd:complexType>
+          </xsd:element>
+        </xsd:choice>
+      </xsd:complexType>
+    </xsd:element>
+  </xsd:schema>
+  <resheader name="resmimetype">
+    <value>text/microsoft-resx</value>
+  </resheader>
+  <resheader name="version">
+    <value>2.0</value>
+  </resheader>
+  <resheader name="reader">
+    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <resheader name="writer">
+    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <data name="CancelRecording" xml:space="preserve">
+    <value>Recording will be cancelled.</value>
+  </data>
+  <data name="DELETE" xml:space="preserve">
+    <value>DELETE</value>
+  </data>
+  <data name="Deleted" xml:space="preserve">
+    <value>Deleted.</value>
+    <comment>.</comment>
+  </data>
+  <data name="Deleting" xml:space="preserve">
+    <value>Deleting...</value>
+  </data>
+  <data name="Languages" xml:space="preserve">
+    <value>Languages</value>
+  </data>
+  <data name="NoRecordings" xml:space="preserve">
+    <value>No Recordings</value>
+  </data>
+  <data name="RecognitionFailed" xml:space="preserve">
+    <value>Recognition failed</value>
+  </data>
+  <data name="Recordings" xml:space="preserve">
+    <value>Recordings</value>
+  </data>
+  <data name="SpeechToText" xml:space="preserve">
+    <value>Speech-to-text:</value>
+  </data>
+  <data name="StandByTitleMemo" xml:space="preserve">
+    <value>Voice memo</value>
+  </data>
+  <data name="StandByTitleRecorder" xml:space="preserve">
+    <value>Voice recorder</value>
+  </data>
+  <data name="SttOff" xml:space="preserve">
+    <value>Off</value>
+  </data>
+  <data name="SttOn" xml:space="preserve">
+    <value>On</value>
+  </data>
+</root>
\ No newline at end of file
diff --git a/Test/Voicememo2020/VoiceMemo/Services/AppDataService.cs b/Test/Voicememo2020/VoiceMemo/Services/AppDataService.cs
new file mode 100755 (executable)
index 0000000..7acbf11
--- /dev/null
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://floralicense.org/license/
+ *
+ * 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 Tizen.Applications;
+
+
+namespace VoiceMemo.Services
+{
+    class AppDataService
+    {
+        private static readonly Lazy<AppDataService> instance = new Lazy<AppDataService>(() => new AppDataService());
+        public static AppDataService Instance
+        {
+            get => instance.Value;
+        }
+
+        readonly object _locker;
+        private AppDataService()
+        {
+            _locker = new object();
+        }
+
+        /// <summary>
+        /// Check if the specified key exists or not
+        /// </summary>
+        /// <param name="key">key string</param>
+        /// <returns>true if it exists</returns>
+        public bool Contain(string key)
+        {
+            return Preference.Contains(key);
+        }
+        /// <summary>
+        /// Get value for the specific key
+        /// </summary>
+        /// <param name="key">key string</param>
+        /// <returns>value string</returns>
+        public string GetValue(string key)
+        {
+            lock (_locker)
+            {
+                try
+                {
+                    return Preference.Get<string>(key);
+                }
+                catch (Exception ex)
+                {
+                    Console.WriteLine("[Preference.GetValue] key : " + key + ", exception:" + ex.Message);
+                    return null;
+                }
+            }
+        }
+        /// <summary>
+        /// Set key-value pair
+        /// </summary>
+        /// <param name="key">key to save</param>
+        /// <param name="value">value to save</param>
+        public void SetValue(string key, string value)
+        {
+            lock (_locker)
+            {
+                try
+                {
+                    Preference.Set(key, value);
+                }
+                catch (Exception ex)
+                {
+                    Console.WriteLine("[Preference.SetValue] key : " + key + ", exception:" + ex.Message);
+                }
+            }
+        }
+
+        public T GetValue<T>(string key)
+        {
+            object result = null;
+            lock (_locker)
+            {
+                try
+                {
+                    if (typeof(T) == typeof(bool))
+                    {
+                        result = Preference.Get<bool>(key);
+                    }
+                    else if (typeof(T) == typeof(int))
+                    {
+                        result = Preference.Get<int>(key);
+                    }
+                    else if (typeof(T) == typeof(double))
+                    {
+                        result = Preference.Get<double>(key);
+                    }
+                    else if (typeof(T) == typeof(string))
+                    {
+                        result = Preference.Get<string>(key);
+                    }
+                }
+                catch (Exception ex)
+                {
+                    Console.WriteLine("[Preference.GetValue] key : " + key + ", exception:" + ex.Message);
+                }
+            }
+
+            return (result != null) ? (T)result : default(T);
+        }
+
+        /// <summary>
+        /// Set key-value pair
+        /// </summary>
+        /// <param name="key">key to save</param>
+        /// <param name="value">value to save</param>
+        public void SetValue(string key, object value)
+        {
+            lock (_locker)
+            {
+                try
+                {
+                    Preference.Set(key, value);
+                }
+                catch (Exception ex)
+                {
+                    Console.WriteLine("[Preference.SetValue] key : " + key + ", exception:" + ex.Message);
+                }
+            }
+        }
+    }
+}
diff --git a/Test/Voicememo2020/VoiceMemo/Services/AppTerminator.cs b/Test/Voicememo2020/VoiceMemo/Services/AppTerminator.cs
new file mode 100755 (executable)
index 0000000..a372283
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://floralicense.org/license/
+ *
+ * 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 Native = Tizen.Applications;
+using VoiceMemo.Services;
+//using VoiceMemo.Tizen.Wearable.Services;
+using Xamarin.Forms;
+
+
+namespace VoiceMemo.Services
+{
+    /// <summary>
+    /// class AppTerminator
+    /// It provides a way to kill this application
+    /// </summary>
+    class AppTerminator
+    {
+        public AppTerminator()
+        {
+        }
+
+        /// <summary>
+        /// Terminate the the current application.
+        /// </summary>
+        public void TerminateApp()
+        {
+            Native.Application.Current.Exit();
+        }
+    }
+}
diff --git a/Test/Voicememo2020/VoiceMemo/Services/AudioPlayService.cs b/Test/Voicememo2020/VoiceMemo/Services/AudioPlayService.cs
new file mode 100755 (executable)
index 0000000..0f28fa8
--- /dev/null
@@ -0,0 +1,331 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://floralicense.org/license/
+ *
+ * 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.Threading.Tasks;
+using Tizen.Multimedia;
+using VoiceMemo.ViewModels;
+using Xamarin.Forms;
+
+namespace VoiceMemo.Services
+{
+    /// <summary>
+    /// AudioPlayerService
+    /// The main role is playing the recorded voice memo.
+    /// Use Tizen.Multimedia.Player
+    /// </summary>
+    class AudioPlayService
+    {
+        private static readonly Lazy<AudioPlayService> instance = new Lazy<AudioPlayService>(() => new AudioPlayService());
+        public static AudioPlayService Instance
+        {
+            get => instance.Value;
+        }
+        // Constructor
+        private AudioPlayService()
+        {
+            if (audioVolume == null)
+            {
+                audioVolume = AudioManager.VolumeController;
+                _state = AudioPlayState.Init;
+            }
+
+            // Create a player
+            if (player == null)
+            {
+                player = new Player();
+                if (player.State == PlayerState.Idle)
+                {
+                    _state = StateConvert(player.State);
+                    MessagingCenter.Send<AudioPlayService, AudioPlayState>(this, MessageKeys.PlayerStateChanged, StateConvert(player.State));
+                }
+
+                player.Volume = (float)Volume / GetMaxVolume();
+                player.PlaybackCompleted += Player_PlaybackCompleted;
+                player.PlaybackInterrupted += Player_PlaybackInterrupted;
+                player.ErrorOccurred += Player_ErrorOccurred;
+            }
+
+            if (player.State == PlayerState.Ready)
+            {
+                _state = StateConvert(player.State);
+                MessagingCenter.Send<AudioPlayService, AudioPlayState>(this, MessageKeys.PlayerStateChanged, StateConvert(player.State));
+            }
+        }
+
+        /// <summary>
+        /// Initialize Player
+        /// When PlaybackPage is shown, 
+        /// </summary>
+        /// <param name="path">audio file path to play</param>
+        /// <returns>Task</returns>
+        async public Task Init(string path)
+        {
+            player.SetSource(new MediaUriSource(path));
+            await Task.Run(() => player.PrepareAsync());
+            Start();
+        }
+
+        AudioVolume audioVolume;
+        Player player;
+        AudioPlayState _state;
+        /// <summary>
+        /// The state of audio play
+        /// </summary>
+        public AudioPlayState State
+        {
+            get
+            {
+                return _state;
+            }
+        }
+
+        // Indicate that Mute is on or off
+        public bool Muted
+        {
+            get { return player.Muted; }
+            set
+            {
+                if (player.Muted != value)
+                {
+                    player.Muted = value;
+                }
+            }
+        }
+        /// <summary>
+        /// Media volume
+        /// </summary>
+        public int Volume
+        {
+            get
+            {
+                return audioVolume.Level[AudioVolumeType.Media];
+            }
+        }
+        /// <summary>
+        /// Make volume level up
+        /// </summary>
+        public void IncreaseVolume()
+        {
+            // if volume level is already max, ignore it.
+            if (audioVolume.Level[AudioVolumeType.Media] == audioVolume.MaxLevel[AudioVolumeType.Media])
+            {
+                return;
+            }
+
+            AudioManager.VolumeController.Level[AudioVolumeType.Media] = AudioManager.VolumeController.Level[AudioVolumeType.Media] + 1;
+        }
+        /// <summary>
+        /// Make volume level down
+        /// </summary>
+        public void DecreaseVolume()
+        {
+            // ignore when volume level has already reached zero
+            if (audioVolume.Level[AudioVolumeType.Media] == 0)
+            {
+                return;
+            }
+
+            AudioManager.VolumeController.Level[AudioVolumeType.Media] = AudioManager.VolumeController.Level[AudioVolumeType.Media] - 1;
+        }
+        /// <summary>
+        /// Get the maximum volume value
+        /// </summary>
+        /// <returns>maximum volume value</returns>
+        public int GetMaxVolume()
+        {
+            return audioVolume.MaxLevel[AudioVolumeType.Media];
+        }
+        /// <summary>
+        /// Register callback to get notified when the volume has been changed
+        /// </summary>
+        public void RegisterVolumeChangedCallback()
+        {
+            audioVolume.Changed += AudioVolume_Changed;
+        }
+        // <summary>
+        /// Unregister callback to get notified when the volume has been changed
+        /// </summary>
+        public void UnregisterVolumeChangedCallback()
+        {
+            audioVolume.Changed -= AudioVolume_Changed;
+        }
+        /// <summary>
+        /// Start to play voice audio file
+        /// </summary>
+        public void Start()
+        {
+            if (player.State == PlayerState.Ready || player.State == PlayerState.Paused)
+            {
+                // Player's state will be "Playing"
+                player.Start();
+                if (player.State == PlayerState.Playing)
+                {
+                    _state = StateConvert(player.State);
+                    MessagingCenter.Send<AudioPlayService, AudioPlayState>(this, MessageKeys.PlayerStateChanged, StateConvert(player.State));
+                }
+            }
+        }
+        /// <summary>
+        /// Pause to play audio file
+        /// </summary>
+        public void Pause()
+        {
+            if (player.State == PlayerState.Playing)
+            {
+                // Player's state will be "Paused"
+                player.Pause();
+                if (player.State == PlayerState.Paused)
+                {
+                    _state = StateConvert(player.State);
+                    MessagingCenter.Send<AudioPlayService, AudioPlayState>(this, MessageKeys.PlayerStateChanged, StateConvert(player.State));
+                }
+
+                Console.WriteLine(" AudioPlayService.Pause() : ", (player.State != PlayerState.Paused) ? "Failed to Pause()" : "Successfully finish to Pause()");
+            }
+        }
+
+        /// <summary>
+        /// If you want to leave PlaybackPage, you need to 
+        /// </summary>
+        public void Stop()
+        {
+            if (player.State == PlayerState.Playing || player.State == PlayerState.Paused)
+            {
+                // Player's state will be "Ready"
+                player.Stop();
+                if (player.State == PlayerState.Ready)
+                {
+                    _state = StateConvert(player.State);
+                    MessagingCenter.Send<AudioPlayService, AudioPlayState>(this, MessageKeys.PlayerStateChanged, StateConvert(player.State));
+                }
+            }
+            // Player's state will be "Idle"
+            player.Unprepare();
+            if (player.State == PlayerState.Idle)
+            {
+                _state = StateConvert(player.State);
+                MessagingCenter.Send<AudioPlayService, AudioPlayState>(this, MessageKeys.PlayerStateChanged, StateConvert(player.State));
+            }
+        }
+        /// <summary>
+        /// Destroy Audio Play Service
+        /// </summary>
+        public void Destroy()
+        {
+            if (player.State == PlayerState.Playing || player.State == PlayerState.Paused)
+            {
+                Stop();
+            }
+
+            player.Dispose();
+        }
+        /// <summary>
+        /// Invoked when audio volume level has been changed
+        /// </summary>
+        /// <param name="sender">object</param>
+        /// <param name="e">VolumeChangedEventArgs</param>
+        private void AudioVolume_Changed(object sender, VolumeChangedEventArgs e)
+        {
+            //MessagingCenter.Send<IPlayService, int>(this, "VOLUME_CHANGE", e.Level);
+            VolumeChanged?.Invoke(this, new AudioVolumeChangedEventArgs(e.Level));
+        }
+        /// <summary>
+        /// Invoked when an error occurs at playing
+        /// </summary>
+        /// <param name="sender">object</param>
+        /// <param name="e">PlayerErrorOccurredEventArgs</param>
+        private void Player_ErrorOccurred(object sender, PlayerErrorOccurredEventArgs e)
+        {
+            Console.WriteLine(" Player_ErrorOccurred  :" + e.Error);
+        }
+        /// <summary>
+        /// Invoked when an interruption occurs
+        /// </summary>
+        /// <param name="sender">object</param>
+        /// <param name="e">PlaybackInterruptedEventArgs</param>
+        private void Player_PlaybackInterrupted(object sender, PlaybackInterruptedEventArgs e)
+        {
+            Console.WriteLine(" Player_PlaybackInterrupted  :" + e.Reason);
+        }
+        /// <summary>
+        /// Invoked when playing audio is done
+        /// </summary>
+        /// <param name="sender">object</param>
+        /// <param name="e">EventArgs</param>
+        private void Player_PlaybackCompleted(object sender, EventArgs e)
+        {
+            Stop();
+            AudioPlayFinished?.Invoke(this, e);
+        }
+        /// <summary>
+        /// player's state converter
+        /// </summary>
+        /// <param name="state">PlayerState</param>
+        /// <returns>AudioPlayState</returns>
+        AudioPlayState StateConvert(PlayerState state)
+        {
+            switch (state)
+            {
+                case PlayerState.Idle:
+                    return AudioPlayState.Idle;
+                case PlayerState.Paused:
+                    return AudioPlayState.Paused;
+                case PlayerState.Playing:
+                    return AudioPlayState.Playing;
+                case PlayerState.Preparing:
+                    return AudioPlayState.Preparing;
+                case PlayerState.Ready:
+                    return AudioPlayState.Ready;
+                default:
+                    return AudioPlayState.Init;
+            }
+        }
+        /// <summary>
+        /// Called whenever volume level has been changed
+        /// </summary>
+        public event EventHandler<AudioVolumeChangedEventArgs> VolumeChanged;
+        /// <summary>
+        /// Called when playing audio file is done
+        /// </summary>
+        public event EventHandler AudioPlayFinished;
+    }
+
+    public class AudioVolumeChangedEventArgs : EventArgs
+    {
+        public AudioVolumeChangedEventArgs(int level)
+        {
+            Level = level;
+        }
+
+        /// <summary>
+        /// Gets the new volume level.
+        /// </summary>
+        /// <value>The new volume level.</value>
+        /// <since_tizen> 3 </since_tizen>
+        public int Level { get; }
+    }
+
+    public enum AudioPlayState
+    {
+        Init,
+        Idle,
+        Ready,
+        Playing,
+        Preparing,
+        Paused,
+    }
+}
diff --git a/Test/Voicememo2020/VoiceMemo/Services/AudioRecordService.cs b/Test/Voicememo2020/VoiceMemo/Services/AudioRecordService.cs
new file mode 100755 (executable)
index 0000000..fc2b55b
--- /dev/null
@@ -0,0 +1,446 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://floralicense.org/license/
+ *
+ * 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.Linq;
+using System.Threading.Tasks;
+using Tizen.Multimedia;
+using Tizen.System;
+using SystemStorage = Tizen.System.Storage;
+using VoiceMemo.Services;
+//using VoiceMemo.Tizen.Wearable.Services;
+using VoiceMemo.ViewModels;
+using Xamarin.Forms;
+using System.IO;
+using Tizen.Wearable.CircularUI.Forms;
+
+
+namespace VoiceMemo.Services
+{
+    /// <summary>
+    /// AudioRecordService
+    /// The main role is recording voice.
+    /// Use Tizen.Multimedia and Tizen.System classes
+    /// </summary>
+    public class AudioRecordService
+    {
+        private static readonly Lazy<AudioRecordService> instance = new Lazy<AudioRecordService>(() => new AudioRecordService());
+        public static AudioRecordService Instance
+        {
+            get => instance.Value;
+        }
+
+        // Time limit of stt recording is 5 minutes.
+        public const int STT_RECORDING_TIME_LIMIT = 5 * 60;
+        // Time limit of recording is 30 minutes.
+        public const int VOICE_ONLY_RECORDING_TIME_LIMIT = 30 * 60;
+
+        // based on document(https://developer.tizen.org/development/guides/.net-application/media-and-camera/media-recording)
+        const int AMC_CODEC_AUDIO_SAMPLE_RATE = 8000;
+        AudioRecorder _recorder;
+        // based on document (https://developer.tizen.org/development/guides/.net-application/media-and-camera/media-recording)
+        // The following file formats are supported:
+        // Audio: M4A and AMR
+        const RecorderFileFormat AudioFileFormat = RecorderFileFormat.Amr;
+        public static int numbering;
+        //string StoragePath;
+        AudioRecordState _state;
+        string audioStoragePath;
+        string filepath;
+        private Action<Object, AudioRecordState, AudioRecordState> stateCallbacks;
+        /// <summary>
+        /// Get the state of audio recording
+        /// </summary>
+        public AudioRecordState State
+        {
+            get
+            {
+                return _state;
+            }
+        }
+
+        private AudioRecordService()
+        {
+            _state = AudioRecordState.Init;
+            numbering = 0;
+
+            // Create an audio recorder
+            if (_recorder == null)
+            {
+                // find out the available audio codec and file format
+                RecorderAudioCodec AudioCodec = RecorderAudioCodec.Amr;
+                foreach (RecorderAudioCodec codec in Recorder.GetSupportedAudioCodecs())
+                {
+                    //Console.WriteLine("RecorderAudioCodec : " + codec);
+                    foreach (RecorderFileFormat format in codec.GetSupportedFileFormats())
+                    {
+                        //Console.WriteLine("  RecorderFileFormat : " + format);
+                        if (format == AudioFileFormat)
+                        {
+                            AudioCodec = codec;
+                            break;
+                        }
+                    }
+                }
+                //
+
+                Console.WriteLine("+++  Selected AudioCodec : " + AudioCodec + " Format : " + AudioFileFormat);
+                // 2017-12-08: Todo need to roll back..
+                //_recorder = new AudioRecorder(AudioCodec, AudioFileFormat);
+                //RecorderAudioCodec audioCodec, RecorderFileFormat fileFormat
+                _recorder = new AudioRecorder(AudioCodec, AudioFileFormat);
+                _recorder.StateChanged += AudioRecorder_StateChanged;
+                _recorder.RecordingStatusChanged += AudioRecorder_RecordingStatusChanged;
+                _recorder.RecordingLimitReached += AudioRecorder_RecordingLimitReached;
+                _recorder.ErrorOccurred += AudioRecorder_ErrorOccurred;
+                AudioRecorder.DeviceStateChanged += AudioRecorder_DeviceStateChanged;
+                _recorder.Interrupting += AudioRecorder_Interrupting;
+                //audioRecorder.ApplyAudioStreamPolicy(new AudioStreamPolicy(AudioStreamType.Media));
+                //audioRecorder.AudioChannels = 2;
+                _recorder.AudioDevice = RecorderAudioDevice.Mic;
+                _recorder.AudioBitRate = 128000;
+                _recorder.AudioSampleRate = AMC_CODEC_AUDIO_SAMPLE_RATE;
+
+                if (_recorder.State != RecorderState.Idle)
+                {
+                    Console.WriteLine("AudioRecordService() : Invalid State (" + _recorder.State + ")" + "...may retry?");
+                }
+
+                _recorder.Prepare();
+                if (_recorder.State != RecorderState.Ready)
+                {
+                    Console.WriteLine("AudioRecordService() : Invalid State (" + _recorder.State + ")" + "...may retry?");
+                }
+
+                try
+                {
+                    SystemStorage internalStorage = StorageManager.Storages.Where(s => s.StorageType == StorageArea.Internal).FirstOrDefault();
+                    var SoundsDir = internalStorage.GetAbsolutePath(DirectoryType.Sounds);
+                    audioStoragePath = Path.Combine(SoundsDir, "DotnetVoiceMemo");
+                    // Create directory to save audio files
+                    Directory.CreateDirectory(audioStoragePath);
+                }
+                catch (Exception e)
+                {
+                    Toast.DisplayText(e.Message + " - DotnetVoiceMemo directory creation failed.");
+                }
+            }
+        }
+
+        // The model class object for RecordingPage
+        RecordingPageModel _viewModel;
+        public RecordingPageModel ViewModel
+        {
+            get
+            {
+                return _viewModel;
+            }
+
+            set
+            {
+                if (_viewModel != value)
+                {
+                    _viewModel = value;
+                }
+            }
+        }
+
+        ~AudioRecordService()
+        {
+            Console.WriteLine("                 @@@ ~AudioRecordService() ");
+            Destroy();
+        }
+
+        /// <summary>
+        /// Start recording voice
+        /// </summary>
+        /// <param name="title">file path to store audio file</param>
+        /// <param name="sttOn">indicate that Speech-To-Text service is on or not</param>
+        /// <returns>Task<bool></returns>
+        public Task<bool> Start(string title, bool sttOn)
+        {
+            return Task.Run(() =>
+            {
+                if (sttOn)
+                {
+                    // Recording time limits 5 minutes when speech-to-text function is enabled
+                    _recorder.TimeLimit = STT_RECORDING_TIME_LIMIT;
+                }
+                else
+                {
+                    // Recording time limits 30 minutes when speech-to-text function is disabled
+                    _recorder.TimeLimit = VOICE_ONLY_RECORDING_TIME_LIMIT;
+                }
+
+                try
+                {
+                    filepath = Path.Combine(audioStoragePath, title + "_T_" + DateTime.Now.ToString("yyyyMMddHHmmss") + ".amr");
+                    _recorder.Start(filepath);
+                }
+                catch (Exception e)
+                {
+                    Console.WriteLine(" _recorder.Start() Exception : " + e.Message);
+                    HandleError("Start", e);
+                    // TODO: Phase 2
+                    // Toast Popup Message should be shown.
+                    // Message : Recording failed.
+                }
+
+                return true;
+            });
+        }
+        /// <summary>
+        /// Pause recording voice
+        /// </summary>
+        public void Pause()
+        {
+            if (_recorder.State != RecorderState.Recording)
+            {
+                Console.WriteLine("AudioRecordService.Pause : Invalid State (" + _recorder.State + ")");
+                return;
+            }
+
+            try
+            {
+                _recorder.Pause();
+                if (_recorder.State != RecorderState.Paused)
+                {
+                    Console.WriteLine("    AudioRecordService.Pause state error");
+                }
+            }
+            catch (Exception e)
+            {
+                HandleError("Pause", e);
+            }
+        }
+        /// <summary>
+        /// Resume recording voice
+        /// </summary>
+        public void Resume()
+        {
+            if (_recorder.State != RecorderState.Paused)
+            {
+                Console.WriteLine("AudioRecordService.Resume : Invalid State (" + _recorder.State + ")");
+                return;
+            }
+
+            try
+            {
+                _recorder.Resume();
+                if (_recorder.State != RecorderState.Recording)
+                {
+                    Console.WriteLine("    AudioRecordService.Resume state error");
+                }
+            }
+            catch (Exception e)
+            {
+                HandleError("Resume", e);
+            }
+        }
+        /// <summary>
+        /// Cancel recording voice
+        /// </summary>
+        public void Cancel()
+        {
+            if (_recorder.State == RecorderState.Idle || _recorder.State == RecorderState.Ready)
+            {
+                Console.WriteLine("AudioRecordService.Cancel : No need to cancel in State (" + _recorder.State + ") ");
+                return;
+            }
+
+            try
+            {
+                _recorder.Cancel();
+                if (_recorder.State != RecorderState.Ready)
+                {
+                    Console.WriteLine("    AudioRecordService.Cancel state error");
+                }
+            }
+            catch (Exception e)
+            {
+                HandleError("Cancel", e);
+            }
+        }
+        /// <summary>
+        /// Stop recording and save the voice recording file
+        /// </summary>
+        /// <returns>file path to save audio file</returns>
+        public string Save()
+        {
+            if ((_recorder.State == RecorderState.Idle) || (_recorder.State == RecorderState.Ready))
+            {
+                Console.WriteLine("AudioRecordService.Save : No need to cancel in State (" + _recorder.State + ") ");
+                return null;
+            }
+
+            try
+            {
+                // Stop recording and save the result in file
+                _recorder.Commit();
+                if (_recorder.State != RecorderState.Ready)
+                {
+                    Console.WriteLine("    AudioRecordService.Save state error");
+                    // TODO : Handle error case
+                    Toast.DisplayText("Fail to save audio file because of recording fw issue.");
+                }
+
+                string name = filepath.Substring(filepath.IndexOf(' '));
+                string final = name.Substring(0, name.IndexOf("_T_"));
+                //string final = name.Substring(name.IndexOf("_T_"), name.Length - name.IndexOf("_T_"));
+                numbering = Convert.ToInt32(final);
+                Console.WriteLine("   ######  Voice File name - " + name + " --> final : " + final + " , numbering : " + numbering);
+            }
+            catch (Exception e)
+            {
+                HandleError("Commit", e);
+            }
+
+            return filepath;
+        }
+
+        public void Destroy()
+        {
+            try
+            {
+                // release resources
+                _recorder.StateChanged -= AudioRecorder_StateChanged;
+                _recorder.RecordingStatusChanged -= AudioRecorder_RecordingStatusChanged;
+                _recorder.RecordingLimitReached -= AudioRecorder_RecordingLimitReached;
+                _recorder.ErrorOccurred -= AudioRecorder_ErrorOccurred;
+                AudioRecorder.DeviceStateChanged -= AudioRecorder_DeviceStateChanged;
+                _recorder.Interrupting -= AudioRecorder_Interrupting;
+                _recorder.Unprepare();
+                if (_recorder.State != RecorderState.Idle)
+                {
+                    Console.WriteLine("   ########################################");
+                    Console.WriteLine("    AudioRecordService.Destroy state error");
+                    Console.WriteLine("   ########################################");
+                }
+
+                Console.WriteLine("    AudioRecordService.Destroy() " + _recorder.State);
+                _recorder.Dispose();
+            }
+            catch (Exception e)
+            {
+                HandleError("Destroy", e);
+            }
+        }
+        /// <summary>
+        /// Get voice recording level
+        /// </summary>
+        /// <returns>volume level</returns>
+        public double GetRecordingLevel()
+        {
+            return _recorder.GetPeakAudioLevel();
+        }
+
+        void HandleError(string method, Exception e)
+        {
+            switch (_recorder.State)
+            {
+                case RecorderState.Idle:
+                    Console.WriteLine("[RecordingService.HandleError in " + method + "()] State:Idle " + e.Message);
+                    break;
+                case RecorderState.Paused:
+                    Console.WriteLine("[RecordingService.HandleError in " + method + "()] State:Paused " + e.Message);
+                    Cancel();
+                    break;
+                case RecorderState.Ready:
+                    Console.WriteLine("[RecordingService.HandleError in " + method + "()] State:Ready " + e.Message);
+                    break;
+                case RecorderState.Recording:
+                    Console.WriteLine("[RecordingService.HandleError in " + method + "()] State:Recording " + e.Message);
+                    Cancel();
+                    break;
+                default:
+                    break;
+            }
+        }
+
+        private void AudioRecorder_Interrupting(object sender, RecorderInterruptingEventArgs e)
+        {
+            Console.WriteLine("");
+            Console.WriteLine("[AudioRecorder_Interrupting] : " + e.Reason);
+        }
+
+        private void AudioRecorder_ErrorOccurred(object sender, RecordingErrorOccurredEventArgs e)
+        {
+            Console.WriteLine("");
+            Console.WriteLine("[AudioRecorder_ErrorOccurred] : " + e.Error + ", Type: " + e.GetType() + ", " + e.ToString());
+            // TODO: Phase 2
+            // Toast Popup Message should be shown.
+            // Message : Recording failed.
+        }
+
+        private void AudioRecorder_RecordingLimitReached(object sender, RecordingLimitReachedEventArgs e)
+        {
+            Console.WriteLine("[AudioRecorder_RecordingLimitReached] type: " + e.Type);
+            // Request stop to save voice recording
+            ViewModel.RequestCommand.Execute(RecordingCommandType.Stop);
+        }
+
+        private void AudioRecorder_RecordingStatusChanged(object sender, RecordingStatusChangedEventArgs e)
+        {
+            //Console.WriteLine("[AudioRecorder_RecordingStatusChanged] ElapsedTime:" + e.ElapsedTime + ", FileSize:" + e.FileSize);
+        }
+
+        private void AudioRecorder_DeviceStateChanged(object sender, RecorderDeviceStateChangedEventArgs e)
+        {
+            Console.WriteLine("");
+            Console.WriteLine("[AudioRecorder_DeviceStateChanged] deviceState : " + e.DeviceState);
+            Console.WriteLine("");
+        }
+
+        private void AudioRecorder_StateChanged(object sender, RecorderStateChangedEventArgs e)
+        {
+            Console.WriteLine("[AudioRecorder_StateChanged] " + e.PreviousState + " --> " + e.CurrentState);
+            switch (e.CurrentState)
+            {
+                case RecorderState.Idle:
+                    _state = AudioRecordState.Idle;
+                    break;
+                case RecorderState.Paused:
+                    _state = AudioRecordState.Paused;
+                    break;
+                case RecorderState.Ready:
+                    _state = AudioRecordState.Ready;
+                    break;
+                case RecorderState.Recording:
+                    _state = AudioRecordState.Recording;
+                    break;
+            }
+
+            stateCallbacks(sender, (AudioRecordState)e.PreviousState, (AudioRecordState)e.CurrentState);
+        }
+              
+        public void RegisterStateCallbacks(Action<Object, AudioRecordState, AudioRecordState> callback)
+        {
+            stateCallbacks = callback;
+        }
+    }
+
+    /// <summary>
+    /// Audio recording state
+    /// </summary>
+    public enum AudioRecordState
+    {
+        Init,
+        Idle,
+        Ready,
+        Recording,
+        Paused,
+    }
+}
diff --git a/Test/Voicememo2020/VoiceMemo/Services/DeviceInformationService.cs b/Test/Voicememo2020/VoiceMemo/Services/DeviceInformationService.cs
new file mode 100755 (executable)
index 0000000..8ea9154
--- /dev/null
@@ -0,0 +1,170 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://floralicense.org/license/
+ *
+ * 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.IO;
+using System.Linq;
+using Tizen.Applications;
+using Tizen.System;
+
+using SQLite;
+using SQLitePCL;
+
+namespace VoiceMemo.Services
+{
+    public static class Features
+    {
+        // Required features
+        // check microphone feature to use a mic for voice recording
+        public const string Microphone = "http://tizen.org/feature/microphone";
+        // check speech.recognition feature to use stt service
+        public const string STT = "http://tizen.org/feature/speech.recognition";
+    }
+    /// <summary>
+    /// Class DeviceInformation
+    /// It provides following functions
+    /// - device capabilities
+    /// - file path in internal storage
+    /// - application's state(e.g. Foreground, Background)
+    /// </summary>
+    public class DeviceInformationService
+    {
+        private static readonly Lazy<DeviceInformationService> instance = new Lazy<DeviceInformationService>(() => new DeviceInformationService());
+        public static DeviceInformationService Instance
+        {
+            get => instance.Value;
+        }
+
+        const int OneKiloBytes = 1024;
+        // indicate that speech-to-text feature is supported or not
+        internal static bool isSpeechRecognitionSupported = false;
+        // indicate that mic is supported or not
+        internal static bool isMicrophoneSupported = false;
+        internal static bool isFeatureSupported = false;
+
+        public const string LastUsedID = "LAST_SAVED_ID_NUMBER";
+        int _numbering;
+
+        public int LastStoredFileIndex
+        {
+            get
+            {
+                return _numbering;
+            }
+        }
+
+        private DeviceInformationService()
+        {
+            // Check whether STT feature is supported or not
+            Information.TryGetValue(Features.STT, out isSpeechRecognitionSupported);
+            // Check whether mic is available or not
+            Information.TryGetValue(Features.Microphone, out isMicrophoneSupported);
+            isFeatureSupported = isSpeechRecognitionSupported && isMicrophoneSupported;
+
+            bool existing = Preference.Contains(LastUsedID);
+            if (existing)
+            {
+                _numbering = Preference.Get<int>(LastUsedID);
+            }
+            else
+            {
+                _numbering = 0;
+            }
+        }
+
+        /// <summary>
+        /// Indicate speech recognition feature is supported or not
+        /// </summary>
+        public bool SpeechRecognitionAvailable
+        {
+            get
+            {
+                return isFeatureSupported;
+            }
+        }
+
+        ApplicationRunningContext _context;
+        /// <summary>
+        /// Application's execution state
+        /// </summary>
+        public AppState AppState
+        {
+            get
+            {
+                
+                if (_context == null)
+                {
+                    var appInfo = Application.Current.ApplicationInfo;
+                    _context = new ApplicationRunningContext(appInfo.ApplicationId);
+                }
+
+                if (_context.State == ApplicationRunningContext.AppState.Background)
+                {
+                    return AppState.Background;
+                }
+                else if (_context.State == ApplicationRunningContext.AppState.Foreground)
+                {
+                    return AppState.Foreground;
+                }
+                else if (_context.State == ApplicationRunningContext.AppState.Terminated)
+                {
+                    return AppState.Terminated;
+                }
+                else
+                {
+                    Console.WriteLine("App State : " + _context.State);
+                    return AppState.Undefined;
+                }
+            }
+        }
+
+        /// <summary>
+        /// Indicate that there is enough storage available to save audio file
+        /// </summary>
+        public bool StorageAvailable
+        {
+            get
+            {
+                // Check if internal storage has sufficient storage available or not
+                Storage internalStorage = StorageManager.Storages.Where(s => s.StorageType == StorageArea.Internal).FirstOrDefault();
+                // 'AvaliableSpace' is deprecated in Tizen 5.0
+                // In Tizen 5.0, 'AvaliableSpace' is recommended instead of 'AvaliableSpace'.
+                return ((internalStorage.AvaliableSpace / OneKiloBytes) > 105) ? true : false;
+            }
+        }
+
+        /// <summary>
+        /// Get the path of database file for this app
+        /// </summary>
+        /// <param name="filename">Database file name</param>
+        /// <returns>The full path  of Database file</returns>
+        public string GetLocalDBFilePath(string filename)
+        {
+            raw.SetProvider(new SQLite3Provider_sqlite3());
+            raw.FreezeProvider(true);
+            string path = Application.Current.DirectoryInfo.Data;
+            return Path.Combine(path, filename);
+        }
+    }
+
+    public enum AppState
+    {
+        Background,
+        Foreground,
+        Terminated,
+        Undefined,
+    }
+}
diff --git a/Test/Voicememo2020/VoiceMemo/Services/LocaleService.cs b/Test/Voicememo2020/VoiceMemo/Services/LocaleService.cs
new file mode 100755 (executable)
index 0000000..3009a08
--- /dev/null
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://floralicense.org/license/
+ *
+ * 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.Globalization;
+using Tizen.System;
+//using VoiceMemo.Tizen.Wearable.Services;
+using VoiceMemo.ViewModels;
+using Xamarin.Forms;
+
+namespace VoiceMemo.Services
+{
+    class LocaleService 
+    {
+        private static readonly Lazy<LocaleService> instance = new Lazy<LocaleService>(() => new LocaleService());
+
+        public static LocaleService Instance { get => instance.Value; }
+        public CultureInfo CurrentCultureInfo;
+
+        private LocaleService()
+        {
+            CurrentCultureInfo = GetCurrentCultureInfo();
+            // To get notified when system locale settings has been changed1
+            //Trace.StartFrom("LocaleService()-LocaleLanguageChanged");
+            //SystemSettings.LocaleLanguageChanged += SystemSettings_LocaleLanguageChanged;
+            //Trace.End();
+        }
+
+        ///// <summary>
+        ///// Get the current CultureInfo
+        ///// </summary>
+        //public CultureInfo CurrentCultureInfo
+        //{
+        //    get
+        //    {
+        //        return _currentCultureInfo;
+        //    }
+        //}
+
+        /// <summary>
+        /// Get CultureInfo from the locale information
+        /// </summary>
+        /// <returns>CultureInfo</returns>
+        public CultureInfo GetCurrentCultureInfo()
+        {
+            var netLanguage = "en";
+            var TizenLocale = SystemSettings.LocaleLanguage;
+            //Console.WriteLine("[GetCurrentCultureInfo] TizenLocale (" + TizenLocale + ")");
+            netLanguage = TizenToDotnetLanguage(TizenLocale.ToString().Replace("_", "-"));
+            //Console.WriteLine("[GetCurrentCultureInfo] netLanguage (" + netLanguage + ")");
+            CultureInfo info = null;
+            try
+            {
+                info = new CultureInfo(netLanguage);
+            }
+            catch (CultureNotFoundException e1)
+            {
+                Console.WriteLine("[GetCurrentCultureInfo] cannot find the current cultureInfo. so use 'en'. (" + e1.Message + ")");
+                info = new CultureInfo("en");
+            }
+
+            return info;
+        }
+        /// <summary>
+        /// Invoked when system locale setting has been changed
+        /// </summary>
+        /// <param name="sender">object</param>
+        /// <param name="e">LocaleLanguageChangedEventArgs</param>
+        private void SystemSettings_LocaleLanguageChanged(object sender, LocaleLanguageChangedEventArgs e)
+        {
+            CultureInfo info = GetCurrentCultureInfo();
+            CurrentCultureInfo = info;
+            // Notify the change of locale information
+            MessagingCenter.Send<LocaleService, CultureInfo>(this, MessageKeys.LanguageChanged, info);
+        }
+
+        string TizenToDotnetLanguage(string androidLanguage)
+        {
+            var netLanguage = androidLanguage;
+            //certain languages need to be converted to CultureInfo equivalent
+            switch (androidLanguage)
+            {
+                case "zh-CN":   // Chinese Simplified (People's Republic of China)
+                    netLanguage = "zh-Hans"; // correct code for .NET
+                    break;
+                case "zh-HK":  // Chinese Traditional (Hong Kong)
+                case "zh-hk":
+                case "zh-tw":  // Chinese Traditional (Taiwan)
+                case "zh-TW":
+                    netLanguage = "zh-Hant"; // correct code for .NET
+                    break;
+                    //case "ar-ae":   // Arabic
+                    //    netLanguage = "ar-sa"; // closest supported for .Net : Arabic (Saudi Arabia)
+                    //    break;
+                    // add more application-specific cases here (if required)
+                    // ONLY use cultures that have been tested and known to work
+            }
+
+            //Console.WriteLine(".NET Language/Locale:" + netLanguage);
+            return netLanguage;
+        }
+    }
+}
diff --git a/Test/Voicememo2020/VoiceMemo/Services/MediaContentService.cs b/Test/Voicememo2020/VoiceMemo/Services/MediaContentService.cs
new file mode 100755 (executable)
index 0000000..25383ff
--- /dev/null
@@ -0,0 +1,141 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://floralicense.org/license/
+ *
+ * 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.IO;
+using Tizen.Content.MediaContent;
+using VoiceMemo.Models;
+using VoiceMemo.Services;
+//using VoiceMemo.Tizen.Wearable.Services;
+using VoiceMemo.ViewModels;
+using Xamarin.Forms;
+
+namespace VoiceMemo.Services
+{
+    class MediaContentService
+    {
+        private static readonly Lazy<MediaContentService> instance = new Lazy<MediaContentService>(() => new MediaContentService());
+        public static MediaContentService Instance { get => instance.Value; }
+        MediaDatabase mediaDB;
+        MediaInfoCommand mediaInfoCmd;
+
+        private MediaContentService()
+        {
+            try
+            {
+                mediaDB = new MediaDatabase();
+#if media_svc_get_storage_id_failed_return_minus_2
+                //mediaDB.Connect();
+                //MediaDatabase.FolderUpdated += MediaDatabase_FolderUpdated;
+                //MediaDatabase.MediaInfoUpdated += MediaDatabase_MediaInfoUpdated;
+                //mediaInfoCmd = new MediaInfoCommand(mediaDB);
+#endif
+            }
+            catch (Exception e)
+            {
+                Console.WriteLine("    FAILED MediaContentService() : " + e.Message);
+                MessagingCenter.Send(this, MessageKeys.ErrorOccur, e);
+            }
+        }
+
+        /// <summary>
+        /// Destroy MediaContentService
+        /// </summary>
+        public void Destroy()
+        {
+            if (mediaDB != null)
+            {
+                Console.WriteLine("MediaContentService.Destroy()   ....");
+#if media_svc_get_storage_id_failed_return_minus_2
+                mediaDB.Disconnect();
+#endif
+                mediaDB.Dispose();
+            }
+        }
+
+        /// <summary>
+        /// Get Record from media file
+        /// </summary>
+        /// <param name="path">recorded audio file</param>
+        /// <param name="SttOn">stt on/off mode</param>
+        /// <returns>Record</returns>
+        public Record GetMediaInfo(string path, bool SttOn)
+        {
+            Record record = null;
+            try
+            {
+                // TODO : scan 
+#if media_svc_get_storage_id_failed_return_minus_2
+#else
+                mediaDB.Connect();
+#endif
+                mediaDB.ScanFile(path);
+#if media_svc_get_storage_id_failed_return_minus_2
+#else
+                mediaInfoCmd = new MediaInfoCommand(mediaDB);
+#endif
+                AudioInfo info = mediaInfoCmd.Add(path) as AudioInfo;
+#if media_svc_get_storage_id_failed_return_minus_2
+#else
+                mediaDB.Disconnect();
+#endif
+
+                //int minutes = info.Duration / 60000;
+                //int seconds = (info.Duration - minutes * 60000) / 1000;
+                //string duration = String.Format("{0:00}:{1:00}", minutes, seconds);
+                record = new Record
+                {
+                    _id = AudioRecordService.numbering,
+                    Title = info.Title.Substring(0, info.Title.IndexOf("_T_")),
+                    Date = info.DateModified.ToLocalTime().ToString("t"),
+                    Duration = info.Duration,
+                    Path = path,
+                    SttEnabled = SttOn,
+                };
+                Console.WriteLine(" ** Record :" + record);
+            }
+            catch (Exception e)
+            {
+                Console.WriteLine("###########################################");
+                Console.WriteLine("    FAILED GetMediaInfo : " + e.Message + ", " + e.Source);
+                Console.WriteLine("###########################################");
+                MessagingCenter.Send(this, MessageKeys.ErrorOccur, e);
+            }
+
+            return record;
+        }
+
+        /// <summary>
+        /// Delete audio file from internal storage
+        /// </summary>
+        /// <param name="Path">file path to delete</param>
+        /// <returns>true if the file is successfully deleted.</returns>
+        public bool RemoveMediaFile(string Path)
+        {
+            try
+            {
+                File.Delete(Path);
+            }
+            catch (Exception e)
+            {
+                Console.WriteLine("[MediaContentService.RemoveMediaFile] Path(" + Path + ") error :" + e.Message);
+                return false;
+            }
+
+            return true;
+        }
+    }
+}
diff --git a/Test/Voicememo2020/VoiceMemo/Services/SpeechToTextService.cs b/Test/Voicememo2020/VoiceMemo/Services/SpeechToTextService.cs
new file mode 100755 (executable)
index 0000000..ceb99ed
--- /dev/null
@@ -0,0 +1,327 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://floralicense.org/license/
+ *
+ * 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.Collections.Generic;
+using System.Threading.Tasks;
+using Tizen.Uix.Stt;
+using VoiceMemo.Services;
+//using VoiceMemo.Tizen.Wearable.Services;
+using VoiceMemo.ViewModels;
+using Xamarin.Forms;
+
+
+namespace VoiceMemo.Services
+{
+    /// <summary>
+    /// SpeechToTextService
+    /// The main role is speech recognition.
+    /// Use Tizen.Uix.Stt
+    /// </summary>
+    public class SpeechToTextService
+    {
+        private static readonly Lazy<SpeechToTextService> instance = new Lazy<SpeechToTextService>(() => new SpeechToTextService());
+        public static SpeechToTextService Instance { get => instance.Value; }
+
+        SttClient _Stt;
+
+        private Action<Object, SttState, SttState> stateCallback;
+        private SpeechToTextService()
+        {
+            try
+            {
+                if (_Stt == null)
+                {
+                    _Stt = new SttClient();
+                    _Stt.StateChanged += _Stt_StateChanged;
+                    _Stt.DefaultLanguageChanged += _Stt_DefaultLanguageChanged;
+                    _Stt.EngineChanged += _Stt_EngineChanged;
+                    _Stt.ErrorOccurred += _Stt_ErrorOccurred;
+                    _Stt.RecognitionResult += _Stt_RecognitionResult;
+                    // Expected State : Created
+                    CurrentSttLanguage = _Stt.DefaultLanguage;
+                    _Stt.Prepare();
+                    Console.WriteLine("DefaultLanguage ..." + _Stt.DefaultLanguage + ", Engine : " + _Stt.Engine);
+                }
+            }
+            catch (Exception e)
+            {
+                Console.WriteLine("SttClient  Exception: " + e.Message);
+                if (e is NotSupportedException)
+                {
+                    Console.WriteLine("SttClient is not supported...");
+                }
+                else if (e is UnauthorizedAccessException)
+                {
+                    Console.WriteLine("UnauthorizedAccessException...");
+                }
+            }
+        }
+        /// <summary>
+        /// Start Speech-to-Text service
+        /// It means that it starts speech recognition, converting audio to text
+        /// </summary>
+        public void StartStt()
+        {
+            _Stt.SetSilenceDetection(SilenceDetection.False);
+            _Stt.Start(CurrentSttLanguage, RecognitionType.Partial);
+        }
+        /// <summary>
+        /// Cancel speech recognition
+        /// </summary>
+        public void Cancel()
+        {
+            Console.WriteLine("\n\n[Cancel] Before SttClient.Cancel(), state: " + _Stt.CurrentState);
+            //To cancel the recording without getting the result, use the stt_cancel() function.
+            if (_Stt.CurrentState == State.Recording || _Stt.CurrentState == State.Processing)
+            {
+                _Stt.Cancel();
+            }
+
+            Console.WriteLine("[Cancel] After SttClient.Cancel(), state: " + _Stt.CurrentState);
+        }
+
+        TaskCompletionSource<string> taskCompletionSource;
+        /// <summary>
+        /// Stop speech recognition and get the converted text
+        /// </summary>
+        /// <returns>text</returns>
+        public Task<string> StopAndGetText()
+        {
+            Console.WriteLine("\n\nBefore SttClient.StopAndGetText(), state: " + _Stt.CurrentState);
+            if (_Stt.CurrentState == State.Ready)
+            {
+                return null;
+            }
+
+            // Return Task object
+            taskCompletionSource = new TaskCompletionSource<string>();
+            //To stop the recording and get the recognition result
+            // TODO: Find out a better solution.
+            switch (_Stt.CurrentState)
+            {
+                case State.Processing:
+                    //requestToStop = true;
+                    MessagingCenter.Subscribe<SpeechToTextService>(this, MessageKeys.CanStopSTT, (obj) =>
+                    {
+                        _Stt.Stop();
+                        MessagingCenter.Unsubscribe<SpeechToTextService>(this, MessageKeys.CanStopSTT);
+                    });
+                    break;
+                case State.Recording:
+                    try
+                    {
+                        _Stt.Stop();
+                    }
+                    catch (Exception e)
+                    {
+                        Console.WriteLine("[StopAndGetText] _Stt.Stop() --> Error e : " + e.Message + ",  " + e.Source + ", " + e.StackTrace + ", " + e.GetType());
+                    }
+
+                    break;
+                default:
+                    break;
+            }
+
+            return taskCompletionSource.Task;
+        }
+        /// <summary>
+        /// Dispose Speech-to-Text service
+        /// </summary>
+        public void Dispose()
+        {
+            Console.WriteLine("SpeechToTextService.Dispose()");
+            try
+            {
+                if (_Stt == null)
+                {
+                    return;
+                }
+
+                _Stt.DefaultLanguageChanged -= _Stt_DefaultLanguageChanged;
+                _Stt.EngineChanged -= _Stt_EngineChanged;
+                _Stt.ErrorOccurred -= _Stt_ErrorOccurred;
+                _Stt.RecognitionResult -= _Stt_RecognitionResult;
+                _Stt.StateChanged -= _Stt_StateChanged;
+                _Stt.Unprepare();
+                _Stt.Dispose();
+                _Stt = null;
+            }
+            catch (Exception e)
+            {
+                Console.WriteLine("SpeechToTextService.Dispose() : Error - " + e.Message);  // Invalid Parameters Provided
+            }
+        }
+
+        /// <summary>
+        ///     Get installed languages.
+        /// </summary>
+        /// <returns>
+        ///     The installed language names.
+        /// </returns>
+        public IEnumerable<string> GetInstalledLanguages()
+        {
+            return _Stt.GetSupportedLanguages();
+        }
+
+        string _currentSttLanguage;
+
+        /// <summary>
+        /// The chosen language for Speech-to-Text service
+        /// </summary>
+        public string CurrentSttLanguage
+        {
+            get
+            {
+                return _currentSttLanguage;
+            }
+
+            set
+            {
+                if (_currentSttLanguage != value)
+                {
+                    _currentSttLanguage = value;
+                }
+            }
+        }
+        /// <summary>
+        /// The state of Speech-to-Text service
+        /// </summary>
+        public SttState SttState
+        {
+            get
+            {
+                return (SttState)_Stt.CurrentState;
+            }
+        }
+
+        private void _Stt_RecognitionResult(object sender, RecognitionResultEventArgs arg)
+        {
+            Console.WriteLine("_Stt_RecognitionResult Message: " + arg.Message);
+            Console.WriteLine("_Stt_RecognitionResult Result: " + arg.Result);
+            Console.WriteLine("_Stt_RecognitionResult DataCount : " + arg.DataCount);
+            Console.WriteLine("_Stt_RecognitionResult Data : " + arg.Data);
+            Console.WriteLine(" **** _Stt_RecognitionResult : " + arg.DataCount + ", " + arg.Data + ", " + arg.Message + ", " + arg.Result);
+            Console.WriteLine(" **** _Stt_RecognitionResult ---  _Stt.CurrentState : " + _Stt.CurrentState);
+
+            string resultText = "";
+            if (arg.Result == ResultEvent.FinalResult && taskCompletionSource != null)
+            {
+                if (arg.Data != null)
+                {
+                    foreach (var part in arg.Data)
+                    {
+                        Console.WriteLine("text : (" + part + ")");
+                        resultText += part;
+                        Console.WriteLine("resultText : (" + resultText + ")");
+                    }
+
+                    if (string.IsNullOrEmpty(resultText))
+                    {
+                        Console.WriteLine("!!!!!!!!!!!!!!!!!!!                resultText is string.IsNullOrEmpty");
+                    }
+
+                    //if (resultText.Equals("") || resultText.Equals(" ") || resultText.Equals("  "))
+                    //{
+                    //    Console.WriteLine("result data is empty. so assign Recognition failed");
+                    //    resultText = AppResources.RecognitionFailed;
+                    //}
+
+                    taskCompletionSource.SetResult(resultText);
+                    //System.InvalidOperationException: An attempt was made to transition a task to a final state when it had already completed.
+                    //    at System.ThrowHelper.ThrowInvalidOperationException(ExceptionResource resource)
+                    //    at System.Threading.Tasks.TaskCompletionSource`1.SetResult(TResult result)
+                    taskCompletionSource = null;
+                }
+            }
+        }
+
+        /// <summary>
+        /// Invoked when an error occurs
+        /// </summary>
+        /// <param name="sender">object</param>
+        /// <param name="e">ErrorOccurredEventArgs</param>
+        private void _Stt_ErrorOccurred(object sender, ErrorOccurredEventArgs e)
+        {
+            Console.WriteLine(" **** _Stt_ErrorOccurred : (" + e.ErrorMessage + "), " + e.ErrorValue);
+            if (taskCompletionSource != null)
+            {
+                taskCompletionSource.SetResult("Stt Error:" + e.ErrorValue);
+            }
+        }
+
+        /// <summary>
+        /// Invoked when Speech-to-Text engine has been changed
+        /// </summary>
+        /// <param name="sender">object</param>
+        /// <param name="e">EngineChangedEventArgs</param>
+        private void _Stt_EngineChanged(object sender, EngineChangedEventArgs e)
+        {
+            Console.WriteLine(" ----_Stt_EngineChanged : " + e.EngineId + ", " + e.Language + ", " + e.NeedCredential + ", " + e.SupportSilence);
+        }
+
+        /// <summary>
+        /// Invoked when the default language for Speech-to-Text service has been changed
+        /// </summary>
+        /// <param name="sender">object</param>
+        /// <param name="e">DefaultLanguageChangedEventArgs</param>
+        private void _Stt_DefaultLanguageChanged(object sender, DefaultLanguageChangedEventArgs e)
+        {
+            Console.WriteLine(" ---- _Stt_DefaultLanguageChanged : " + e.PreviousLanguage + " ---> " + e.CurrentLanguage);
+        }
+
+        /// <summary>
+        /// Invoked when the state of Speech-To-Text service has been changed
+        /// </summary>
+        /// <param name="sender">object</param>
+        /// <param name="e">StateChangedEventArgs</param>
+        private void _Stt_StateChanged(object sender, StateChangedEventArgs e)
+        {
+            Console.WriteLine(" ---- _Stt_StateChanged : " + e.Previous + " ---> " + e.Current);
+            stateCallback?.Invoke(sender, (SttState)e.Previous, (SttState)e.Current);
+        }
+
+        public void RegisterStateCallbacks(Action<object, SttState, SttState> callback)
+        {
+            stateCallback = callback;
+        }
+    }
+
+    public enum SttState
+    {
+        //
+        // Summary:
+        //     Created state.
+        Created = 0,
+        //
+        // Summary:
+        //     Ready state.
+        Ready = 1,
+        //
+        // Summary:
+        //     Recording state.
+        Recording = 2,
+        //
+        // Summary:
+        //     Processing state.
+        Processing = 3,
+        //
+        // Summary:
+        //     Unavailable.
+        Unavailable = 4
+    }
+
+}
diff --git a/Test/Voicememo2020/VoiceMemo/Services/UserPermission.cs b/Test/Voicememo2020/VoiceMemo/Services/UserPermission.cs
new file mode 100755 (executable)
index 0000000..219073a
--- /dev/null
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://floralicense.org/license/
+ *
+ * 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.Threading.Tasks;
+using Tizen.Security;
+using VoiceMemo.Services;
+using Xamarin.Forms;
+
+
+namespace VoiceMemo.Services
+{
+    class UserPermission
+    {
+        public UserPermission()
+        {
+        }
+
+        TaskCompletionSource<bool> tcs;
+        int GrantedPermission;
+
+        /// <summary>
+        /// Request user permission for privacy privileges
+        /// </summary>
+        /// <param name="service">privacy privilege</param>
+        /// <returns>true if user consent is gained</returns>
+        public async Task<bool> GetPermission(string service)
+        {
+            try
+            {
+                GrantedPermission = -1;
+                // Gets the status of a privacy privilege permission.
+                CheckResult result = PrivacyPrivilegeManager.CheckPermission(service);
+                switch (result)
+                {
+                    case CheckResult.Allow:
+                        // user consent for privacy privilege is already gained
+                        return true;
+                    case CheckResult.Deny:
+                    case CheckResult.Ask:
+                        // User permission request should be required
+                        tcs = new TaskCompletionSource<bool>();
+                        // Gets the response context for a given privilege.
+                        var reponseContext = PrivacyPrivilegeManager.GetResponseContext(service);
+                        PrivacyPrivilegeManager.ResponseContext context = null;
+                        if (reponseContext.TryGetTarget(out context))
+                        {
+                            if (context != null)
+                            {
+                                context.ResponseFetched += Context_ResponseFetched;
+                            }
+                        }
+                        // Try to get the permission for service from a user.
+                        PrivacyPrivilegeManager.RequestPermission(service);
+                        // Check if permission is granted or not every second
+                        Device.BeginInvokeOnMainThread(() =>
+                        {
+                            Device.StartTimer(new TimeSpan(0, 0, 0, 1, 0), CheckPermission);
+                        });
+
+                        return await tcs.Task;
+                    default:
+                        return false;
+                }
+            }
+            catch (Exception e)
+            {
+                Console.WriteLine("[UserPermission] (" + service + ") Error :" + e.Message);
+                return false;
+            }
+        }
+
+        bool CheckPermission()
+        {
+            // In case that an app user doesn't give permission yet.
+            if (GrantedPermission == -1)
+            {
+                return true;
+            }
+
+            // In case that an app user gives permission.
+            // Denied
+            if (GrantedPermission == 0)
+            {
+                tcs.SetResult(false);
+            }
+            // Allowed
+            else
+            {
+                tcs.SetResult(true);
+            }
+
+            return false;
+        }
+
+        // Invoked when an app user responses for the permission request
+        private void Context_ResponseFetched(object sender, RequestResponseEventArgs e)
+        {
+            if (e.result == RequestResult.AllowForever)
+            {
+                // User allows an app to grant privacy privilege
+                GrantedPermission = 1;
+            }
+            else
+            {
+                // User doesn't allow an app to grant privacy privilege
+                GrantedPermission = 0;
+            }
+        }
+    }
+}
diff --git a/Test/Voicememo2020/VoiceMemo/Settings.StyleCop b/Test/Voicememo2020/VoiceMemo/Settings.StyleCop
new file mode 100755 (executable)
index 0000000..8c60a6b
--- /dev/null
@@ -0,0 +1,729 @@
+<StyleCopSettings Version="105">
+  <GlobalSettings>
+    <StringProperty Name="MergeSettingsFiles">NoMerge</StringProperty>
+  </GlobalSettings>
+  <Parsers>
+    <Parser ParserId="StyleCop.CSharp.CsParser">
+      <ParserSettings>
+        <BooleanProperty Name="AnalyzeGeneratedFiles">True</BooleanProperty>
+      </ParserSettings>
+    </Parser>
+  </Parsers>
+  <Analyzers>
+    <Analyzer AnalyzerId="StyleCop.CSharp.DocumentationRules">
+      <Rules>
+        <Rule Name="ElementsMustBeDocumented">
+          <RuleSettings>
+            <BooleanProperty Name="Enabled">False</BooleanProperty>
+          </RuleSettings>
+        </Rule>
+        <Rule Name="EnumerationItemsMustBeDocumented">
+          <RuleSettings>
+            <BooleanProperty Name="Enabled">False</BooleanProperty>
+          </RuleSettings>
+        </Rule>
+        <Rule Name="DocumentationMustContainValidXml">
+          <RuleSettings>
+            <BooleanProperty Name="Enabled">False</BooleanProperty>
+          </RuleSettings>
+        </Rule>
+        <Rule Name="ElementDocumentationMustHaveSummary">
+          <RuleSettings>
+            <BooleanProperty Name="Enabled">False</BooleanProperty>
+          </RuleSettings>
+        </Rule>
+        <Rule Name="PartialElementDocumentationMustHaveSummary">
+          <RuleSettings>
+            <BooleanProperty Name="Enabled">False</BooleanProperty>
+          </RuleSettings>
+        </Rule>
+        <Rule Name="ElementDocumentationMustHaveSummaryText">
+          <RuleSettings>
+            <BooleanProperty Name="Enabled">False</BooleanProperty>
+          </RuleSettings>
+        </Rule>
+        <Rule Name="ElementDocumentationMustNotHaveDefaultSummary">
+          <RuleSettings>
+            <BooleanProperty Name="Enabled">False</BooleanProperty>
+          </RuleSettings>
+        </Rule>
+        <Rule Name="VoidReturnValueMustNotBeDocumented">
+          <RuleSettings>
+            <BooleanProperty Name="Enabled">False</BooleanProperty>
+          </RuleSettings>
+        </Rule>
+        <Rule Name="GenericTypeParametersMustBeDocumented">
+          <RuleSettings>
+            <BooleanProperty Name="Enabled">False</BooleanProperty>
+          </RuleSettings>
+        </Rule>
+        <Rule Name="GenericTypeParametersMustBeDocumentedPartialClass">
+          <RuleSettings>
+            <BooleanProperty Name="Enabled">False</BooleanProperty>
+          </RuleSettings>
+        </Rule>
+        <Rule Name="GenericTypeParameterDocumentationMustMatchTypeParameters">
+          <RuleSettings>
+            <BooleanProperty Name="Enabled">False</BooleanProperty>
+          </RuleSettings>
+        </Rule>
+        <Rule Name="GenericTypeParameterDocumentationMustDeclareParameterName">
+          <RuleSettings>
+            <BooleanProperty Name="Enabled">False</BooleanProperty>
+          </RuleSettings>
+        </Rule>
+        <Rule Name="GenericTypeParameterDocumentationMustHaveText">
+          <RuleSettings>
+            <BooleanProperty Name="Enabled">False</BooleanProperty>
+          </RuleSettings>
+        </Rule>
+        <Rule Name="PropertySummaryDocumentationMustMatchAccessors">
+          <RuleSettings>
+            <BooleanProperty Name="Enabled">False</BooleanProperty>
+          </RuleSettings>
+        </Rule>
+        <Rule Name="PropertySummaryDocumentationMustOmitSetAccessorWithRestrictedAccess">
+          <RuleSettings>
+            <BooleanProperty Name="Enabled">False</BooleanProperty>
+          </RuleSettings>
+        </Rule>
+        <Rule Name="ElementDocumentationMustNotBeCopiedAndPasted">
+          <RuleSettings>
+            <BooleanProperty Name="Enabled">False</BooleanProperty>
+          </RuleSettings>
+        </Rule>
+        <Rule Name="SingleLineCommentsMustNotUseDocumentationStyleSlashes">
+          <RuleSettings>
+            <BooleanProperty Name="Enabled">False</BooleanProperty>
+          </RuleSettings>
+        </Rule>
+        <Rule Name="DocumentationTextMustNotBeEmpty">
+          <RuleSettings>
+            <BooleanProperty Name="Enabled">False</BooleanProperty>
+          </RuleSettings>
+        </Rule>
+        <Rule Name="DocumentationTextMustContainWhitespace">
+          <RuleSettings>
+            <BooleanProperty Name="Enabled">False</BooleanProperty>
+          </RuleSettings>
+        </Rule>
+        <Rule Name="DocumentationMustMeetCharacterPercentage">
+          <RuleSettings>
+            <BooleanProperty Name="Enabled">False</BooleanProperty>
+          </RuleSettings>
+        </Rule>
+        <Rule Name="ConstructorSummaryDocumentationMustBeginWithStandardText">
+          <RuleSettings>
+            <BooleanProperty Name="Enabled">False</BooleanProperty>
+          </RuleSettings>
+        </Rule>
+        <Rule Name="DestructorSummaryDocumentationMustBeginWithStandardText">
+          <RuleSettings>
+            <BooleanProperty Name="Enabled">False</BooleanProperty>
+          </RuleSettings>
+        </Rule>
+        <Rule Name="DocumentationHeadersMustNotContainBlankLines">
+          <RuleSettings>
+            <BooleanProperty Name="Enabled">False</BooleanProperty>
+          </RuleSettings>
+        </Rule>
+        <Rule Name="IncludedDocumentationXPathDoesNotExist">
+          <RuleSettings>
+            <BooleanProperty Name="Enabled">False</BooleanProperty>
+          </RuleSettings>
+        </Rule>
+        <Rule Name="IncludeNodeDoesNotContainValidFileAndPath">
+          <RuleSettings>
+            <BooleanProperty Name="Enabled">False</BooleanProperty>
+          </RuleSettings>
+        </Rule>
+        <Rule Name="InheritDocMustBeUsedWithInheritingClass">
+          <RuleSettings>
+            <BooleanProperty Name="Enabled">False</BooleanProperty>
+          </RuleSettings>
+        </Rule>
+        <Rule Name="ElementDocumentationMustBeSpelledCorrectly">
+          <RuleSettings>
+            <BooleanProperty Name="Enabled">False</BooleanProperty>
+          </RuleSettings>
+        </Rule>
+        <Rule Name="FileMustHaveHeader">
+          <RuleSettings>
+            <BooleanProperty Name="Enabled">False</BooleanProperty>
+          </RuleSettings>
+        </Rule>
+        <Rule Name="FileHeaderMustShowCopyright">
+          <RuleSettings>
+            <BooleanProperty Name="Enabled">False</BooleanProperty>
+          </RuleSettings>
+        </Rule>
+        <Rule Name="FileHeaderMustHaveCopyrightText">
+          <RuleSettings>
+            <BooleanProperty Name="Enabled">False</BooleanProperty>
+          </RuleSettings>
+        </Rule>
+        <Rule Name="FileHeaderMustContainFileName">
+          <RuleSettings>
+            <BooleanProperty Name="Enabled">False</BooleanProperty>
+          </RuleSettings>
+        </Rule>
+        <Rule Name="FileHeaderFileNameDocumentationMustMatchFileName">
+          <RuleSettings>
+            <BooleanProperty Name="Enabled">False</BooleanProperty>
+          </RuleSettings>
+        </Rule>
+        <Rule Name="FileHeaderMustHaveValidCompanyText">
+          <RuleSettings>
+            <BooleanProperty Name="Enabled">False</BooleanProperty>
+          </RuleSettings>
+        </Rule>
+        <Rule Name="FileHeaderFileNameDocumentationMustMatchTypeName">
+          <RuleSettings>
+            <BooleanProperty Name="Enabled">False</BooleanProperty>
+          </RuleSettings>
+        </Rule>
+      </Rules>
+      <AnalyzerSettings />
+    </Analyzer>
+    <Analyzer AnalyzerId="StyleCop.CSharp.LayoutRules">
+      <Rules>
+        <Rule Name="AllAccessorsMustBeMultiLineOrSingleLine">
+          <RuleSettings>
+            <BooleanProperty Name="Enabled">False</BooleanProperty>
+          </RuleSettings>
+        </Rule>
+        <Rule Name="OpeningCurlyBracketsMustNotBeFollowedByBlankLine">
+          <RuleSettings>
+            <BooleanProperty Name="Enabled">False</BooleanProperty>
+          </RuleSettings>
+        </Rule>
+        <Rule Name="ElementDocumentationHeadersMustNotBeFollowedByBlankLine">
+          <RuleSettings>
+            <BooleanProperty Name="Enabled">False</BooleanProperty>
+          </RuleSettings>
+        </Rule>
+        <Rule Name="CodeMustNotContainMultipleBlankLinesInARow">
+          <RuleSettings>
+            <BooleanProperty Name="Enabled">False</BooleanProperty>
+          </RuleSettings>
+        </Rule>
+        <Rule Name="ClosingCurlyBracketsMustNotBePrecededByBlankLine">
+          <RuleSettings>
+            <BooleanProperty Name="Enabled">False</BooleanProperty>
+          </RuleSettings>
+        </Rule>
+        <Rule Name="OpeningCurlyBracketsMustNotBePrecededByBlankLine">
+          <RuleSettings>
+            <BooleanProperty Name="Enabled">False</BooleanProperty>
+          </RuleSettings>
+        </Rule>
+        <Rule Name="ChainedStatementBlocksMustNotBePrecededByBlankLine">
+          <RuleSettings>
+            <BooleanProperty Name="Enabled">False</BooleanProperty>
+          </RuleSettings>
+        </Rule>
+        <Rule Name="WhileDoFooterMustNotBePrecededByBlankLine">
+          <RuleSettings>
+            <BooleanProperty Name="Enabled">False</BooleanProperty>
+          </RuleSettings>
+        </Rule>
+        <Rule Name="SingleLineCommentsMustNotBeFollowedByBlankLine">
+          <RuleSettings>
+            <BooleanProperty Name="Enabled">False</BooleanProperty>
+          </RuleSettings>
+        </Rule>
+        <Rule Name="ElementDocumentationHeaderMustBePrecededByBlankLine">
+          <RuleSettings>
+            <BooleanProperty Name="Enabled">False</BooleanProperty>
+          </RuleSettings>
+        </Rule>
+        <Rule Name="SingleLineCommentMustBePrecededByBlankLine">
+          <RuleSettings>
+            <BooleanProperty Name="Enabled">False</BooleanProperty>
+          </RuleSettings>
+        </Rule>
+        <Rule Name="ElementsMustBeSeparatedByBlankLine">
+          <RuleSettings>
+            <BooleanProperty Name="Enabled">False</BooleanProperty>
+          </RuleSettings>
+        </Rule>
+        <Rule Name="CodeMustNotContainBlankLinesAtStartOfFile">
+          <RuleSettings>
+            <BooleanProperty Name="Enabled">False</BooleanProperty>
+          </RuleSettings>
+        </Rule>
+        <Rule Name="CodeMustNotContainBlankLinesAtEndOfFile">
+          <RuleSettings>
+            <BooleanProperty Name="Enabled">False</BooleanProperty>
+          </RuleSettings>
+        </Rule>
+      </Rules>
+      <AnalyzerSettings />
+    </Analyzer>
+    <Analyzer AnalyzerId="StyleCop.CSharp.MaintainabilityRules">
+      <Rules>
+        <Rule Name="AccessModifierMustBeDeclared">
+          <RuleSettings>
+            <BooleanProperty Name="Enabled">False</BooleanProperty>
+          </RuleSettings>
+        </Rule>
+        <Rule Name="FieldsMustBePrivate">
+          <RuleSettings>
+            <BooleanProperty Name="Enabled">False</BooleanProperty>
+          </RuleSettings>
+        </Rule>
+        <Rule Name="CodeAnalysisSuppressionMustHaveJustification">
+          <RuleSettings>
+            <BooleanProperty Name="Enabled">False</BooleanProperty>
+          </RuleSettings>
+        </Rule>
+        <Rule Name="DebugAssertMustProvideMessageText">
+          <RuleSettings>
+            <BooleanProperty Name="Enabled">False</BooleanProperty>
+          </RuleSettings>
+        </Rule>
+        <Rule Name="DebugFailMustProvideMessageText">
+          <RuleSettings>
+            <BooleanProperty Name="Enabled">False</BooleanProperty>
+          </RuleSettings>
+        </Rule>
+        <Rule Name="FileMayOnlyContainASingleClass">
+          <RuleSettings>
+            <BooleanProperty Name="Enabled">False</BooleanProperty>
+          </RuleSettings>
+        </Rule>
+        <Rule Name="FileMayOnlyContainASingleNamespace">
+          <RuleSettings>
+            <BooleanProperty Name="Enabled">False</BooleanProperty>
+          </RuleSettings>
+        </Rule>
+        <Rule Name="StatementMustNotUseUnnecessaryParenthesis">
+          <RuleSettings>
+            <BooleanProperty Name="Enabled">False</BooleanProperty>
+          </RuleSettings>
+        </Rule>
+        <Rule Name="ArithmeticExpressionsMustDeclarePrecedence">
+          <RuleSettings>
+            <BooleanProperty Name="Enabled">False</BooleanProperty>
+          </RuleSettings>
+        </Rule>
+        <Rule Name="ConditionalExpressionsMustDeclarePrecedence">
+          <RuleSettings>
+            <BooleanProperty Name="Enabled">False</BooleanProperty>
+          </RuleSettings>
+        </Rule>
+        <Rule Name="RemoveDelegateParenthesisWhenPossible">
+          <RuleSettings>
+            <BooleanProperty Name="Enabled">False</BooleanProperty>
+          </RuleSettings>
+        </Rule>
+        <Rule Name="AttributeConstructorMustNotUseUnnecessaryParenthesis">
+          <RuleSettings>
+            <BooleanProperty Name="Enabled">False</BooleanProperty>
+          </RuleSettings>
+        </Rule>
+        <Rule Name="RemoveUnnecessaryCode">
+          <RuleSettings>
+            <BooleanProperty Name="Enabled">False</BooleanProperty>
+          </RuleSettings>
+        </Rule>
+      </Rules>
+      <AnalyzerSettings />
+    </Analyzer>
+    <Analyzer AnalyzerId="StyleCop.CSharp.NamingRules">
+      <Rules>
+        <Rule Name="ElementMustBeginWithLowerCaseLetter">
+          <RuleSettings>
+            <BooleanProperty Name="Enabled">False</BooleanProperty>
+          </RuleSettings>
+        </Rule>
+        <Rule Name="ConstFieldNamesMustBeginWithUpperCaseLetter">
+          <RuleSettings>
+            <BooleanProperty Name="Enabled">False</BooleanProperty>
+          </RuleSettings>
+        </Rule>
+        <Rule Name="NonPrivateReadonlyFieldsMustBeginWithUpperCaseLetter">
+          <RuleSettings>
+            <BooleanProperty Name="Enabled">False</BooleanProperty>
+          </RuleSettings>
+        </Rule>
+        <Rule Name="FieldNamesMustNotUseHungarianNotation">
+          <RuleSettings>
+            <BooleanProperty Name="Enabled">False</BooleanProperty>
+          </RuleSettings>
+        </Rule>
+        <Rule Name="FieldNamesMustBeginWithLowerCaseLetter">
+          <RuleSettings>
+            <BooleanProperty Name="Enabled">False</BooleanProperty>
+          </RuleSettings>
+        </Rule>
+        <Rule Name="AccessibleFieldsMustBeginWithUpperCaseLetter">
+          <RuleSettings>
+            <BooleanProperty Name="Enabled">False</BooleanProperty>
+          </RuleSettings>
+        </Rule>
+        <Rule Name="VariableNamesMustNotBePrefixed">
+          <RuleSettings>
+            <BooleanProperty Name="Enabled">False</BooleanProperty>
+          </RuleSettings>
+        </Rule>
+        <Rule Name="FieldNamesMustNotBeginWithUnderscore">
+          <RuleSettings>
+            <BooleanProperty Name="Enabled">False</BooleanProperty>
+          </RuleSettings>
+        </Rule>
+        <Rule Name="FieldNamesMustNotContainUnderscore">
+          <RuleSettings>
+            <BooleanProperty Name="Enabled">False</BooleanProperty>
+          </RuleSettings>
+        </Rule>
+        <Rule Name="StaticReadonlyFieldsMustBeginWithUpperCaseLetter">
+          <RuleSettings>
+            <BooleanProperty Name="Enabled">False</BooleanProperty>
+          </RuleSettings>
+        </Rule>
+      </Rules>
+      <AnalyzerSettings />
+    </Analyzer>
+    <Analyzer AnalyzerId="StyleCop.CSharp.OrderingRules">
+      <Rules>
+        <Rule Name="UsingDirectivesMustBePlacedWithinNamespace">
+          <RuleSettings>
+            <BooleanProperty Name="Enabled">False</BooleanProperty>
+          </RuleSettings>
+        </Rule>
+        <Rule Name="ElementsMustAppearInTheCorrectOrder">
+          <RuleSettings>
+            <BooleanProperty Name="Enabled">False</BooleanProperty>
+          </RuleSettings>
+        </Rule>
+        <Rule Name="ElementsMustBeOrderedByAccess">
+          <RuleSettings>
+            <BooleanProperty Name="Enabled">False</BooleanProperty>
+          </RuleSettings>
+        </Rule>
+        <Rule Name="ConstantsMustAppearBeforeFields">
+          <RuleSettings>
+            <BooleanProperty Name="Enabled">False</BooleanProperty>
+          </RuleSettings>
+        </Rule>
+        <Rule Name="StaticElementsMustAppearBeforeInstanceElements">
+          <RuleSettings>
+            <BooleanProperty Name="Enabled">False</BooleanProperty>
+          </RuleSettings>
+        </Rule>
+        <Rule Name="DeclarationKeywordsMustFollowOrder">
+          <RuleSettings>
+            <BooleanProperty Name="Enabled">False</BooleanProperty>
+          </RuleSettings>
+        </Rule>
+        <Rule Name="ProtectedMustComeBeforeInternal">
+          <RuleSettings>
+            <BooleanProperty Name="Enabled">False</BooleanProperty>
+          </RuleSettings>
+        </Rule>
+        <Rule Name="PropertyAccessorsMustFollowOrder">
+          <RuleSettings>
+            <BooleanProperty Name="Enabled">False</BooleanProperty>
+          </RuleSettings>
+        </Rule>
+        <Rule Name="EventAccessorsMustFollowOrder">
+          <RuleSettings>
+            <BooleanProperty Name="Enabled">False</BooleanProperty>
+          </RuleSettings>
+        </Rule>
+        <Rule Name="StaticReadonlyElementsMustAppearBeforeStaticNonReadonlyElements">
+          <RuleSettings>
+            <BooleanProperty Name="Enabled">False</BooleanProperty>
+          </RuleSettings>
+        </Rule>
+        <Rule Name="InstanceReadonlyElementsMustAppearBeforeInstanceNonReadonlyElements">
+          <RuleSettings>
+            <BooleanProperty Name="Enabled">False</BooleanProperty>
+          </RuleSettings>
+        </Rule>
+        <Rule Name="SystemUsingDirectivesMustBePlacedBeforeOtherUsingDirectives">
+          <RuleSettings>
+            <BooleanProperty Name="Enabled">False</BooleanProperty>
+          </RuleSettings>
+        </Rule>
+        <Rule Name="UsingAliasDirectivesMustBePlacedAfterOtherUsingDirectives">
+          <RuleSettings>
+            <BooleanProperty Name="Enabled">False</BooleanProperty>
+          </RuleSettings>
+        </Rule>
+        <Rule Name="UsingDirectivesMustBeOrderedAlphabeticallyByNamespace">
+          <RuleSettings>
+            <BooleanProperty Name="Enabled">False</BooleanProperty>
+          </RuleSettings>
+        </Rule>
+        <Rule Name="UsingAliasDirectivesMustBeOrderedAlphabeticallyByAliasName">
+          <RuleSettings>
+            <BooleanProperty Name="Enabled">False</BooleanProperty>
+          </RuleSettings>
+        </Rule>
+        <Rule Name="UsingStaticDirectivesMustBePlacedAtTheCorrectLocation">
+          <RuleSettings>
+            <BooleanProperty Name="Enabled">False</BooleanProperty>
+          </RuleSettings>
+        </Rule>
+      </Rules>
+      <AnalyzerSettings />
+    </Analyzer>
+    <Analyzer AnalyzerId="StyleCop.CSharp.ReadabilityRules">
+      <Rules>
+        <Rule Name="CommentsMustContainText">
+          <RuleSettings>
+            <BooleanProperty Name="Enabled">False</BooleanProperty>
+          </RuleSettings>
+        </Rule>
+        <Rule Name="DoNotPrefixCallsWithBaseUnlessLocalImplementationExists">
+          <RuleSettings>
+            <BooleanProperty Name="Enabled">False</BooleanProperty>
+          </RuleSettings>
+        </Rule>
+        <Rule Name="PrefixLocalCallsWithThis">
+          <RuleSettings>
+            <BooleanProperty Name="Enabled">False</BooleanProperty>
+          </RuleSettings>
+        </Rule>
+        <Rule Name="PrefixCallsCorrectly">
+          <RuleSettings>
+            <BooleanProperty Name="Enabled">False</BooleanProperty>
+          </RuleSettings>
+        </Rule>
+        <Rule Name="OpeningParenthesisMustBeOnDeclarationLine">
+          <RuleSettings>
+            <BooleanProperty Name="Enabled">False</BooleanProperty>
+          </RuleSettings>
+        </Rule>
+        <Rule Name="ClosingParenthesisMustBeOnLineOfLastParameter">
+          <RuleSettings>
+            <BooleanProperty Name="Enabled">False</BooleanProperty>
+          </RuleSettings>
+        </Rule>
+        <Rule Name="ClosingParenthesisMustBeOnLineOfOpeningParenthesis">
+          <RuleSettings>
+            <BooleanProperty Name="Enabled">False</BooleanProperty>
+          </RuleSettings>
+        </Rule>
+        <Rule Name="CommaMustBeOnSameLineAsPreviousParameter">
+          <RuleSettings>
+            <BooleanProperty Name="Enabled">False</BooleanProperty>
+          </RuleSettings>
+        </Rule>
+        <Rule Name="ParameterListMustFollowDeclaration">
+          <RuleSettings>
+            <BooleanProperty Name="Enabled">False</BooleanProperty>
+          </RuleSettings>
+        </Rule>
+        <Rule Name="ParameterMustFollowComma">
+          <RuleSettings>
+            <BooleanProperty Name="Enabled">False</BooleanProperty>
+          </RuleSettings>
+        </Rule>
+        <Rule Name="SplitParametersMustStartOnLineAfterDeclaration">
+          <RuleSettings>
+            <BooleanProperty Name="Enabled">False</BooleanProperty>
+          </RuleSettings>
+        </Rule>
+        <Rule Name="ParametersMustBeOnSameLineOrSeparateLines">
+          <RuleSettings>
+            <BooleanProperty Name="Enabled">False</BooleanProperty>
+          </RuleSettings>
+        </Rule>
+        <Rule Name="ParameterMustNotSpanMultipleLines">
+          <RuleSettings>
+            <BooleanProperty Name="Enabled">False</BooleanProperty>
+          </RuleSettings>
+        </Rule>
+        <Rule Name="QueryClauseMustFollowPreviousClause">
+          <RuleSettings>
+            <BooleanProperty Name="Enabled">False</BooleanProperty>
+          </RuleSettings>
+        </Rule>
+        <Rule Name="QueryClausesMustBeOnSeparateLinesOrAllOnOneLine">
+          <RuleSettings>
+            <BooleanProperty Name="Enabled">False</BooleanProperty>
+          </RuleSettings>
+        </Rule>
+        <Rule Name="QueryClauseMustBeginOnNewLineWhenPreviousClauseSpansMultipleLines">
+          <RuleSettings>
+            <BooleanProperty Name="Enabled">False</BooleanProperty>
+          </RuleSettings>
+        </Rule>
+        <Rule Name="QueryClausesSpanningMultipleLinesMustBeginOnOwnLine">
+          <RuleSettings>
+            <BooleanProperty Name="Enabled">False</BooleanProperty>
+          </RuleSettings>
+        </Rule>
+        <Rule Name="DoNotPlaceRegionsWithinElements">
+          <RuleSettings>
+            <BooleanProperty Name="Enabled">False</BooleanProperty>
+          </RuleSettings>
+        </Rule>
+        <Rule Name="CodeMustNotContainEmptyStatements">
+          <RuleSettings>
+            <BooleanProperty Name="Enabled">False</BooleanProperty>
+          </RuleSettings>
+        </Rule>
+        <Rule Name="CodeMustNotContainMultipleStatementsOnOneLine">
+          <RuleSettings>
+            <BooleanProperty Name="Enabled">False</BooleanProperty>
+          </RuleSettings>
+        </Rule>
+        <Rule Name="BlockStatementsMustNotContainEmbeddedComments">
+          <RuleSettings>
+            <BooleanProperty Name="Enabled">False</BooleanProperty>
+          </RuleSettings>
+        </Rule>
+        <Rule Name="BlockStatementsMustNotContainEmbeddedRegions">
+          <RuleSettings>
+            <BooleanProperty Name="Enabled">False</BooleanProperty>
+          </RuleSettings>
+        </Rule>
+        <Rule Name="UseReadableConditions">
+          <RuleSettings>
+            <BooleanProperty Name="Enabled">False</BooleanProperty>
+          </RuleSettings>
+        </Rule>
+        <Rule Name="UseStringEmptyForEmptyStrings">
+          <RuleSettings>
+            <BooleanProperty Name="Enabled">False</BooleanProperty>
+          </RuleSettings>
+        </Rule>
+        <Rule Name="UseBuiltInTypeAlias">
+          <RuleSettings>
+            <BooleanProperty Name="Enabled">False</BooleanProperty>
+          </RuleSettings>
+        </Rule>
+        <Rule Name="UseShorthandForNullableTypes">
+          <RuleSettings>
+            <BooleanProperty Name="Enabled">False</BooleanProperty>
+          </RuleSettings>
+        </Rule>
+      </Rules>
+      <AnalyzerSettings />
+    </Analyzer>
+    <Analyzer AnalyzerId="StyleCop.CSharp.SpacingRules">
+      <Rules>
+        <Rule Name="CommasMustBeSpacedCorrectly">
+          <RuleSettings>
+            <BooleanProperty Name="Enabled">False</BooleanProperty>
+          </RuleSettings>
+        </Rule>
+        <Rule Name="SemicolonsMustBeSpacedCorrectly">
+          <RuleSettings>
+            <BooleanProperty Name="Enabled">False</BooleanProperty>
+          </RuleSettings>
+        </Rule>
+        <Rule Name="DocumentationLinesMustBeginWithSingleSpace">
+          <RuleSettings>
+            <BooleanProperty Name="Enabled">False</BooleanProperty>
+          </RuleSettings>
+        </Rule>
+        <Rule Name="SingleLineCommentsMustBeginWithSingleSpace">
+          <RuleSettings>
+            <BooleanProperty Name="Enabled">False</BooleanProperty>
+          </RuleSettings>
+        </Rule>
+        <Rule Name="PreprocessorKeywordsMustNotBePrecededBySpace">
+          <RuleSettings>
+            <BooleanProperty Name="Enabled">False</BooleanProperty>
+          </RuleSettings>
+        </Rule>
+        <Rule Name="OperatorKeywordMustBeFollowedBySpace">
+          <RuleSettings>
+            <BooleanProperty Name="Enabled">False</BooleanProperty>
+          </RuleSettings>
+        </Rule>
+        <Rule Name="OpeningCurlyBracketsMustBeSpacedCorrectly">
+          <RuleSettings>
+            <BooleanProperty Name="Enabled">False</BooleanProperty>
+          </RuleSettings>
+        </Rule>
+        <Rule Name="ClosingCurlyBracketsMustBeSpacedCorrectly">
+          <RuleSettings>
+            <BooleanProperty Name="Enabled">False</BooleanProperty>
+          </RuleSettings>
+        </Rule>
+        <Rule Name="OpeningGenericBracketsMustBeSpacedCorrectly">
+          <RuleSettings>
+            <BooleanProperty Name="Enabled">False</BooleanProperty>
+          </RuleSettings>
+        </Rule>
+        <Rule Name="ClosingGenericBracketsMustBeSpacedCorrectly">
+          <RuleSettings>
+            <BooleanProperty Name="Enabled">False</BooleanProperty>
+          </RuleSettings>
+        </Rule>
+        <Rule Name="OpeningAttributeBracketsMustBeSpacedCorrectly">
+          <RuleSettings>
+            <BooleanProperty Name="Enabled">False</BooleanProperty>
+          </RuleSettings>
+        </Rule>
+        <Rule Name="ClosingAttributeBracketsMustBeSpacedCorrectly">
+          <RuleSettings>
+            <BooleanProperty Name="Enabled">False</BooleanProperty>
+          </RuleSettings>
+        </Rule>
+        <Rule Name="NullableTypeSymbolsMustNotBePrecededBySpace">
+          <RuleSettings>
+            <BooleanProperty Name="Enabled">False</BooleanProperty>
+          </RuleSettings>
+        </Rule>
+        <Rule Name="MemberAccessSymbolsMustBeSpacedCorrectly">
+          <RuleSettings>
+            <BooleanProperty Name="Enabled">False</BooleanProperty>
+          </RuleSettings>
+        </Rule>
+        <Rule Name="IncrementDecrementSymbolsMustBeSpacedCorrectly">
+          <RuleSettings>
+            <BooleanProperty Name="Enabled">False</BooleanProperty>
+          </RuleSettings>
+        </Rule>
+        <Rule Name="NegativeSignsMustBeSpacedCorrectly">
+          <RuleSettings>
+            <BooleanProperty Name="Enabled">False</BooleanProperty>
+          </RuleSettings>
+        </Rule>
+        <Rule Name="PositiveSignsMustBeSpacedCorrectly">
+          <RuleSettings>
+            <BooleanProperty Name="Enabled">False</BooleanProperty>
+          </RuleSettings>
+        </Rule>
+        <Rule Name="DereferenceAndAccessOfSymbolsMustBeSpacedCorrectly">
+          <RuleSettings>
+            <BooleanProperty Name="Enabled">False</BooleanProperty>
+          </RuleSettings>
+        </Rule>
+        <Rule Name="ColonsMustBeSpacedCorrectly">
+          <RuleSettings>
+            <BooleanProperty Name="Enabled">False</BooleanProperty>
+          </RuleSettings>
+        </Rule>
+        <Rule Name="CodeMustNotContainMultipleWhitespaceInARow">
+          <RuleSettings>
+            <BooleanProperty Name="Enabled">False</BooleanProperty>
+          </RuleSettings>
+        </Rule>
+        <Rule Name="CodeMustNotContainSpaceAfterNewKeywordInImplicitlyTypedArrayAllocation">
+          <RuleSettings>
+            <BooleanProperty Name="Enabled">False</BooleanProperty>
+          </RuleSettings>
+        </Rule>
+        <Rule Name="TabsMustNotBeUsed">
+          <RuleSettings>
+            <BooleanProperty Name="Enabled">False</BooleanProperty>
+          </RuleSettings>
+        </Rule>
+        <Rule Name="DoNotSplitNullConditionalOperators">
+          <RuleSettings>
+            <BooleanProperty Name="Enabled">False</BooleanProperty>
+          </RuleSettings>
+        </Rule>
+      </Rules>
+      <AnalyzerSettings />
+    </Analyzer>
+  </Analyzers>
+</StyleCopSettings>
\ No newline at end of file
diff --git a/Test/Voicememo2020/VoiceMemo/Utility.cs b/Test/Voicememo2020/VoiceMemo/Utility.cs
new file mode 100755 (executable)
index 0000000..a64af3d
--- /dev/null
@@ -0,0 +1,38 @@
+using System;
+using System.Reflection;
+
+namespace VoiceMemo
+{
+    public class Utility
+    {
+        public Utility()
+        {
+
+        }
+
+        public static void PrintProperties(object obj)
+        {
+            try
+            {
+                var type = obj.GetType();
+
+                foreach (PropertyInfo p in type.GetProperties())
+                {
+                    object propertyValue = p.GetValue(obj, null);
+                    Console.WriteLine(p.Name + ":- " + propertyValue);
+                    //Console.WriteLine(p.Name + ":- " + p.GetValue(obj, null));
+
+                    //if (p.PropertyType.GetProperties().Count() > 0)
+                    //{
+                    //    // what to pass in to recursive method
+                    //    PrintProperties(propertyValue);
+                    //}
+                }
+            }
+            catch (Exception e)
+            {
+                Console.WriteLine("    FAILED PrintProperties : " + e.Message);
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/Test/Voicememo2020/VoiceMemo/Utility/ColorConverter.cs b/Test/Voicememo2020/VoiceMemo/Utility/ColorConverter.cs
new file mode 100755 (executable)
index 0000000..eb0309a
--- /dev/null
@@ -0,0 +1,181 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using Xamarin.Forms;
+
+namespace VoiceMemo.Utility
+{
+    internal struct RGB : IEquatable<RGB>
+    {
+        internal RGB(byte r, byte g, byte b)
+        {
+            R = r;
+            G = g;
+            B = b;
+        }
+        
+        internal byte R { get; set; }
+
+        internal byte G { get; set; }
+
+        internal byte B { get; set; }
+
+        bool IEquatable<RGB>.Equals(RGB rgb)
+        {
+            return (R == rgb.R) && (G == rgb.G) && (B == rgb.B);
+        }
+    }
+
+    internal struct HSB
+    {
+        internal HSB(double h, double s, double b)
+        {
+            H = h;
+            S = s;
+            B = b;
+            A = null;
+        }
+
+        internal HSB(double h, double s, double b, double a)
+        {
+            H = h;
+            S = s;
+            B = b;
+            A = a;
+        }
+
+        internal double H { get; set; }
+
+        internal double S { get; set; }
+
+        internal double B { get; set; }
+
+        internal double? A { get; set; }
+
+        internal bool Equals(HSB hsb)
+        {
+            return (this.H == hsb.H) && (this.S == hsb.S) && (this.B == hsb.B) && (this.A == hsb.A);
+        }
+    }
+
+    internal static class OneUITheme
+    {
+        internal static HSB BlackTheme = new HSB(0, 0, 0);
+
+        internal static HSB WhiteTheme = new HSB(0, 0, 98);
+
+        internal static HSB[] DefaultTheme =
+        {
+            // 1st
+            new HSB(207,75,16),
+            // 2nd
+            new HSB(203, 98, 37),
+            // 3rd
+            new HSB(207, 91, 37),
+            // 4th
+            new HSB(208, 70, 100)
+        };
+    }
+
+    internal static class ColorConverter
+    {
+
+        internal static Xamarin.Forms.Color OneUIColorConverter(HSB hsb, HSB? input)
+        {
+            // Get component's color
+            float h = (input == null) ? (float)hsb.H : (float)hsb.H + (float)input?.H;
+            float s = (input == null) ? (float)hsb.S : (float)hsb.S + (float)input?.S;
+            float b = (input == null) ? (float)hsb.B : (float)hsb.B + (float)input?.B;
+
+            // Check the range
+            h = (h > 360.0f) ? (h - 360.0f) : ((h < 0.0f) ? (h + 360.0f) : h);
+            s = (s > 100.0f) ? (100.0f) : ((s < 0.0f) ? (0.0f) : s);
+            b = (b > 100.0f) ? (100.0f) : ((b < 0.0f) ? (0.0f) : b);
+
+            s /= 100.0f;
+            b /= 100.0f;
+
+            RGB rgb = HsbToRgb(
+                new HSB {
+                    H = h,
+                    S = s,
+                    B = b
+                });
+
+            float a;    
+            a = (int)(255 * hsb.A / 100);
+            a = (a > 255) ? (255) : ((a < 0) ? 0 : a);
+            return Color.FromRgba((int)rgb.R, (int)rgb.G, (int)rgb.B, (int)a);
+        }
+
+        internal static RGB HsbToRgb(HSB hsb)
+        {
+            double r = 0, g = 0, b = 0;
+
+            if (hsb.S == 0)
+            {
+                r = hsb.B;
+                g = hsb.B;
+                b = hsb.B;
+            }
+            else
+            {
+                int i;
+                double f, p, q, t;
+
+                if (hsb.H == 360)
+                    hsb.H = 0;
+                else
+                    hsb.H /= 60;
+
+                i = (int)Math.Truncate(hsb.H);
+                f = hsb.H - i;
+
+                p = hsb.B * (1.0 - hsb.S);
+                q = hsb.B * (1.0 - (hsb.S * f));
+                t = hsb.B * (1.0 - (hsb.S * (1.0 - f)));
+
+                switch (i)
+                {
+                    case 0:
+                        r = hsb.B;
+                        g = t;
+                        b = p;
+                        break;
+
+                    case 1:
+                        r = q;
+                        g = hsb.B;
+                        b = p;
+                        break;
+
+                    case 2:
+                        r = p;
+                        g = hsb.B;
+                        b = t;
+                        break;
+
+                    case 3:
+                        r = p;
+                        g = q;
+                        b = hsb.B;
+                        break;
+
+                    case 4:
+                        r = t;
+                        g = p;
+                        b = hsb.B;
+                        break;
+
+                    default:
+                        r = hsb.B;
+                        g = p;
+                        b = q;
+                        break;
+                }
+            }
+            return new RGB((byte)(r * 255), (byte)(g * 255), (byte)(b * 255));
+        }
+    }
+}
diff --git a/Test/Voicememo2020/VoiceMemo/Utility/LogInformation.cs b/Test/Voicememo2020/VoiceMemo/Utility/LogInformation.cs
new file mode 100755 (executable)
index 0000000..186cd9b
--- /dev/null
@@ -0,0 +1,12 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace VoiceMemo.Utility
+{
+    internal static class LOG
+    {
+        internal const string TAG = "Voicememo-2019";
+    }
+}
diff --git a/Test/Voicememo2020/VoiceMemo/Utility/PrivilegeInformation.cs b/Test/Voicememo2020/VoiceMemo/Utility/PrivilegeInformation.cs
new file mode 100755 (executable)
index 0000000..a2bbd80
--- /dev/null
@@ -0,0 +1,13 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace VoiceMemo.Utility
+{
+    internal static class PrivilegeInformation
+    {
+        internal const string RecorderPrivilege = "http://tizen.org/privilege/recorder";
+        internal const string MediaStoragePrivilege = "http://tizen.org/privilege/mediastorage";
+    }
+}
diff --git a/Test/Voicememo2020/VoiceMemo/ViewModels/BasePageModel.cs b/Test/Voicememo2020/VoiceMemo/ViewModels/BasePageModel.cs
new file mode 100755 (executable)
index 0000000..53647e0
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://floralicense.org/license/
+ *
+ * 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.Collections.Generic;
+using System.ComponentModel;
+using System.Runtime.CompilerServices;
+
+namespace VoiceMemo.ViewModels
+{
+    // Base page model class
+    public class BasePageModel : INotifyPropertyChanged
+    {
+        public virtual void UpdateText()
+        {
+        }
+
+        protected bool SetProperty<T>(ref T backingStore, T value,
+            [CallerMemberName]string propertyName = "",
+            Action onChanged = null)
+        {
+            if (EqualityComparer<T>.Default.Equals(backingStore, value))
+            {
+                return false;
+            }
+
+            backingStore = value;
+            onChanged?.Invoke();
+            OnPropertyChanged(propertyName);
+            return true;
+        }
+
+#region INotifyPropertyChanged
+        public event PropertyChangedEventHandler PropertyChanged;
+        /// <summary>
+        /// Called to notify that a change of property happened
+        /// </summary>
+        /// <param name="propertyName">The name of the property that changed</param>
+        protected void OnPropertyChanged([CallerMemberName] string propertyName = "")
+        {
+            var changed = PropertyChanged;
+            if (changed == null)
+            {
+                return;
+            }
+
+            changed.Invoke(this, new PropertyChangedEventArgs(propertyName));
+        }
+#endregion
+    }
+}
\ No newline at end of file
diff --git a/Test/Voicememo2020/VoiceMemo/ViewModels/DetailsPageModel.cs b/Test/Voicememo2020/VoiceMemo/ViewModels/DetailsPageModel.cs
new file mode 100755 (executable)
index 0000000..e74926c
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://floralicense.org/license/
+ *
+ * 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 VoiceMemo.Models;
+
+namespace VoiceMemo.ViewModels
+{
+    // The model class for DetailPage
+    public class DetailsPageModel : BasePageModel
+    {
+        // Record that is shown in DetailsPage
+        Record _record;
+        public bool IsNew
+        {
+            get;
+            set;
+        }
+        /// <summary>
+        /// Record to display in Details Page
+        /// </summary>
+        public Record Record
+        {
+            get
+            {
+                return _record;
+            }
+
+            set
+            {
+                SetProperty(ref _record, value, "Record");
+            }
+        }
+
+        public DetailsPageModel(Record record = null)
+        {
+            Init(record);
+        }
+        /// <summary>
+        /// Initialize Detail Page with Record
+        /// </summary>
+        /// <param name="record">Record to be shown</param>
+        public void Init(Record record)
+        {
+            if (record is LatestRecord)
+            {
+                IsNew = true;
+                Record = ((LatestRecord)record).Record;
+            }
+            else
+            {
+                IsNew = false;
+                Record = record;
+            }
+        }
+    }
+}
diff --git a/Test/Voicememo2020/VoiceMemo/ViewModels/MainPageModel.cs b/Test/Voicememo2020/VoiceMemo/ViewModels/MainPageModel.cs
new file mode 100755 (executable)
index 0000000..7123121
--- /dev/null
@@ -0,0 +1,580 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://floralicense.org/license/
+ *
+ * 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.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Globalization;
+using System.Threading.Tasks;
+using System.Windows.Input;
+using VoiceMemo.Models;
+using VoiceMemo.Resx;
+using VoiceMemo.Services;
+using Xamarin.Forms;
+
+namespace VoiceMemo.ViewModels
+{
+    // The model class for MainPage
+    public class MainPageModel : BasePageModel
+    {
+        // Collection of Records
+        ObservableCollection<Record> _Records;
+        // Language for STT recognition
+        string _CurrentLanguage;
+        // Speech-To-Text Service
+        SpeechToTextService _SttService;
+        // Media Content Service to get the path of audio record file
+        MediaContentService _ContentService;
+        // App data service to store / restore app data
+        AppDataService _AppDataService;
+        // indicate whether it is possible to record voice
+        public bool availableToRecord;
+
+        public MainPageModel()
+        {
+            if (Records == null)
+            {
+                Records = new ObservableCollection<Record>();
+            }
+
+            Init();
+
+            RegisterForImportantEvents();
+        }
+
+        // Initialize
+        void Init()
+        {
+            IsCheckable = false;
+            _AppDataService = AppDataService.Instance;
+            if (_AppDataService.Contain(STT_ON_OFF))
+            {
+                SttEnabled = _AppDataService.GetValue<bool>(STT_ON_OFF);
+                //Console.WriteLine(" STT_ON_OFF ???  : " + SttEnabled);
+            }
+            else
+            {
+                SttEnabled = false;
+                //Console.WriteLine(" There's no default value for SttEnabled so make it false. : " + SttEnabled);
+            }
+
+            if (SttEnabled)
+            {
+                MainLabelText = AppResources.StandByTitleMemo;
+            }
+            else
+            {
+                MainLabelText = AppResources.StandByTitleRecorder;
+            }
+            
+            availableToRecord = true;
+        }
+
+        // Subscribe to get notified when some events occur.
+        // 1. When a new voice memo is saved in an internal storage
+        // 2. When a voice memo is deleted from an internal storage
+        // 3. When it's checked whether user consent is obtained
+        /*async*/ void RegisterForImportantEvents()
+        {
+            try
+            {
+                //Console.WriteLine("[RegisterForImportantEvents] 1");
+                // You can get notified whenever a new voice memo record is created.
+                // At this point of time, information(record) about that voice memo is needed to store
+                MessagingCenter.Subscribe<RecordingPageModel, Record>(this, MessageKeys.SaveVoiceMemo, (obj, item) =>
+                {
+                    // Add it to the collection of records
+                    var record = ((LatestRecord)item).Record;
+                    //if (Records == null)
+                    //{
+                    //    Records = new ObservableCollection<Record>();
+                    //}
+                    Records.Add(record);
+                });
+                //Console.WriteLine("[RegisterForImportantEvents] 2");
+                // You can get notified whenever translated text via speech-to-text service is ready
+                // Now, we can update Record to database
+                MessagingCenter.Subscribe<RecordingPageModel, Record>(this, MessageKeys.SaveVoiceMemoInDB, async (obj, record) =>
+                {
+                    // add it to database
+                    await App.Database.SaveItemAsync(record);
+                });
+                //Console.WriteLine("[RegisterForImportantEvents] 3");
+                // You can get notified whenever a voice memo record is deleted from a storage
+                MessagingCenter.Subscribe<Page, Record>(this, MessageKeys.DeleteVoiceMemo, async (obj, item) =>
+                {
+                    var record = item as Record;
+                    for (int i = Records.Count - 1; i >= 0; i--)
+                    {
+                        if (Records[i]._id == record._id)
+                        {
+                        // Delete record from database
+                        await App.Database.DeleteItemAsync(Records[i]);
+                        // Delete audio file from internal storage
+                        _ContentService.RemoveMediaFile(Records[i].Path);
+                        // Delete it from collection of records
+                        Records.RemoveAt(i);
+                        }
+                    }
+                });
+
+                // You can get notified when an app user allows this app to use recorder and internal storage.
+                //MessagingCenter.Subscribe<App, bool>(this, MessageKeys.UserPermission, (obj, item) =>
+                //{
+                //    var NonUItask = Task.Run(async () =>
+                //    {
+                //        //await Task.Delay(3000);
+                //        // Restore recorded voice memos
+                //        List<Record> tmp = await App.Database.GetItemsAsync();
+                //        for (int i = 0; i < tmp.Count; i++)
+                //        {
+                //            Records.Add(tmp[i]);
+                //        }
+                //        // Speech-To-Text Service
+                //        GetSttService();
+
+                //        // Media Content Service
+                //        if (_ContentService == null)
+                //        {
+                //            _ContentService = MediaContentService.Instance;
+                //        }
+                //    });
+                //});
+                //Console.WriteLine("[RegisterForImportantEvents] 4");
+                //List<Record> tmp = await App.Database.GetItemsAsync();
+                //for (int i = 0; i < tmp.Count; i++)
+                //{
+                //    Records.Add(tmp[i]);
+                //}
+                // Speech-To-Text Service
+                //GetSttService();
+                //Console.WriteLine("[RegisterForImportantEvents] 5");
+                // Media Content Service
+                if (_ContentService == null)
+                {
+                    _ContentService = MediaContentService.Instance;
+                }
+            }
+            catch (Exception e)
+            {
+                Console.WriteLine("[RegisterForImportantEvents] " + e.Message +", " + e.StackTrace);
+            }
+        }
+
+        /// <summary>
+        /// Unsubscribe from notifications
+        /// </summary>
+        void UnregisterForImportantEvents()
+        {
+            MessagingCenter.Unsubscribe<RecordingPageModel, Record>(this, MessageKeys.SaveVoiceMemo);
+            MessagingCenter.Unsubscribe<Page, Record>(this, MessageKeys.DeleteVoiceMemo);
+            MessagingCenter.Unsubscribe<App, bool>(this, MessageKeys.UserPermission);
+        }
+
+        public void Dispose()
+        {
+            Console.WriteLine("### MainPageModel.Dispose()  -----_SttService?.Dispose()----");
+            UnregisterForImportantEvents();
+            _AppDataService.SetValue(STT_ON_OFF, SttEnabled);
+            if (SelectedItemIndex != null)
+            {
+                Console.WriteLine("### MainPageModel.Dispose()   SAVE Language : " + SelectedItemIndex.Lang);
+                _AppDataService.SetValue(LANGUAGE_FOR_STT, SelectedItemIndex.Lang);
+            }
+            
+            _SttService?.Dispose();
+            _ContentService?.Destroy();
+        }
+
+        /// <summary>
+        /// Collection of Records
+        /// </summary>
+        public ObservableCollection<Record> Records
+        {
+            get
+            {
+                return _Records;
+            }
+
+            set
+            {
+                bool changed = SetProperty(ref _Records, value, "Records");
+
+                Console.WriteLine(" ##########  Records  changed? " + changed);
+                if (changed && Records.Count == 0)
+                {
+                    Console.WriteLine(" ##########  Records.Count is 0!!");
+                }
+            }
+        }
+
+        // Language for STT recognition
+        public string CurrentLanguage
+        {
+            get
+            {
+                return _CurrentLanguage;
+            }
+
+            set
+            {
+                if (SetProperty(ref _CurrentLanguage, value, "CurrentLanguage"))
+                {
+                    Console.WriteLine("Language for STT service has been changed. So update _SttService's CurrentSttLanguage. : " + CurrentLanguage);
+                    if (_SttService != null)
+                    {
+                        _SttService.CurrentSttLanguage = CurrentLanguage;
+                    }
+                }
+            }
+        }
+
+        SttLanguage _SelectedItemIndex;
+        public SttLanguage SelectedItemIndex
+        {
+            get
+            {
+                return _SelectedItemIndex;
+            }
+
+            set
+            {
+                SetProperty(ref _SelectedItemIndex, value, "SelectedItemIndex");
+            }
+        }
+
+        public ObservableCollection<SttLanguage> Languages { get; set; }
+
+        //public ICommand DoInitCommand => new Command(Initialize);
+        //async void Initialize()
+        //{
+        //    //List<Record> tmp = await App.Database.GetItemsAsync();
+        //    //for (int i = 0; i < tmp.Count; i++)
+        //    //{
+        //    //    Records.Add(tmp[i]);
+        //    //}
+        //    // Speech-To-Text Service
+        //    await GetSttService();
+
+        //    // Media Content Service
+        //    //if (_contentservice == null)
+        //    //{
+        //    //    _contentservice = mediacontentservice.instance;
+        //    //}
+        //}
+
+        //public static readonly BindableProperty GetSttServiceCommandProperty =
+        //BindableProperty.Create("GetSttServiceCommand", typeof(Command), typeof(MainPageModel), default(Command));
+        public ICommand GetSttServiceCommand => new Command(async () => await GetSttService());
+        
+        //public static readonly BindableProperty SttOnOffCommandProperty =
+        //    BindableProperty.Create("SttOnOffCommand", typeof(Command), typeof(MainPageModel), default(Command));
+
+        public ICommand SttOnOffCommand => new Command(SttOnOff);
+
+        Task GetSttService()
+        {
+            if (_SttService == null)
+            {
+                Console.WriteLine(" GetSttService()  ------------1-  CurrentLanguage : " + CurrentLanguage);
+                _SttService = SpeechToTextService.Instance;
+                Languages = new ObservableCollection<SttLanguage>();
+
+                // TODO: how to check if the current language is supported by STT engine.
+                //CultureInfo _cultureInfo = new CultureInfo(CurrentLanguage);
+                //RegionInfo _regionInfo = new RegionInfo(CurrentLanguage.Replace("_", "-"));
+                //Languages.Add(new SttLanguage(CurrentLanguage, "Automatic", Regex.Replace(_cultureInfo.DisplayName, @"\t|\n|\r", "")));
+
+                
+                var dafaultLang = "en_US";
+                // Restore the selected language for STT or use the STT service's current language
+                if (_AppDataService.Contain(LANGUAGE_FOR_STT))
+                {
+                    dafaultLang = _AppDataService.GetValue(LANGUAGE_FOR_STT);
+                    Console.WriteLine(" IAppDataService.GetValue =>  language for stt  : " + dafaultLang);
+                }
+                else
+                {
+                    dafaultLang = _SttService.CurrentSttLanguage;
+                    Console.WriteLine(" IAppDataService no value =>  CurrentSttLanguage  : " + dafaultLang);
+                }
+                // For updating STT service's CurrentSttLanguage
+                CurrentLanguage = dafaultLang;
+
+                foreach (var lang in _SttService.GetInstalledLanguages())
+                {
+                    CultureInfo cultureInfo = new CultureInfo(lang);
+                    RegionInfo regionInfo = new RegionInfo(lang.Replace("_", "-"));
+                    Console.WriteLine(" [GetSttService]  lang : " + lang + ", " + cultureInfo.DisplayName + ", " + regionInfo.EnglishName);
+                    var stt = new SttLanguage(lang, cultureInfo.DisplayName, regionInfo.EnglishName);
+                    Languages.Add(stt);
+                    //Languages.Add(new SttLanguage(lang, cultureInfo.DisplayName, regionInfo.EnglishName));
+                    if (lang == dafaultLang)
+                    {
+                        stt.IsOn = true;
+                        SelectedItemIndex = stt;
+                    }
+                }
+#if ENABLE_DEBUG_PRINT
+                foreach (var lang in Languages)
+                {
+                    Console.WriteLine(" Languages  -- " + lang.Country + ", " + lang.Name + ", " + lang.IsOn); /*+ " vs. " + lang.isNotOn*/
+                }
+#endif
+                Console.WriteLine(" GetSttService()  ------------2-   " + _SttService.GetHashCode());
+            }
+            return Task.CompletedTask;
+        }
+
+        // STT feature usability
+        // in case of true : while recording voice, you can convert your voice to text (Speech to text)
+        // in case of false : just record voice.
+        bool _sttEnabled;
+        public bool SttEnabled
+        {
+            get
+            {
+                return _sttEnabled;
+            }
+
+            set
+            {
+                SetProperty(ref _sttEnabled, value, "SttEnabled");
+            }
+        }
+
+        void SttOnOff(object sender)
+        {
+            Console.WriteLine(" StandByPageModel.SttOnOff() : " + SttEnabled);
+            if (SttEnabled)
+            {
+                SttEnabled = false;
+                MainLabelText = AppResources.StandByTitleRecorder;
+            }
+            else
+            {
+                SttEnabled = true;
+                MainLabelText = AppResources.StandByTitleMemo;
+                GetSttService();
+            }
+
+            MessagingCenter.Send<MainPageModel, bool>(this, MessageKeys.SttSupportedChanged, SttEnabled);
+        }
+
+        // main label text : voice memo or voice recorder
+        string _mainlabeltext;
+        public string MainLabelText
+        {
+            get
+            {
+                return _mainlabeltext;
+            }
+
+            set
+            {
+                SetProperty(ref _mainlabeltext, value, "MainLabelText");
+            }
+        }
+
+        // Update the text of main label, depending on enabling or disabling stt service
+        public override void UpdateText()
+        {
+            if (SttEnabled)
+            {
+                // voice memo
+                MainLabelText = AppResources.StandByTitleMemo;
+            }
+            else
+            {
+                // voice recorder
+                MainLabelText = AppResources.StandByTitleRecorder;
+            }
+        }
+
+        ///////////////////////
+        const string SelectAll = "Select all";
+        const string DeselectAll = "Deselect all";
+
+        bool _isCheckable;
+        public bool IsCheckable
+        {
+            get
+            {
+                return _isCheckable;
+            }
+
+            set
+            {
+                bool result = SetProperty(ref _isCheckable, value, "IsCheckable");
+                if (result)
+                {
+                    Console.WriteLine("-----IsCheckable  : it's changed  ---> " + IsCheckable);
+                    if (!IsCheckable)
+                    {
+                        foreach (var record in Records)
+                        {
+                            record.Checked = false;
+                        }
+                    }
+                }
+            }
+        }
+
+        bool _popupVisibility;
+        public bool PopupVisibility
+        {
+            get
+            {
+                return _popupVisibility;
+            }
+
+            set
+            {
+                SetProperty(ref _popupVisibility, value, "PopupVisibility");
+            }
+        }
+
+        int _checkedNamesCount;
+        public int CheckedNamesCount
+        {
+            get
+            {
+                return _checkedNamesCount;
+            }
+
+            set
+            {
+                bool changed = SetProperty(ref _checkedNamesCount, value, "CheckedNamesCount");
+                if (changed)
+                {
+                    UpdateSelectOptionMessage();
+                }
+            }
+        }
+
+        string _selectOptionMessage1;
+        public string SelectOptionMessage1
+        {
+            get
+            {
+                return _selectOptionMessage1;
+            }
+
+            set
+            {
+                SetProperty(ref _selectOptionMessage1, value, "SelectOptionMessage1");
+            }
+        }
+
+        string _selectOptionMessage2;
+        public string SelectOptionMessage2
+        {
+            get
+            {
+                return _selectOptionMessage2;
+            }
+
+            set
+            {
+                SetProperty(ref _selectOptionMessage2, value, "SelectOptionMessage2");
+            }
+        }
+
+        void OnLongClick()
+        {
+            Console.WriteLine("OnLongClick() is invoked!!");
+            if (!IsCheckable)
+            {
+                IsCheckable = true;
+            }
+        }
+
+        void OnCheckedCounterClicked()
+        {
+            Console.WriteLine("OnCheckedCounterClicked() is invoked!!");
+            PopupVisibility = true;
+
+            Console.WriteLine("Checked is clicked!!!");
+        }
+
+        void SelectOption1Job()
+        {
+            bool r = CheckedNamesCount < Records.Count;
+            Console.WriteLine("CheckedNamesCount : " + CheckedNamesCount + " vs. CheckableNames.Count: " + Records.Count);
+            foreach (var x in Records)
+            {
+                x.Checked = r;
+            }
+        }
+
+        void SelectOption2Job()
+        {
+            Console.WriteLine("CheckedNamesCount : " + CheckedNamesCount + " vs. CheckableNames.Count: " + Records.Count);
+            if (CheckedNamesCount > 0 && CheckedNamesCount != Records.Count)
+            {
+                foreach (var x in Records)
+                {
+                    x.Checked = false;
+                }
+            }
+        }
+
+        void UpdateSelectOptionMessage()
+        {
+            SelectOptionMessage1 = CheckedNamesCount < Records.Count ? SelectAll : DeselectAll;
+            SelectOptionMessage2 = CheckedNamesCount != 0 && CheckedNamesCount != Records.Count ? DeselectAll : "";
+        }
+
+        async void DeleteRecords()
+        {
+            Console.WriteLine("   ########  DeleteRecords ");
+            for (int i = Records.Count - 1; i >= 0; i--)
+            {
+                //if (Records[i].ID == record.ID)
+                if (Records[i].Checked)
+                {
+                    await App.Database.DeleteItemAsync(Records[i]);
+                    _ContentService.RemoveMediaFile(Records[i].Path);
+                    Records.RemoveAt(i);
+                }
+            }
+
+            IsCheckable = false;
+            CheckedNamesCount = 0;
+        }
+
+        void ChangeToDeleteMode()
+        {
+            IsCheckable = true;
+        }
+
+        public ICommand SelectCommand1 => new Command(SelectOption1Job);
+        public ICommand SelectCommand2 => new Command(SelectOption2Job);
+        public ICommand DeleteRecordsCommand => new Command(DeleteRecords);
+        public ICommand ChangeToDeleteModeCommand => new Command(ChangeToDeleteMode);
+
+        public static readonly BindableProperty SelectModeActionButtonPressedCommandProperty =
+            BindableProperty.Create("SelectModeActionButtonPressedCommand", typeof(Command), typeof(MainPageModel), default(Command));
+        public ICommand SelectModeActionButtonPressedCommand => new Command(OnCheckedCounterClicked);
+
+        public static readonly BindableProperty LongClickCommandProperty =
+            BindableProperty.Create("LongClickCommand", typeof(Command), typeof(MainPageModel), default(Command));
+        public ICommand LongClickCommand => new Command(OnLongClick);
+
+        private const string LANGUAGE_FOR_STT = "language_for_stt";
+        private const string STT_ON_OFF = "stt_on_off";
+    }
+}
diff --git a/Test/Voicememo2020/VoiceMemo/ViewModels/MessageKeys.cs b/Test/Voicememo2020/VoiceMemo/ViewModels/MessageKeys.cs
new file mode 100755 (executable)
index 0000000..c960908
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://floralicense.org/license/
+ *
+ * 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.
+ */
+
+namespace VoiceMemo.ViewModels
+{
+    public class MessageKeys
+    {
+        // Notify that player's state has changed
+        public const string PlayerStateChanged = "PlayerStateChanged";
+
+        // Notify that Audio play has done
+        public const string AudioPlayDone = "AudioPlayDone";
+
+        // Notify that Error occurs
+        public const string ErrorOccur = "ErrorOccur";
+
+        // Notify that a voice memo is saved
+        public const string SaveVoiceMemo = "SaveVoiceMemo";
+
+        // Notify that a voice memo is saved in Database
+        public const string SaveVoiceMemoInDB = "SaveVoiceMemoInDB";
+
+        // Notify that a voice memo is deleted
+        public const string DeleteVoiceMemo = "DeleteVoiceMemo";
+
+        // Notify that language has been changed
+        public const string LanguageChanged = "LanguageChanged";
+
+        // Notify that STT configuration has been changed
+        public const string SttSupportedChanged = "SttSupportedChanged";
+
+        // TODO: It's not used yet.
+        // Notify that Stt text is ready
+        public const string SttText = "SttText";
+
+        // Notify that permission from an user is got or not
+        public const string UserPermission = "UserPermission";
+
+        // Notify that long click event occurs in RecordListPage
+        //public const string RecordListLongPressed = "RecordListLongPressed";
+
+        // TODO : It's a missing feature
+        // Notify that volume level is too high
+        //public const string WarnHearingDamange = "WarnHearingDamange";
+
+        // TODO : Need to consider this case
+        public const string CanStopSTT = "CanStopSTT";
+
+        // Notify that the state of audio recording service get Recording.
+        public const string ReadyToRecord = "ReadyToRecord";
+
+        // TODO : Need to consider this case
+        // forcibly go back to main page when stt state is not ready for recording.
+        // Even though stt is not ready, recording can be started. We can change it.
+        public const string ForcePopRecordingPage = "ForcePopRecordingPage";
+
+        // Notify that the some texts are needed to update for localization when the language has been changed.
+        public const string UpdateByLanguageChange = "UpdateByLanguageChange";
+    }
+}
diff --git a/Test/Voicememo2020/VoiceMemo/ViewModels/PlayBackPageModel.cs b/Test/Voicememo2020/VoiceMemo/ViewModels/PlayBackPageModel.cs
new file mode 100755 (executable)
index 0000000..2211127
--- /dev/null
@@ -0,0 +1,518 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://floralicense.org/license/
+ *
+ * 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.Diagnostics;
+using System.Windows.Input;
+using VoiceMemo.Models;
+using VoiceMemo.Services;
+using Xamarin.Forms;
+
+namespace VoiceMemo.ViewModels
+{
+    public enum VolumeControlType
+    {
+        Minus,
+        Plus,
+    }
+
+    /// <summary>
+    /// Page model class for PlayBack page
+    /// </summary>
+    public class PlayBackPageModel : BasePageModel
+    {
+        const string VOLUME_ON = "voice_mamo_slider_volume_on.png"; //"button/details_vol_icon_on.png"
+        const string VOLUME_OFF = "voice_mamo_slider_mute.png";  //"button/details_vol_icon_off.png"
+        const string VOLUME_ON_SMALL_IMAGE = "button/details_vol_icon_on.png";
+        const string VOLUME_OFF_SMALL_IMAGE = "button/details_vol_icon_off.png";
+        const string PLAY_ON = "voicerecorder_btn_play.png";
+        const string PLAY_OFF = "voicerecorder_btn_pause.png";
+        double play_progressbar_delta;
+
+        public PlayBackPageModel(Record record = null)
+        {
+            if (PlayWatch == null)
+            {
+                PlayWatch = new Stopwatch();
+            }
+
+            _playService = AudioPlayService.Instance;
+            _playService.AudioPlayFinished += _playService_AudioPlayFinished;
+            MaxVolumeLevel = _playService.GetMaxVolume();
+            // You can get notified whenever the state of audio player has been changed
+            MessagingCenter.Subscribe<AudioPlayService, AudioPlayState>(this, MessageKeys.PlayerStateChanged, (obj, state) =>
+            {
+                if (state == AudioPlayState.Playing)
+                {
+                    PlayControlImage = PLAY_OFF;
+                    // start to update the remaining time
+                    StartTimerForRemainingTime();
+                }
+                else
+                {
+                    PlayControlImage = PLAY_ON;
+                    // Stop updating the remaining time
+                    StopTimerForRemainingTime();
+                }
+            });
+            Init(record);
+        }
+
+        async public void Init(Record record)
+        {
+            PlayControlImage = PLAY_ON;
+            _record = record;
+            VolumeViewVisible = false;
+            CurrentVolume = _playService.Volume;
+            if (CurrentVolume == 0)
+            {
+                Mute = true;
+                MuteOnOffImage = VOLUME_OFF;
+                MuteOnOffSmallImage = VOLUME_OFF_SMALL_IMAGE;
+            }
+            else
+            {
+                Mute = false;
+                MuteOnOffImage = VOLUME_ON;
+                MuteOnOffSmallImage = VOLUME_ON_SMALL_IMAGE;
+            }
+
+            RemainingTime = record.Duration;
+            Console.WriteLine(" [PlayBackPageModel] RemainingTime : " + RemainingTime);
+            int minutes = RemainingTime / 60000;
+            int seconds = (RemainingTime - minutes * 60000) / 1000;
+            int total = minutes * 60 + seconds;
+            Console.WriteLine(" [PlayBackPageModel] minutes : " + minutes + ", seconds:" + seconds + ", total:" + total);
+            PlayingProcess = 0.0;
+            VolumeLevelProcess = CurrentVolume / MaxVolumeLevel;
+            Console.WriteLine(" [PlayBackPageModel] VolumeLevelProcess : " + VolumeLevelProcess);
+            // calculate value (unit: 100ms)
+            play_progressbar_delta = (1.0 / total) / 10;
+            Console.WriteLine(" [PlayBackPageModel] play_progressbar_delta : " + play_progressbar_delta);
+            _Touched = false;
+
+            PlayWatch.Reset();
+
+            _playService.VolumeChanged += _playService_VolumeChanged;
+            _playService.RegisterVolumeChangedCallback();
+            await _playService.Init(record.Path);
+        }
+
+        // It's called when PlayBackPage is hidden.
+        public void Stop()
+        {
+            Console.WriteLine("[PlayBackPageModel.Stop()]  current playService's state :" + _playService.State);
+            // stop playing audio file
+            _playService.Stop();
+            // unregister event callbacks
+            _playService.VolumeChanged -= _playService_VolumeChanged;
+            _playService.UnregisterVolumeChangedCallback();
+        }
+
+        /// <summary>
+        /// Start to update the remaining time
+        /// </summary>
+        void StartTimerForRemainingTime()
+        {
+            PlayWatch.Start();
+            // Any background code that needs to update the user interface
+            Device.BeginInvokeOnMainThread(() =>
+            {
+                // interact with UI elements
+                Device.StartTimer(new TimeSpan(0, 0, 0, 1, 0), UpdateRemainingPlayTime);
+                Device.StartTimer(new TimeSpan(0, 0, 0, 0, 100), UpdateProgressbar);
+            });
+        }
+
+        void StopTimerForRemainingTime()
+        {
+            PlayWatch.Stop();
+        }
+
+        /// <summary>
+        /// Update the value of progressbar at every 100 ms
+        /// </summary>
+        /// <returns>bool</returns>
+        bool UpdateProgressbar()
+        {
+            if (_playService.State == AudioPlayState.Playing)
+            {
+                PlayingProcess += play_progressbar_delta;
+                //Console.WriteLine("[UpdateRemainingPlayTime]  PlayingProcess " + PlayingProcess);
+                return true;
+            }
+            else
+            {
+                return false;
+            }
+        }
+
+        /// <summary>
+        /// Update the remaining time at every second
+        /// </summary>
+        /// <returns>bool</returns>
+        bool UpdateRemainingPlayTime()
+        {
+            //return true to keep the timer running or false to stop it after the current invocation.
+            if (_playService.State == AudioPlayState.Playing)
+            {
+                RemainingTime = RemainingTime - 1000;
+                return true;
+            }
+            else if (_playService.State == AudioPlayState.Idle)
+            {
+                RemainingTime = 0;
+                return false;
+            }
+            else
+            {
+                return false;
+            }
+        }
+
+        Stopwatch PlayWatch;
+        AudioPlayService _playService;
+        Record _record;
+        bool _Touched;
+
+        /// <summary>
+        /// Record to play
+        /// </summary>
+        public Record Record
+        {
+            get
+            {
+                return _record;
+            }
+        }
+
+        int _remainTime;
+        /// <summary>
+        /// The remaining time (ms)
+        /// </summary>
+        public int RemainingTime
+        {
+            get
+            {
+                return _remainTime;
+            }
+
+            set
+            {
+                SetProperty(ref _remainTime, value, "RemainingTime");
+            }
+        }
+
+        double _PlayingProcess;
+        public double PlayingProcess
+        {
+            get
+            {
+                return _PlayingProcess;
+            }
+
+            set
+            {
+                SetProperty(ref _PlayingProcess, value, "PlayingProcess");
+            }
+        }
+
+        double MaxVolumeLevel;
+        double _VolumeLevelProcess;
+        public double VolumeLevelProcess
+        {
+            get
+            {
+                return _VolumeLevelProcess;
+            }
+
+            set
+            {
+                SetProperty(ref _VolumeLevelProcess, value, "VolumeLevelProcess");
+            }
+        }
+
+        int _currentVolume;
+        /// <summary>
+        /// Volume level
+        /// </summary>
+        public int CurrentVolume
+        {
+            get
+            {
+                return _currentVolume;
+            }
+
+            set
+            {
+                bool changed = SetProperty(ref _currentVolume, value, "CurrentVolume");
+                if (changed)
+                {
+                    // Decide mute mode according to volume level
+                    if (CurrentVolume == 0)
+                    {
+                        Mute = true;
+                    }
+                    else
+                    {
+                        Mute = false;
+                    }
+                }
+
+            }
+        }
+
+        bool _volumeViewVisible;
+        /// <summary>
+        /// Indicate that volume control view is visible or not
+        /// </summary>
+        public bool VolumeViewVisible
+        {
+            get
+            {
+                return _volumeViewVisible;
+            }
+
+            set
+            {
+                SetProperty(ref _volumeViewVisible, value, "VolumeViewVisible");
+            }
+        }
+
+        bool _mute;
+        /// <summary>
+        /// indicate that silent mode is on or off
+        /// </summary>
+        public bool Mute
+        {
+            get
+            {
+                return _mute;
+            }
+
+            set
+            {
+                if (SetProperty(ref _mute, value, "Mute"))
+                {
+                    if (Mute)
+                    {
+                        // In case that Mute is on
+                        _playService.Muted = true;
+                        MuteOnOffImage = VOLUME_OFF;
+                        MuteOnOffSmallImage = VOLUME_OFF_SMALL_IMAGE;
+                        CurrentVolume = 0;
+                    }
+                    else
+                    {
+                        // In case that Mute is off
+                        _playService.Muted = false;
+                        MuteOnOffImage = VOLUME_ON;
+                        MuteOnOffSmallImage = VOLUME_ON_SMALL_IMAGE;
+                        CurrentVolume = _playService.Volume;
+                    }
+                }
+            }
+        }
+
+        string _playcontrolImage;
+        public string PlayControlImage
+        {
+            get
+            {
+                return _playcontrolImage;
+            }
+
+            set
+            {
+                SetProperty(ref _playcontrolImage, value, "PlayControlImage");
+            }
+        }
+
+        string _muteOnOffImage;
+        /// <summary>
+        /// image which show that silent mode is on or not
+        /// </summary>
+        public string MuteOnOffImage
+        {
+            get
+            {
+                return _muteOnOffImage;
+            }
+
+            set
+            {
+                SetProperty(ref _muteOnOffImage, value, "MuteOnOffImage");
+            }
+        }
+
+        string _muteOnOffSmallImage;
+        public string MuteOnOffSmallImage
+        {
+            get
+            {
+                return _muteOnOffSmallImage;
+            }
+
+            set
+            {
+                SetProperty(ref _muteOnOffSmallImage, value, "MuteOnOffSmallImage");
+            }
+        }
+
+        // For changing the visibility of a View which provides a way to control volume level
+        public ICommand VolumeViewVisibilityCommand => new Command<bool>(ChangeVolumeViewVisibility);/* { private set; get; }*/
+        // To show up VolumeView which provides a way to make the volume up and down
+        public ICommand VolumeViewCommand => new Command(ControlVolumeView);
+        // For Volume Up/Down
+        public ICommand VolumeControlCommand => new Command<VolumeControlType>(ControlVolume);
+        // For toggling play / pause functions
+        public ICommand PlayControlCommand => new Command(ControlPlay);
+        // For Mute On/Off
+        public ICommand MuteControlCommand => new Command(ControlMute);
+        // Update delay time
+        public ICommand DelayTimeCommand => new Command(DelayTime);
+
+        /// <summary>
+        /// Make volume level up/down
+        /// </summary>
+        /// <param name="type">VolumeControlType</param>
+        void ControlVolume(VolumeControlType type)
+        {
+            switch (type)
+            {
+                case VolumeControlType.Minus:
+                    VolumeLevelProcess -= 1 / MaxVolumeLevel;
+                    _playService.DecreaseVolume();
+                    break;
+                case VolumeControlType.Plus:
+                    //if (CurrentVolume == 9)
+                    //{
+                    //    NotifyHearingDamage();
+                    //}
+
+                    VolumeLevelProcess += 1 / MaxVolumeLevel;
+                    _playService.IncreaseVolume();
+                    break;
+            }
+        }
+
+        void NotifyHearingDamage()
+        {
+            // TODO
+            //MessagingCenter.Send<PlayBackPageModel>(this, MessageKeys.WarnHearingDamange);
+        }
+
+        // Toggle Mute On/Off
+        void ControlMute()
+        {
+            Mute = !Mute;
+        }
+
+        void ChangeVolumeViewVisibility(bool visible = true)
+        {
+            VolumeViewVisible = visible;
+        }
+
+        void ControlVolumeView()
+        {
+            Console.WriteLine("[ControlVolumeView] need to show VolumeView.");
+            VolumeViewVisible = true;
+
+            // Any background code that needs to update the user interface
+            Device.BeginInvokeOnMainThread(() =>
+            {
+                // interact with UI elements
+                Device.StartTimer(new TimeSpan(0, 0, 0, 3, 0), HideVolumeView);
+            });
+        }
+
+        bool HideVolumeView()
+        {
+            // In case that screen is touched, VolumeView is still visible.
+            if (_Touched)
+            {
+                Console.WriteLine("In case that screen is touched, VolumeView is still visible.");
+                _Touched = false;
+                return true;
+            }
+            else
+            {
+                // Screen is not touched for last 3 seconds. So VolumeView will be hidden.
+                Console.WriteLine("Screen is not touched for last 3 seconds. So VolumeView will be hidden.");
+                VolumeViewVisible = false;
+                return false;
+            }
+        }
+
+        void DelayTime()
+        {
+            Console.WriteLine("  $$$$$$$$$$$$     ");
+            Console.WriteLine("  $$$$$$$$$$$$     ");
+            Console.WriteLine("          Screen is touched. So delaytime will be updated.");
+            Console.WriteLine("  $$$$$$$$$$$$     ");
+            Console.WriteLine("  $$$$$$$$$$$$     ");
+            _Touched = true;
+        }
+
+        void ControlPlay()
+        {
+            Console.WriteLine(" [ControlPlay]  STATE: " + _playService.State);
+            if (_playService.State == AudioPlayState.Playing)
+            {
+                Console.WriteLine(" [ControlPlay]  Pause");
+                _playService.Pause();
+                //StopTimerForRemainingTime();
+            }
+            else if (_playService.State == AudioPlayState.Paused)
+            {
+                Console.WriteLine(" [ControlPlay]  Start");
+                _playService.Start();
+                //StartTimerForRemainingTime();
+            }
+            else if (_playService.State == AudioPlayState.Idle)
+            {
+                Init(_record);
+                _playService.Start();
+            }
+        }
+
+        private void _playService_VolumeChanged(object sender, AudioVolumeChangedEventArgs e)
+        {
+            Console.WriteLine("[_playService_VolumeChanged] e.Level : " + e.Level);
+            CurrentVolume = e.Level;
+        }
+
+        private void _playService_AudioPlayFinished(object sender, System.EventArgs e)
+        {
+            Console.WriteLine("_playService_AudioPlayFinished()   ");
+            MessagingCenter.Send<PlayBackPageModel, bool>(this, MessageKeys.AudioPlayDone, true);
+        }
+
+        public void Dispose()
+        {
+            Console.WriteLine("PlayBackPageModel.Dispose()   _playService.State: " + _playService.State);
+            MessagingCenter.Unsubscribe<AudioPlayService, AudioPlayState>(this, MessageKeys.PlayerStateChanged);
+            if (_playService.State == AudioPlayState.Playing)
+            {
+                _playService.Stop();
+            }
+
+            _playService.AudioPlayFinished -= _playService_AudioPlayFinished;
+            _playService.VolumeChanged -= _playService_VolumeChanged;
+            _playService.Destroy();
+        }
+    }
+}
diff --git a/Test/Voicememo2020/VoiceMemo/ViewModels/RecordingPageModel.cs b/Test/Voicememo2020/VoiceMemo/ViewModels/RecordingPageModel.cs
new file mode 100755 (executable)
index 0000000..f741095
--- /dev/null
@@ -0,0 +1,647 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://floralicense.org/license/
+ *
+ * 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.Diagnostics;
+using System.Windows.Input;
+using VoiceMemo.Models;
+using VoiceMemo.Resx;
+using VoiceMemo.Services;
+using Xamarin.Forms;
+using Native = Tizen.Applications;
+
+namespace VoiceMemo.ViewModels
+{
+    public enum RecordingViewModelState
+    {
+        Ready,
+        Recording,
+        Paused,
+        PausedForCancel,
+        Cancelled,
+        Stopped,
+    }
+
+    public enum RecordingCommandType
+    {
+        Record,
+        Pause,
+        PauseForCancelRequest,
+        Resume,
+        Cancel,
+        Stop
+    }
+
+    // The model class for RecordingPage
+    public class RecordingPageModel : BasePageModel
+    {
+        /// <summary>
+        /// It works while recording.
+        /// </summary>
+        private static Stopwatch RecordingWatch;
+
+        // For recording voice
+        AudioRecordService _audioRecordingService;
+
+        public AudioRecordService AudioRecordingService
+        {
+            get => _audioRecordingService;
+            private set
+            {
+                SetProperty(ref _audioRecordingService, value, "AudioRecordingService");
+            }
+        }
+
+        RecordingViewModelState _recordingViewModelState;
+        public RecordingViewModelState RecordingViewModelState
+        {
+            get => _recordingViewModelState;
+            private set
+            {
+                SetProperty(ref _recordingViewModelState, value, "RecordingViewModelState");
+            }
+        }
+
+        bool _SttOn;
+        public bool SttOn
+        {
+            get
+            {
+                return _SttOn;
+            }
+
+            set
+            {
+                SetProperty(ref _SttOn, value, "SttOn");
+            }
+        }
+
+        string _recordTitle;
+        public string RecordTitle
+        {
+            get => _recordTitle;
+            set
+            {
+                SetProperty(ref _recordTitle, value, "RecordTitle");
+            }
+        }
+
+        string _recordingTime;
+        public string RecordingTime
+        {
+            get => _recordingTime;
+            set
+            {
+                SetProperty(ref _recordingTime, value, "RecordingTime");
+            }
+        }
+
+        string _toggleImage;
+        public string PauseRecordToggleImage
+        {
+            get => _toggleImage;
+            set
+            {
+                SetProperty(ref _toggleImage, value, "PauseRecordToggleImage");
+            }
+        }
+
+        double _RecordingProcess;
+        public double RecordingProcess
+        {
+            get
+            {
+                return _RecordingProcess;
+            }
+
+            set
+            {
+                SetProperty(ref _RecordingProcess, value, "RecordingProcess");
+            }
+        }
+
+        public ICommand RequestCommand { private set; get; }
+
+        // For restoring information of the created voice media file
+        MediaContentService _ContentService;
+        // For
+        DeviceInformationService _DeviceInfoService;
+        SpeechToTextService _SttService;
+        public int Index;
+
+        double RECORDING_PROGRESSBAR_DELTA;
+
+        bool _isRecordingEffectOn;
+
+        public bool RecordingEffectOn
+        {
+            get
+            {
+                return _isRecordingEffectOn;
+            }
+
+            set
+            {
+                SetProperty(ref _isRecordingEffectOn, value, "RecordingEffectOn");
+            }
+        }
+
+        bool _isTimeFlickeringOn;
+        private bool _requestSttStart;
+        private bool _requestSttStop;
+
+        public bool TimeFlickeringOn
+        {
+            get
+            {
+                return _isTimeFlickeringOn;
+            }
+
+            set
+            {
+                SetProperty(ref _isTimeFlickeringOn, value, "TimeFlickeringOn");
+            }
+        }
+
+        bool disposing;
+
+        private void RecordingStateCallback(Object o, AudioRecordState prev, AudioRecordState current)
+        {
+            switch (current)
+            {
+                case AudioRecordState.Idle:
+                    HandleRecorderIdleState(o, prev, current);
+                    break;
+                case AudioRecordState.Init:
+                    HandleRecorderInitState(o, prev, current);
+                    break;
+                case AudioRecordState.Ready:
+                    HandleRecorderReadyState(o, prev, current);
+                    break;
+                case AudioRecordState.Recording:
+                    HandleRecorderRecordingState(o, prev, current);
+                    break;
+                case AudioRecordState.Paused:
+                    HandleRecorderPauseState(o, prev, current);
+                    break;
+            }
+        }
+
+        public void SttStateCallback(Object o, SttState prev, SttState current)
+        {
+            switch (current)
+            {
+                case SttState.Created:
+                    HandleSttCreatedState(o, prev, current);
+                    break;
+                case SttState.Ready:
+                    HandleSttReadyState(o, prev, current);
+                    ((App)App.Current).mainPageModel.availableToRecord = true;
+                    break;
+                case SttState.Recording:
+                    HandleSttRecordingState(o, prev, current);
+                    ((App)App.Current).mainPageModel.availableToRecord = false;
+                    break;
+                case SttState.Processing:
+                    HandleSttProcessingState(o, prev, current);
+                    ((App)App.Current).mainPageModel.availableToRecord = false;
+                    break;
+                case SttState.Unavailable:
+                    HandleSttUnavailableState(o, prev, current);
+                    break;
+            }
+        }
+
+        private void HandleSttProcessingState(object o, SttState prev, SttState current)
+        {
+            if (_requestSttStop)
+            {
+                _requestSttStop = false;
+                _SttService.Cancel();
+            }
+        }
+
+        private void HandleSttUnavailableState(object o, SttState prev, SttState current)
+        {
+        }
+
+        private void HandleSttRecordingState(object o, SttState prev, SttState current)
+        {
+            if (_requestSttStop)
+            {
+                _requestSttStop = false;
+                _SttService.Cancel();
+            }
+        }
+
+        private void HandleSttReadyState(object o, SttState prev, SttState current)
+        {
+            if (_requestSttStart && !_requestSttStop)
+            {
+                _requestSttStart = false;
+                _SttService.StartStt();
+            }
+        }
+
+        private void HandleSttCreatedState(object o, SttState prev, SttState current)
+        {
+            throw new NotImplementedException();
+        }
+
+        private void HandleRecorderPauseState(object o, AudioRecordState prev, AudioRecordState current)
+        {
+            StopTimer();
+            StopRecordingEffect();
+            if (RecordingViewModelState != RecordingViewModelState.PausedForCancel)
+            {
+                StartTimeFlickering();
+                RecordingViewModelState = RecordingViewModelState.Paused;
+                PauseRecordToggleImage = "record_stop_icon.png";
+            }
+        }
+
+        private void HandleRecorderRecordingState(object o, AudioRecordState prev, AudioRecordState current)
+        {
+            if (prev == AudioRecordState.Paused) // from pause -> recording
+            {
+                StopTimeFlickering();
+            }
+
+            // Start recording UI on
+            StartTimer();
+            StartRecordingEffect();
+            PauseRecordToggleImage = "recording_icon_pause.png";
+            RecordingViewModelState = RecordingViewModelState.Recording;
+        }
+
+        private void HandleRecorderReadyState(object o, AudioRecordState prev, AudioRecordState current)
+        {
+
+        }
+
+        private void HandleRecorderInitState(object o, AudioRecordState prev, AudioRecordState current)
+        {
+
+        }
+
+        private void HandleRecorderIdleState(object o, AudioRecordState prev, AudioRecordState current)
+        {
+            throw new NotImplementedException();
+        }
+
+        public RecordingPageModel(bool sttOn)
+        {
+            RequestCommand = new Command<RecordingCommandType>(Request);
+
+            if (RecordingWatch == null)
+            {
+                RecordingWatch = new Stopwatch();
+            }
+
+            _audioRecordingService = AudioRecordService.Instance;
+            _audioRecordingService.ViewModel = this;
+            _audioRecordingService.RegisterStateCallbacks(new Action<Object, AudioRecordState, AudioRecordState>(RecordingStateCallback));
+            AudioRecordingService = _audioRecordingService;
+            _DeviceInfoService = DeviceInformationService.Instance;
+            _SttService = SpeechToTextService.Instance;
+            _SttService.RegisterStateCallbacks(new Action<object, SttState, SttState>(SttStateCallback));
+            _ContentService = MediaContentService.Instance;
+            string.Format("{0:00}", _DeviceInfoService.LastStoredFileIndex);
+            Index = _DeviceInfoService.LastStoredFileIndex + 1;
+            SttOn = sttOn;
+            MessagingCenter.Subscribe<MainPageModel, bool>(this, MessageKeys.SttSupportedChanged, (obj, sttIsOn) =>
+            {
+                Console.WriteLine("### MessagingCenter ## [RecordingPageModel] just received << MessageKeys.SttSupportedChanged >>  On? :" + sttIsOn);
+                SttOn = sttIsOn;
+            });
+            disposing = false;
+        }
+
+        public void Init()
+        {
+            // This is an entry point to any service 
+            // Recorder: ready 
+            // Stt: ready if present
+            Console.WriteLine("[RecordingPageModel.Init]   SttOn:" + SttOn + ", stt state:" + _SttService.SttState);
+            if (!_DeviceInfoService.StorageAvailable)
+            {
+                // TODO: ContextPopup
+                return;
+            }
+
+            // initialize page
+            RecordingViewModelState = RecordingViewModelState.Ready;
+            RecordingTime = "00:00";
+            RecordingProcess = 0;
+            RecordingWatch.Reset();
+            RecordingEffectOn = false;
+            TimeFlickeringOn = false;
+            RecordTitle = "Memo " + Index.ToString();
+            RECORDING_PROGRESSBAR_DELTA = 0.003333;
+            _requestSttStart = false;
+            _requestSttStop = false;
+
+            if (SttOn)
+            {
+                switch (_SttService.SttState)
+                {
+                    case SttState.Created:
+                        _requestSttStart = true; // this should be false in Ready callback
+                        break;
+                    case SttState.Ready:
+                        _SttService.StartStt();
+                        break;
+                    case SttState.Recording:
+                    case SttState.Processing:
+                        try
+                        {
+                            Console.WriteLine("[RecordingPageModel.Init] STT state: " + _SttService.SttState + " --> Cancel it");
+                            _SttService.Cancel();
+                        }
+                        catch (Exception e)
+                        {
+                            Console.WriteLine("Catch possible error while cancel " + e.Message + ", " + e.Source);
+                        }
+
+                        MessagingCenter.Send<RecordingPageModel>(this, MessageKeys.ForcePopRecordingPage);
+                        return;
+                    case SttState.Unavailable:
+                        break;
+                }
+            }
+            else
+            {
+                RecordTitle = "Voice " + Index.ToString();
+                RECORDING_PROGRESSBAR_DELTA = 0.000555556;
+            }
+
+            _audioRecordingService.Start(RecordTitle, SttOn);
+        }
+
+        void StartTimer()
+        {
+            // TODO: Need to check recorded time and display time
+            RecordingWatch.Start();
+            // Any background code that needs to update the user interface
+            Device.BeginInvokeOnMainThread(() =>
+            {
+                // interact with UI elements
+                Device.StartTimer(new TimeSpan(0, 0, 0, 1, 0), UpdateRecordingTimeAndProgressBar);
+            });
+        }
+
+        void StopTimer()
+        {
+            RecordingWatch.Stop();
+        }
+
+        bool UpdateRecordingTimeAndProgressBar()
+        {
+            //return true to keep the timer running or false to stop it after the current invocation.
+            if (_audioRecordingService.State == AudioRecordState.Recording)
+            {
+                RecordingProcess += RECORDING_PROGRESSBAR_DELTA;
+
+                RecordingTime = string.Format("{0:00}:{1:00}", RecordingWatch.Elapsed.Minutes, RecordingWatch.Elapsed.Seconds);
+                return true;
+            }
+            else
+            {
+                return false;
+            }
+        }
+
+        void Request(RecordingCommandType request)
+        {
+            switch (request)
+            {
+                case RecordingCommandType.Record:
+                    RecordingCommandRequested();
+                    break;
+                case RecordingCommandType.Pause:
+                    PauseCommandRequested();
+                    break;
+                case RecordingCommandType.PauseForCancelRequest:
+                    PauseForCancelCommandRequested();
+                    break;
+                case RecordingCommandType.Resume:
+                    ResumeCommandRequested();
+                    break;
+                case RecordingCommandType.Cancel:
+                    CancelCommandRequested();
+                    break;
+                case RecordingCommandType.Stop:
+                    StopCommandRequested();
+                    break;
+            }
+        }
+
+        private void RecordingCommandRequested()
+        {
+            // 20180220-vincent: At this point audioRecordingService is either Recording or Paused
+            if (_audioRecordingService.State == AudioRecordState.Paused)
+            {
+                _audioRecordingService.Resume();
+            }
+        }
+
+        private async void StopCommandRequested()
+        {
+            if (RecordingViewModelState == RecordingViewModelState.Stopped)
+            {
+                return; // if already set to stopped, then do not repeat
+            }
+
+            RecordingViewModelState = RecordingViewModelState.Stopped;
+
+            if (!disposing)
+            {
+                StopTimer();
+                StopRecordingEffect();
+                StopTimeFlickering();
+            }
+
+            Record record = SaveRecording();
+            bool ExistText = SttOn && _SttService.SttState == SttState.Recording;
+            if (ExistText)
+            {
+                string SttText = await _SttService.StopAndGetText();
+                record.Text = SttText;
+                Console.WriteLine("[StopCommandRequested] record.Text : (" + record.Text + ")");
+            }
+            else if (SttOn)
+            {
+                // TODO: remove it.
+                record.Text = "STT Error? " + _SttService.SttState;
+            }
+
+            // Notify that it's time to save Record in database
+            MessagingCenter.Send<RecordingPageModel, Record>(this, MessageKeys.SaveVoiceMemoInDB, record);
+
+            if (ExistText &&
+                (string.IsNullOrEmpty(record.Text) || record.Text.Equals("") || record.Text.Equals(" ") || record.Text.Equals("  ")))
+            {
+                Console.WriteLine("[StopCommandRequested]         !!!!!!!!!        resultText is string.IsNullOrEmpty");
+                record.Text = AppResources.RecognitionFailed;
+            }
+
+            if (disposing)
+            {
+                DisposeServices();
+            }
+        }
+
+        Record SaveRecording()
+        {
+            var filePath = _audioRecordingService.Save();
+            // TODO: Handle audio recording failure case
+            Index++;
+            Record record = _ContentService.GetMediaInfo(filePath, SttOn);
+            MessagingCenter.Send<RecordingPageModel, Record>(this, MessageKeys.SaveVoiceMemo, new LatestRecord(record));
+            return record;
+        }
+
+        private void CancelCommandRequested()
+        {
+            Console.WriteLine("\n\n  CANCEL ---  AUDIO RECORDING & STT");
+            _requestSttStart = false; // initialize stt start request
+            if (RecordingViewModelState == RecordingViewModelState.Paused)
+            {
+                StopTimeFlickering();
+            }
+
+            if (SttOn)
+            {
+                _requestSttStop = true;
+                if (_SttService.SttState == SttState.Recording || _SttService.SttState == SttState.Processing)
+                {
+                    _SttService.Cancel();
+                }
+                else // created, ready
+                {
+                    // do not need to cancel but should not start
+                    if (_requestSttStart)
+                    {
+                        _requestSttStart = false; // prevent create->ready (should not start)
+                    }
+                }
+            }
+
+            _audioRecordingService.Cancel();
+            RecordingViewModelState = RecordingViewModelState.Cancelled;
+        }
+
+        private void ResumeCommandRequested()
+        {
+            if (RecordingViewModelState == RecordingViewModelState.PausedForCancel)
+            {
+                Request(RecordingCommandType.Record);
+            }
+        }
+
+        private void PauseCommandRequested()
+        {
+            if (_audioRecordingService.State == AudioRecordState.Recording)
+            {
+                _audioRecordingService.Pause();
+                // Any background code that needs to update the user interface
+                Device.BeginInvokeOnMainThread(() =>
+                {
+                    // interact with UI elements
+                    Device.StartTimer(new TimeSpan(0, 0, 0, 60, 0), DoAutoSaveAndTerminate);
+                });
+            }
+        }
+
+        bool DoAutoSaveAndTerminate()
+        {
+            
+            //if (_audioRecordingService.State == AudioRecordState.Paused)
+            //{
+            //    RequestCommand.Execute(RecordingCommandType.Stop);
+
+            //}
+            Console.WriteLine("        Now, save recording and terminate this application. ");
+            // Terminate this application
+            Native.Application.Current.Exit();
+            return false;
+        }
+
+        private void PauseForCancelCommandRequested()
+        {
+            if (_audioRecordingService.State == AudioRecordState.Recording)
+            {
+                RecordingViewModelState = RecordingViewModelState.PausedForCancel;
+                _audioRecordingService.Pause();
+            }
+        }
+
+        private void StartRecordingEffect()
+        {
+            RecordingEffectOn = true;
+        }
+
+        private void StopRecordingEffect()
+        {
+            RecordingEffectOn = false;
+        }
+
+        private void StartTimeFlickering()
+        {
+            TimeFlickeringOn = true;
+        }
+
+        private void StopTimeFlickering()
+        {
+            TimeFlickeringOn = false;
+        }
+
+        public void Dispose()
+        {
+            Console.WriteLine("RecordingPageModel.Dispose()   START");
+
+            MessagingCenter.Unsubscribe<MainPageModel, bool>(this, MessageKeys.SttSupportedChanged);
+            if (_audioRecordingService.State == AudioRecordState.Recording || _audioRecordingService.State == AudioRecordState.Paused)
+            {
+                disposing = true;
+                RequestCommand.Execute(RecordingCommandType.Stop);
+            }
+            else
+            {
+                DisposeServices();
+            }
+            //////#if STT_ON
+            //////            if (SttOn)
+            //////            {
+            //////                Console.WriteLine("RecordingPageModel.Dispose()   _SttService.Dispose");
+            //////                _SttService.Dispose();
+            //////            }
+            //////#endif
+            //////            _ContentService.Destroy();
+            //////            _audioRecordingService.Destroy();
+            Console.WriteLine("RecordingPageModel.Dispose()   DONE");
+        }
+
+        void DisposeServices()
+        {
+            Console.WriteLine("RecordingPageModel.DisposeServices()   START");
+            _audioRecordingService.Destroy();
+            _SttService.Dispose();
+            _ContentService.Destroy();
+            Console.WriteLine("RecordingPageModel.DisposeServices()   DONE");
+        }
+    }
+}
diff --git a/Test/Voicememo2020/VoiceMemo/Views/BindableToolbarItem.cs b/Test/Voicememo2020/VoiceMemo/Views/BindableToolbarItem.cs
new file mode 100755 (executable)
index 0000000..eb4fa73
--- /dev/null
@@ -0,0 +1,61 @@
+using Xamarin.Forms;
+using Tizen.Wearable.CircularUI.Forms;
+
+namespace VoiceMemo.Views
+{
+    /// <summary>
+    /// class custom circle toolbar item
+    /// Its visibility can be changeable.
+    /// </summary>
+    public class BindableToolbarItem : CircleToolbarItem
+    {
+        public static readonly BindableProperty IsVisibleProperty =
+            BindableProperty.Create("BindableToolbarItem", typeof(bool), typeof(ToolbarItem),
+                true, BindingMode.TwoWay, propertyChanged: OnIsVisibleChanged);
+
+        public BindableToolbarItem()
+        {
+            InitVisibility();
+        }
+
+        /// <summary>
+        /// ToolbarItem's visibility
+        /// </summary>
+        public bool IsVisible
+        {
+            get { return (bool)GetValue(IsVisibleProperty); }
+            set { SetValue(IsVisibleProperty, value); }
+        }
+
+        private void InitVisibility()
+        {
+            OnIsVisibleChanged(this, false, IsVisible);
+        }
+
+        private static void OnIsVisibleChanged(BindableObject bindable, object oldvalue, object newvalue)
+        {
+            var item = bindable as BindableToolbarItem;
+
+            if (item != null && item.Parent == null)
+            {
+                return;
+            }
+
+            if (item != null)
+            {
+                var items = ((ContentPage)item.Parent).ToolbarItems;
+
+                // case : add to toolbar items
+                if ((bool)newvalue && !items.Contains(item))
+                {
+                    Device.BeginInvokeOnMainThread(() => { items.Add(item); });
+                }
+                // case : remove from toolbar items
+                else if (!(bool)newvalue && items.Contains(item))
+                {
+                    Device.BeginInvokeOnMainThread(() => { items.Remove(item); });
+                }
+            }
+        }
+    }
+}
diff --git a/Test/Voicememo2020/VoiceMemo/Views/CancelPage.xaml b/Test/Voicememo2020/VoiceMemo/Views/CancelPage.xaml
new file mode 100755 (executable)
index 0000000..a61bd66
--- /dev/null
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<w:TwoButtonPage
+    x:Class="VoiceMemo.Views.CancelPage"
+    xmlns="http://xamarin.com/schemas/2014/forms"
+    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
+    xmlns:resx="clr-namespace:VoiceMemo.Resx;"
+    xmlns:w="clr-namespace:Tizen.Wearable.CircularUI.Forms;assembly=XSF.CircularUI.Forms">
+    <w:TwoButtonPage.FirstButton>
+        <MenuItem Clicked="OnAbortCancelClicked" Icon="tw_ic_popup_btn_delete.png" />
+    </w:TwoButtonPage.FirstButton>
+    <w:TwoButtonPage.SecondButton>
+        <MenuItem Clicked="OnCancelClicked" Icon="tw_ic_popup_btn_check.png" />
+    </w:TwoButtonPage.SecondButton>
+
+    <w:TwoButtonPage.Content>
+        <StackLayout BackgroundColor="Black">
+            <Label
+                x:Name="CancelLabel"
+                FontSize="Medium"
+                HorizontalOptions="Center"
+                HorizontalTextAlignment="Center"
+                Text="{x:Static resx:AppResources.CancelRecording}"
+                TextColor="White"
+                VerticalOptions="CenterAndExpand"
+                VerticalTextAlignment="Center"
+                />
+        </StackLayout>
+    </w:TwoButtonPage.Content>
+</w:TwoButtonPage>
\ No newline at end of file
diff --git a/Test/Voicememo2020/VoiceMemo/Views/CancelPage.xaml.cs b/Test/Voicememo2020/VoiceMemo/Views/CancelPage.xaml.cs
new file mode 100755 (executable)
index 0000000..217fee7
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://floralicense.org/license/
+ *
+ * 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 VoiceMemo.ViewModels;
+using VoiceMemo.Resx;
+using Xamarin.Forms;
+using Tizen.Wearable.CircularUI.Forms;
+using Xamarin.Forms.Xaml;
+
+namespace VoiceMemo.Views
+{
+    /// <summary>
+    /// CancelPage class
+    /// It provides a way to cancel voice recording
+    /// </summary>
+    public partial class CancelPage : TwoButtonPage
+    {
+        RecordingPageModel ViewModel;
+
+        public CancelPage(RecordingPageModel vm)
+        {
+            // Hide navigation bar
+            NavigationPage.SetHasNavigationBar(this, false);
+            // Subscribe notification of locale changes to update text based on locale
+            MessagingCenter.Subscribe<App>(this, MessageKeys.UpdateByLanguageChange, (obj) =>
+            {
+                // Update text that has been translated into the current language.
+                CancelLabel.Text = AppResources.CancelRecording;
+            });
+            InitializeComponent();
+            Init(vm);
+        }
+
+        void Init(RecordingPageModel vm)
+        {
+            BindingContext = ViewModel = vm;
+        }
+        
+        // Keep recording
+        // CancelPage --> RecordingPage
+        async void OnAbortCancelClicked(object sender, EventArgs args)
+        {
+            // Request to Resume
+            ViewModel.RequestCommand.Execute(RecordingCommandType.Resume);
+            await Navigation.PopAsync();
+        }
+
+        // Cancel recording voice
+        // CancelPage --> StandByPage(First main page)
+        async void OnCancelClicked(object sender, EventArgs args)
+        {
+            // Request to Cancel
+            ViewModel.RequestCommand.Execute(RecordingCommandType.Cancel);
+            await Navigation.PopToRootAsync(); // @20180218-vincent: This should never be used without clearing
+        }
+    }
+}
\ No newline at end of file
diff --git a/Test/Voicememo2020/VoiceMemo/Views/CirclePageEx.xaml b/Test/Voicememo2020/VoiceMemo/Views/CirclePageEx.xaml
new file mode 100755 (executable)
index 0000000..5cf0cf0
--- /dev/null
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<w:CirclePage xmlns="http://xamarin.com/schemas/2014/forms"
+            xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
+            xmlns:w="clr-namespace:Tizen.Wearable.CircularUI.Forms;assembly=XSF.CircularUI.Forms"
+            x:Class="VoiceMemo.Views.CirclePageEx">
+</w:CirclePage>
\ No newline at end of file
diff --git a/Test/Voicememo2020/VoiceMemo/Views/CirclePageEx.xaml.cs b/Test/Voicememo2020/VoiceMemo/Views/CirclePageEx.xaml.cs
new file mode 100755 (executable)
index 0000000..7c9232b
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://floralicense.org/license/
+ *
+ * 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 Tizen.Wearable.CircularUI.Forms;
+using Xamarin.Forms;
+using Xamarin.Forms.Xaml;
+
+namespace VoiceMemo.Views
+{
+    /// <summary>
+    /// Base Page class
+    /// </summary>
+       public partial class CirclePageEx : CirclePage
+    {
+               public CirclePageEx()
+               {
+            // Hide navigation bar
+            NavigationPage.SetHasNavigationBar(this, false);
+
+            InitializeComponent();
+        }
+       }
+}
\ No newline at end of file
diff --git a/Test/Voicememo2020/VoiceMemo/Views/DetailsPage.xaml b/Test/Voicememo2020/VoiceMemo/Views/DetailsPage.xaml
new file mode 100755 (executable)
index 0000000..b64078d
--- /dev/null
@@ -0,0 +1,79 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<view:CirclePageEx
+    x:Class="VoiceMemo.Views.DetailsPage"
+    xmlns="http://xamarin.com/schemas/2014/forms"
+    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
+    xmlns:converters="clr-namespace:VoiceMemo.Converters;"
+    xmlns:view="clr-namespace:VoiceMemo.Views;"
+    xmlns:vm="clr-namespace:VoiceMemo.ViewModels;"
+    xmlns:w="clr-namespace:Tizen.Wearable.CircularUI.Forms;assembly=XSF.CircularUI.Forms"
+    RotaryFocusObject="{x:Reference ScrollTextView}"
+    x:Name="Details">
+    <ContentPage.Resources>
+        <ResourceDictionary>
+            <Color x:Key="AT0116">#FF4DCFFF</Color>
+            <Style x:Key="LabelStyle-AT0116" TargetType="Label" BasedOn="{StaticResource LabelStyle-Base}">
+                <Setter Property="FontSize" Value="10" />
+                <Setter Property="TextColor" Value="{StaticResource AT0116}" />
+            </Style>
+            <Color x:Key="AT0114">#FFB3B3B3</Color>
+            <Style x:Key="LabelStyle-AT0114" TargetType="Label" BasedOn="{StaticResource LabelStyle-Base}">
+                <Setter Property="FontSize" Value="8" />
+                <Setter Property="TextColor" Value="{StaticResource AT0114}" />
+            </Style>
+            <converters:DurationToRemainingTimeConverter x:Key="TimeConverter" />
+            <converters:RemainingTimeType x:Key="TimeType" />
+        </ResourceDictionary>
+    </ContentPage.Resources>
+    <ContentPage.Content>
+        <w:CircleScrollView
+            x:Name="ScrollTextView"
+            Orientation="Vertical">
+            <RelativeLayout x:Name="mainLayout">
+                <Label
+                    x:Name="TitleLabel"
+                    RelativeLayout.XConstraint="{ConstraintExpression Type=RelativeToParent, Property=Width, Factor=0, Constant=64}"
+                    RelativeLayout.YConstraint="{ConstraintExpression Type=RelativeToParent, Property=Height, Factor=0, Constant=51}"
+                    WidthRequest="232"
+                    HeightRequest="39"
+                    Text="{Binding Record.Title}"
+                    Style="{StaticResource LabelStyle-AT0116}" />
+                <Label
+                    x:Name="DateInfoLabel"
+                    RelativeLayout.XConstraint="{ConstraintExpression Type=RelativeToParent, Property=Width, Factor=0, Constant=33}"
+                    RelativeLayout.YConstraint="{ConstraintExpression Type=RelativeToParent, Property=Height, Factor=0, Constant=115}"
+                    WidthRequest="294"
+                    HeightRequest="32"
+                    Text="{Binding Record.Date}"
+                    Style="{StaticResource LabelStyle-AT0114}" />
+                <Label
+                    x:Name="TimeInfoLabel"
+                    RelativeLayout.XConstraint="{ConstraintExpression Type=RelativeToParent, Property=Width, Factor=0, Constant=33}"
+                    RelativeLayout.YConstraint="{ConstraintExpression Type=RelativeToParent, Property=Height, Factor=0, Constant=147}"
+                    WidthRequest="294"
+                    HeightRequest="32"
+                    Text="{Binding Record.Duration, Converter={StaticResource TimeConverter}, ConverterParameter={x:Static converters:RemainingTimeType.TimeText}}"
+                    Style="{StaticResource LabelStyle-AT0114}"/>
+                <Label
+                    x:Name="ContentLabel"
+                    RelativeLayout.XConstraint="{ConstraintExpression Type=RelativeToParent, Property=Width, Factor=0, Constant=33}"
+                    RelativeLayout.YConstraint="{ConstraintExpression Type=RelativeToParent, Property=Height, Factor=0, Constant=179}"
+                    WidthRequest="294"
+                    Text="{Binding Record.Text}"
+                    TextColor="White"
+                    HorizontalTextAlignment="Center"
+                    VerticalTextAlignment="Center" />
+                <!-- default font size of label : 9.2936170212766-->
+            </RelativeLayout>
+        </w:CircleScrollView>
+    </ContentPage.Content>
+    <w:CirclePage.ActionButton>
+        <w:ActionButtonItem Clicked="OnPlayBackClicked" Icon="details_playback_icon.png" />
+    </w:CirclePage.ActionButton>
+    <w:CirclePage.ToolbarItems>
+        <w:CircleToolbarItem
+            Clicked="OnCircleToolbarItemClicked_DeleteRecord"
+            Icon="more_option_icon_delete.png"
+            Text="Delete" />
+    </w:CirclePage.ToolbarItems>
+</view:CirclePageEx>
\ No newline at end of file
diff --git a/Test/Voicememo2020/VoiceMemo/Views/DetailsPage.xaml.cs b/Test/Voicememo2020/VoiceMemo/Views/DetailsPage.xaml.cs
new file mode 100755 (executable)
index 0000000..60ebb37
--- /dev/null
@@ -0,0 +1,132 @@
+using VoiceMemo.Resx;
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://floralicense.org/license/
+ *
+ * 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 VoiceMemo.Models;
+using VoiceMemo.ViewModels;
+using Xamarin.Forms;
+using Xamarin.Forms.Xaml;
+
+namespace VoiceMemo.Views
+{
+    /// <summary>
+    /// DetailsPage class
+    /// It shows the details of voice memo
+    /// file name, recorded time, recording time
+    /// </summary>
+    public partial class DetailsPage : CirclePageEx
+    {
+        DetailsPageModel viewModel;
+
+        public DetailsPage(DetailsPageModel _viewModel)
+        {
+            InitializeComponent();
+            BindingContext = viewModel = _viewModel;
+
+            // Spare as high as an action button when a text is long
+            mainLayout.Children.Add(new BoxView(), Constraint.RelativeToView(ContentLabel, (Parent, sibling) =>
+            {
+                return sibling.X;
+            }), Constraint.RelativeToView(ContentLabel, (parent, sibling) =>
+            {
+                return sibling.Y + sibling.Height;
+            }), Constraint.RelativeToParent((parent) =>
+            {
+                return 294;
+            }), Constraint.RelativeToParent((parent) =>
+            {
+                return 78 + 7;
+            }));
+        }
+
+        /// <summary>
+        /// Request to play voice memo/record
+        /// </summary>
+        /// <param name="sender">object</param>
+        /// <param name="args">EventArgs</param>
+        async void OnPlayBackClicked(object sender, EventArgs args)
+        {
+            // Move to the recording page to keep recording
+            Console.WriteLine("[DetailsPage.OnPlayBackClicked]     ");
+            await Navigation.PushAsync(PageFactory.GetInstance(Pages.PlayBack, viewModel.Record/*new PlayBackPageModel(viewModel.Record)*/));
+        }
+
+        /// <summary>
+        /// Request to delete the record
+        /// </summary>
+        /// <param name="sender">object</param>
+        /// <param name="args">EventArgs</param>
+        /*async*/ void OnCircleToolbarItemClicked_DeleteRecord(object sender, EventArgs args)
+        {
+            Console.WriteLine("[OnCircleToolbarItemClicked_DeleteRecord] sender : " + sender + ", record: " + ((DetailsPageModel)viewModel).Record);
+
+            //await DisplayAlert("Delete", "Delete this recording", "OK");
+            GraphicPopUp popup = new GraphicPopUp
+            {
+                Text = AppResources.Deleted,
+            };
+            popup.TimedOut += Popup_TimedOut;
+            popup.Show();
+
+            // Publish "DeleteVoiceMemo" message for a listener to remove this record from database.
+            MessagingCenter.Send<Page, Record>(this, MessageKeys.DeleteVoiceMemo, ((DetailsPageModel)viewModel).Record);
+        }
+
+        private async void Popup_TimedOut(object sender, EventArgs e)
+        {
+            Console.WriteLine("[DetailsPage]  Popup_TimedOut() ...");
+            await Navigation.PopToRootAsync();
+        }
+
+        /// <summary>
+        /// Invoked immediately prior to the Page becoming visible.
+        /// </summary>
+        protected override void OnAppearing()
+        {
+            Console.WriteLine("[DetailsPage]  OnAppearing() ...");
+        }
+
+        /// <summary>
+        /// Invoked when this page disappears.
+        /// </summary>
+        protected override void OnDisappearing()
+        {
+            Console.WriteLine("[DetailsPage]  OnDisappearing");
+        }
+
+        /// <summary>
+        /// Invoked when backbutton is pressed
+        /// VoiceMemoStandByPage will be shown.
+        /// </summary>
+        /// <returns>bool value</returns>
+        protected override bool OnBackButtonPressed()
+        {
+            if (((DetailsPageModel)BindingContext).IsNew)
+            {
+                Console.WriteLine("[DetailsPage-OnBackButtonPressed]  PopToRootAsync");
+                Navigation.PopToRootAsync();
+            }
+            else
+            {
+                Console.WriteLine("[DetailsPage-OnBackButtonPressed]  PopAsync");
+                Navigation.PopAsync();
+            }
+
+            return true;
+        }
+    }
+}
diff --git a/Test/Voicememo2020/VoiceMemo/Views/GraphicPopup.cs b/Test/Voicememo2020/VoiceMemo/Views/GraphicPopup.cs
new file mode 100755 (executable)
index 0000000..d691fd3
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://floralicense.org/license/
+ *
+ * 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 System;
+using VoiceMemo.Tizen.Wearable.Renderers;
+
+namespace VoiceMemo.Views
+{
+    /// <summary>
+    /// Class GraphicPopUp
+    /// </summary>
+    public class GraphicPopUp : BindableObject
+    {
+        public static readonly BindableProperty TextProperty = BindableProperty.Create(nameof(Text), typeof(string), typeof(GraphicPopUp), null);
+
+        public static readonly BindableProperty DurationProperty = BindableProperty.Create(nameof(Duration), typeof(double), typeof(GraphicPopUp), 1.5);
+
+        IGraphicPopup _popUp = null;
+
+        public event EventHandler BackButtonPressed;
+        public event EventHandler TimedOut;
+
+        // Constructor
+        public GraphicPopUp()
+        {
+            _popUp = new GraphicPopUpRenderer();
+            if (_popUp == null)
+            {
+                throw new Exception("Object reference not set to an instance of a Popup.");
+            }
+
+            _popUp.BackButtonPressed += (s, e) =>
+            {
+                BackButtonPressed?.Invoke(this, EventArgs.Empty);
+            };
+
+            _popUp.TimedOut += (s, e) =>
+            {
+                TimedOut?.Invoke(this, EventArgs.Empty);
+            };
+
+            SetBinding(TextProperty, new Binding(nameof(Text), mode: BindingMode.OneWayToSource, source: _popUp));
+            SetBinding(DurationProperty, new Binding(nameof(Duration), mode: BindingMode.OneWayToSource, source: _popUp));
+        }
+
+        /// <summary>
+        /// Gets or sets text of the Popup.
+        /// </summary>
+        public string Text
+        {
+            get { return (string)GetValue(TextProperty); }
+            set { SetValue(TextProperty, value); }
+        }
+
+        /// <summary>
+        /// Gets or sets duration of the Popup.
+        /// </summary>
+        public double Duration
+        {
+            get { return (double)GetValue(DurationProperty); }
+            set { SetValue(DurationProperty, value); }
+        }
+
+        /// <summary>
+        /// Show Toast Popup
+        /// </summary>
+        public void Show()
+        {
+            _popUp.Show();
+        }
+    }
+}
diff --git a/Test/Voicememo2020/VoiceMemo/Views/IGraphicPopup.cs b/Test/Voicememo2020/VoiceMemo/Views/IGraphicPopup.cs
new file mode 100755 (executable)
index 0000000..7449534
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://floralicense.org/license/
+ *
+ * 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;
+
+namespace VoiceMemo.Views
+{
+    /// <summary>
+    /// Interface IPopup for Toast Popup
+    /// </summary>
+    public interface IGraphicPopup
+    {
+        /// <summary>
+        /// Text for Toast Popup
+        /// </summary>
+        string Text { get; set; }
+
+        /// <summary>
+        /// Duration for Toast Popup
+        /// How long to display the text message
+        /// </summary>
+        double Duration { get; set; }
+
+        /// <summary>
+        /// Make Toast Popup show
+        /// </summary>
+        void Show();
+
+        /// <summary>
+        /// Raised when back button is pressed
+        /// </summary>
+        event EventHandler BackButtonPressed;
+
+        /// <summary>
+        /// Raised after the text is shown for the specified duration
+        /// </summary>
+        event EventHandler TimedOut;
+    }
+}
diff --git a/Test/Voicememo2020/VoiceMemo/Views/IProgressbarPopup.cs b/Test/Voicememo2020/VoiceMemo/Views/IProgressbarPopup.cs
new file mode 100755 (executable)
index 0000000..b5c904b
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://floralicense.org/license/
+ *
+ * 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.
+ */
+
+namespace VoiceMemo.Views
+{
+    /// <summary>
+    /// IProgressbarPopup interface
+    /// </summary>
+    public interface IProgressbarPopup : IGraphicPopup
+    {
+        /// <summary>
+        /// Text for Progressbar
+        /// </summary>
+        string ProgressbarText { get; set; }
+
+        /// <summary>
+        /// Duration for Progressbar
+        /// How long to display the text message with progressbar
+        /// </summary>
+        double ProgressbarDuration { get; set; }
+    }
+}
diff --git a/Test/Voicememo2020/VoiceMemo/Views/LanguageSelectionPage.xaml b/Test/Voicememo2020/VoiceMemo/Views/LanguageSelectionPage.xaml
new file mode 100755 (executable)
index 0000000..7438e14
--- /dev/null
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<view:CirclePageEx
+    x:Class="VoiceMemo.Views.LanguageSelectionPage"
+    xmlns="http://xamarin.com/schemas/2014/forms"
+    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
+    xmlns:converters="clr-namespace:VoiceMemo.Converters;"
+    xmlns:vms="clr-namespace:VoiceMemo.ViewModels;"
+    xmlns:view="clr-namespace:VoiceMemo.Views;"
+    xmlns:resx="clr-namespace:VoiceMemo.Resx;"
+    xmlns:w="clr-namespace:Tizen.Wearable.CircularUI.Forms;assembly=XSF.CircularUI.Forms"
+    RotaryFocusObject="{x:Reference LangListView}">
+    <ContentPage.Resources>
+        <ResourceDictionary>
+            <Style x:Key="BaseLabelStyle" TargetType="Label">
+                <Setter Property="HorizontalOptions" Value="Center" />
+                <Setter Property="VerticalOptions" Value="Center" />
+                <Setter Property="VerticalTextAlignment" Value="Center" />
+                <Setter Property="HorizontalTextAlignment" Value="Center" />
+                <Setter Property="TextColor" Value="White" />
+            </Style>
+            <converters:CountryCodeToNameConverter x:Key="LangConverter" />
+        </ResourceDictionary>
+    </ContentPage.Resources>
+    <view:CirclePageEx.Content>
+        <w:CircleListView
+            x:Name="LangListView"
+            HasUnevenRows="True"
+            HorizontalOptions="FillAndExpand"
+            ItemTapped="OnItemTapped"
+            ItemsSource="{Binding Languages}"
+            VerticalOptions="FillAndExpand">
+            <ListView.Footer>
+                <StackLayout HeightRequest="115">
+                    <BoxView />
+                </StackLayout>
+            </ListView.Footer>
+            <ListView.Header>
+                <StackLayout HeightRequest="115">
+                    <!--original #4DCFFF-->
+                    <Label
+                        x:Name="headerLabel"
+                        TextColor="#5aFFFF"
+                        Style="{StaticResource BaseLabelStyle}"
+                        Text="{x:Static resx:AppResources.Languages}"
+                        FontSize="16"
+                        FontAttributes="Bold"
+                        VerticalOptions="FillAndExpand" />
+                </StackLayout>
+            </ListView.Header>
+            <ListView.ItemTemplate>
+                <DataTemplate>
+                    <view:SttLanguageViewCell />
+                </DataTemplate>
+            </ListView.ItemTemplate>
+        </w:CircleListView>
+    </view:CirclePageEx.Content>
+</view:CirclePageEx>
\ No newline at end of file
diff --git a/Test/Voicememo2020/VoiceMemo/Views/LanguageSelectionPage.xaml.cs b/Test/Voicememo2020/VoiceMemo/Views/LanguageSelectionPage.xaml.cs
new file mode 100755 (executable)
index 0000000..b7072df
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://floralicense.org/license/
+ *
+ * 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 VoiceMemo.Models;
+using VoiceMemo.Resx;
+using VoiceMemo.ViewModels;
+using Xamarin.Forms;
+using Xamarin.Forms.Xaml;
+
+namespace VoiceMemo.Views
+{
+    /// <summary>
+    /// LanguageSelectionPage class
+    /// </summary>
+    public partial class LanguageSelectionPage : CirclePageEx
+    {
+        MainPageModel ViewModel;
+        public bool ignoreRadioSelection = true;
+
+        public LanguageSelectionPage(MainPageModel viewModel)
+        {
+            BindingContext = ViewModel = viewModel;
+            // Subscribe notification of locale changes to update text based on locale
+            MessagingCenter.Subscribe<App>(this, MessageKeys.UpdateByLanguageChange, (obj) =>
+            {
+                // Update text that has been translated into the current language.
+                headerLabel.Text = AppResources.Languages;
+            });
+            InitializeComponent();
+            Init();
+        }
+
+        public void Init()
+        {
+            Console.WriteLine("[LanguageSelectionPage.Init()] LangListView.SelectedItem :" + LangListView.SelectedItem 
+                + " VS. ViewModel.SelectedItemIndex :" + ViewModel.SelectedItemIndex);
+            ignoreRadioSelection = true;
+
+            // Scroll to the previously selected language if it exists.
+            if (ViewModel.SelectedItemIndex != null)
+            {
+                LangListView.ScrollTo(ViewModel.SelectedItemIndex, ScrollToPosition.Center, false);
+            }
+        }
+
+        /// <summary>
+        /// Invoked when an item is tapped
+        /// </summary>
+        /// <param name="sender">object</param>
+        /// <param name="args">ItemTappedEventArgs</param>
+        void OnItemTapped(object sender, ItemTappedEventArgs args)
+        {
+            ignoreRadioSelection = false;
+
+            ViewModel.CurrentLanguage = ((SttLanguage)args.Item).Lang;
+            SttLanguage item = args.Item as SttLanguage;
+            for (int i = 0; i < ((MainPageModel)BindingContext).Languages.Count; i++)
+            {
+                if (((MainPageModel)BindingContext).Languages[i].Combo == item.Combo)
+                {
+                    Console.WriteLine("OnItemTapped : *" + i + " )  FOUND!!  IsOn will be true! ");
+                    // The following code makes the Radio button of SttLanguageViewCell is selected.
+                    ((MainPageModel)BindingContext).Languages[i].IsOn = true;
+                }
+            }
+        }
+
+        /// <summary>
+        /// Invoked immediately prior to the Page becoming visible.
+        /// </summary>
+        protected override void OnAppearing()
+        {
+            Console.WriteLine("[LanguageSelectionPage]  OnAppearing() ...");
+        }
+
+        protected override void OnDisappearing()
+        {
+            Console.WriteLine("[LanguageSelectionPage]  OnDisappearing");
+        }
+    }
+}
\ No newline at end of file
diff --git a/Test/Voicememo2020/VoiceMemo/Views/MainPage.xaml b/Test/Voicememo2020/VoiceMemo/Views/MainPage.xaml
new file mode 100755 (executable)
index 0000000..8b26c2d
--- /dev/null
@@ -0,0 +1,70 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<views:CirclePageEx x:Class="VoiceMemo.Views.MainPage"
+                    xmlns="http://xamarin.com/schemas/2014/forms"
+                    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
+                    xmlns:converters="clr-namespace:VoiceMemo.Converters;"
+                    xmlns:views="clr-namespace:VoiceMemo.Views;"
+                    xmlns:vm="clr-namespace:VoiceMemo.ViewModels;"
+                    xmlns:w="clr-namespace:Tizen.Wearable.CircularUI.Forms;assembly=XSF.CircularUI.Forms"
+                    xmlns:resx="clr-namespace:VoiceMemo.Resx;"
+                    x:Name="StandBy"
+                    Title="MainPage">
+    <views:CirclePageEx.Resources>
+        <ResourceDictionary>
+            <Color x:Key="AT011">#FFFAFAFA</Color>
+            <Style x:Key="LabelStyle-AT011" TargetType="Label" BasedOn="{StaticResource LabelStyle-Base}">
+                <Setter Property="FontSize" Value="20" />
+                <Setter Property="TextColor" Value="{StaticResource AT011}" />
+            </Style>
+            <Color x:Key="AT0116">#FF4DCFFF</Color>
+            <Style x:Key="LabelStyle-AT0116" TargetType="Label" BasedOn="{StaticResource LabelStyle-Base}">
+                <Setter Property="FontSize" Value="10" />
+                <Setter Property="TextColor" Value="{StaticResource AT0116}" />
+            </Style>
+        </ResourceDictionary>
+    </views:CirclePageEx.Resources>
+    <views:CirclePageEx.BindingContext>
+        <vm:MainPageModel x:Name="ViewModel" />
+    </views:CirclePageEx.BindingContext>
+    <views:CirclePageEx.Content>
+        <AbsoluteLayout x:Name="MainView" BackgroundColor="Black">
+            <!--  Stand by  -->
+            <Image AbsoluteLayout.LayoutBounds=".5, .5, 96, 96"
+                   AbsoluteLayout.LayoutFlags="PositionProportional"
+                   Source="2019_custom_button/voicerecorder_btn_bg.png"
+                   x:Name="VoiceRecorderBgImage" />
+            <Image AbsoluteLayout.LayoutBounds=".5, .5, 96, 96"
+                   AbsoluteLayout.LayoutFlags="PositionProportional"
+                   Source="2019_custom_button/voicerecorder_stop_icon.png"
+                   x:Name="VoiceRecorderIconImage" />            
+            <Label x:Name="TitleLabel"
+                AbsoluteLayout.LayoutBounds="64,51,232,39"
+                AbsoluteLayout.LayoutFlags="None"
+                Text="{Binding MainLabelText}"
+                Style="{StaticResource LabelStyle-AT0116}" />
+            <Label
+                x:Name="MinTimeLabel"
+                AbsoluteLayout.LayoutBounds="102,249,156,79"
+                AbsoluteLayout.LayoutFlags="None"
+                Text="00:00"
+                Style="{StaticResource LabelStyle-AT011}" />
+        </AbsoluteLayout>
+    </views:CirclePageEx.Content>
+    <w:CirclePage.ToolbarItems>
+        <w:CircleToolbarItem
+            x:Name="recordsMenu"
+            Icon="2019_images_icons/more_option_icon_stt_recording.png"
+            Clicked="OnCircleToolbarItemClicked_DisplayRecordings"
+            Text="{x:Static resx:AppResources.Recordings}" />
+        <w:CircleToolbarItem
+            x:Name="sttOnOfMenu"
+            Icon="2019_images_icons/more_option_icon_stt_on.png"
+            Clicked="OnCircleToolbarItemClicked_OnOffStt"
+            Text="{x:Static resx:AppResources.SpeechToText}" />
+        <w:CircleToolbarItem
+            x:Name="languageList"
+            Icon="2019_images_icons/more_option_icon_language.png"
+            Clicked="OnCircleToolbarItemClicked_SelectLanguage"
+            Text="{x:Static resx:AppResources.Languages}" />
+    </w:CirclePage.ToolbarItems>
+</views:CirclePageEx>
diff --git a/Test/Voicememo2020/VoiceMemo/Views/MainPage.xaml.cs b/Test/Voicememo2020/VoiceMemo/Views/MainPage.xaml.cs
new file mode 100755 (executable)
index 0000000..8f28c64
--- /dev/null
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://floralicense.org/license/
+ *
+ * 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 Xamarin.Forms.Xaml;
+using VoiceMemo.ViewModels;
+using VoiceMemo.Resx;
+using Xamarin.Forms;
+using Tizen.Wearable.CircularUI.Forms;
+using VoiceMemo.Effects;
+using VoiceMemo.Utility;
+
+namespace VoiceMemo.Views
+{
+    /// <summary>
+    /// The MainPage of VoiceMemo application
+    /// </summary>
+    public partial class MainPage : CirclePageEx
+    {
+        /// <summary>
+        /// Constructor of StandByPage()
+        /// </summary>
+        public MainPage()
+        {
+            InitializeComponent();
+            Color stopIconColor = ColorConverter.OneUIColorConverter(new HSB(0, 98, 88, 100), null);
+            ImageAttributes.SetBlendColor(VoiceRecorderIconImage, stopIconColor); 
+            var tapGestureRecognizer = new TapGestureRecognizer();
+            tapGestureRecognizer.Tapped += OnImageButtonClicked;
+            VoiceRecorderIconImage.GestureRecognizers.Add(tapGestureRecognizer);
+        }
+
+        /// <summary>
+        /// Invoked when recording(red) button is tapped.
+        /// RecordingPage will be shown.
+        /// </summary>
+        /// <param name="sender"> Sender object</param>
+        /// <param name="e">EventArgs</param>
+        async void OnImageButtonClicked(object sender, EventArgs e)
+        {
+            // While STT is in progress, a new recording cannot be started.
+            if (((App)App.Current).mainPageModel.availableToRecord)
+            {
+                // can record
+                await Navigation.PushAsync(PageFactory.GetInstance(Pages.Recording, ((MainPageModel)ViewModel).SttEnabled));
+            }
+            else
+            {
+                // cannot record
+                await DisplayAlert("Recording", "Stt service is in progress. Please wait a moment.", "OK");
+            }
+        }
+
+        /// <summary>
+        /// Standby > More options > Recordings
+        /// A list of Recordings will be shown if there are recordings.
+        /// </summary>
+        /// <param name="sender"> Sender object</param>
+        /// <param name="e">EventArgs</param>
+        async void OnCircleToolbarItemClicked_DisplayRecordings(object sender, EventArgs e)
+        {
+            Console.WriteLine(" MainPage.OnCircleToolbarItemClicked_DisplayRecordings()");
+            await Navigation.PushAsync(PageFactory.GetInstance(Pages.RecordList, ViewModel));
+        }
+
+        /// <summary>
+        /// Standby > More options > Speech to text
+        /// Invoked when "Speech to text" more option is selected to turn Speech to text feature on/off
+        /// </summary>
+        /// <param name="sender">sender object </param>
+        /// <param name="e">EventArgs</param>
+        void OnCircleToolbarItemClicked_OnOffStt(object sender, EventArgs e)
+        {
+            Console.WriteLine(" MainPage.OnCircleToolbarItemClicked_OnOffStt()");
+        }
+
+        /// <summary>
+        /// Called when Language is selected in More option
+        /// Standby > More options > Language
+        /// </summary>
+        /// <param name="sender">sender object </param>
+        /// <param name="e">EventArgs</param>
+        async void OnCircleToolbarItemClicked_SelectLanguage(object sender, EventArgs e)
+        {
+            await Navigation.PushAsync(PageFactory.GetInstance(Pages.Languages, ViewModel));
+        }
+
+
+        /// <summary>
+        /// Invoked immediately prior to the Page becoming visible.
+        /// </summary>
+        protected override void OnAppearing()
+        {
+        }
+
+        /// <summary>
+        /// Invoked when this page disappears.
+        /// </summary>
+        protected override void OnDisappearing()
+        {
+        }
+
+        public void Dispose()
+        {
+            ((MainPageModel)BindingContext).Dispose();
+        }
+    }
+}
\ No newline at end of file
diff --git a/Test/Voicememo2020/VoiceMemo/Views/PageFactory.cs b/Test/Voicememo2020/VoiceMemo/Views/PageFactory.cs
new file mode 100755 (executable)
index 0000000..d232ce3
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://floralicense.org/license/
+ *
+ * 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 VoiceMemo.Models;
+using VoiceMemo.ViewModels;
+using Xamarin.Forms;
+
+namespace VoiceMemo.Views
+{
+    public enum Pages
+    {
+        StandBy,
+        StandByCS,
+        Recording,
+        TryCancel,
+        Details,
+        RecordList,
+        PlayBack,
+        Languages,
+    }
+
+    public static class PageFactory
+    {
+        static MainPage main;
+        //static MainPageCS main2;
+        static RecordingPage record;
+        static CancelPage cancel;
+        static RecordListPage list;
+        static DetailsPage detail;
+        static PlayBackPage playback;
+        static LanguageSelectionPage lang;
+
+        public static Page GetInstance(Pages page, Object o = null)
+        {
+            switch (page)
+            {
+                //case Pages.StandByCS:
+                //    return PageFactory.main2 ?? (main2 = new MainPageCS());
+                case Pages.StandBy:
+                    return PageFactory.main ?? (main = new MainPage());
+                case Pages.Recording:
+                    var sttOn = System.Convert.ToBoolean(o);
+                    record?.Init(/*sttOn*/);
+                    return PageFactory.record ?? (record = new RecordingPage(new RecordingPageModel(sttOn)));
+                case Pages.TryCancel:
+                    //VoiceRecordingPageModel vm = o as VoiceRecordingPageModel;
+                    return PageFactory.cancel ?? (cancel = new CancelPage(o as RecordingPageModel));
+                case Pages.Details:
+                    if (detail != null)
+                    {
+                        //Console.WriteLine("<PageFactory> DetailsPageModel : " + ((DetailsPageModel)detail.BindingContext));
+                        ((DetailsPageModel)detail.BindingContext).Init(o as Record);
+                    }
+                    //Console.WriteLine("<PageFactory> Return detail : " + detail);
+                    return PageFactory.detail ?? (detail = new DetailsPage(new DetailsPageModel(o as Record)));
+                case Pages.RecordList:
+                    return PageFactory.list ?? (list = new RecordListPage((MainPageModel)o));
+
+                case Pages.PlayBack:
+                    if (playback != null)
+                    {
+                        ((PlayBackPageModel)playback.BindingContext).Init(o as Record);
+                    }
+
+                    return PageFactory.playback ?? (playback = new PlayBackPage(new PlayBackPageModel(o as Record)));
+                case Pages.Languages:
+                    Console.WriteLine("<PageFactory>                ++++++++++++   Languages");
+                    lang?.Init();
+                    return PageFactory.lang ?? (lang = new LanguageSelectionPage((MainPageModel)o));
+                default:
+                    return null;
+            }
+        }
+
+        public static void DestoryPage()
+        {
+            //cancel?.Dispose();
+            ////list?.Dispose();
+            ////detail?.Dispose();
+            ////lang?.Dispose();
+            playback?.Dispose();
+            record?.Dispose();
+            //main2?.Dispose();
+            main?.Dispose();
+        }
+    }
+}
+
diff --git a/Test/Voicememo2020/VoiceMemo/Views/PlayBackPage.xaml b/Test/Voicememo2020/VoiceMemo/Views/PlayBackPage.xaml
new file mode 100755 (executable)
index 0000000..c9bedc9
--- /dev/null
@@ -0,0 +1,179 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<views:CirclePageEx
+    x:Class="VoiceMemo.Views.PlayBackPage"
+    xmlns="http://xamarin.com/schemas/2014/forms"
+    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
+    xmlns:converters="clr-namespace:VoiceMemo.Converters;"
+    xmlns:views="clr-namespace:VoiceMemo.Views;"
+    xmlns:vm="clr-namespace:VoiceMemo.ViewModels;"
+    xmlns:w="clr-namespace:Tizen.Wearable.CircularUI.Forms;assembly=XSF.CircularUI.Forms" >
+    <!--TODO: it is possible to cast CircleSlider to RotaryFocusable object. RotaryFocusTargetName="PlayProgress">-->
+    <w:CirclePage.CircleSurfaceItems>
+        <w:CircleProgressBarSurfaceItem x:Name="PlayProgress" Value="{Binding PlayingProcess}" />
+        <!--// BG Dim Code :  AO0241 - #FF404040
+        // BG Normal Code : AO0231 - #FF004373
+        // Progress BG : Normal : AO0232  - #FF467ea6
+        // Progress BG : DIM : AO0242 -  #994673A6
+        // Progress BG : MAX VOLUME : AO025 - #ffe84c0e-->
+
+        <!--<w:CircleSliderSurfaceItem
+            x:Name="VolumeProgress"
+            BackgroundColor="DarkBlue"
+            BarColor="Cyan"
+            IsVisible="{Binding VolumeViewVisible}"
+            Value="{Binding VolumeLevelProcess}" />-->
+        <!--<w:CircleProgressBarSurfaceItem
+            x:Name="VolumeProgress"
+
+            BackgroundColor="DarkBlue"
+            BarColor="Cyan"
+            IsVisible="{Binding VolumeViewVisible}" />-->
+        <!--Value="{Binding VolumeLevelProcess}" />-->
+    </w:CirclePage.CircleSurfaceItems>
+    <ContentPage.Resources>
+        <ResourceDictionary>
+            <Color x:Key="AT011">#FFFAFAFA</Color>
+            <Style x:Key="LabelStyle-AT011" TargetType="Label" BasedOn="{StaticResource LabelStyle-Base}">
+                <Setter Property="FontSize" Value="20" />
+                <Setter Property="TextColor" Value="{StaticResource AT011}" />
+            </Style>
+            <Color x:Key="AT0211">#FFFAFAFA</Color>
+            <Style x:Key="LabelStyle-AT0211" TargetType="Label">
+                <Setter Property="FontAttributes" Value="Bold" />
+                <!--<Setter Property="HorizontalOptions" Value="Center" />
+                <Setter Property="VerticalOptions" Value="Center" />-->
+                <Setter Property="HorizontalTextAlignment" Value="Center" />
+                <Setter Property="VerticalTextAlignment" Value="Center" />
+                <Setter Property="FontSize" Value="13" />
+                <Setter Property="TextColor" Value="{StaticResource AT0211}" />
+            </Style>
+            <converters:DurationToRemainingTimeConverter x:Key="TimeConverter" />
+        </ResourceDictionary>
+    </ContentPage.Resources>
+    <ContentPage.Content>
+        <AbsoluteLayout x:Name="PlaybackLayout">
+            <Image x:Name="VolumeImage"
+                   AbsoluteLayout.LayoutBounds="145,32,70,70"
+                   AbsoluteLayout.LayoutFlags="None"
+                   Source="{Binding MuteOnOffSmallImage}">
+                <Image.GestureRecognizers>
+                    <TapGestureRecognizer Command="{Binding VolumeViewCommand}" />
+                </Image.GestureRecognizers>
+            </Image>
+            <Image x:Name="PlaybackImage"
+                   AbsoluteLayout.LayoutBounds="117,116,126,126"
+                   AbsoluteLayout.LayoutFlags="None"
+                   Source="{Binding PlayControlImage}">
+                <Image.GestureRecognizers>
+                    <TapGestureRecognizer Command="{Binding PlayControlCommand}" />
+                </Image.GestureRecognizers>
+            </Image>
+            <Label x:Name="RemainingTimeLabel"
+                   AbsoluteLayout.LayoutBounds="102,242,156,85"
+                   AbsoluteLayout.LayoutFlags="None"
+                   Text="{Binding RemainingTime, Converter={StaticResource TimeConverter}, ConverterParameter={x:Static converters:RemainingTimeType.TimeText}}}"
+                   Style="{StaticResource LabelStyle-AT011}" />
+            <!--Volume control View-->
+            <ContentView x:Name="VolumeView" IsVisible="{Binding VolumeViewVisible}">
+                <ContentView.GestureRecognizers>
+                    <TapGestureRecognizer Command="{Binding DelayTimeCommand}" />
+                </ContentView.GestureRecognizers>
+                <AbsoluteLayout>
+                    <AbsoluteLayout.GestureRecognizers>
+                        <TapGestureRecognizer Command="{Binding DelayTimeCommand}" />
+                    </AbsoluteLayout.GestureRecognizers>
+                    <BoxView AbsoluteLayout.LayoutBounds="0, 0, 1, 1"
+                             AbsoluteLayout.LayoutFlags="All"
+                             BackgroundColor="#80000000" />
+                    <Grid
+                        AbsoluteLayout.LayoutBounds="83,39,194,64"
+                        AbsoluteLayout.LayoutFlags="None"
+                        VerticalOptions="FillAndExpand">
+                        <Grid.RowDefinitions>
+                            <RowDefinition Height="Auto" />
+                        </Grid.RowDefinitions>
+                        <Grid.ColumnDefinitions>
+                            <ColumnDefinition Width="*" />
+                            <ColumnDefinition Width="*" />
+                            <ColumnDefinition Width="*" />
+                        </Grid.ColumnDefinitions>
+                        <Button
+                            x:Name="MinusButton"
+                            Grid.Row="0"
+                            Grid.Column="0"
+                            BackgroundColor="Transparent"
+                            Command="{Binding VolumeControlCommand}"
+                            CommandParameter="{x:Static vm:VolumeControlType.Minus}"
+                            Image="icons/b_slider_icon_minus.png">
+                            <Button.GestureRecognizers>
+                                <TapGestureRecognizer Command="{Binding DelayTimeCommand}" />
+                            </Button.GestureRecognizers>
+                            <Button.Triggers>
+                                <Trigger TargetType="Button" Property="IsEnabled" Value="False">
+                                    <Setter Property="BackgroundColor" Value="Black" />
+                                </Trigger>
+                                <Trigger TargetType="Button" Property="IsEnabled" Value="True">
+                                    <Setter Property="BackgroundColor" Value="Transparent" />
+                                </Trigger>
+                                <DataTrigger
+                                    Binding="{Binding CurrentVolume}"
+                                    TargetType="Button"
+                                    Value="0">
+                                    <Setter Property="IsEnabled" Value="False" />
+                                </DataTrigger>
+                            </Button.Triggers>
+                        </Button>
+
+                        <!--This Label shows the current volume level.-->
+                        <Label x:Name="VolumeLevelLabel"
+                            Grid.Row="0"
+                            Grid.Column="1"
+                            Style="{StaticResource LabelStyle-AT0211}"
+                            Text="{Binding CurrentVolume}" />
+
+                        <!--  By clicking/tapping this button, volume level will increase  -->
+                        <Button
+                            Grid.Row="0"
+                            Grid.Column="2"
+                            BackgroundColor="Transparent"
+                            Command="{Binding VolumeControlCommand}"
+                            CommandParameter="{x:Static vm:VolumeControlType.Plus}"
+                            Image="icons/b_slider_icon_plus.png">
+                            <Button.GestureRecognizers>
+                                <TapGestureRecognizer Command="{Binding DelayTimeCommand}" />
+                            </Button.GestureRecognizers>
+                            <Button.Triggers>
+                                <Trigger TargetType="Button" Property="IsEnabled" Value="False">
+                                    <Setter Property="BackgroundColor" Value="Black" />
+                                </Trigger>
+                                <Trigger TargetType="Button" Property="IsEnabled" Value="True">
+                                    <Setter Property="BackgroundColor" Value="Transparent" />
+                                </Trigger>
+                                <DataTrigger
+                                    Binding="{Binding CurrentVolume}"
+                                    TargetType="Button"
+                                    Value="15">
+                                    <Setter Property="IsEnabled" Value="False" />
+                                </DataTrigger>
+                            </Button.Triggers>
+                        </Button>
+                    </Grid>
+                    <!--Volume Image-->
+                    <Image AbsoluteLayout.LayoutBounds="105,105,150,150"
+                           AbsoluteLayout.LayoutFlags="None"
+                           Source="voice_mamo_slider_btn_bg.png" />
+                    <Image AbsoluteLayout.LayoutBounds="105,105,150,150"
+                           AbsoluteLayout.LayoutFlags="None"
+                           Source="{Binding MuteOnOffImage}" />
+                    <BoxView AbsoluteLayout.LayoutBounds="105,105,150,150"
+                             AbsoluteLayout.LayoutFlags="None">
+                        <BoxView.GestureRecognizers>
+                            <TapGestureRecognizer Command="{Binding DelayTimeCommand}" />
+                            <TapGestureRecognizer Command="{Binding MuteControlCommand}" />
+                        </BoxView.GestureRecognizers>
+                    </BoxView>
+                </AbsoluteLayout>
+            </ContentView>
+        </AbsoluteLayout>
+    </ContentPage.Content>
+</views:CirclePageEx>
\ No newline at end of file
diff --git a/Test/Voicememo2020/VoiceMemo/Views/PlayBackPage.xaml.cs b/Test/Voicememo2020/VoiceMemo/Views/PlayBackPage.xaml.cs
new file mode 100755 (executable)
index 0000000..e271877
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://floralicense.org/license/
+ *
+ * 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 VoiceMemo.ViewModels;
+using Xamarin.Forms;
+using Xamarin.Forms.Xaml;
+
+namespace VoiceMemo.Views
+{
+    /// <summary>
+    /// PlayBackPage class
+    /// In this page, recorded content will play.
+    /// </summary>
+    public partial class PlayBackPage : CirclePageEx
+    {
+        PlayBackPageModel viewModel;
+        bool hidePageRequested;
+        public PlayBackPage(PlayBackPageModel _viewModel)
+        {
+            BindingContext = this.viewModel = _viewModel;
+            InitializeComponent();
+            RegisterSomeNotifications();
+        }
+
+        void RegisterSomeNotifications()
+        {
+            // You can get notified whenever playing audio is done.
+            MessagingCenter.Subscribe<PlayBackPageModel, bool>(this, MessageKeys.AudioPlayDone, async (obj, finished) =>
+            {
+                // If playing audio is done, this page will be hidden. (MainPage will be shown.)
+                if (finished)
+                {
+                    await Navigation.PopAsync();
+                }
+            });
+        }
+                
+        protected override bool OnBackButtonPressed()
+        {
+            if (hidePageRequested)
+            {
+                return true;
+            }
+            else
+            {
+                hidePageRequested = true;
+            }
+
+            if (VolumeView.IsVisible)
+            {
+                Console.WriteLine("[PlaybackPage.OnBackButtonPressed] VolumeView is shown.");
+                viewModel.VolumeViewVisibilityCommand?.Execute(false);
+                return false;
+            }
+
+            Console.WriteLine("[PlaybackPage.OnBackButtonPressed]  PlayBackPage will be hidden.");
+            viewModel.Stop();
+            return base.OnBackButtonPressed();
+        }
+
+        /// <summary>
+        /// Invoked immediately prior to the Page becoming visible.
+        /// </summary>
+        protected override void OnAppearing()
+        {
+            Console.WriteLine("[PlaybackPage]  OnAppearing() ...");
+            hidePageRequested = false;
+        }
+
+        /// <summary>
+        /// Invoked when this page disappears.
+        /// </summary>
+        protected override void OnDisappearing()
+        {
+            Console.WriteLine("[PlaybackPage]  OnDisappearing");
+            viewModel.Stop();
+        }
+
+        public void Dispose()
+        {
+            Console.WriteLine("[PlayBackPageModel]  Dispose");
+            MessagingCenter.Unsubscribe<PlayBackPageModel, bool>(this, MessageKeys.AudioPlayDone);
+            ((PlayBackPageModel)BindingContext).Dispose();
+        }
+    }
+}
\ No newline at end of file
diff --git a/Test/Voicememo2020/VoiceMemo/Views/ProgressbarPopup.cs b/Test/Voicememo2020/VoiceMemo/Views/ProgressbarPopup.cs
new file mode 100755 (executable)
index 0000000..188657c
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://floralicense.org/license/
+ *
+ * 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 VoiceMemo.Tizen.Wearable.Renderers;
+using Xamarin.Forms;
+
+namespace VoiceMemo.Views
+{
+    public class ProgressbarPopup : BindableObject
+    {
+        public static readonly BindableProperty TextProperty = BindableProperty.Create(nameof(Text), typeof(string), typeof(ProgressbarPopup), null);
+
+        public static readonly BindableProperty DurationProperty = BindableProperty.Create(nameof(Duration), typeof(double), typeof(ProgressbarPopup), 1.5);
+
+        public static readonly BindableProperty ProgressbarTextProperty = BindableProperty.Create(nameof(ProgressbarText), typeof(string), typeof(ProgressbarPopup), null);
+
+        public static readonly BindableProperty ProgressbarDurationProperty = BindableProperty.Create(nameof(ProgressbarDuration), typeof(double), typeof(ProgressbarPopup), 0.8);
+
+        IProgressbarPopup _popUp = null;
+        public event EventHandler BackButtonPressed;
+        public event EventHandler TimedOut;
+
+        public ProgressbarPopup()
+        {
+            _popUp = new ProgressbarPopupRenderer();
+            if (_popUp == null)
+            {
+                throw new Exception("Object reference not set to an instance of a Popup.");
+            }
+
+            _popUp.BackButtonPressed += (s, e) =>
+            {
+                BackButtonPressed?.Invoke(this, EventArgs.Empty);
+            };
+
+            _popUp.TimedOut += (s, e) =>
+            {
+                TimedOut?.Invoke(this, EventArgs.Empty);
+            };
+
+            SetBinding(TextProperty, new Binding(nameof(Text), mode: BindingMode.OneWayToSource, source: _popUp));
+            SetBinding(DurationProperty, new Binding(nameof(Duration), mode: BindingMode.OneWayToSource, source: _popUp));
+            SetBinding(ProgressbarTextProperty, new Binding(nameof(ProgressbarText), mode: BindingMode.OneWayToSource, source: _popUp));
+            SetBinding(ProgressbarDurationProperty, new Binding(nameof(ProgressbarDuration), mode: BindingMode.OneWayToSource, source: _popUp));
+        }
+
+        /// <summary>
+        /// Gets or sets text of the Popup.
+        /// </summary>
+        public string Text
+        {
+            get { return (string)GetValue(TextProperty); }
+            set { SetValue(TextProperty, value); }
+        }
+
+        /// <summary>
+        /// Gets or sets duration of the Popup.
+        /// </summary>
+        public double Duration
+        {
+            get { return (double)GetValue(DurationProperty); }
+            set { SetValue(DurationProperty, value); }
+        }
+
+        /// <summary>
+        /// Gets or sets text of the Popup.
+        /// </summary>
+        public string ProgressbarText
+        {
+            get { return (string)GetValue(ProgressbarTextProperty); }
+            set { SetValue(ProgressbarTextProperty, value); }
+        }
+
+        /// <summary>
+        /// Duration for Progressbar
+        /// How long to display the text message with progressbar
+        /// </summary>
+        double ProgressbarDuration
+        {
+            get { return (double)GetValue(ProgressbarDurationProperty); }
+            set { SetValue(ProgressbarDurationProperty, value); }
+        }
+
+        /// <summary>
+        /// Show Toast Popup
+        /// </summary>
+        public void Show()
+        {
+            _popUp.Show();
+        }
+    }
+}
diff --git a/Test/Voicememo2020/VoiceMemo/Views/RecordListPage.xaml b/Test/Voicememo2020/VoiceMemo/Views/RecordListPage.xaml
new file mode 100755 (executable)
index 0000000..2401769
--- /dev/null
@@ -0,0 +1,210 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<views:CirclePageEx
+    x:Class="VoiceMemo.Views.RecordListPage"
+    xmlns="http://xamarin.com/schemas/2014/forms"
+    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
+    xmlns:converters="clr-namespace:VoiceMemo.Converters;"
+    xmlns:views="clr-namespace:VoiceMemo.Views;"
+    xmlns:effect="clr-namespace:VoiceMemo.Effects;"
+    xmlns:resx="clr-namespace:VoiceMemo.Resx;"
+    xmlns:w="clr-namespace:Tizen.Wearable.CircularUI.Forms;assembly=XSF.CircularUI.Forms"
+    x:Name="myRecordListPage"
+    RotaryFocusObject="{x:Reference DataListView}">
+    <views:CirclePageEx.Resources>
+        <ResourceDictionary>
+            <!--  First line  size 13 -->
+            <Color x:Key="T0211">#FFFAFAFA</Color>
+            <!--  Second line size 8 -->
+            <Color x:Key="T022">#FFB3B3B3</Color>
+
+            <Color x:Key="AT011">#FFFAFAFA</Color>
+            <Style x:Key="LabelStyle-AT011" TargetType="Label" BasedOn="{StaticResource LabelStyle-Base}">
+                <Setter Property="FontSize" Value="20" />
+                <Setter Property="TextColor" Value="{StaticResource AT011}" />
+            </Style>
+            <Color x:Key="AT0116">#FF4DCFFF</Color>
+            <Style x:Key="LabelStyle-AT0116" TargetType="Label" BasedOn="{StaticResource LabelStyle-Base}">
+                <Setter Property="FontSize" Value="10" />
+                <Setter Property="TextColor" Value="{StaticResource AT0116}" />
+            </Style>
+            <converters:RecordsCountToViewVisibilityConverter x:Key="ViewVisibilityConverter" />
+        </ResourceDictionary>
+    </views:CirclePageEx.Resources>
+
+    <views:CirclePageEx.Content>
+        <AbsoluteLayout x:Name="RecordListView" BackgroundColor="Black">
+            <Image
+                x:Name="NoImage"
+                AbsoluteLayout.LayoutBounds="0,0,1,1"
+                AbsoluteLayout.LayoutFlags="All"
+                IsVisible="{Binding Records.Count, Converter={StaticResource ViewVisibilityConverter}, ConverterParameter={x:Static converters:ViewType.NoRecordView}}"
+                Source="tw_no_item_bg.png"/>
+            <Label
+                x:Name="recordingsLabel"
+                AbsoluteLayout.LayoutBounds="64,51,232,39"
+                AbsoluteLayout.LayoutFlags="None"
+                IsVisible="{Binding Records.Count, Converter={StaticResource ViewVisibilityConverter}, ConverterParameter={x:Static converters:ViewType.NoRecordView}}"
+                Text="{x:Static resx:AppResources.Recordings}"
+                HorizontalTextAlignment="Center" VerticalTextAlignment="Center"
+                FontSize="10"
+                TextColor="#FF4DCFFF" />
+            <Label
+                x:Name="noRecordingsLabel"
+                AbsoluteLayout.LayoutBounds=".5,.8,360,79"
+                AbsoluteLayout.LayoutFlags="PositionProportional"
+                IsVisible="{Binding Records.Count, Converter={StaticResource ViewVisibilityConverter}, ConverterParameter={x:Static converters:ViewType.NoRecordView}}"
+                HorizontalTextAlignment="Center" VerticalTextAlignment="Center"
+                TextColor="#FFFAFAFA"
+                FontSize="10"
+                Text="{x:Static resx:AppResources.NoRecordings}" />
+            <Image
+                AbsoluteLayout.LayoutBounds=".5, .5, 98, 98"
+                AbsoluteLayout.LayoutFlags="PositionProportional"
+                IsVisible="{Binding Records.Count, Converter={StaticResource ViewVisibilityConverter}, ConverterParameter={x:Static converters:ViewType.NoRecordView}}"
+                Source="b_icon_voicememo.png"/>
+            <w:CircleListView
+                x:Name="DataListView"
+                AbsoluteLayout.LayoutBounds="0, 0, 1, 1"
+                AbsoluteLayout.LayoutFlags="All"
+                IsVisible="{Binding Records.Count, Converter={StaticResource ViewVisibilityConverter}, ConverterParameter={x:Static converters:ViewType.RecordListView}}"
+                Header="Recordings"
+                ItemSelected="OnItemSelected"
+                ItemTapped="OnItemTapped"
+                effect:ItemLongPressEffect.Command="{Binding LongClickCommand}"
+                ItemsSource="{Binding Records}">
+                <w:CircleListView.Effects>
+                    <effect:ItemLongPressEffect />
+                </w:CircleListView.Effects>
+                <ListView.Footer>
+                    <StackLayout HeightRequest="115">
+                        <BoxView />
+                    </StackLayout>
+                </ListView.Footer>
+                <ListView.Header>
+                    <AbsoluteLayout HeightRequest="115" BackgroundColor="Black">
+                        <Label
+                            x:Name="headerLabel"
+                            AbsoluteLayout.LayoutBounds="0.5, 0.5, 1, 0.5"
+                            AbsoluteLayout.LayoutFlags="All"
+                            Text="{x:Static resx:AppResources.Recordings}"
+                            Style="{StaticResource LabelStyle-AT0116}"
+                            TextColor="#FF00FFF0"
+                            FontSize="14" />
+                    </AbsoluteLayout>
+                </ListView.Header>
+                <ListView.ItemTemplate>
+                    <DataTemplate>
+                        <ViewCell>
+                            <RelativeLayout HeightRequest="130" WidthRequest="360">
+                                <RelativeLayout.Resources>
+                                    <ResourceDictionary>
+                                        <converters:DurationToRemainingTimeConverter x:Key="TimeConverter" />
+                                        <converters:SttToPropertyConverter x:Key="SttConverter" />
+                                        <Style TargetType="Label">
+                                            <Setter Property="HorizontalTextAlignment" Value="Center" />
+                                            <Setter Property="VerticalTextAlignment" Value="Center" />
+                                            <Setter Property="WidthRequest" Value="200" />
+                                            <Setter Property="TextColor" Value="White" />
+                                            <!--<Setter Property="BackgroundColor" Value="Pink" />-->
+                                            <Setter Property="RelativeLayout.XConstraint"
+                                                Value="{ConstraintExpression Type=RelativeToParent, Property=Width, Factor=0, Constant=30}" />
+                                        </Style>
+                                    </ResourceDictionary>
+                                </RelativeLayout.Resources>
+                                <Label
+                                    Text="{Binding Title}"
+                                    HeightRequest="47"
+                                    WidthRequest="230"
+                                    TextColor="{StaticResource T0211}"
+                                    FontSize="13"
+                                    RelativeLayout.YConstraint="{ConstraintExpression Type=RelativeToParent,
+                                                                                  Property=Height,
+                                                                                  Factor=0,
+                                                                                  Constant=9}" />
+                                <Label
+                                    Text="{Binding Date}"
+                                    HeightRequest="32"
+                                    WidthRequest="230"
+                                    TextColor="{StaticResource T022}"
+                                    FontSize="8"
+                                    RelativeLayout.YConstraint="{ConstraintExpression Type=RelativeToParent,
+                                                                                  Property=Height,
+                                                                                  Factor=0,
+                                                                                  Constant=56}" />
+                                <Label
+                                    Text="{Binding Duration, Converter={StaticResource TimeConverter}, ConverterParameter={x:Static converters:RemainingTimeType.TimeText}}}"
+                                    HeightRequest="32"
+                                    WidthRequest="230"
+                                    TextColor="{StaticResource T022}"
+                                    FontSize="8"
+                                    RelativeLayout.YConstraint="{ConstraintExpression Type=RelativeToParent,
+                                                                                    Property=Height,
+                                                                                    Factor=0,
+                                                                                    Constant=90}" />
+                                <Image Source="{Binding SttEnabled, Converter={StaticResource SttConverter}, ConverterParameter={x:Static converters:SttPropertyType.RecordImageSource}}" 
+                                    WidthRequest="76"
+                                    HeightRequest="76"
+                                    RelativeLayout.XConstraint="{ConstraintExpression Type=RelativeToParent,
+                                                                                    Property=Width,
+                                                                                    Factor=0,
+                                                                                    Constant=268}"
+                                    RelativeLayout.YConstraint="{ConstraintExpression Type=RelativeToParent,
+                                                                                    Property=Height,
+                                                                                    Factor=0,
+                                                                                    Constant=27}" />
+                                <w:Check DisplayStyle="Default"
+                                     IsToggled="{Binding Checked, Mode=TwoWay}"
+                                     IsEnabled="{Binding BindingContext.IsCheckable, Source={x:Reference myRecordListPage}}"
+                                     WidthRequest="76"
+                                     HeightRequest="76"
+                                     RelativeLayout.XConstraint="{ConstraintExpression Type=RelativeToParent,
+                                                                                  Property=Width,
+                                                                                  Factor=0,
+                                                                                  Constant=150}"
+                                     RelativeLayout.YConstraint="{ConstraintExpression Type=RelativeToParent,
+                                                                                  Property=Height,
+                                                                                  Factor=0,
+                                                                                  Constant=30}"
+                                     effect:TizenStyleEffect.Style="genlist/select_mode"
+                                     effect:TizenEventPropagationEffect.EnablePropagation="True">
+                                    <w:Check.Effects>
+                                        <effect:TizenStyleEffect/>
+                                        <effect:TizenEventPropagationEffect/>
+                                    </w:Check.Effects>
+                                </w:Check>
+                            </RelativeLayout>
+                        </ViewCell>
+                    </DataTemplate>
+                </ListView.ItemTemplate>
+            </w:CircleListView>
+            <Button x:Name="CheckedCounter"
+                    IsVisible="{Binding IsCheckable}"
+                    Text="{Binding CheckedNamesCount}"
+                    AbsoluteLayout.LayoutBounds="0.5, 10, 100, 80"
+                    AbsoluteLayout.LayoutFlags="XProportional"
+                    Command="{Binding SelectModeActionButtonPressedCommand}">
+                <Button.Behaviors>
+                    <w:ContextPopupEffectBehavior x:Name="CheckedCounterBehavior"
+                        PositionOption="BottomOfView" />
+                </Button.Behaviors>
+            </Button>
+        </AbsoluteLayout>
+    </views:CirclePageEx.Content>
+    <w:CirclePage.ActionButton>
+        <w:ActionButtonItem
+            x:Name="deleteActionButton"
+            IsVisible="{Binding IsCheckable}"
+            IsEnable="{Binding CheckedNamesCount, Converter={StaticResource ViewVisibilityConverter}, ConverterParameter={x:Static converters:ViewType.RecordCheckView}}"
+            Clicked="DeleteActionButtonClicked"
+            Command="{Binding DeleteRecordsCommand}"
+            Text="{x:Static resx:AppResources.DELETE}" />
+    </w:CirclePage.ActionButton>
+    <w:CirclePage.ToolbarItems>
+        <views:BindableToolbarItem
+            x:Name="toolbarItem"
+            IsVisible="{Binding Records.Count, Converter={StaticResource ViewVisibilityConverter}, ConverterParameter={x:Static converters:ViewType.RecordListView}}"
+            Command="{Binding ChangeToDeleteModeCommand}"
+            Icon="more_option_icon_delete.png"
+            Text="{x:Static resx:AppResources.DELETE}" />
+    </w:CirclePage.ToolbarItems>
+</views:CirclePageEx>
\ No newline at end of file
diff --git a/Test/Voicememo2020/VoiceMemo/Views/RecordListPage.xaml.cs b/Test/Voicememo2020/VoiceMemo/Views/RecordListPage.xaml.cs
new file mode 100755 (executable)
index 0000000..16b97f8
--- /dev/null
@@ -0,0 +1,202 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://floralicense.org/license/
+ *
+ * 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 VoiceMemo.Effects;
+using VoiceMemo.Models;
+using VoiceMemo.Resx;
+using VoiceMemo.ViewModels;
+using Xamarin.Forms;
+using Tizen.Wearable.CircularUI.Forms;
+using Xamarin.Forms.Xaml;
+
+namespace VoiceMemo.Views
+{
+    /// <summary>
+    /// RecordListPage class
+    /// It shows the list of recordings
+    /// </summary>
+    public partial class RecordListPage : CirclePageEx
+    {
+        MainPageModel ViewModel;
+        public RecordListPage(MainPageModel viewModel)
+        {
+            BindingContext = ViewModel = viewModel;
+            // Subscribe notification of locale changes to update text based on locale
+            MessagingCenter.Subscribe<App>(this, MessageKeys.UpdateByLanguageChange, (obj) =>
+            {
+                UpdateUI();
+            });
+            InitializeComponent();
+            ImageAttributes.SetBlendColor(NoImage, Color.FromRgba(94, 94, 94, 77));
+            // Binding for ContextPopupEffectBehavior's properties
+            // BindingContext is not inherited by Behavior and Effect.
+            // Source of Binding should be specified explicitly.
+            CheckedCounterBehavior.SetBinding(ContextPopupEffectBehavior.AcceptTextProperty, new Binding("SelectOptionMessage1", BindingMode.OneWay, source: BindingContext));
+            CheckedCounterBehavior.SetBinding(ContextPopupEffectBehavior.AcceptCommandProperty, new Binding("SelectCommand1", BindingMode.OneWay, source: BindingContext));
+            CheckedCounterBehavior.SetBinding(ContextPopupEffectBehavior.CancelTextProperty, new Binding("SelectOptionMessage2", BindingMode.OneWay, source: BindingContext));
+            CheckedCounterBehavior.SetBinding(ContextPopupEffectBehavior.CancelCommandProperty, new Binding("SelectCommand2", BindingMode.OneWay, source: BindingContext));
+            CheckedCounterBehavior.SetBinding(ContextPopupEffectBehavior.VisibilityProperty, new Binding("PopupVisibility", BindingMode.TwoWay, source: BindingContext));
+        }
+
+        void UpdateUI()
+        {
+            // Update text that has been translated into the current language.
+            noRecordingsLabel.Text = AppResources.NoRecordings;
+            recordingsLabel.Text = AppResources.Recordings;
+            headerLabel.Text = AppResources.Recordings;
+            deleteActionButton.Text = AppResources.DELETE;
+            toolbarItem.Text = AppResources.DELETE;
+        }
+
+        /// <summary>
+        /// Invoked immediately prior to the Page becoming visible.
+        /// </summary>
+        protected override void OnAppearing()
+        {
+            Console.WriteLine("[RecordListPage]  OnAppearing() ...");
+            foreach (var record in ViewModel.Records)
+            {
+                record.Checked = false;
+            }
+        }
+
+        public void Rotate(RotaryEventArgs args)
+        {
+            Console.WriteLine("[RecordListPage]  Rotate() IsClockwise ? " + args.IsClockwise);
+            //DataListView.ScrollTo();
+        }
+
+        /// <summary>
+        /// Invoked when this page disappears.
+        /// </summary>
+        protected override void OnDisappearing()
+        {
+            Console.WriteLine("[RecordListPage]  OnDisappearing");
+            ViewModel.IsCheckable = false;
+        }
+
+        /*async*/
+        void OnItemSelected(object sender, SelectedItemChangedEventArgs args)
+        {
+            var item = args.SelectedItem as Record;
+            if (item == null)
+            {
+                return;
+            }
+            Console.WriteLine(" RecordListPage.OnItemSelected :  " + args.SelectedItem/* + " , index: " + args.SelectedItemIndex*/);
+            //await Navigation.PushAsync(new ItemDetailPage(new ItemDetailViewModel(item)));
+
+            // Manually deselect item
+            DataListView.SelectedItem = null;
+        }
+
+        async void OnItemTapped(object sender, ItemTappedEventArgs args)
+        {
+            if (((MainPageModel)BindingContext).IsCheckable)
+            {
+                Console.WriteLine(" RecordListPage.OnItemTapped :  Checkable mode so ignore tapped event");
+                return;
+            }
+
+            Console.WriteLine(" RecordListPage.OnItemTapped :  " + args.Item);
+            await Navigation.PushAsync(PageFactory.GetInstance(Pages.Details, args.Item));
+        }
+
+        void OnCircleToolbarItemClicked_DeleteRecord(object sender, EventArgs args)
+        {
+            Console.WriteLine("[RecordListPage.OnCircleToolbarItemClicked_DeleteRecord] sender : " + sender);
+
+            //MessagingCenter.Send<Page, Record>(this, MessageKeys.DeleteVoiceMemo, ((DetailsPageModel)viewModel).Record);
+            //await Navigation.PopToRootAsync();
+
+            //MessagingCenter.Send<Page, Record>(this, MessageKeys.DeleteVoiceMemo, ((DetailsPageModel)viewModel).Record);
+            //await Navigation.PushAsync(PageFactory.GetInstance(Pages.PlayBack, viewModel.Record/*new PlayBackPageModel(viewModel.Record)*/));
+        }
+/*
+        async void DeleteActionButtonClicked(object sender, EventArgs args)
+        {
+            Console.WriteLine("[RecordListPage.DeleteActionButtonClicked] sender : " + sender + " CheckedNamesCount : " + ViewModel.CheckedNamesCount);
+            //if (ViewModel.CheckedNamesCount == 1)
+            //{
+            //    await DisplayAlert("Delete", "Deleted..", "OK");
+            //    //GraphicPopUp popup = new GraphicPopUp
+            //    //{
+            //    //    Text = AppResources.Deleted,
+            //    //};
+            //    //popup.TimedOut += Popup_TimedOut;
+            //    //popup.Show();
+            //}
+            //else
+            //{
+            //    ProgressbarPopup popup = new ProgressbarPopup
+            //    {
+            //        Text = AppResources.Deleted,
+            //        ProgressbarText = AppResources.Deleting,
+            //    };
+            //    popup.TimedOut += Popup_TimedOut;
+            //    popup.Show();
+            //}
+            await DisplayAlert("Delete", "Deleted..", "OK");
+        }
+*/
+
+        void DeleteActionButtonClicked(object sender, EventArgs args)
+        {
+            Console.WriteLine("[RecordListPage.DeleteActionButtonClicked] sender : " + sender + " CheckedNamesCount : " + ViewModel.CheckedNamesCount);
+            if (ViewModel.CheckedNamesCount == 1)
+            {
+                GraphicPopUp popup = new GraphicPopUp
+                {
+                    Text = AppResources.Deleted,
+                };
+                popup.TimedOut += Popup_TimedOut;
+                popup.Show();
+            }
+            else
+            {
+                ProgressbarPopup popup = new ProgressbarPopup
+                {
+                    Text = AppResources.Deleted,
+                    ProgressbarText = AppResources.Deleting,
+                };
+                popup.TimedOut += Popup_TimedOut;
+                popup.Show();
+            }
+        }
+
+        private void Popup_TimedOut(object sender, EventArgs e)
+        {
+            Console.WriteLine("[RecordListPage.Popup_TimedOut] sender : " + sender);
+            //await Navigation.PopToRootAsync();
+        }
+
+        protected override bool OnBackButtonPressed()
+        {
+            if (ViewModel.IsCheckable)
+            {
+                Console.WriteLine("[RecordListPage.OnBackButtonPressed] IsCheckable = true");
+                ViewModel.IsCheckable = false;
+                return true;
+            }
+            else
+            {
+                Console.WriteLine("[RecordListPage.OnBackButtonPressed] IsCheckable = false");
+                return false;
+            }
+        }
+    }
+}
diff --git a/Test/Voicememo2020/VoiceMemo/Views/RecordingPage.xaml b/Test/Voicememo2020/VoiceMemo/Views/RecordingPage.xaml
new file mode 100755 (executable)
index 0000000..cf8d7da
--- /dev/null
@@ -0,0 +1,153 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<views:CirclePageEx
+    x:Class="VoiceMemo.Views.RecordingPage"
+    xmlns="http://xamarin.com/schemas/2014/forms"
+    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
+    xmlns:views="clr-namespace:VoiceMemo.Views;"
+    xmlns:vm="clr-namespace:VoiceMemo.ViewModels;"
+    xmlns:converter="clr-namespace:VoiceMemo.Converters"
+    xmlns:w="clr-namespace:Tizen.Wearable.CircularUI.Forms;assembly=XSF.CircularUI.Forms"
+    Title="{Binding Title}">
+    <views:CirclePageEx.Resources>
+        <ResourceDictionary>
+            <!--  record_controller_bg.png  -->
+            <Color x:Key="AO012L1">#FFFAFAFA</Color>
+            <Color x:Key="AO012L1P">#66FAFAFA</Color>
+            <Color x:Key="AO012L1D">#66FAFAFA</Color>
+            <!--  recording_icon_cancel(_pause).png  -->
+            <Color x:Key="AO012L3">#FF4F4F4F</Color>
+            <Color x:Key="AO012L3P">#64F4F4F</Color>
+            <Color x:Key="AO012L3D">#664F4F4F</Color>
+            <!--  record_stop_icon.png  -->
+            <Color x:Key="AO016L1">#FFE00404</Color>
+            <Color x:Key="AO016L1P">#66E00404</Color>
+            <Color x:Key="AO016L1D">#66E00404</Color>
+            <!--  recording_stt_icon.png  -->
+            <Color x:Key="AO0210">#FFFAFAFA</Color>
+            <Color x:Key="AT011">#FFFAFAFA</Color>
+            <Color x:Key="AO028">#8C11B4FF</Color>
+            <!--  voicerecorder_btn_stop(_pause, _play).png  -->
+            <Color x:Key="AO014L3">#FFFAFAFA</Color>
+            <Color x:Key="AO014L3P">#66FAFAFA</Color>
+            <Color x:Key="AO014L3D">#66FAFAFA</Color>
+            <!--  voicerecorder_btn_bg.png  -->
+            <Color x:Key="AO014L1">#FF12B4FF</Color>
+            <!--  FF467EA6  -->
+            <Color x:Key="AO014L1P">#6612B4FF</Color>
+            <Color x:Key="AO014L1D">#6612B4FF</Color>
+            
+            <Style x:Key="LabelStyle-AT011" TargetType="Label" BasedOn="{StaticResource LabelStyle-Base}">
+                <Setter Property="FontSize" Value="20" />
+                <Setter Property="TextColor" Value="{StaticResource AT011}" />
+            </Style>
+            <Color x:Key="AT0116">#FF4DCFFF</Color>
+            <Style x:Key="LabelStyle-AT0116" TargetType="Label" BasedOn="{StaticResource LabelStyle-Base}">
+                <Setter Property="FontSize" Value="10" />
+                <Setter Property="TextColor" Value="{StaticResource AT0116}" />
+            </Style>
+            <converter:RecordImageSourceColorConverter x:Key="RecordImageSourceColorConverter" />
+        </ResourceDictionary>    
+    </views:CirclePageEx.Resources>
+    <w:CirclePage.CircleSurfaceItems>
+        <w:CircleProgressBarSurfaceItem
+            x:Name="RecordingProgress"
+            Value="{Binding RecordingProcess}" />
+    </w:CirclePage.CircleSurfaceItems>
+    <ContentPage.Content>
+        <AbsoluteLayout BackgroundColor="Black">
+            <!--  Recorder  -->
+            <Image
+                x:Name="VoiceRecorderBtnEffectImage"
+                AbsoluteLayout.LayoutBounds="117,117,126,126"
+                AbsoluteLayout.LayoutFlags="None"
+                Source="voicememo_effect.png" />
+            <Image
+                x:Name="VoiceRecorderBtnEffectImage2"
+                AbsoluteLayout.LayoutBounds="117,117,126,126"
+                AbsoluteLayout.LayoutFlags="None"
+                Source="voicememo_effect.png" />
+            <Image
+                x:Name="VoiceRecorderBtnBgImage"
+                AbsoluteLayout.LayoutBounds="117,117,126,126"
+                AbsoluteLayout.LayoutFlags="None"
+                Source="voicerecorder_btn_bg.png">
+            </Image>
+            <Image
+                x:Name="VoiceRecorderBtnStopImage"
+                AbsoluteLayout.LayoutBounds="117,117,126,126"
+                AbsoluteLayout.LayoutFlags="None"
+                Source="voicerecorder_btn_stop.png">
+            </Image>
+            <BoxView
+                AbsoluteLayout.LayoutBounds="117,117,126,126"
+                AbsoluteLayout.LayoutFlags="None"
+                x:Name="TapLayer">
+                <BoxView.GestureRecognizers>
+                    <TapGestureRecognizer Tapped="CompleteRecording_Tapped" />
+                </BoxView.GestureRecognizers>
+            </BoxView>
+
+            <Image
+                x:Name="RecordingSttImage"
+                AbsoluteLayout.LayoutBounds="162,18,36,36"
+                AbsoluteLayout.LayoutFlags="None"
+                IsVisible="{Binding SttOn}"
+                Source="recording_stt_icon.png" />
+
+            <!--  Record Controller in Left  -->
+            <Image
+                x:Name="RecordControllerCancelBgImage"
+                AbsoluteLayout.LayoutBounds="30,139,82,82"
+                AbsoluteLayout.LayoutFlags="None"
+                Source="record_controller_bg.png" />
+            <Image
+                x:Name="RecordingIconCancelImage"
+                AbsoluteLayout.LayoutBounds="30,139,82,82"
+                AbsoluteLayout.LayoutFlags="None"
+                Source="recording_icon_cancel.png">
+                <Image.GestureRecognizers>
+                    <TapGestureRecognizer Tapped="TryToCancel_Tapped" />
+                    <!--<TapGestureRecognizer Command="{Binding TryToCancelCommand}"/>-->
+                </Image.GestureRecognizers>
+            </Image>
+
+            <!--  Record Controller in Right  -->
+            <Image
+                x:Name="RecordControllerPauseBgImage"
+                AbsoluteLayout.LayoutBounds="248,139,82,82"
+                AbsoluteLayout.LayoutFlags="None"
+                Source="record_controller_bg.png">
+                <Image.GestureRecognizers>
+                    <TapGestureRecognizer Tapped="PauseRecording_Tapped" />
+                </Image.GestureRecognizers>
+                <!--<Image.GestureRecognizers>
+                    <TapGestureRecognizer Command="{Binding RequestCommand}" CommandParameter="{x:Static vm:RecordingCommandType.PAUSE}"/>
+                </Image.GestureRecognizers>-->
+            </Image>
+            <Image
+                x:Name="RecordingIconPauseImage"
+                AbsoluteLayout.LayoutBounds="248,139,82,82"
+                AbsoluteLayout.LayoutFlags="None"
+                Source="{Binding PauseRecordToggleImage, Converter={StaticResource RecordImageSourceColorConverter}, ConverterParameter={x:Reference RecordingIconPauseImage}}">
+                <Image.GestureRecognizers>
+                    <TapGestureRecognizer Tapped="PauseRecording_Tapped" />
+                </Image.GestureRecognizers>
+                <!--<Image.GestureRecognizers>
+                    <TapGestureRecognizer Command="{Binding RequestCommand}" CommandParameter="{x:Static vm:RecordingCommandType.PAUSE}"/>
+                </Image.GestureRecognizers>-->
+            </Image>
+            <Label
+                x:Name="TitleLabel"
+                AbsoluteLayout.LayoutBounds="64,51,232,39"
+                AbsoluteLayout.LayoutFlags="None"
+                Text="{Binding RecordTitle}"
+                Style="{StaticResource LabelStyle-AT0116}" />
+            <Label
+                x:Name="RecordingTimeLabel"
+                AbsoluteLayout.LayoutBounds="102,249,156,79"
+                AbsoluteLayout.LayoutFlags="None"
+                Text="{Binding RecordingTime}"
+                Style="{StaticResource LabelStyle-AT011}" />
+        </AbsoluteLayout>
+    </ContentPage.Content>
+</views:CirclePageEx>
\ No newline at end of file
diff --git a/Test/Voicememo2020/VoiceMemo/Views/RecordingPage.xaml.cs b/Test/Voicememo2020/VoiceMemo/Views/RecordingPage.xaml.cs
new file mode 100755 (executable)
index 0000000..0f8e3e2
--- /dev/null
@@ -0,0 +1,398 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://floralicense.org/license/
+ *
+ * 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.Threading.Tasks;
+using VoiceMemo.Effects;
+using VoiceMemo.Models;
+using VoiceMemo.Services;
+using VoiceMemo.ViewModels;
+using Xamarin.Forms;
+using Xamarin.Forms.Xaml;
+
+namespace VoiceMemo.Views
+{
+    /// <summary>
+    /// RecordingPage class
+    /// It provides voice recording, pausing, and canceling.
+    /// </summary>
+    public partial class RecordingPage : CirclePageEx
+    {
+        public RecordingPageModel ViewModel;
+        double prevScale;
+        double prevShadowScale;
+        double prevAudioLevel;
+        bool currentOpaque = true;
+        double opacity;
+
+        public static readonly BindableProperty RecordingEffectAnimationProperty = BindableProperty.Create(nameof(RecordingEffectAnimation), typeof(bool), typeof(RecordingPage), false, propertyChanged: OnAnimationPropertyChanged);
+
+        private static void OnAnimationPropertyChanged(BindableObject bindable, object oldValue, object newValue)
+        {
+            if ((bool)oldValue == false && (bool)newValue == true)
+            {
+                ((RecordingPage)(bindable)).StartVolumeEffectAnimation();
+            }
+        }
+
+        public static readonly BindableProperty TimeFlickeringAnimationProperty = BindableProperty.Create(nameof(TimeFlickeringAnimation), typeof(bool), typeof(RecordingPage), false, propertyChanged: OnTimeFlickeringPropertyChanged);
+
+        private static void OnTimeFlickeringPropertyChanged(BindableObject bindable, object oldValue, object newValue)
+        {
+            if ((bool)oldValue == false && (bool)newValue == true)
+            {
+                ((RecordingPage)(bindable)).Blink();
+            }
+        }
+
+        public bool RecordingEffectAnimation
+        {
+            get { return (bool)GetValue(RecordingEffectAnimationProperty); }
+            set
+            {
+                SetValue(RecordingEffectAnimationProperty, value);
+            }
+        }
+
+        public bool TimeFlickeringAnimation
+        {
+            get { return (bool)GetValue(TimeFlickeringAnimationProperty); }
+            set
+            {
+                SetValue(TimeFlickeringAnimationProperty, value);
+            }
+        }
+
+        public RecordingPage(RecordingPageModel viewModel)
+        {
+            BindingContext = ViewModel = viewModel;
+            InitializeComponent();
+            UpdateColor();
+
+            RegisterForEvents();
+
+            RecordingEffectAnimation = false;
+            TimeFlickeringAnimation = false;
+
+            SetBinding(RecordingEffectAnimationProperty, new Binding("RecordingEffectOn", mode: BindingMode.Default));
+            SetBinding(TimeFlickeringAnimationProperty, new Binding("TimeFlickeringOn", mode: BindingMode.Default));
+
+            Init();
+        }
+
+        void RegisterForEvents()
+        {
+            //// Get notified when AudioRecordService's State is Recording
+            //MessagingCenter.Subscribe<IAudioRecordService>(this, MessageKeys.ReadyToRecord, async (obj) =>
+            //{
+            //    Console.WriteLine("### MessagingCenter ## [RecordingPage] ReadyToRecord!! ");
+            //});
+
+            MessagingCenter.Subscribe<RecordingPageModel, Record>(this, MessageKeys.SaveVoiceMemo, async (obj, item) =>
+            {
+                var _DeviceInfoService = DeviceInformationService.Instance;
+                if (_DeviceInfoService.AppState == AppState.Terminated)
+                {
+                    //Toast.DisplayText("Memo " + item.ID + " saved.", 3000);
+                    // TODO: show popup using app control
+                    return;
+                }
+
+                await Navigation.PushAsync(PageFactory.GetInstance(Pages.Details, item/*new DetailsPageModel(item)*/));
+
+                if (_DeviceInfoService.AppState == AppState.Background)
+                {
+                    Console.WriteLine(" ************   TO DO SOMETHING  *************");
+                }
+            });
+
+            // Called when an error occurs while recording
+            MessagingCenter.Subscribe<MediaContentService, Exception>(this, MessageKeys.ErrorOccur, (obj, exception) =>
+            {
+                DisplayAlert("Recording", exception.Message, "OK");
+            });
+
+            MessagingCenter.Subscribe<RecordingPageModel>(this, MessageKeys.ForcePopRecordingPage, async (obj) =>
+            {
+                Console.WriteLine("### MessagingCenter ## [RecordingPage] just received ForcePopRecordingPage");
+                await Navigation.PopAsync();
+            });
+        }
+
+        /// <summary>
+        /// Initialize Recording page
+        /// </summary>
+        public void Init()
+        {
+            RecordingTimeLabel.TextColor = Color.White;
+            ImageAttributes.SetBlendColor(RecordingIconPauseImage, (Color)Resources["AO012L3"]);
+            ((RecordingPageModel)ViewModel).Init();
+        }
+
+        /// <summary>
+        /// Start volume effect animation
+        /// </summary>
+        void StartVolumeEffectAnimation()
+        {
+            // Any background code that needs to update the user interface
+            // interact with UI elements
+            // call CheckVolumeAndResizeAnimationAsync method every 100ms
+            Device.StartTimer(TimeSpan.FromMilliseconds(100), CheckVolumeAndResizeAnimationAsync);
+        }
+
+        // Draw animation effects depending on volume level
+        private bool CheckVolumeAndResizeAnimationAsync()
+        {
+            RecordingPageModel recordingViewModel = (RecordingPageModel)BindingContext;
+            // @20180217-vincent: async chain can be stopped by using Task.Factory.StartNew(...)
+            //                    Device.InovkeOnMainThread was removed because it is guaranteed main thread
+            Task.Factory.StartNew(async () =>
+            {
+                if (recordingViewModel.AudioRecordingService.State == AudioRecordState.Recording)
+                {
+                    double fScaleValue = 0, fShodowScaleValue = 0;
+                    double volume = recordingViewModel.AudioRecordingService.GetRecordingLevel(); //-300 ~ 0
+                    int uwLevel = 0;
+                    int uwShadowLevel = 0;
+                    int effectLevel = 0;
+                    double db = volume;
+                    const int VOLUME_LEVEL_MIN = -55;
+                    const int VOLUME_LEVEL_MAX = -10;
+                    const double LINEAR_VI_SCALE = 1.0 / 20.0;
+
+                    if (db < VOLUME_LEVEL_MIN)
+                    {
+                        effectLevel = 0;
+                    }
+                    else if (db > VOLUME_LEVEL_MAX)
+                    {
+                        effectLevel = VOLUME_LEVEL_MAX - VOLUME_LEVEL_MIN;
+                    }
+                    else
+                    {
+                        effectLevel = (int)(db - VOLUME_LEVEL_MIN);
+                    }
+
+                    uwLevel = effectLevel;
+
+                    if (uwLevel > 1)
+                    {
+                        uwShadowLevel = uwLevel / 4 + (new Random().Next() % (uwLevel / 2));
+                    }
+
+                    if (uwLevel > prevAudioLevel)
+                    {
+                        fScaleValue = (30 + 70 * (uwLevel) / (VOLUME_LEVEL_MAX - VOLUME_LEVEL_MIN)) / 100.0;
+                        fShodowScaleValue = (30 + 70 * (uwShadowLevel) / (VOLUME_LEVEL_MAX - VOLUME_LEVEL_MIN)) / 100.0;
+
+                        if (fScaleValue < prevScale)
+                        {
+                            fScaleValue = prevScale - LINEAR_VI_SCALE;
+                        }
+
+                        if (fShodowScaleValue < prevShadowScale)
+                        {
+                            fShodowScaleValue = prevShadowScale - LINEAR_VI_SCALE;
+                        }
+                    }
+                    else
+                    {
+                        fScaleValue = prevScale - LINEAR_VI_SCALE;
+                        fShodowScaleValue = prevShadowScale - LINEAR_VI_SCALE;
+                    }
+
+                    if (fScaleValue < 0.3)
+                    {
+                        fScaleValue = 0.3;
+                    }
+                    else if (fScaleValue > 1.0)
+                    {
+                        fScaleValue = 1.0;
+                    }
+
+                    if (fShodowScaleValue < 0.3)
+                    {
+                        fShodowScaleValue = 0.3;
+                    }
+                    else if (fShodowScaleValue > 1.0)
+                    {
+                        fShodowScaleValue = 1.0;
+                    }
+
+                    int actualSize = (int)(fScaleValue * 360);
+                    int acutalShadowSize = (int)(fShodowScaleValue * 360);
+
+                    await DrawVolumeEffectAnimationAsync(actualSize, acutalShadowSize);
+
+                    prevAudioLevel = uwLevel;
+                    prevScale = fScaleValue;
+                    prevShadowScale = fShodowScaleValue;
+                }
+            });
+            return ((RecordingPageModel)BindingContext).RecordingEffectOn;
+        }
+
+        // Draw animation depending on volume level while recording
+        private async Task DrawVolumeEffectAnimationAsync(int imageSize, int shadowImageSize)
+        {
+            double image2Ratio = (double)imageSize / 126;
+            double imageRatio = (double)shadowImageSize / 126;
+            await Task.WhenAll(
+                VoiceRecorderBtnEffectImage2.ScaleTo(image2Ratio,50),
+                VoiceRecorderBtnEffectImage.ScaleTo(imageRatio,50));
+        }
+
+        /// <summary>
+        /// Invoked immediately prior to the Page becoming visible.
+        /// </summary>
+        protected override void OnAppearing()
+        {
+        }
+
+        /// <summary>
+        /// Invoked when this page disappears.
+        /// </summary>
+        protected override void OnDisappearing()
+        {
+        }
+
+        /// <summary>
+        /// Invoked when backbutton is pressed
+        /// As a result, CancelPage will be shown.
+        /// </summary>
+        /// <returns>bool</returns>
+        protected override bool OnBackButtonPressed()
+        {
+            TryToCancel_Tapped(this, new EventArgs());
+            return true;
+        }
+
+        // When it is no need to receive notifications anymore, unsubscribes subscribers from the specified messages 
+        void UnregisterForEvents()
+        {
+            //MessagingCenter.Unsubscribe<IAudioRecordService>(this, MessageKeys.ReadyToRecord);
+            MessagingCenter.Unsubscribe<RecordingPageModel, Record>(this, MessageKeys.SaveVoiceMemo);
+            MessagingCenter.Unsubscribe<MediaContentService, Exception>(this, MessageKeys.ErrorOccur);
+            MessagingCenter.Unsubscribe<RecordingPageModel>(this, MessageKeys.ForcePopRecordingPage);
+        }
+
+        /// <summary>
+        /// Dispose this page
+        /// </summary>
+        public void Dispose()
+        {
+            UnregisterForEvents();
+            ((RecordingPageModel)BindingContext).Dispose();
+        }
+
+        /// <summary>
+        /// Invoked when RecordingIconCancelImage is tapped
+        /// Recording is temporarily paused.
+        /// </summary>
+        /// <param name="sender">sender object</param>
+        /// <param name="e">EventArgs</param>
+        async void TryToCancel_Tapped(object sender, EventArgs e)
+        {
+            if (ViewModel.RecordingViewModelState == RecordingViewModelState.Recording)
+            {
+                ViewModel.RequestCommand.Execute(RecordingCommandType.PauseForCancelRequest);
+            }
+
+            await Navigation.PushAsync(PageFactory.GetInstance(Pages.TryCancel, ViewModel));
+        }
+
+        /// <summary>
+        /// Invoked when RecordControllerPauseBgImage or RecordingIconPauseImage is tapped
+        /// Recording is temporarily paused.
+        /// paused and recording states are toggled every time this image button is pressed
+        /// </summary>
+        /// <param name="sender">sender object</param>
+        /// <param name="e">EventArgs</param>
+        void PauseRecording_Tapped(object sender, EventArgs e)
+        {
+            if (((RecordingPageModel)BindingContext).RecordingViewModelState == RecordingViewModelState.Paused)
+            {
+                ViewModel.RequestCommand.Execute(RecordingCommandType.Record);
+            }
+            else if (((RecordingPageModel)BindingContext).RecordingViewModelState == RecordingViewModelState.Recording)
+            {
+                ViewModel.RequestCommand.Execute(RecordingCommandType.Pause);
+            }
+        }
+
+        private void Blink()
+        {
+            currentOpaque = true;
+            Device.StartTimer(TimeSpan.FromMilliseconds(700), BlinkInvoker);
+        }
+
+        private bool BlinkInvoker()
+        {
+            Task.Factory.StartNew(async () =>
+                {
+                    opacity = currentOpaque ? 0 : 1;
+                    await BlinkAnimation();
+                    currentOpaque = !currentOpaque;
+            });
+
+            return ((RecordingPageModel)BindingContext).TimeFlickeringOn;
+        }
+
+        private async Task BlinkAnimation()
+        {
+            if (!((RecordingPageModel)BindingContext).TimeFlickeringOn)
+            {
+                RecordingTimeLabel.Opacity = 1.0;
+            }
+            else
+            {
+                await Task.WhenAny(RecordingTimeLabel.FadeTo(opacity, 500, Easing.Linear));
+            }
+        }
+            
+        /// <summary>
+        /// Invoked when VoiceRecorderBtnBgImage and VoiceRecorderBtnStopImage is tapped
+        /// Audio recording will be done
+        /// </summary>
+        /// <param name="sender">sender object</param>
+        /// <param name="args">EventArgs</param>
+        void CompleteRecording_Tapped(object sender, EventArgs args)
+        {
+            Console.WriteLine("RecordingPage   ============   CompleteRecording_Tapped");
+            ViewModel.RequestCommand.Execute(RecordingCommandType.Stop);
+        }
+
+        void UpdateColor()
+        {
+            // For case that STT is On, recording_stt_icon.png
+            ImageAttributes.SetBlendColor(RecordingSttImage, (Color)Resources["AO0210"]);
+
+            // Recorder
+            ImageAttributes.SetBlendColor(VoiceRecorderBtnEffectImage, (Color)Resources["AO028"]);
+            ImageAttributes.SetBlendColor(VoiceRecorderBtnEffectImage2, (Color)Resources["AO028"]);
+            ImageAttributes.SetBlendColor(VoiceRecorderBtnBgImage, (Color)Resources["AO014L1"]);
+            ImageAttributes.SetBlendColor(VoiceRecorderBtnStopImage, (Color)Resources["AO014L3"]);
+
+            // Record Controller in Left
+            ImageAttributes.SetBlendColor(RecordControllerCancelBgImage, (Color)Resources["AO012L1"]);
+            ImageAttributes.SetBlendColor(RecordingIconCancelImage, (Color)Resources["AO012L3"]);
+
+            // Record Controller in Right
+            ImageAttributes.SetBlendColor(RecordControllerPauseBgImage, (Color)Resources["AO012L1"]);
+            ImageAttributes.SetBlendColor(RecordingIconPauseImage, (Color)Resources["AO012L3"]);
+        }
+    }
+}
\ No newline at end of file
diff --git a/Test/Voicememo2020/VoiceMemo/Views/SttLanguageViewCell.xaml b/Test/Voicememo2020/VoiceMemo/Views/SttLanguageViewCell.xaml
new file mode 100755 (executable)
index 0000000..7f5a03b
--- /dev/null
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<ViewCell
+    x:Class="VoiceMemo.Views.SttLanguageViewCell"
+    xmlns="http://xamarin.com/schemas/2014/forms"
+    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
+    xmlns:w="clr-namespace:Tizen.Wearable.CircularUI.Forms;assembly=XSF.CircularUI.Forms">
+    <ViewCell.View>
+        <RelativeLayout HeightRequest="130" WidthRequest="360">
+            <Label
+                FontAttributes="Bold"
+                HorizontalTextAlignment="Center"
+                RelativeLayout.XConstraint="{ConstraintExpression Type=RelativeToParent,
+                                                                  Property=Width,
+                                                                  Factor=0,
+                                                                  Constant=30}"
+                RelativeLayout.YConstraint="{ConstraintExpression Type=RelativeToParent,
+                                                                  Property=Height,
+                                                                  Factor=0,
+                                                                  Constant=15}"
+                Style="{StaticResource BaseLabelStyle}"
+                Text="{Binding Name}"
+                FontSize="11"
+                VerticalTextAlignment="Center"
+                WidthRequest="220" />
+            <Label
+                FontAttributes="None"
+                HorizontalTextAlignment="Center"
+                RelativeLayout.XConstraint="{ConstraintExpression Type=RelativeToParent,
+                                                                  Property=Width,
+                                                                  Factor=0,
+                                                                  Constant=30}"
+                RelativeLayout.YConstraint="{ConstraintExpression Type=RelativeToParent,
+                                                                  Property=Height,
+                                                                  Factor=0,
+                                                                  Constant=80}"
+                Style="{StaticResource BaseLabelStyle}"
+                Text="{Binding Country}"
+                FontSize="7"
+                VerticalTextAlignment="Center"
+                WidthRequest="220" />
+            <w:Radio
+                x:Name="onOffSwitch"
+                GroupName="Language"
+                RelativeLayout.XConstraint="{ConstraintExpression Type=RelativeToParent,
+                                                                  Property=Width,
+                                                                  Factor=0.7,
+                                                                  Constant=0}"
+                RelativeLayout.YConstraint="{ConstraintExpression Type=RelativeToParent,
+                                                                  Property=Height,
+                                                                  Factor=0.15,
+                                                                  Constant=0}"
+                IsSelected="{Binding IsOn, Mode=TwoWay}" 
+                Selected="OnSelected"
+                Value="{Binding Combo}"/>
+        </RelativeLayout>
+    </ViewCell.View>
+</ViewCell>
\ No newline at end of file
diff --git a/Test/Voicememo2020/VoiceMemo/Views/SttLanguageViewCell.xaml.cs b/Test/Voicememo2020/VoiceMemo/Views/SttLanguageViewCell.xaml.cs
new file mode 100755 (executable)
index 0000000..1b70b06
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://floralicense.org/license/
+ *
+ * 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 VoiceMemo.Models;
+using VoiceMemo.ViewModels;
+using Xamarin.Forms;
+using Tizen.Wearable.CircularUI.Forms;
+using Xamarin.Forms.Xaml;
+
+namespace VoiceMemo.Views
+{
+    /// <summary>
+    /// SttLanguageViewCell
+    /// It's a custom view cell for CircleListView in LanguageSelectionPage
+    /// </summary>
+       public partial class SttLanguageViewCell : ViewCell
+       {
+               public SttLanguageViewCell()
+               {
+                       InitializeComponent();
+               }
+
+        // Called when radio button is selected
+        public async void OnSelected(object sender, SelectedEventArgs args)
+        {
+            Console.WriteLine($"Radio.OnSoundSelected!! value:{args.Value}");
+            Radio radio = sender as Radio;
+            if (Application.Current.MainPage.Navigation.NavigationStack.Count > 0)
+            {
+                int index = Application.Current.MainPage.Navigation.NavigationStack.Count - 1;
+
+                LanguageSelectionPage currPage = Application.Current.MainPage.Navigation.NavigationStack[index] as LanguageSelectionPage;
+                //Error CS0023  Operator '!' cannot be applied to operand of type 'string'
+                if (args.Value != null)
+                {
+                    Console.WriteLine("  < UNSELECTED >  XXXXXX sender " + sender + " -  " + radio.Value);
+                    currPage.ignoreRadioSelection = false;
+                    return;
+                }
+                else
+                {
+                    if (currPage.ignoreRadioSelection)
+                    {
+                        Console.WriteLine("\n\nRadio_Selected  >>>>>>>  SKIP!\n\n");
+                        currPage.ignoreRadioSelection = false;
+                        return;
+                    }
+
+                    Console.WriteLine("  < SELECTED >  XXXXXX sender " + sender + " -  " + radio.Value);
+                    SttLanguage item = radio.BindingContext as SttLanguage;
+                    ((MainPageModel)currPage.BindingContext).CurrentLanguage = item.Lang;
+
+                    ((MainPageModel)currPage.BindingContext).SelectedItemIndex = item;
+                    await currPage.Navigation.PopToRootAsync();
+                }
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/Test/Voicememo2020/VoiceMemo/Views/ViewExtensions.cs b/Test/Voicememo2020/VoiceMemo/Views/ViewExtensions.cs
new file mode 100755 (executable)
index 0000000..f979c3c
--- /dev/null
@@ -0,0 +1,14 @@
+using System;
+using System.Threading.Tasks;
+using Xamarin.Forms;
+
+namespace VoiceMemo.Views
+{
+    public static class ViewExtensions
+    {
+        public static void CancelAnimation(this VisualElement self)
+        {
+            self.AbortAnimation("ColorTo");
+        }
+    }
+}
diff --git a/Test/Voicememo2020/VoiceMemo/VoiceMemo.cs b/Test/Voicememo2020/VoiceMemo/VoiceMemo.cs
new file mode 100755 (executable)
index 0000000..7279f4a
--- /dev/null
@@ -0,0 +1,158 @@
+using System;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using Tizen.Applications;
+using Tizen.Security;
+using Tizen.Wearable.CircularUI.Forms;
+using Tizen.Wearable.CircularUI.Forms.Renderer;
+using VoiceMemo.EffectRenderers;
+using VoiceMemo.Services;
+using VoiceMemo.Utility;
+using Xamarin.Forms;
+using Xamarin.Forms.Platform.Tizen;
+using TLog = Tizen.Log;
+
+namespace VoiceMemo
+{
+    class Program : global::Xamarin.Forms.Platform.Tizen.ApplicationLifecycle
+    {
+        static App app;
+        protected async override void OnCreate()
+        {
+            bool recorderGranted = false;
+            if (PrivacyPrivilegeManager.CheckPermission(PrivilegeInformation.RecorderPrivilege) != CheckResult.Allow)
+            {
+                recorderGranted = await RequestPermission(PrivilegeInformation.RecorderPrivilege);
+            }
+            else
+            {
+                recorderGranted = true;
+            }
+
+            bool mediaStorageGranted = false;
+            if (PrivacyPrivilegeManager.CheckPermission(PrivilegeInformation.MediaStoragePrivilege) != CheckResult.Allow)
+            {
+                mediaStorageGranted = await RequestPermission(PrivilegeInformation.MediaStoragePrivilege);
+            }
+            else
+            {
+                mediaStorageGranted = true;
+            }
+
+            if (!(recorderGranted && mediaStorageGranted))
+            {
+                Log.Error(LOG.TAG, "Failed to obtain user consent. So, app is going to be terminated.");
+                // Terminate this application.
+                FormsApplication.Current.Exit();
+                return;
+            }
+
+            app = new App();
+            FormsApplication.LoadApplication(app);
+        }
+        static Task<bool> RequestPermission(string privilege)
+        {
+            TaskCompletionSource<bool> tcs = new TaskCompletionSource<bool>();
+            var response = PrivacyPrivilegeManager.GetResponseContext(privilege);
+            PrivacyPrivilegeManager.ResponseContext target;
+            response.TryGetTarget(out target);
+            target.ResponseFetched += (s, e) =>
+            {
+                if (e.cause == CallCause.Error)
+                {
+                    /// Handle errors
+                    Log.Error(LOG.TAG, "An error occurred while requesting an user permission");
+                    tcs.SetResult(false);
+                    return;
+                }
+
+                // Now, we can check if the permission is granted or not
+                switch (e.result)
+                {
+                    case RequestResult.AllowForever:
+                        // Permission is granted.
+                        // We can do this permission-related task we want to do.
+                        Log.Info(LOG.TAG, "Response: RequestResult.AllowForever");
+                        tcs.SetResult(true);
+                        break;
+                    case RequestResult.DenyForever:
+                    case RequestResult.DenyOnce:
+                        // Functionality that depends on this permission will not be available
+                        Log.Info(LOG.TAG, "Response: RequestResult." + e.result.ToString());
+                        tcs.SetResult(false);
+                        break;
+                }
+
+            };
+            PrivacyPrivilegeManager.RequestPermission(privilege);
+            return tcs.Task;
+        }
+
+        /// <summary>
+        /// Called when this application is terminated
+        /// </summary>
+        protected override void OnTerminate()
+        {
+            // Save the index of recording files
+            Preference.Set(DeviceInformationService.LastUsedID, AudioRecordService.numbering);
+            base.OnTerminate();
+            app.Terminate();
+        }
+
+        static void Main(string[] args)
+        {
+            var app = new Program();
+
+            // define your custom handlers
+            var customRenderers = new Dictionary<Type, Func<IRegisterable>>()
+            {
+                { typeof(CirclePage), ()=> new CirclePageRenderer() },
+                { typeof(global:: Tizen.Wearable.CircularUI.Forms.CircleListView), () => new CircleListViewRenderer() },
+                { typeof(global:: Tizen.Wearable.CircularUI.Forms.CircleScrollView), ()=> new global::Tizen.Wearable.CircularUI.Forms.Renderer.CircleScrollViewRenderer() },
+                { typeof(global:: Tizen.Wearable.CircularUI.Forms.TwoButtonPage), ()=> new global::Tizen.Wearable.CircularUI.Forms.Renderer.TwoButtonPageRenderer() },
+            };
+
+            var option = new InitializationOptions(app)
+            {
+                UseMessagingCenter = true,
+                UseStyle = true,
+                UseShell = false,
+                UseVisual = false,
+                StaticRegistarStrategy = StaticRegistrarStrategy.StaticRegistrarOnly,
+                CustomHandlers = customRenderers,
+                Flags = InitializationFlags.DisableCss
+            };
+
+            Xamarin.Forms.InitializationOptions.EffectScope myeffect = new Xamarin.Forms.InitializationOptions.EffectScope();
+            myeffect.Name = "SEC";
+            //myeffect.Name = "MyCompany";
+
+            ExportEffectAttribute attr1 = new ExportEffectAttribute(typeof(BlendColorEffect), "BlendColorEffect");
+            myeffect.Effects = new ExportEffectAttribute[] { attr1 };
+
+            Xamarin.Forms.InitializationOptions.EffectScope circleEffect = new Xamarin.Forms.InitializationOptions.EffectScope();
+            circleEffect.Name = "CircleUI";
+            ExportEffectAttribute attr2 = new ExportEffectAttribute(typeof(TizenConfirmPopupEffect), "ContextPopupEffectBehavior");
+
+            ExportEffectAttribute attr3 = new ExportEffectAttribute(typeof(TizenCircleSurfaceEffect), "CircleSurfaceEffect");
+
+            circleEffect.Effects = new ExportEffectAttribute[] { attr2, attr3 };
+
+            option.EffectScopes = new InitializationOptions.EffectScope[] { myeffect, circleEffect };
+
+
+            // NOTE(vincent): Note that this setenv should be called per app.
+            string productTheme = Interop.Interop.SystemCall.GetEnv("ELM_DEVICE_PROD_THEME");
+            if (productTheme == "pulse")
+            {
+                Interop.Interop.SystemCall.SetEnv("ELM_PROD_THEME", "pulse", 1);
+            }
+            Forms.Init(option);
+            // TODO(vincent): Remove this line if OneUI is supported in Xamarin. 
+            //                Precondition: oneui-theme-1.1.0-1.armv7l.rpm should be installed.
+            //Elementary.AddThemeOverlay("/usr/share/elementary/themes/oneui-theme.edj");
+            global::Tizen.Wearable.CircularUI.Forms.Renderer.FormsCircularUI.Init();
+            app.FormsApplication.Run(args);
+        }
+    }
+}
\ No newline at end of file
diff --git a/Test/Voicememo2020/VoiceMemo/VoiceMemo.csproj b/Test/Voicememo2020/VoiceMemo/VoiceMemo.csproj
new file mode 100755 (executable)
index 0000000..7b27b2f
--- /dev/null
@@ -0,0 +1,100 @@
+<Project Sdk="Tizen.NET.Sdk/1.0.8">
+
+  <PropertyGroup>
+    <OutputType>Exe</OutputType>
+    <TargetFramework>tizen40</TargetFramework>
+  </PropertyGroup>
+
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugType>portable</DebugType>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>None</DebugType>
+  </PropertyGroup>
+  <ItemGroup>
+    <Compile Remove="Utility.cs" />
+  </ItemGroup>
+
+  <ItemGroup>
+    <Folder Include="Effects\" />
+    <Folder Include="lib\" />
+    <Folder Include="Resx\" />
+    <Folder Include="res\2019_custom_button\" />
+    <Folder Include="res\2019\" />
+    <Folder Include="res\2019_images_icons\" />
+  </ItemGroup>
+
+  <ItemGroup>
+    <PackageReference Include="sqlite" Version="3.13.0" />
+    <PackageReference Include="sqlite-net-base" Version="1.5.166-beta" />
+    <PackageReference Include="SQLitePCLRaw.provider.sqlite3.netstandard11" Version="1.1.14" />
+  </ItemGroup>
+
+  <ItemGroup>
+    <ProjectReference Include="..\..\..\Tizen.CircularUI\Tizen.Wearable.CircularUI.Forms.Renderer\XSF.CircularUI.Forms.Renderer.csproj" />
+    <!--<ProjectReference Include="..\..\..\Tizen.CircularUI\Tizen.Wearable.CircularUI.Forms\XSF.CircularUI.Forms.csproj" />
+    <ProjectReference Include="..\..\..\Xamarin.Forms\Xamarin.Forms.Core\XSF.Core.csproj" />
+    <ProjectReference Include="..\..\..\Xamarin.Forms\Xamarin.Forms.Platform.Tizen\XSF.Platform.Tizen.csproj" />
+    <ProjectReference Include="..\..\..\Xamarin.Forms\Xamarin.Forms.Platform\XSF.Platform.csproj" />
+    <ProjectReference Include="..\..\..\Xamarin.Forms\Xamarin.Forms.Xaml\XSF.Xaml.csproj" />-->
+  </ItemGroup>
+
+  <ItemGroup>
+    <Reference Include="ElmSharp">
+      <HintPath>lib\ElmSharp.dll</HintPath>
+    </Reference>
+    <Reference Include="ElmSharp.Wearable">
+      <HintPath>lib\ElmSharp.Wearable.dll</HintPath>
+    </Reference>
+  </ItemGroup>
+
+  <ItemGroup>
+    <EmbeddedResource Update="Views\NoRecordView.xaml">
+      <Generator>MSBuild:UpdateDesignTimeXaml</Generator>
+    </EmbeddedResource>
+  </ItemGroup>
+
+  <ItemGroup>
+    <None Update="App.xaml">
+      <Generator>MSBuild:Compile</Generator>
+    </None>
+    <None Update="Views\CancelPage.xaml">
+      <Generator>MSBuild:Compile</Generator>
+    </None>
+    <None Update="Views\CirclePageEx.xaml">
+      <Generator>MSBuild:Compile</Generator>
+    </None>
+    <None Update="Views\DetailsPage.xaml">
+      <Generator>MSBuild:Compile</Generator>
+    </None>
+    <None Update="Views\LanguageSelectionPage.xaml">
+      <Generator>MSBuild:Compile</Generator>
+    </None>
+    <None Update="Views\MainPage.xaml">
+      <Generator>MSBuild:Compile</Generator>
+    </None>
+    <None Update="Views\PlayBackPage.xaml">
+      <Generator>MSBuild:Compile</Generator>
+    </None>
+    <None Update="Views\RecordingPage.xaml">
+      <Generator>MSBuild:Compile</Generator>
+    </None>
+    <None Update="Views\RecordListPage.xaml">
+      <Generator>MSBuild:Compile</Generator>
+    </None>
+    <None Update="Views\SttLanguageViewCell.xaml">
+      <Generator>MSBuild:Compile</Generator>
+    </None>
+  </ItemGroup>
+
+  <!--<ItemGroup>
+    <EmbeddedResource Update="App.xaml">
+      <Generator>MSBuild:UpdateDesignTimeXaml</Generator>
+    </EmbeddedResource>
+    <EmbeddedResource Update="MainPage.xaml">
+      <Generator>MSBuild:UpdateDesignTimeXaml</Generator>
+    </EmbeddedResource>
+  </ItemGroup>-->
+
+</Project>
+
diff --git a/Test/Voicememo2020/VoiceMemo/res/2019/details_playback_icon.png b/Test/Voicememo2020/VoiceMemo/res/2019/details_playback_icon.png
new file mode 100755 (executable)
index 0000000..1008ed8
Binary files /dev/null and b/Test/Voicememo2020/VoiceMemo/res/2019/details_playback_icon.png differ
diff --git a/Test/Voicememo2020/VoiceMemo/res/2019/recording_stt_icon.png b/Test/Voicememo2020/VoiceMemo/res/2019/recording_stt_icon.png
new file mode 100755 (executable)
index 0000000..4d2f789
Binary files /dev/null and b/Test/Voicememo2020/VoiceMemo/res/2019/recording_stt_icon.png differ
diff --git a/Test/Voicememo2020/VoiceMemo/res/2019/voice_mamo_slider_btn_bg.png b/Test/Voicememo2020/VoiceMemo/res/2019/voice_mamo_slider_btn_bg.png
new file mode 100755 (executable)
index 0000000..c061f95
Binary files /dev/null and b/Test/Voicememo2020/VoiceMemo/res/2019/voice_mamo_slider_btn_bg.png differ
diff --git a/Test/Voicememo2020/VoiceMemo/res/2019/voicememo_effect.png b/Test/Voicememo2020/VoiceMemo/res/2019/voicememo_effect.png
new file mode 100755 (executable)
index 0000000..6541ef7
Binary files /dev/null and b/Test/Voicememo2020/VoiceMemo/res/2019/voicememo_effect.png differ
diff --git a/Test/Voicememo2020/VoiceMemo/res/2019/voicememo_volume_control_cover_bg.png b/Test/Voicememo2020/VoiceMemo/res/2019/voicememo_volume_control_cover_bg.png
new file mode 100755 (executable)
index 0000000..49ea3a5
Binary files /dev/null and b/Test/Voicememo2020/VoiceMemo/res/2019/voicememo_volume_control_cover_bg.png differ
diff --git a/Test/Voicememo2020/VoiceMemo/res/2019/voicerecorder_effect_bg.png b/Test/Voicememo2020/VoiceMemo/res/2019/voicerecorder_effect_bg.png
new file mode 100755 (executable)
index 0000000..0c23d67
Binary files /dev/null and b/Test/Voicememo2020/VoiceMemo/res/2019/voicerecorder_effect_bg.png differ
diff --git a/Test/Voicememo2020/VoiceMemo/res/2019_custom_button/details_vol_icon_off.png b/Test/Voicememo2020/VoiceMemo/res/2019_custom_button/details_vol_icon_off.png
new file mode 100755 (executable)
index 0000000..a0a0740
Binary files /dev/null and b/Test/Voicememo2020/VoiceMemo/res/2019_custom_button/details_vol_icon_off.png differ
diff --git a/Test/Voicememo2020/VoiceMemo/res/2019_custom_button/details_vol_icon_on.png b/Test/Voicememo2020/VoiceMemo/res/2019_custom_button/details_vol_icon_on.png
new file mode 100755 (executable)
index 0000000..2beb81b
Binary files /dev/null and b/Test/Voicememo2020/VoiceMemo/res/2019_custom_button/details_vol_icon_on.png differ
diff --git a/Test/Voicememo2020/VoiceMemo/res/2019_custom_button/record_controller_bg.png b/Test/Voicememo2020/VoiceMemo/res/2019_custom_button/record_controller_bg.png
new file mode 100755 (executable)
index 0000000..556b8ac
Binary files /dev/null and b/Test/Voicememo2020/VoiceMemo/res/2019_custom_button/record_controller_bg.png differ
diff --git a/Test/Voicememo2020/VoiceMemo/res/2019_custom_button/recording_icon_cancel.png b/Test/Voicememo2020/VoiceMemo/res/2019_custom_button/recording_icon_cancel.png
new file mode 100755 (executable)
index 0000000..64743c4
Binary files /dev/null and b/Test/Voicememo2020/VoiceMemo/res/2019_custom_button/recording_icon_cancel.png differ
diff --git a/Test/Voicememo2020/VoiceMemo/res/2019_custom_button/recording_icon_stop.png b/Test/Voicememo2020/VoiceMemo/res/2019_custom_button/recording_icon_stop.png
new file mode 100755 (executable)
index 0000000..78e0ef0
Binary files /dev/null and b/Test/Voicememo2020/VoiceMemo/res/2019_custom_button/recording_icon_stop.png differ
diff --git a/Test/Voicememo2020/VoiceMemo/res/2019_custom_button/voicerecorder_btn_bg.png b/Test/Voicememo2020/VoiceMemo/res/2019_custom_button/voicerecorder_btn_bg.png
new file mode 100755 (executable)
index 0000000..79806ac
Binary files /dev/null and b/Test/Voicememo2020/VoiceMemo/res/2019_custom_button/voicerecorder_btn_bg.png differ
diff --git a/Test/Voicememo2020/VoiceMemo/res/2019_custom_button/voicerecorder_btn_pause.png b/Test/Voicememo2020/VoiceMemo/res/2019_custom_button/voicerecorder_btn_pause.png
new file mode 100755 (executable)
index 0000000..bb88f36
Binary files /dev/null and b/Test/Voicememo2020/VoiceMemo/res/2019_custom_button/voicerecorder_btn_pause.png differ
diff --git a/Test/Voicememo2020/VoiceMemo/res/2019_custom_button/voicerecorder_btn_play.png b/Test/Voicememo2020/VoiceMemo/res/2019_custom_button/voicerecorder_btn_play.png
new file mode 100755 (executable)
index 0000000..0f2b959
Binary files /dev/null and b/Test/Voicememo2020/VoiceMemo/res/2019_custom_button/voicerecorder_btn_play.png differ
diff --git a/Test/Voicememo2020/VoiceMemo/res/2019_custom_button/voicerecorder_playback_btn_pause.png b/Test/Voicememo2020/VoiceMemo/res/2019_custom_button/voicerecorder_playback_btn_pause.png
new file mode 100755 (executable)
index 0000000..262f65b
Binary files /dev/null and b/Test/Voicememo2020/VoiceMemo/res/2019_custom_button/voicerecorder_playback_btn_pause.png differ
diff --git a/Test/Voicememo2020/VoiceMemo/res/2019_custom_button/voicerecorder_stop_icon.png b/Test/Voicememo2020/VoiceMemo/res/2019_custom_button/voicerecorder_stop_icon.png
new file mode 100755 (executable)
index 0000000..7810b0f
Binary files /dev/null and b/Test/Voicememo2020/VoiceMemo/res/2019_custom_button/voicerecorder_stop_icon.png differ
diff --git a/Test/Voicememo2020/VoiceMemo/res/2019_images_icons/b_icon_voicememo.png b/Test/Voicememo2020/VoiceMemo/res/2019_images_icons/b_icon_voicememo.png
new file mode 100755 (executable)
index 0000000..51c3725
Binary files /dev/null and b/Test/Voicememo2020/VoiceMemo/res/2019_images_icons/b_icon_voicememo.png differ
diff --git a/Test/Voicememo2020/VoiceMemo/res/2019_images_icons/b_slider_icon_minus.png b/Test/Voicememo2020/VoiceMemo/res/2019_images_icons/b_slider_icon_minus.png
new file mode 100755 (executable)
index 0000000..35affbe
Binary files /dev/null and b/Test/Voicememo2020/VoiceMemo/res/2019_images_icons/b_slider_icon_minus.png differ
diff --git a/Test/Voicememo2020/VoiceMemo/res/2019_images_icons/b_slider_icon_plus.png b/Test/Voicememo2020/VoiceMemo/res/2019_images_icons/b_slider_icon_plus.png
new file mode 100755 (executable)
index 0000000..63e81d4
Binary files /dev/null and b/Test/Voicememo2020/VoiceMemo/res/2019_images_icons/b_slider_icon_plus.png differ
diff --git a/Test/Voicememo2020/VoiceMemo/res/2019_images_icons/details_playback_icon.png b/Test/Voicememo2020/VoiceMemo/res/2019_images_icons/details_playback_icon.png
new file mode 100755 (executable)
index 0000000..0c21d09
Binary files /dev/null and b/Test/Voicememo2020/VoiceMemo/res/2019_images_icons/details_playback_icon.png differ
diff --git a/Test/Voicememo2020/VoiceMemo/res/2019_images_icons/more_option_icon_delete.png b/Test/Voicememo2020/VoiceMemo/res/2019_images_icons/more_option_icon_delete.png
new file mode 100755 (executable)
index 0000000..14afa15
Binary files /dev/null and b/Test/Voicememo2020/VoiceMemo/res/2019_images_icons/more_option_icon_delete.png differ
diff --git a/Test/Voicememo2020/VoiceMemo/res/2019_images_icons/more_option_icon_language.png b/Test/Voicememo2020/VoiceMemo/res/2019_images_icons/more_option_icon_language.png
new file mode 100755 (executable)
index 0000000..4fc54e0
Binary files /dev/null and b/Test/Voicememo2020/VoiceMemo/res/2019_images_icons/more_option_icon_language.png differ
diff --git a/Test/Voicememo2020/VoiceMemo/res/2019_images_icons/more_option_icon_stt_off.png b/Test/Voicememo2020/VoiceMemo/res/2019_images_icons/more_option_icon_stt_off.png
new file mode 100755 (executable)
index 0000000..a589835
Binary files /dev/null and b/Test/Voicememo2020/VoiceMemo/res/2019_images_icons/more_option_icon_stt_off.png differ
diff --git a/Test/Voicememo2020/VoiceMemo/res/2019_images_icons/more_option_icon_stt_on.png b/Test/Voicememo2020/VoiceMemo/res/2019_images_icons/more_option_icon_stt_on.png
new file mode 100755 (executable)
index 0000000..98a4994
Binary files /dev/null and b/Test/Voicememo2020/VoiceMemo/res/2019_images_icons/more_option_icon_stt_on.png differ
diff --git a/Test/Voicememo2020/VoiceMemo/res/2019_images_icons/more_option_icon_stt_recording.png b/Test/Voicememo2020/VoiceMemo/res/2019_images_icons/more_option_icon_stt_recording.png
new file mode 100755 (executable)
index 0000000..b36704c
Binary files /dev/null and b/Test/Voicememo2020/VoiceMemo/res/2019_images_icons/more_option_icon_stt_recording.png differ
diff --git a/Test/Voicememo2020/VoiceMemo/res/2019_images_icons/play_volume_slider_ic.png b/Test/Voicememo2020/VoiceMemo/res/2019_images_icons/play_volume_slider_ic.png
new file mode 100755 (executable)
index 0000000..4359d3f
Binary files /dev/null and b/Test/Voicememo2020/VoiceMemo/res/2019_images_icons/play_volume_slider_ic.png differ
diff --git a/Test/Voicememo2020/VoiceMemo/res/2019_images_icons/tw_ic_menu_delete_holo_dark.png b/Test/Voicememo2020/VoiceMemo/res/2019_images_icons/tw_ic_menu_delete_holo_dark.png
new file mode 100755 (executable)
index 0000000..0539342
Binary files /dev/null and b/Test/Voicememo2020/VoiceMemo/res/2019_images_icons/tw_ic_menu_delete_holo_dark.png differ
diff --git a/Test/Voicememo2020/VoiceMemo/res/2019_images_icons/tw_ic_menu_selectall_holo_dark.png b/Test/Voicememo2020/VoiceMemo/res/2019_images_icons/tw_ic_menu_selectall_holo_dark.png
new file mode 100755 (executable)
index 0000000..f8fc3c3
Binary files /dev/null and b/Test/Voicememo2020/VoiceMemo/res/2019_images_icons/tw_ic_menu_selectall_holo_dark.png differ
diff --git a/Test/Voicememo2020/VoiceMemo/res/2019_images_icons/tw_ic_popup_btn_check.png b/Test/Voicememo2020/VoiceMemo/res/2019_images_icons/tw_ic_popup_btn_check.png
new file mode 100755 (executable)
index 0000000..085687e
Binary files /dev/null and b/Test/Voicememo2020/VoiceMemo/res/2019_images_icons/tw_ic_popup_btn_check.png differ
diff --git a/Test/Voicememo2020/VoiceMemo/res/2019_images_icons/tw_ic_popup_btn_delete.png b/Test/Voicememo2020/VoiceMemo/res/2019_images_icons/tw_ic_popup_btn_delete.png
new file mode 100755 (executable)
index 0000000..a978d8f
Binary files /dev/null and b/Test/Voicememo2020/VoiceMemo/res/2019_images_icons/tw_ic_popup_btn_delete.png differ
diff --git a/Test/Voicememo2020/VoiceMemo/res/2019_images_icons/tw_toast_popup_memory_full_gear.png b/Test/Voicememo2020/VoiceMemo/res/2019_images_icons/tw_toast_popup_memory_full_gear.png
new file mode 100755 (executable)
index 0000000..325d5e7
Binary files /dev/null and b/Test/Voicememo2020/VoiceMemo/res/2019_images_icons/tw_toast_popup_memory_full_gear.png differ
diff --git a/Test/Voicememo2020/VoiceMemo/res/2019_images_icons/tw_toast_popup_memory_full_mobile.png b/Test/Voicememo2020/VoiceMemo/res/2019_images_icons/tw_toast_popup_memory_full_mobile.png
new file mode 100755 (executable)
index 0000000..1d66741
Binary files /dev/null and b/Test/Voicememo2020/VoiceMemo/res/2019_images_icons/tw_toast_popup_memory_full_mobile.png differ
diff --git a/Test/Voicememo2020/VoiceMemo/res/2019_images_icons/voice_mamo_slider_mute.png b/Test/Voicememo2020/VoiceMemo/res/2019_images_icons/voice_mamo_slider_mute.png
new file mode 100755 (executable)
index 0000000..e0a6b86
Binary files /dev/null and b/Test/Voicememo2020/VoiceMemo/res/2019_images_icons/voice_mamo_slider_mute.png differ
diff --git a/Test/Voicememo2020/VoiceMemo/res/2019_images_icons/voice_mamo_slider_volume_on.png b/Test/Voicememo2020/VoiceMemo/res/2019_images_icons/voice_mamo_slider_volume_on.png
new file mode 100755 (executable)
index 0000000..3db692a
Binary files /dev/null and b/Test/Voicememo2020/VoiceMemo/res/2019_images_icons/voice_mamo_slider_volume_on.png differ
diff --git a/Test/Voicememo2020/VoiceMemo/res/2019_images_icons/voice_memo_slash.png b/Test/Voicememo2020/VoiceMemo/res/2019_images_icons/voice_memo_slash.png
new file mode 100755 (executable)
index 0000000..baac1ec
Binary files /dev/null and b/Test/Voicememo2020/VoiceMemo/res/2019_images_icons/voice_memo_slash.png differ
diff --git a/Test/Voicememo2020/VoiceMemo/res/2019_images_icons/voicememo_effect.png b/Test/Voicememo2020/VoiceMemo/res/2019_images_icons/voicememo_effect.png
new file mode 100755 (executable)
index 0000000..6541ef7
Binary files /dev/null and b/Test/Voicememo2020/VoiceMemo/res/2019_images_icons/voicememo_effect.png differ
diff --git a/Test/Voicememo2020/VoiceMemo/res/2019_images_icons/voicerecorder_bt_headset_image.png b/Test/Voicememo2020/VoiceMemo/res/2019_images_icons/voicerecorder_bt_headset_image.png
new file mode 100755 (executable)
index 0000000..3e083e4
Binary files /dev/null and b/Test/Voicememo2020/VoiceMemo/res/2019_images_icons/voicerecorder_bt_headset_image.png differ
diff --git a/Test/Voicememo2020/VoiceMemo/res/2019_images_icons/voicerecorder_bt_mobile_image.png b/Test/Voicememo2020/VoiceMemo/res/2019_images_icons/voicerecorder_bt_mobile_image.png
new file mode 100755 (executable)
index 0000000..b55d97e
Binary files /dev/null and b/Test/Voicememo2020/VoiceMemo/res/2019_images_icons/voicerecorder_bt_mobile_image.png differ
diff --git a/Test/Voicememo2020/VoiceMemo/res/2019_images_icons/voicerecorder_btn_pause.png b/Test/Voicememo2020/VoiceMemo/res/2019_images_icons/voicerecorder_btn_pause.png
new file mode 100755 (executable)
index 0000000..bb88f36
Binary files /dev/null and b/Test/Voicememo2020/VoiceMemo/res/2019_images_icons/voicerecorder_btn_pause.png differ
diff --git a/Test/Voicememo2020/VoiceMemo/res/2019_images_icons/voicerecorder_btn_play.png b/Test/Voicememo2020/VoiceMemo/res/2019_images_icons/voicerecorder_btn_play.png
new file mode 100755 (executable)
index 0000000..0f2b959
Binary files /dev/null and b/Test/Voicememo2020/VoiceMemo/res/2019_images_icons/voicerecorder_btn_play.png differ
diff --git a/Test/Voicememo2020/VoiceMemo/res/2019_images_icons/voicerecorder_effect_bg.png b/Test/Voicememo2020/VoiceMemo/res/2019_images_icons/voicerecorder_effect_bg.png
new file mode 100755 (executable)
index 0000000..0c23d67
Binary files /dev/null and b/Test/Voicememo2020/VoiceMemo/res/2019_images_icons/voicerecorder_effect_bg.png differ
diff --git a/Test/Voicememo2020/VoiceMemo/res/2019_images_icons/voicerecorder_icon_stt.png b/Test/Voicememo2020/VoiceMemo/res/2019_images_icons/voicerecorder_icon_stt.png
new file mode 100755 (executable)
index 0000000..fb8dd9e
Binary files /dev/null and b/Test/Voicememo2020/VoiceMemo/res/2019_images_icons/voicerecorder_icon_stt.png differ
diff --git a/Test/Voicememo2020/VoiceMemo/res/2019_images_icons/weather_toast_popup_show_on_divice.png b/Test/Voicememo2020/VoiceMemo/res/2019_images_icons/weather_toast_popup_show_on_divice.png
new file mode 100755 (executable)
index 0000000..213a2f7
Binary files /dev/null and b/Test/Voicememo2020/VoiceMemo/res/2019_images_icons/weather_toast_popup_show_on_divice.png differ
diff --git a/Test/Voicememo2020/VoiceMemo/res/b_icon_voicememo.png b/Test/Voicememo2020/VoiceMemo/res/b_icon_voicememo.png
new file mode 100755 (executable)
index 0000000..d8badf8
Binary files /dev/null and b/Test/Voicememo2020/VoiceMemo/res/b_icon_voicememo.png differ
diff --git a/Test/Voicememo2020/VoiceMemo/res/button/details_vol_icon_off.png b/Test/Voicememo2020/VoiceMemo/res/button/details_vol_icon_off.png
new file mode 100755 (executable)
index 0000000..0365f31
Binary files /dev/null and b/Test/Voicememo2020/VoiceMemo/res/button/details_vol_icon_off.png differ
diff --git a/Test/Voicememo2020/VoiceMemo/res/button/details_vol_icon_on.png b/Test/Voicememo2020/VoiceMemo/res/button/details_vol_icon_on.png
new file mode 100755 (executable)
index 0000000..45ebc05
Binary files /dev/null and b/Test/Voicememo2020/VoiceMemo/res/button/details_vol_icon_on.png differ
diff --git a/Test/Voicememo2020/VoiceMemo/res/details_playback_icon.png b/Test/Voicememo2020/VoiceMemo/res/details_playback_icon.png
new file mode 100755 (executable)
index 0000000..1008ed8
Binary files /dev/null and b/Test/Voicememo2020/VoiceMemo/res/details_playback_icon.png differ
diff --git a/Test/Voicememo2020/VoiceMemo/res/details_vol_icon_off.png b/Test/Voicememo2020/VoiceMemo/res/details_vol_icon_off.png
new file mode 100755 (executable)
index 0000000..5540e46
Binary files /dev/null and b/Test/Voicememo2020/VoiceMemo/res/details_vol_icon_off.png differ
diff --git a/Test/Voicememo2020/VoiceMemo/res/details_vol_icon_on.png b/Test/Voicememo2020/VoiceMemo/res/details_vol_icon_on.png
new file mode 100755 (executable)
index 0000000..cf4a9b1
Binary files /dev/null and b/Test/Voicememo2020/VoiceMemo/res/details_vol_icon_on.png differ
diff --git a/Test/Voicememo2020/VoiceMemo/res/icons/b_slider_icon_minus.png b/Test/Voicememo2020/VoiceMemo/res/icons/b_slider_icon_minus.png
new file mode 100755 (executable)
index 0000000..35affbe
Binary files /dev/null and b/Test/Voicememo2020/VoiceMemo/res/icons/b_slider_icon_minus.png differ
diff --git a/Test/Voicememo2020/VoiceMemo/res/icons/b_slider_icon_plus.png b/Test/Voicememo2020/VoiceMemo/res/icons/b_slider_icon_plus.png
new file mode 100755 (executable)
index 0000000..63e81d4
Binary files /dev/null and b/Test/Voicememo2020/VoiceMemo/res/icons/b_slider_icon_plus.png differ
diff --git a/Test/Voicememo2020/VoiceMemo/res/more_option_icon_delete.png b/Test/Voicememo2020/VoiceMemo/res/more_option_icon_delete.png
new file mode 100755 (executable)
index 0000000..79eaec4
Binary files /dev/null and b/Test/Voicememo2020/VoiceMemo/res/more_option_icon_delete.png differ
diff --git a/Test/Voicememo2020/VoiceMemo/res/more_option_icon_language.png b/Test/Voicememo2020/VoiceMemo/res/more_option_icon_language.png
new file mode 100755 (executable)
index 0000000..88e0dd8
Binary files /dev/null and b/Test/Voicememo2020/VoiceMemo/res/more_option_icon_language.png differ
diff --git a/Test/Voicememo2020/VoiceMemo/res/more_option_icon_stt_list.png b/Test/Voicememo2020/VoiceMemo/res/more_option_icon_stt_list.png
new file mode 100755 (executable)
index 0000000..30cb5f8
Binary files /dev/null and b/Test/Voicememo2020/VoiceMemo/res/more_option_icon_stt_list.png differ
diff --git a/Test/Voicememo2020/VoiceMemo/res/more_option_icon_stt_off.png b/Test/Voicememo2020/VoiceMemo/res/more_option_icon_stt_off.png
new file mode 100755 (executable)
index 0000000..75b19aa
Binary files /dev/null and b/Test/Voicememo2020/VoiceMemo/res/more_option_icon_stt_off.png differ
diff --git a/Test/Voicememo2020/VoiceMemo/res/more_option_icon_stt_on.png b/Test/Voicememo2020/VoiceMemo/res/more_option_icon_stt_on.png
new file mode 100755 (executable)
index 0000000..abe0151
Binary files /dev/null and b/Test/Voicememo2020/VoiceMemo/res/more_option_icon_stt_on.png differ
diff --git a/Test/Voicememo2020/VoiceMemo/res/record_controller_bg.png b/Test/Voicememo2020/VoiceMemo/res/record_controller_bg.png
new file mode 100755 (executable)
index 0000000..ad24ab7
Binary files /dev/null and b/Test/Voicememo2020/VoiceMemo/res/record_controller_bg.png differ
diff --git a/Test/Voicememo2020/VoiceMemo/res/record_stop_icon.png b/Test/Voicememo2020/VoiceMemo/res/record_stop_icon.png
new file mode 100755 (executable)
index 0000000..639beda
Binary files /dev/null and b/Test/Voicememo2020/VoiceMemo/res/record_stop_icon.png differ
diff --git a/Test/Voicememo2020/VoiceMemo/res/recording_icon_cancel.png b/Test/Voicememo2020/VoiceMemo/res/recording_icon_cancel.png
new file mode 100755 (executable)
index 0000000..47dae79
Binary files /dev/null and b/Test/Voicememo2020/VoiceMemo/res/recording_icon_cancel.png differ
diff --git a/Test/Voicememo2020/VoiceMemo/res/recording_icon_pause.png b/Test/Voicememo2020/VoiceMemo/res/recording_icon_pause.png
new file mode 100755 (executable)
index 0000000..02439cc
Binary files /dev/null and b/Test/Voicememo2020/VoiceMemo/res/recording_icon_pause.png differ
diff --git a/Test/Voicememo2020/VoiceMemo/res/recording_stt_icon.png b/Test/Voicememo2020/VoiceMemo/res/recording_stt_icon.png
new file mode 100755 (executable)
index 0000000..f311f4b
Binary files /dev/null and b/Test/Voicememo2020/VoiceMemo/res/recording_stt_icon.png differ
diff --git a/Test/Voicememo2020/VoiceMemo/res/tw_ic_popup_btn_check.png b/Test/Voicememo2020/VoiceMemo/res/tw_ic_popup_btn_check.png
new file mode 100755 (executable)
index 0000000..f20f62e
Binary files /dev/null and b/Test/Voicememo2020/VoiceMemo/res/tw_ic_popup_btn_check.png differ
diff --git a/Test/Voicememo2020/VoiceMemo/res/tw_ic_popup_btn_delete.png b/Test/Voicememo2020/VoiceMemo/res/tw_ic_popup_btn_delete.png
new file mode 100755 (executable)
index 0000000..5f346cb
Binary files /dev/null and b/Test/Voicememo2020/VoiceMemo/res/tw_ic_popup_btn_delete.png differ
diff --git a/Test/Voicememo2020/VoiceMemo/res/tw_no_item_bg.png b/Test/Voicememo2020/VoiceMemo/res/tw_no_item_bg.png
new file mode 100755 (executable)
index 0000000..2e06046
Binary files /dev/null and b/Test/Voicememo2020/VoiceMemo/res/tw_no_item_bg.png differ
diff --git a/Test/Voicememo2020/VoiceMemo/res/voice_mamo_slider_btn_bg.png b/Test/Voicememo2020/VoiceMemo/res/voice_mamo_slider_btn_bg.png
new file mode 100755 (executable)
index 0000000..c061f95
Binary files /dev/null and b/Test/Voicememo2020/VoiceMemo/res/voice_mamo_slider_btn_bg.png differ
diff --git a/Test/Voicememo2020/VoiceMemo/res/voice_mamo_slider_mute.png b/Test/Voicememo2020/VoiceMemo/res/voice_mamo_slider_mute.png
new file mode 100755 (executable)
index 0000000..4b88d58
Binary files /dev/null and b/Test/Voicememo2020/VoiceMemo/res/voice_mamo_slider_mute.png differ
diff --git a/Test/Voicememo2020/VoiceMemo/res/voice_mamo_slider_volume_on.png b/Test/Voicememo2020/VoiceMemo/res/voice_mamo_slider_volume_on.png
new file mode 100755 (executable)
index 0000000..af75774
Binary files /dev/null and b/Test/Voicememo2020/VoiceMemo/res/voice_mamo_slider_volume_on.png differ
diff --git a/Test/Voicememo2020/VoiceMemo/res/voicememo_effect.png b/Test/Voicememo2020/VoiceMemo/res/voicememo_effect.png
new file mode 100755 (executable)
index 0000000..6541ef7
Binary files /dev/null and b/Test/Voicememo2020/VoiceMemo/res/voicememo_effect.png differ
diff --git a/Test/Voicememo2020/VoiceMemo/res/voicerecorder_btn_bg.png b/Test/Voicememo2020/VoiceMemo/res/voicerecorder_btn_bg.png
new file mode 100755 (executable)
index 0000000..691a5fa
Binary files /dev/null and b/Test/Voicememo2020/VoiceMemo/res/voicerecorder_btn_bg.png differ
diff --git a/Test/Voicememo2020/VoiceMemo/res/voicerecorder_btn_pause.png b/Test/Voicememo2020/VoiceMemo/res/voicerecorder_btn_pause.png
new file mode 100755 (executable)
index 0000000..fa9086f
Binary files /dev/null and b/Test/Voicememo2020/VoiceMemo/res/voicerecorder_btn_pause.png differ
diff --git a/Test/Voicememo2020/VoiceMemo/res/voicerecorder_btn_play.png b/Test/Voicememo2020/VoiceMemo/res/voicerecorder_btn_play.png
new file mode 100755 (executable)
index 0000000..0032808
Binary files /dev/null and b/Test/Voicememo2020/VoiceMemo/res/voicerecorder_btn_play.png differ
diff --git a/Test/Voicememo2020/VoiceMemo/res/voicerecorder_btn_stop.png b/Test/Voicememo2020/VoiceMemo/res/voicerecorder_btn_stop.png
new file mode 100755 (executable)
index 0000000..b427c57
Binary files /dev/null and b/Test/Voicememo2020/VoiceMemo/res/voicerecorder_btn_stop.png differ
diff --git a/Test/Voicememo2020/VoiceMemo/res/voicerecorder_icon_stt.png b/Test/Voicememo2020/VoiceMemo/res/voicerecorder_icon_stt.png
new file mode 100755 (executable)
index 0000000..431e0df
Binary files /dev/null and b/Test/Voicememo2020/VoiceMemo/res/voicerecorder_icon_stt.png differ
diff --git a/Test/Voicememo2020/VoiceMemo/res/voicerecorder_icon_stt_off.png b/Test/Voicememo2020/VoiceMemo/res/voicerecorder_icon_stt_off.png
new file mode 100755 (executable)
index 0000000..c5da5e6
Binary files /dev/null and b/Test/Voicememo2020/VoiceMemo/res/voicerecorder_icon_stt_off.png differ
diff --git a/Test/Voicememo2020/VoiceMemo/res/voicerecorder_stop_bg.png b/Test/Voicememo2020/VoiceMemo/res/voicerecorder_stop_bg.png
new file mode 100755 (executable)
index 0000000..46672b8
Binary files /dev/null and b/Test/Voicememo2020/VoiceMemo/res/voicerecorder_stop_bg.png differ
diff --git a/Test/Voicememo2020/VoiceMemo/res/voicerecorder_stop_icon.png b/Test/Voicememo2020/VoiceMemo/res/voicerecorder_stop_icon.png
new file mode 100755 (executable)
index 0000000..cfbb20b
Binary files /dev/null and b/Test/Voicememo2020/VoiceMemo/res/voicerecorder_stop_icon.png differ
diff --git a/Test/Voicememo2020/VoiceMemo/res/xml/accessoryservices.xml b/Test/Voicememo2020/VoiceMemo/res/xml/accessoryservices.xml
new file mode 100755 (executable)
index 0000000..e3f5d04
--- /dev/null
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources>
+       <application name="org.tizen.example.VoiceMemo.Tizen.Wearable" >
+               <serviceProfile
+                               id="/dotnetvoicememo/filetransfer"
+                               name="FileTransferSender"
+                               role="consumer"
+                               version="1.0"
+                               serviceLimit="ONE_PEERAGENT"
+                               serviceTimeout="30">
+                       <supportedTransports>
+                               <transport type="TRANSPORT_BT" />
+                               <transport type="TRANSPORT_WIFI"/>
+                               <transport type="TRANSPORT_BLE"/>
+                       </supportedTransports>
+                       <serviceChannel
+                                       id="113"
+                                       dataRate="low"
+                                       priority="low"
+                                       reliability= "enable">
+                       </serviceChannel>
+               </serviceProfile>
+       </application>
+</resources>
diff --git a/Test/Voicememo2020/VoiceMemo/shared/res/VoiceMemo.png b/Test/Voicememo2020/VoiceMemo/shared/res/VoiceMemo.png
new file mode 100755 (executable)
index 0000000..93e9a03
Binary files /dev/null and b/Test/Voicememo2020/VoiceMemo/shared/res/VoiceMemo.png differ
diff --git a/Test/Voicememo2020/VoiceMemo/shared/res/splash.png b/Test/Voicememo2020/VoiceMemo/shared/res/splash.png
new file mode 100755 (executable)
index 0000000..9563a40
Binary files /dev/null and b/Test/Voicememo2020/VoiceMemo/shared/res/splash.png differ
diff --git a/Test/Voicememo2020/VoiceMemo/tizen-manifest.xml b/Test/Voicememo2020/VoiceMemo/tizen-manifest.xml
new file mode 100755 (executable)
index 0000000..89c94d1
--- /dev/null
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest package="org.tizen.example.VoiceMemo" version="1.0.0" api-version="4" xmlns="http://tizen.org/ns/packages">
+    <profile name="wearable" />
+    <ui-application appid="org.tizen.example.VoiceMemo" exec="VoiceMemo.dll" multiple="false" nodisplay="false" taskmanage="true" type="dotnet" splash-screen-display="true" process-pool="true" launch_mode="single">
+        <label xml:lang="en-us">Voice Recorder</label>
+        <label xml:lang="hi-in">.NET वॉइस मेमो</label>
+        <label xml:lang="ko-kr">닷넷 음성 메모</label>
+        <icon>VoiceMemo.png</icon>
+        <metadata key="http://tizen.org/metadata/prefer_dotnet_aot" value="true" />
+        <background-category value="media" />
+        <splash-screens />
+    </ui-application>
+    <shortcut-list />
+    <privileges>
+        <privilege>http://tizen.org/privilege/mediastorage</privilege>
+        <privilege>http://tizen.org/privilege/externalstorage</privilege>
+        <privilege>http://tizen.org/privilege/externalstorage.appdata</privilege>
+        <privilege>http://tizen.org/privilege/recorder</privilege>
+        <privilege>http://tizen.org/privilege/volume.set</privilege>
+        <privilege>http://tizen.org/privilege/content.write</privilege>
+        <privilege>http://tizen.org/privilege/window.priority.set</privilege>
+        <privilege>http://developer.samsung.com/tizen/privilege/screen.top</privilege>
+    </privileges>
+    <dependencies />
+    <provides-appdefined-privileges />
+    <feature name="http://tizen.org/feature/microphone">true</feature>
+    <feature name="http://tizen.org/feature/speech.recognition">true</feature>
+</manifest>
+
+<!--<splash-screens>
+  <splash-screen orientation="portrait" src="splash.png" type="img" />
+</splash-screens>-->
\ No newline at end of file
old mode 100644 (file)
new mode 100755 (executable)
index c3521f4..4d558d6
@@ -28,7 +28,7 @@ using XForms = Xamarin.Forms.Forms;
 
 namespace Tizen.Wearable.CircularUI.Forms.Renderer
 {
-    class CircleScrollViewRenderer : ViewRenderer<CircleScrollView, ElmSharp.Wearable.CircleScroller>
+    public class CircleScrollViewRenderer : ViewRenderer<CircleScrollView, ElmSharp.Wearable.CircleScroller>
     {
         Xamarin.Forms.Platform.Tizen.Native.Box _scrollCanvas;
         ElmSharp.SmartEvent _scrollAnimationStart, _scrollAnimationStop;
diff --git a/XSF.sln b/XSF.sln
old mode 100644 (file)
new mode 100755 (executable)
index f9e480c..f693549
--- a/XSF.sln
+++ b/XSF.sln
@@ -37,6 +37,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Alarm", "Alarm", "{232D191B
 EndProject
 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Alarm", "Test\Alarm\Alarm\Alarm.csproj", "{4653BFED-31B5-412F-8076-A609A4E5D851}"
 EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "VoiceMemo", "VoiceMemo", "{E1BF76E2-0454-490C-964A-587E7926CA13}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "VoiceMemo", "Test\Voicememo2020\VoiceMemo\VoiceMemo.csproj", "{6DADDF43-87F3-43C6-822D-12DE155CCF86}"
+EndProject
 Global
        GlobalSection(SolutionConfigurationPlatforms) = preSolution
                Debug|Any CPU = Debug|Any CPU
@@ -79,6 +83,10 @@ Global
                {4653BFED-31B5-412F-8076-A609A4E5D851}.Debug|Any CPU.Build.0 = Debug|Any CPU
                {4653BFED-31B5-412F-8076-A609A4E5D851}.Release|Any CPU.ActiveCfg = Release|Any CPU
                {4653BFED-31B5-412F-8076-A609A4E5D851}.Release|Any CPU.Build.0 = Release|Any CPU
+               {6DADDF43-87F3-43C6-822D-12DE155CCF86}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+               {6DADDF43-87F3-43C6-822D-12DE155CCF86}.Debug|Any CPU.Build.0 = Debug|Any CPU
+               {6DADDF43-87F3-43C6-822D-12DE155CCF86}.Release|Any CPU.ActiveCfg = Release|Any CPU
+               {6DADDF43-87F3-43C6-822D-12DE155CCF86}.Release|Any CPU.Build.0 = Release|Any CPU
        EndGlobalSection
        GlobalSection(SolutionProperties) = preSolution
                HideSolutionNode = FALSE
@@ -95,6 +103,8 @@ Global
                {CE5F5031-BE26-42D9-8B86-87770CB01226} = {087187F9-A361-4269-88EB-47A44185FA7F}
                {232D191B-486D-4EC3-BCB2-F776124AF705} = {087187F9-A361-4269-88EB-47A44185FA7F}
                {4653BFED-31B5-412F-8076-A609A4E5D851} = {232D191B-486D-4EC3-BCB2-F776124AF705}
+               {E1BF76E2-0454-490C-964A-587E7926CA13} = {087187F9-A361-4269-88EB-47A44185FA7F}
+               {6DADDF43-87F3-43C6-822D-12DE155CCF86} = {E1BF76E2-0454-490C-964A-587E7926CA13}
        EndGlobalSection
        GlobalSection(ExtensibilityGlobals) = postSolution
                SolutionGuid = {81158F7F-D003-4C6D-9937-5002C54D57EA}
old mode 100644 (file)
new mode 100755 (executable)
index eec5628..d80cb38
@@ -483,7 +483,7 @@ namespace Xamarin.Forms
                                        {
                                                for (var i = 0; i < effectScopes.Length; i++)
                                                {
-                                                       var effectScope = effectScopes[0];
+                                                       var effectScope = effectScopes[i];
                                                        Registrar.RegisterEffects(effectScope.Name, effectScope.Effects);
                                                }
                                        }