Initial Code for Tray Application 78/278578/1
authorShivam Varshney/Core S/W Group /SRI-Delhi/Engineer/Samsung Electronics <shivam.v2@samsung.com>
Fri, 22 Jul 2022 06:34:58 +0000 (12:04 +0530)
committerShivam Varshney/Core S/W Group /SRI-Delhi/Engineer/Samsung Electronics <shivam.v2@samsung.com>
Fri, 22 Jul 2022 06:39:01 +0000 (12:09 +0530)
Change-Id: Ic5acc1f79164dbde04e79c3db6bed193635ac25b
Signed-off-by: Shivam Varshney/Core S/W Group /SRI-Delhi/Engineer/Samsung Electronics <shivam.v2@samsung.com>
37 files changed:
.gitignore
TrayApplication/Common/DeviceInfo.cs [new file with mode: 0644]
TrayApplication/Common/PropertyNotifier.cs [new file with mode: 0644]
TrayApplication/Common/Resources.cs [new file with mode: 0644]
TrayApplication/Core/AppLauncher.cs [new file with mode: 0644]
TrayApplication/Core/AppScoreDataBase.cs [new file with mode: 0644]
TrayApplication/Models/AppInfoModel.cs [new file with mode: 0644]
TrayApplication/TrayApplication.cs [new file with mode: 0644]
TrayApplication/TrayApplication.csproj [new file with mode: 0644]
TrayApplication/TrayApplication.sln [new file with mode: 0644]
TrayApplication/ViewModels/ApplicationViewModel.cs [new file with mode: 0644]
TrayApplication/ViewModels/QuickAccessViewModel.cs [new file with mode: 0644]
TrayApplication/Views/AppItemView.cs [new file with mode: 0644]
TrayApplication/Views/ApplicationsView.cs [new file with mode: 0644]
TrayApplication/Views/MainView.cs [new file with mode: 0644]
TrayApplication/Views/QuickAccessView.cs [new file with mode: 0644]
TrayApplication/res/images/dark/apps.png [new file with mode: 0644]
TrayApplication/res/images/dark/cross_button.png [new file with mode: 0644]
TrayApplication/res/images/dark/cross_button_selected.png [new file with mode: 0644]
TrayApplication/res/images/dark/home.png [new file with mode: 0644]
TrayApplication/res/images/dark/notifications.png [new file with mode: 0644]
TrayApplication/res/images/dark/power.png [new file with mode: 0644]
TrayApplication/res/images/dark/settings.png [new file with mode: 0644]
TrayApplication/res/images/dark/volume.png [new file with mode: 0644]
TrayApplication/res/images/light/apps.png [new file with mode: 0644]
TrayApplication/res/images/light/cross_button.png [new file with mode: 0644]
TrayApplication/res/images/light/cross_button_selected.png [new file with mode: 0644]
TrayApplication/res/images/light/home.png [new file with mode: 0644]
TrayApplication/res/images/light/notifications.png [new file with mode: 0644]
TrayApplication/res/images/light/power.png [new file with mode: 0644]
TrayApplication/res/images/light/settings.png [new file with mode: 0644]
TrayApplication/res/images/light/volume.png [new file with mode: 0644]
TrayApplication/res/themes/dark.xaml [new file with mode: 0644]
TrayApplication/res/themes/light.xaml [new file with mode: 0644]
TrayApplication/shared/res/TrayApplication.png [new file with mode: 0644]
TrayApplication/tizen-manifest.xml [new file with mode: 0644]
packaging/org.tizen.TrayApplication.spec [new file with mode: 0644]

index 010c61f1394c5d9aa19cbfcd3b58f9cc731a6796..5af97cdb33da9dd287cc7f21fbbdee88073ce5b8 100644 (file)
@@ -1,3 +1,7 @@
+TrayApplication/.vs/
+TrayApplication/bin/
+TrayApplication/obj/
+TrayApplication/TrayApplication.csproj.user
 Apps/.vs/
 Apps/bin/
 Apps/obj/
diff --git a/TrayApplication/Common/DeviceInfo.cs b/TrayApplication/Common/DeviceInfo.cs
new file mode 100644 (file)
index 0000000..248a18a
--- /dev/null
@@ -0,0 +1,31 @@
+using Tizen.System;
+
+namespace TrayApplication.Common
+{
+    public static class DeviceInfo
+    {
+        private static int width;
+        private static int height;
+        private const string WidthKey = "tizen.org/feature/screen.width";
+        private const string HeightKey = "tizen.org/feature/screen.height";
+
+        static DeviceInfo()
+        {
+            bool isWidthAvailable = Information.TryGetValue(WidthKey, out width);
+            bool isHeightAvailable = Information.TryGetValue(HeightKey, out height);
+            if (isHeightAvailable == false || isWidthAvailable == false)
+            {
+                width = 1920;
+                height = 1080;
+                Tizen.Log.Debug(Resources.LogTag, "Width and height are not available , setting default size as 1920 x 1080");
+            }
+            IsPortrait = width < height;
+        }
+
+        public static bool IsPortrait { get; private set; }
+
+        public static int DisplayWidth => width;
+
+        public static int DisplayHeight => height;
+    }
+}
diff --git a/TrayApplication/Common/PropertyNotifier.cs b/TrayApplication/Common/PropertyNotifier.cs
new file mode 100644 (file)
index 0000000..2794eaa
--- /dev/null
@@ -0,0 +1,27 @@
+using System.ComponentModel;
+using System.Runtime.CompilerServices;
+
+namespace TrayApplication.Common
+{
+    class PropertyNotifier : INotifyPropertyChanged
+    {
+        public event PropertyChangedEventHandler PropertyChanged;
+
+        protected bool SetProperty<T>(ref T storage, T value, [CallerMemberName] string propertyName = null)
+        {
+            if (Equals(storage, value))
+            {
+                return false;
+            }
+
+            storage = value;
+            OnPropertyChanged(propertyName);
+            return true;
+        }
+
+        protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
+        {
+            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
+        }
+    }
+}
diff --git a/TrayApplication/Common/Resources.cs b/TrayApplication/Common/Resources.cs
new file mode 100644 (file)
index 0000000..2071129
--- /dev/null
@@ -0,0 +1,40 @@
+using Tizen.NUI;
+
+namespace TrayApplication.Common
+{
+    class Resources
+    {
+        public const string LogTag = "Tray_Application";
+        public const string LightPlatformThemeId = "org.tizen.default-light-theme";
+        public const string DarkPlatformThemeId = "org.tizen.default-dark-theme";
+        public static readonly Color LightApplicationsBackground = new Color(1.0f, 1.0f, 1.0f, 0.3f);
+        public static readonly Color LightQuickAccessBackground = new Color(1.0f, 1.0f, 1.0f, 0.5f);
+        public static readonly Color DarkApplicationsBackground = new Color(0.0863f, 0.0745f, 0.098f, 0.3f);
+        public static readonly Color DarkQuickAccessBackground = new Color(0.0863f, 0.0745f, 0.098f, 0.5f);
+
+        public static string GetImagePath()
+        {
+            return Tizen.Applications.Application.Current.DirectoryInfo.Resource + "images/";
+        }
+
+        public static string GetLightImagePath()
+        {
+            return GetImagePath() + "light/";
+        }
+
+        public static string GetDarkImagePath()
+        {
+            return GetImagePath() + "dark/";
+        }
+
+        public static string GetThemePath()
+        {
+            return Tizen.Applications.Application.Current.DirectoryInfo.Resource + "themes/";
+        }
+
+        public static string GetCurrentThemePath()
+        {
+            return (ThemeManager.PlatformThemeId == LightPlatformThemeId) ? GetLightImagePath() : GetDarkImagePath(); 
+        }
+    }
+}
diff --git a/TrayApplication/Core/AppLauncher.cs b/TrayApplication/Core/AppLauncher.cs
new file mode 100644 (file)
index 0000000..3b88850
--- /dev/null
@@ -0,0 +1,17 @@
+using Tizen.Applications;
+
+namespace TrayApplication.Core
+{
+    static class AppLauncher
+    {
+        public static void LaunchApplication(string id)
+        {
+            AppControl appControl = new AppControl()
+            {
+                ApplicationId = id,
+                Operation = id == "org.tizen.homescreen-efl" ? AppControlOperations.Main : AppControlOperations.Default,
+            };
+            AppControl.SendLaunchRequest(appControl);
+        }
+    }
+}
diff --git a/TrayApplication/Core/AppScoreDataBase.cs b/TrayApplication/Core/AppScoreDataBase.cs
new file mode 100644 (file)
index 0000000..b54ea09
--- /dev/null
@@ -0,0 +1,191 @@
+using System;
+using System.Collections.Generic;
+using Microsoft.Data.Sqlite;
+using Tizen.Applications;
+using TrayApplication.Common;
+
+namespace TrayApplication.Core
+{
+    static class AppScoreDataBase
+    {
+        private const string CREATE_TABLE_QUERY = "CREATE TABLE APP_INFO(NAME VARCHAR(30), SCORE FLOAT(10));";
+        private const string INSERT_VALUES_QUERY = "INSERT INTO APP_INFO(NAME, SCORE) VALUES('";
+        private const string SELECT_MAX_SCORE_QUERY = "SELECT MAX(SCORE) FROM APP_INFO;";
+        private const string UPDATE_LAUNCHED_APP_QUERY = "UPDATE APP_INFO SET SCORE = SCORE + 50.00 WHERE NAME = '";
+        private const string UPDATE_OTHER_APPS_QUERY = "UPDATE APP_INFO SET SCORE = SCORE * 0.90 WHERE NAME !='";
+        private const string DELETE_APP_QUERY = "DELETE FROM APP_INFO WHERE NAME = '";
+        private const string SELECT_APPS_QUERY = "SELECT * FROM APP_INFO ORDER BY SCORE DESC LIMIT ";
+        private static SqliteConnection sqliteConn;
+
+        public static event EventHandler<EventArgs> OnDatabaseUpdate;
+
+        public static void InitializeDataBase()
+        {
+            Connect();
+            CreateTable();
+            PackageManager.InstallProgressChanged += OnInstallProgressChanged;
+            PackageManager.UninstallProgressChanged += OnUninstallProgressChanged;
+            ApplicationManager.ApplicationLaunched += OnApplicationLaunched;
+        }
+
+        private static void OnInstallProgressChanged(object sender, PackageManagerEventArgs e)
+        {
+            if (e.State == PackageEventState.Completed)
+            {
+                Package package = PackageManager.GetPackage(e.PackageId);
+                foreach (ApplicationInfo appInfo in package.GetApplications())
+                {
+                    Tizen.Log.Info(Resources.LogTag, "Updating " + appInfo.ApplicationId);
+                    if (appInfo.Label == "TrayApplication" || appInfo.Label == "Apps" || string.IsNullOrEmpty(appInfo.IconPath) || appInfo.IsNoDisplay == true)
+                    {
+                        continue;
+                    }
+                    IncreaseScore(appInfo.ApplicationId, true);
+                    OnDatabaseUpdate.Invoke(null, new EventArgs());
+                }
+            }
+        }
+
+        private static void OnUninstallProgressChanged(object sender, PackageManagerEventArgs e)
+        {
+            if (e.Progress ==0)
+            {
+                Package package = PackageManager.GetPackage(e.PackageId);
+                foreach (ApplicationInfo appInfo in package.GetApplications())
+                {
+                    Tizen.Log.Info(Resources.LogTag, "Updating " + appInfo.ApplicationId);
+                    if (appInfo.Label == "TrayApplication" || appInfo.Label == "Apps" || string.IsNullOrEmpty(appInfo.IconPath) || appInfo.IsNoDisplay == true)
+                    {
+                        continue;
+                    }
+                    RemoveAppScore(appInfo.ApplicationId);
+                    OnDatabaseUpdate.Invoke(null, new EventArgs());
+                }
+            }
+        }
+
+        private static void OnApplicationLaunched(object sender, ApplicationLaunchedEventArgs e)
+        {
+            ApplicationInfo appInfo = ApplicationManager.GetInstalledApplication(e.ApplicationRunningContext.ApplicationId);
+            if (appInfo.Label == "TrayApplication" || appInfo.Label == "Apps" || string.IsNullOrEmpty(appInfo.IconPath) || appInfo.IsNoDisplay == true)
+            {
+                return;
+            }
+            IncreaseScore(e.ApplicationRunningContext.ApplicationId, false);
+            OnDatabaseUpdate.Invoke(null, new EventArgs());
+        }
+
+        private static void Connect()
+        {
+            string path = "Data Source = " + Application.Current.DirectoryInfo.Data + "database.db";
+            Tizen.Log.Info(Resources.LogTag, "path = " + path);
+            try
+            {
+                sqliteConn = new SqliteConnection(path);
+            }
+            catch(Exception ex)
+            {
+                Tizen.Log.Error(Resources.LogTag, "Error " + ex.Message);
+            }
+            try
+            {
+                sqliteConn.Open();
+            }
+            catch (Exception ex)
+            {
+                Tizen.Log.Error(Resources.LogTag, "Error " + ex.Message);
+            }
+            Tizen.Log.Info(Resources.LogTag, "Connection Open");
+        }
+
+        private static void CreateTable()
+        {
+            SqliteCommand sqliteCmd = sqliteConn.CreateCommand();
+            sqliteCmd.CommandText = CREATE_TABLE_QUERY;
+            try
+            {
+                sqliteCmd.ExecuteNonQuery();
+                InsertData();
+            }
+            catch (Exception ex)
+            {
+                Tizen.Log.Error(Resources.LogTag, "Error " + ex.Message);
+            }
+            Tizen.Log.Info(Resources.LogTag, "Create Table Done");
+        }
+        private static void InsertData()
+        {
+            SqliteCommand sqliteCmd = sqliteConn.CreateCommand();
+            ApplicationInfoFilter appInfoFilter = new ApplicationInfoFilter();
+            appInfoFilter.Filter.Add(ApplicationInfoFilter.Keys.NoDisplay, "False");
+            var task = ApplicationManager.GetInstalledApplicationsAsync(appInfoFilter);
+            task.Wait();
+            IEnumerable<ApplicationInfo> applicationsList = task.Result;
+            foreach( ApplicationInfo appInfo in applicationsList)
+            {
+                if (appInfo.Label == "TrayApplication" || appInfo.Label == "Apps" || string.IsNullOrEmpty(appInfo.IconPath))
+                {
+                    continue;
+                }
+                sqliteCmd.CommandText = INSERT_VALUES_QUERY + appInfo.ApplicationId + "', 50.00); ";
+                sqliteCmd.ExecuteNonQuery();
+            }
+        }
+
+        private static void IncreaseScore(string appId, bool isInstalled)
+        {
+            SqliteCommand sqliteCmd = sqliteConn.CreateCommand();
+            
+            if (isInstalled)
+            {
+                sqliteCmd.CommandText = SELECT_MAX_SCORE_QUERY;
+                SqliteDataReader sqliteDatareader = sqliteCmd.ExecuteReader();
+                sqliteDatareader.Read();
+                float score = sqliteDatareader.GetFloat(0);
+                sqliteCmd.Dispose();
+                sqliteCmd = sqliteConn.CreateCommand();
+                sqliteCmd.CommandText = INSERT_VALUES_QUERY + appId + "', " + score + ");";
+                sqliteCmd.ExecuteNonQuery();
+            }
+            else
+            {
+                sqliteCmd.CommandText = UPDATE_LAUNCHED_APP_QUERY + appId + "';";
+                sqliteCmd.ExecuteNonQuery();
+            }
+
+            sqliteCmd.CommandText = UPDATE_OTHER_APPS_QUERY + appId + "';";
+            sqliteCmd.ExecuteNonQuery();
+            Tizen.Log.Info(Resources.LogTag, "Score Updated of App: " + appId);
+        }
+
+        private static void RemoveAppScore(string appId)
+        {
+            SqliteCommand sqliteCmd = sqliteConn.CreateCommand();
+            sqliteCmd.CommandText = DELETE_APP_QUERY + appId + "';";
+            sqliteCmd.ExecuteNonQuery();
+            Tizen.Log.Info(Resources.LogTag, "App Removed from DB: " + appId);
+        }
+
+        public static Dictionary<string,int> ReadData(int count)
+        {
+            SqliteDataReader sqliteDatareader;
+            SqliteCommand sqliteCmd = sqliteConn.CreateCommand();
+            sqliteCmd.CommandText = SELECT_APPS_QUERY + count + ";";
+            Dictionary<string, int> appsScoreData = new Dictionary<string, int>();
+            sqliteDatareader = sqliteCmd.ExecuteReader();
+            while (sqliteDatareader.Read())
+            {
+                string appName = sqliteDatareader.GetString(0);
+                int appScore = sqliteDatareader.GetInt32(1);
+                Tizen.Log.Info(Resources.LogTag, "appName " + appName + " score " + appScore);
+                appsScoreData.Add(appName, appScore);
+            }
+            return appsScoreData;
+        }
+
+        public static void Disconnect()
+        {
+            sqliteConn.Close();
+        }
+    }
+}
diff --git a/TrayApplication/Models/AppInfoModel.cs b/TrayApplication/Models/AppInfoModel.cs
new file mode 100644 (file)
index 0000000..2c96be2
--- /dev/null
@@ -0,0 +1,41 @@
+using System.Windows.Input;
+using Tizen.NUI.Binding;
+using TrayApplication.Common;
+using TrayApplication.Core;
+
+namespace TrayApplication.Models
+{
+    class AppInfoModel : PropertyNotifier
+    {
+        public AppInfoModel(string name, string applicationId, string url)
+        {
+            Name = name;
+            ApplicationId = applicationId;
+            IconUrl = url;
+            AppSelectCommand = new Command(OnAppSelect);
+        }
+
+        public string Name { get; internal set; }
+
+        public string ApplicationId { get; internal set; }
+
+        private string iconUrl;
+        public string IconUrl
+        {
+            get => iconUrl;
+            set => SetProperty(ref iconUrl, value);
+        }
+
+        private ICommand appSelectCommand;
+        public ICommand AppSelectCommand
+        {
+            get => appSelectCommand;
+            set => SetProperty(ref appSelectCommand, value);
+        }
+
+        private void OnAppSelect(object selectedItem)
+        {
+            AppLauncher.LaunchApplication(ApplicationId);
+        }
+    }
+}
diff --git a/TrayApplication/TrayApplication.cs b/TrayApplication/TrayApplication.cs
new file mode 100644 (file)
index 0000000..dd2896b
--- /dev/null
@@ -0,0 +1,148 @@
+using System;
+using Tizen.NUI;
+using Tizen.NUI.WindowSystem.Shell;
+using TrayApplication.Views;
+using TrayApplication.Common;
+using TrayApplication.Core;
+
+namespace TrayApplication
+{
+    public class Program : NUIApplication
+    {
+        public Program() : base(ThemeOptions.PlatformThemeEnabled)
+        {
+        }
+
+        private const int WindowHeight = 313;
+        private int positionX;
+        private int positionY;
+        private bool isTrayVisible = true;
+
+        private Window window;
+        private MainView mainView;
+        private TizenShell tzShell;
+        private SoftkeyService softkeyService;
+
+        private float touchStartPosition;
+        protected override void OnCreate()
+        {
+            Tizen.Log.Info(Resources.LogTag, "Program OnCreate");
+            base.OnCreate();
+            window = GetDefaultWindow();
+            int sizeWidth = (int)((DeviceInfo.IsPortrait ? 0.6 : 0.5) * DeviceInfo.DisplayWidth);
+            int sizeHeight = WindowHeight.SpToPx();
+            positionX = (int)((DeviceInfo.IsPortrait ? 0.2 : 0.25) * DeviceInfo.DisplayWidth);
+            positionY = DeviceInfo.DisplayHeight;
+            window.WindowSize = new Size2D(sizeWidth, sizeHeight);
+            window.WindowPosition = new Position2D(positionX, positionY);
+            window.BackgroundColor = Color.Transparent;
+            window.SetTransparency(true);
+
+            tzShell = new TizenShell();
+            softkeyService = new SoftkeyService(tzShell, window);
+            softkeyService.Show();
+
+            window.KeyEvent += OnKeyEvent;
+            window.TouchEvent += OnTouch;
+            AppScoreDataBase.InitializeDataBase();
+
+            mainView = new MainView();
+            window.Add(mainView);
+            mainView.RemovedFromWindow += MainViewRemovedFromWindow;
+            mainView.VisibilityChanged += MainViewVisibilityChanged;
+            mainView.HideView();
+            Tizen.Log.Info(Resources.LogTag, "Tray Application Created");
+        }
+
+        protected override void OnTerminate()
+        {
+            Tizen.Log.Info(Resources.LogTag, "Program OnTerminate");
+            AppScoreDataBase.Disconnect();
+            base.OnTerminate();
+        }
+
+        private void MainViewRemovedFromWindow(object sender, EventArgs e)
+        {
+            Tizen.Log.Info(Resources.LogTag, "Main View Removed");
+            mainView = null;
+            Exit();
+        }
+
+        private void MainViewVisibilityChanged(object sender, Tizen.NUI.BaseComponents.View.VisibilityChangedEventArgs e)
+        {
+            Tizen.Log.Info(Resources.LogTag, "Main View Visibility Changed");
+            if (isTrayVisible == true)
+            {
+                positionY = DeviceInfo.DisplayHeight - 36.SpToPx();
+                window.WindowPosition = new Position2D(positionX, positionY);
+            }
+            else
+            {
+                positionY = DeviceInfo.DisplayHeight - (WindowHeight + 48).SpToPx();
+                window.WindowPosition = new Position2D(positionX, positionY);
+            }
+            isTrayVisible = !isTrayVisible;
+        }
+
+        private void OnTouch(object sender, Window.TouchEventArgs e)
+        {
+            Tizen.Log.Info(Resources.LogTag, "Touch Type " + e.Touch.GetState(0).ToString());
+            if (isTrayVisible == true)
+            {
+                if (e.Touch.GetState(0) == PointStateType.Started)
+                {
+                    touchStartPosition = e.Touch.GetScreenPosition(0).Y;
+                }
+                if (e.Touch.GetState(0) == PointStateType.Finished)
+                {
+                    float touchEndPosition = e.Touch.GetScreenPosition(0).Y;
+                    if (touchEndPosition - touchStartPosition >= 60.SpToPx())
+                    {
+                        if (mainView != null)
+                        {
+                            mainView.HideView();
+                        }
+                    }
+                }
+            }
+            else
+            {
+                if (e.Touch.GetState(0) == PointStateType.Started)
+                {
+                    touchStartPosition = e.Touch.GetScreenPosition(0).Y;
+                }
+                if (e.Touch.GetState(0) == PointStateType.Motion || e.Touch.GetState(0) == PointStateType.Finished)
+                {
+                    float touchEndPosition = e.Touch.GetScreenPosition(0).Y;
+                    if (touchStartPosition - touchEndPosition >= 5.SpToPx())
+                    {
+                        if (mainView != null)
+                        {
+                            mainView.ShowView();
+                        }
+                        touchStartPosition = 313.SpToPx();
+                    }
+                }
+            }
+        }
+
+        public void OnKeyEvent(object sender, Window.KeyEventArgs e)
+        {
+            if (e.Key.State == Key.StateType.Down && (e.Key.KeyPressedName == "XF86Back" || e.Key.KeyPressedName == "Escape"))
+            {
+                if (mainView != null)
+                {
+                    mainView.HideView();
+                }
+            }
+        }
+
+        static void Main(string[] args)
+        {
+            Tizen.Log.Info(Resources.LogTag, "Main statrted");
+            Program app = new Program();
+            app.Run(args);
+            Tizen.Log.Info(Resources.LogTag, "Main ended");
+        }
+    }
+}
diff --git a/TrayApplication/TrayApplication.csproj b/TrayApplication/TrayApplication.csproj
new file mode 100644 (file)
index 0000000..b827d0e
--- /dev/null
@@ -0,0 +1,36 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+  <PropertyGroup>
+    <OutputType>Exe</OutputType>
+    <TargetFramework>netcoreapp3.1</TargetFramework>
+      <TargetFrameworkIdentifier>Tizen</TargetFrameworkIdentifier>
+    <AssemblyName>TrayApplication</AssemblyName>
+  </PropertyGroup>
+
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugType>portable</DebugType>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>None</DebugType>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <Folder Include="res\images\" />
+  </ItemGroup>
+
+  <ItemGroup>
+    <PackageReference Include="Microsoft.Data.Sqlite" Version="6.0.7" />
+    <PackageReference Include="Tizen.NET" Version="10.0.0.17305" />
+    <PackageReference Include="Tizen.NET.Sdk" Version="1.1.8" />
+  </ItemGroup>
+
+  <ItemGroup>
+    <None Update="res\themes\dark.xaml">
+      <Generator>MSBuild:Compile</Generator>
+    </None>
+    <None Update="res\themes\light.xaml">
+      <Generator>MSBuild:Compile</Generator>
+    </None>
+  </ItemGroup>
+
+</Project>
diff --git a/TrayApplication/TrayApplication.sln b/TrayApplication/TrayApplication.sln
new file mode 100644 (file)
index 0000000..0a80bef
--- /dev/null
@@ -0,0 +1,25 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.30907.101
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TrayApplication", "TrayApplication.csproj", "{A49D73AA-CB7E-4D21-B865-E61570EEF070}"
+EndProject
+Global
+       GlobalSection(SolutionConfigurationPlatforms) = preSolution
+               Debug|Any CPU = Debug|Any CPU
+               Release|Any CPU = Release|Any CPU
+       EndGlobalSection
+       GlobalSection(ProjectConfigurationPlatforms) = postSolution
+               {A49D73AA-CB7E-4D21-B865-E61570EEF070}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+               {A49D73AA-CB7E-4D21-B865-E61570EEF070}.Debug|Any CPU.Build.0 = Debug|Any CPU
+               {A49D73AA-CB7E-4D21-B865-E61570EEF070}.Release|Any CPU.ActiveCfg = Release|Any CPU
+               {A49D73AA-CB7E-4D21-B865-E61570EEF070}.Release|Any CPU.Build.0 = Release|Any CPU
+       EndGlobalSection
+       GlobalSection(SolutionProperties) = preSolution
+               HideSolutionNode = FALSE
+       EndGlobalSection
+       GlobalSection(ExtensibilityGlobals) = postSolution
+               SolutionGuid = {BEA88B8F-9C50-44CA-8A31-B3DDC15622F5}
+       EndGlobalSection
+EndGlobal
diff --git a/TrayApplication/ViewModels/ApplicationViewModel.cs b/TrayApplication/ViewModels/ApplicationViewModel.cs
new file mode 100644 (file)
index 0000000..3b24279
--- /dev/null
@@ -0,0 +1,81 @@
+using System.Collections;
+using System.Collections.Generic;
+using Tizen.Applications;
+using Tizen.NUI;
+using TrayApplication.Common;
+using TrayApplication.Core;
+using TrayApplication.Models;
+
+namespace TrayApplication.ViewModels
+{
+    class ApplicationViewModel : PropertyNotifier
+    {
+        Dictionary<string, int> appScoreData;
+        private readonly int appsCount;
+        public ApplicationViewModel(int appsCount)
+        {
+            this.appsCount = appsCount;
+            appScoreData = AppScoreDataBase.ReadData(appsCount - 1);
+            BackgroundColor = ThemeManager.PlatformThemeId == Resources.DarkPlatformThemeId ? Resources.DarkApplicationsBackground : Resources.LightApplicationsBackground;
+            AddButtonsInfo();
+            AppScoreDataBase.OnDatabaseUpdate += OnDatabaseUpdate;
+            ThemeManager.ThemeChanged += (object sender, ThemeChangedEventArgs e) =>
+            {
+                if (e.IsPlatformThemeChanged)
+                {
+                    Tizen.Log.Info(Resources.LogTag, "Theme Changed: " + e.ThemeId);
+                    UpdateTheme();
+                }
+            };
+            Tizen.Log.Info(Resources.LogTag, "ApplicationViewModel");
+        }
+
+        private void OnDatabaseUpdate(object sender, System.EventArgs e)
+        {
+            UpdateButtonsInfo();
+        }
+
+        private void AddButtonsInfo()
+        {
+            List<object> buttons = new List<object>();
+            foreach (var item in appScoreData)
+            {
+                ApplicationInfo appInfo = new ApplicationInfo(item.Key);
+                buttons.Add(new AppInfoModel(appInfo.Label, item.Key, appInfo.IconPath));
+                appInfo.Dispose();
+            }
+            buttons.Add(new AppInfoModel("Apps", "org.tizen.Apps", Resources.GetCurrentThemePath() + "apps.png"));
+            ButtonsInfo = buttons;
+        }
+
+        public void UpdateButtonsInfo()
+        {
+            appScoreData.Clear();
+            appScoreData = AppScoreDataBase.ReadData(appsCount - 1);
+            ((List<object>)ButtonsInfo).Clear();
+            AddButtonsInfo();
+        }
+
+        public void UpdateTheme()
+        {
+            BackgroundColor = ThemeManager.PlatformThemeId == Resources.DarkPlatformThemeId ? Resources.DarkApplicationsBackground : Resources.LightApplicationsBackground;
+            ((AppInfoModel)((List<object>)buttonsInfo)[^1]).IconUrl = Resources.GetCurrentThemePath() + "apps.png";
+        }
+
+        private Color backgroundColor;
+
+        public Color BackgroundColor
+        {
+            get => backgroundColor;
+            set => SetProperty(ref backgroundColor, value);
+        }
+
+        private IEnumerable buttonsInfo;
+
+        public IEnumerable ButtonsInfo
+        {
+            get => buttonsInfo;
+            set => SetProperty(ref buttonsInfo, value);
+        }
+    }
+}
diff --git a/TrayApplication/ViewModels/QuickAccessViewModel.cs b/TrayApplication/ViewModels/QuickAccessViewModel.cs
new file mode 100644 (file)
index 0000000..da4529c
--- /dev/null
@@ -0,0 +1,71 @@
+using System.Collections;
+using System.Collections.Generic;
+using Tizen.NUI;
+using TrayApplication.Common;
+using TrayApplication.Models;
+
+namespace TrayApplication.ViewModels
+{
+    class QuickAccessViewModel : PropertyNotifier
+    {
+        private readonly List<string> AppNames = new List<string>() { "home", "settings", "volume", "notifications", "gallery", "power" };
+
+        public QuickAccessViewModel()
+        {
+            ButtonsInfo = new List<object>();
+            BackgroundColor = ThemeManager.PlatformThemeId == Resources.DarkPlatformThemeId ? Resources.DarkQuickAccessBackground : Resources.LightQuickAccessBackground;
+            AddButtonsInfo();
+            ThemeManager.ThemeChanged += (object sender, ThemeChangedEventArgs e) =>
+            {
+                if (e.IsPlatformThemeChanged)
+                {
+                    Tizen.Log.Info(Resources.LogTag, "Theme Changed: " + e.ThemeId);
+                    UpdateTheme();
+                }
+            };
+            Tizen.Log.Info(Resources.LogTag, "QuickAccessViewModel");
+        }
+
+        private void AddButtonsInfo()
+        {
+            string imagePath = Resources.GetCurrentThemePath();
+            ((List<object>)ButtonsInfo).Clear();
+            List<object> buttons = new List<object>
+            {
+                new AppInfoModel(AppNames[0], "org.tizen.homescreen-efl", imagePath + AppNames[0] + ".png"),
+                new AppInfoModel(AppNames[1], "org.tizen.setting", imagePath + AppNames[1] + ".png"),
+                new AppInfoModel(AppNames[2], "org.tizen.volume", imagePath + AppNames[2] + ".png"),
+                new AppInfoModel(AppNames[3], "org.tizen.quickpanel", imagePath + AppNames[3] + ".png"),
+                new AppInfoModel(AppNames[5], "org.tizen.powerkey-syspopup", imagePath + AppNames[5] + ".png")
+            };
+            ButtonsInfo = buttons;
+            Tizen.Log.Info(Resources.LogTag, "Done Adding ButtonsInfo");
+        }
+
+        public void UpdateTheme()
+        {
+            BackgroundColor = ThemeManager.PlatformThemeId == Resources.DarkPlatformThemeId ? Resources.DarkQuickAccessBackground : Resources.LightQuickAccessBackground;
+            string imagePath = Resources.GetCurrentThemePath();
+            foreach (AppInfoModel item in ButtonsInfo)
+            {
+                item.IconUrl = imagePath + item.Name + ".png";
+            }
+        }
+
+        private Color backgroundColor;
+
+        public Color BackgroundColor
+        {
+            get => backgroundColor;
+            set => SetProperty(ref backgroundColor, value);
+        }
+
+        private IEnumerable buttonsInfo;
+
+        public IEnumerable ButtonsInfo
+        {
+            get => buttonsInfo;
+            set => SetProperty(ref buttonsInfo, value);
+        }
+    }
+}
diff --git a/TrayApplication/Views/AppItemView.cs b/TrayApplication/Views/AppItemView.cs
new file mode 100644 (file)
index 0000000..745916e
--- /dev/null
@@ -0,0 +1,180 @@
+using System;
+using System.Windows.Input;
+using Tizen.NUI;
+using Tizen.NUI.BaseComponents;
+using Tizen.NUI.Binding;
+using Tizen.NUI.Components;
+using TrayApplication.Common;
+
+namespace TrayApplication.Views
+{
+    internal class AppItemView : View
+    {
+        public event EventHandler<EventArgs> LongPressed;
+
+        private bool isMoved;
+        private bool isLongPressed;
+        private Timer timer;
+
+        public static readonly BindableProperty AppSelectCommandProperty = BindableProperty.Create(nameof(AppSelectCommand), typeof(ICommand), typeof(AppItemView), null, propertyChanged: (bindable, oldValue, newValue) =>
+        {
+            var instance = (AppItemView)bindable;
+            if (oldValue != newValue)
+            {
+                instance.appSelectCommand = (ICommand)newValue;
+            }
+        },
+        defaultValueCreator: (bindable) => ((AppItemView)bindable).appSelectCommand);
+
+        public AppItemView() : base()
+        {
+            ThemeChangeSensitive = true;
+            StyleName = "AppItemBackGround";
+            WidthSpecification = 138.SpToPx();
+            HeightSpecification = 138.SpToPx();
+            CornerRadius = new Vector4(12, 12, 12, 12);
+            Layout = new RelativeLayout()
+            {
+                Padding = new Extents(8, 0, 0, 2).SpToPx(),
+            };
+
+            IconBackground = new View()
+            {
+                WidthSpecification = 122.SpToPx(),
+                HeightSpecification = 102.SpToPx(),
+                CornerRadius = new Vector4(12, 12, 12, 12),
+                Margin = new Extents(0, 8, 8, 0).SpToPx(),
+                Layout = new LinearLayout()
+                {
+                    VerticalAlignment = VerticalAlignment.Center,
+                    HorizontalAlignment = HorizontalAlignment.Center,
+                },
+            };
+            Add(IconBackground);
+            RelativeLayout.SetHorizontalAlignment(IconBackground, RelativeLayout.Alignment.Center);
+            RelativeLayout.SetVerticalAlignment(IconBackground, RelativeLayout.Alignment.Start);
+
+            Icon = new ImageView()
+            {
+                MaximumSize = new Size2D(96, 96).SpToPx(),
+            };
+            IconBackground.Add(Icon);
+
+            Label = new TextLabel()
+            {
+                ThemeChangeSensitive = true,
+                StyleName = "AppItemLabel",
+                FontFamily = "BreezeSans",
+                WidthSpecification = LayoutParamPolicies.MatchParent,
+                HeightSpecification = 24.SpToPx(),
+                PixelSize = 16.SpToPx(),
+                HorizontalAlignment = HorizontalAlignment.Center,
+                VerticalAlignment = VerticalAlignment.Center,
+            };
+            Add(Label);
+            RelativeLayout.SetHorizontalAlignment(Label, RelativeLayout.Alignment.Center);
+            RelativeLayout.SetVerticalAlignment(Label, RelativeLayout.Alignment.End);
+
+            TouchEvent += OnTouched;
+            Tizen.Log.Info(Resources.LogTag, "AppItemView");
+        }
+
+        private bool OnTouched(object source, TouchEventArgs e)
+        {
+            if (e.Touch.GetState(0) == PointStateType.Down)
+            {
+                timer = new Timer(1000);
+                timer.Start();
+                isMoved = false;
+                isLongPressed = false;
+                timer.Tick += (object source, Timer.TickEventArgs ev) =>
+                {
+                    if (isMoved == false)
+                    {
+                        isLongPressed = true;
+                        LongPressed.Invoke(this, new EventArgs());
+                        Tizen.Log.Debug(Resources.LogTag, "Long Pressed");
+                    }
+                    return false;
+                };
+            }
+            else
+            {
+                if (timer != null)
+                {
+                    timer.Stop();
+                    timer.Dispose();
+                    timer = null;
+                }
+                if (e.Touch.GetState(0) == PointStateType.Up)
+                {
+                    if (isLongPressed == false && isMoved == false)
+                    {
+                        AppSelectCommand.Execute(BindingContext);
+                        Tizen.Log.Debug(Resources.LogTag, "Clicked");
+                    }
+                    isLongPressed = false;
+                }
+                else
+                {
+                    isMoved = true;
+                }
+            }
+            return true;
+        }
+
+        public TextLabel Label { get; }
+
+        public ImageView Icon { get; }
+
+        public View IconBackground { get; }
+
+        public Button CrossButton { get; internal set; }
+
+        private ICommand appSelectCommand;
+
+        public ICommand AppSelectCommand
+        {
+            get => (ICommand)GetValue(AppSelectCommandProperty);
+            set => SetValue(AppSelectCommandProperty, value);
+        }
+
+        public void AddCrossButton()
+        {
+            if (CrossButton == null)
+            {
+                CrossButton = new Button("CrossButton")
+                {
+                    Size2D = new Size2D(48, 48).SpToPx(),
+                };
+                Add(CrossButton);
+                RelativeLayout.SetHorizontalAlignment(CrossButton, RelativeLayout.Alignment.End);
+                RelativeLayout.SetVerticalAlignment(CrossButton, RelativeLayout.Alignment.Start);
+            }
+        }
+
+        protected override void Dispose(DisposeTypes type)
+        {
+            if (Disposed)
+            {
+                return;
+            }
+            if (type == DisposeTypes.Explicit)
+            {
+                Remove(Label);
+                Label?.Dispose();
+
+                IconBackground.Remove(Icon);
+                Icon?.Dispose();
+
+                Remove(IconBackground);
+                IconBackground?.Dispose();
+
+                Remove(CrossButton);
+                CrossButton?.Dispose();
+            }
+            Tizen.Log.Info(Resources.LogTag, "AppItemView Dispose");
+            base.Dispose(type);
+        }
+    }
+}
diff --git a/TrayApplication/Views/ApplicationsView.cs b/TrayApplication/Views/ApplicationsView.cs
new file mode 100644 (file)
index 0000000..630867f
--- /dev/null
@@ -0,0 +1,153 @@
+using System;
+using System.Collections.Generic;
+using System.Collections;
+using Tizen.NUI;
+using Tizen.NUI.BaseComponents;
+using Tizen.NUI.Binding;
+using TrayApplication.Common;
+
+namespace TrayApplication.Views
+{
+    public class ApplicationsView : View
+    {
+        private const int ApplicationViewHeight = 189;
+        private List<AppItemView> appIcons;
+        private readonly int maxAppsCount;
+        private int currentAppsCount;
+
+        public static readonly BindableProperty AppListProperty = BindableProperty.Create(nameof(AppList), typeof(IEnumerable), typeof(ApplicationsView), null, propertyChanged: (bindable, oldValue, newValue) =>
+        {
+            ApplicationsView instance = (ApplicationsView)bindable;
+            if (oldValue != newValue)
+            {
+                if (oldValue != null)
+                {
+                    ((List<object>)oldValue).Clear();
+                }
+                if(newValue != null)
+                {
+                    instance.appList = (IEnumerable)newValue;
+                }
+                instance.UpdateAppIcons();
+            }
+        },
+        defaultValueCreator: (bindable) => ((ApplicationsView)bindable).appList);
+
+        public ApplicationsView(int appsCount) : base()
+        {
+            Name = "ApplicationsView";
+            WidthSpecification = LayoutParamPolicies.MatchParent;
+            HeightSpecification = ApplicationViewHeight.SpToPx();
+            CornerRadius = new Vector4(20, 20, 0, 0);
+            Layout = new LinearLayout()
+            {
+                LinearOrientation = LinearLayout.Orientation.Horizontal,
+                HorizontalAlignment = HorizontalAlignment.Center,
+                VerticalAlignment = VerticalAlignment.Center,
+                CellPadding = new Size2D(16, 0).SpToPx()
+            };
+            maxAppsCount = appsCount;
+            currentAppsCount = 0;
+            appList = new List<object>();
+            CreateDefaultAppItems();
+            Tizen.Log.Info(Resources.LogTag, "ApplicationsView");
+        }
+
+        private void CreateDefaultAppItems()
+        {
+            appIcons = new List<AppItemView>();
+            for (int i = 0; i < maxAppsCount; i++)
+            {
+                AppItemView itemView = new AppItemView();
+                itemView.Hide();
+                itemView.LongPressed += (object sender, EventArgs e) =>
+                {
+                    AddDeleteOption();
+                };
+                appIcons.Add(itemView);
+            }
+            Tizen.Log.Info(Resources.LogTag, "Icons Added");
+        }
+
+        private IEnumerable appList;
+        public IEnumerable AppList
+        {
+            get => (IEnumerable)GetValue(AppListProperty);
+            set => SetValue(AppListProperty, value);
+        }
+
+        private void UpdateAppIcons()
+        {
+            List<object> appDataList = (List<object>)appList;
+            int totalCount = appDataList.Count;
+
+            if (totalCount <= currentAppsCount)
+            {
+                for (int i = 0; i < totalCount; i++)
+                {
+                    appIcons[i].BindingContext = appDataList[i];
+                }
+                for (int i = totalCount; i < currentAppsCount; i++)
+                {
+                    AppItemView appItemView = appIcons[i];
+                    appItemView.Hide();
+                    Remove(appItemView);
+                }
+            }
+            else
+            {
+                for (int i = 0; i < currentAppsCount; i++)
+                {
+                    appIcons[i].BindingContext = appDataList[i];
+                }
+                for (int i = currentAppsCount; i < totalCount; i++)
+                {
+                    AppItemView itemView = appIcons[i];
+                    itemView.Show();
+                    Add(itemView);
+                    itemView.BindingContext = appDataList[i];
+                    itemView.Icon.SetBinding(ImageView.ResourceUrlProperty, "IconUrl");
+                    itemView.Label.SetBinding(TextLabel.TextProperty, "Name");
+                    itemView.SetBinding(AppItemView.AppSelectCommandProperty, "AppSelectCommand");
+                }
+            }
+            currentAppsCount = totalCount;
+            Tizen.Log.Info(Resources.LogTag, "Icons Updated");
+        }
+
+        private void AddDeleteOption()
+        {
+            for(int i = 0; i < currentAppsCount - 1; i++)
+            {
+                appIcons[i].AddCrossButton();
+            }
+        }
+
+        protected override void Dispose(DisposeTypes type)
+        {
+            if (Disposed)
+            {
+                return;
+            }
+            if (type == DisposeTypes.Explicit)
+            {
+                while (appIcons.Count != 0)
+                {
+                    AppItemView view = appIcons[0];
+                    appIcons.RemoveAt(0);
+                    Remove(view);
+                    view.Dispose();
+                }
+                appIcons.Clear();
+                appIcons = null;
+            }
+            Tizen.Log.Info(Resources.LogTag, "ApplicationsView Dispose");
+            base.Dispose(type);
+        }
+
+        public void DeleteView()
+        {
+            Dispose(DisposeTypes.Explicit);
+        }
+    }
+}
diff --git a/TrayApplication/Views/MainView.cs b/TrayApplication/Views/MainView.cs
new file mode 100644 (file)
index 0000000..0576dcd
--- /dev/null
@@ -0,0 +1,154 @@
+using System;
+using System.IO;
+using Tizen.NUI;
+using Tizen.NUI.BaseComponents;
+using Tizen.NUI.Binding;
+using Tizen.NUI.Xaml;
+using TrayApplication.Common;
+using TrayApplication.ViewModels;
+
+namespace TrayApplication.Views
+{
+    public class MainView : View
+    {
+        private ApplicationsView applicationsView;
+        private QuickAccessView quickAccessView;
+        private Animation animation;
+
+        public MainView() : base()
+        {
+            Name = "MainView";
+            WidthSpecification = LayoutParamPolicies.MatchParent;
+            HeightSpecification = LayoutParamPolicies.MatchParent;
+            CornerRadius = new Vector4(20, 20, 20, 20);
+            BackgroundColor = Color.Transparent;
+            Layout = new LinearLayout()
+            {
+                LinearOrientation = LinearLayout.Orientation.Vertical
+            };
+            UpdateTheme(ThemeManager.PlatformThemeId);
+            int appsCount = Window.Instance.Size.Width / 154.SpToPx();
+            ApplicationViewModel applicationViewModel = new ApplicationViewModel(appsCount);
+            applicationsView = new ApplicationsView(appsCount);
+            Add(applicationsView);
+            applicationsView.BindingContext = applicationViewModel;
+            applicationsView.SetBinding(BackgroundColorProperty, "BackgroundColor");
+            applicationsView.SetBinding(ApplicationsView.AppListProperty, "ButtonsInfo");
+            QuickAccessViewModel quickAccessViewModel = new QuickAccessViewModel();
+            quickAccessView = new QuickAccessView();
+            Add(quickAccessView);
+            quickAccessView.BindingContext = quickAccessViewModel;
+            quickAccessView.SetBinding(BackgroundColorProperty, "BackgroundColor");
+            quickAccessView.SetBinding(QuickAccessView.AppListProperty, "ButtonsInfo");
+            ThemeManager.ThemeChanged += OnThemeUpdated;
+        }
+
+        private void OnThemeUpdated(object sender, ThemeChangedEventArgs e)
+        {
+            if (e.IsPlatformThemeChanged)
+            {
+                Tizen.Log.Error(Resources.LogTag, "Theme Changed: " + e.ThemeId);
+                UpdateTheme(e.PlatformThemeId);
+            }
+        }
+
+        private void HideAnimation()
+        {
+            animation = new Animation(500);
+            animation.Play();
+            animation.AnimateTo(this, "PositionY", 313.SpToPx());
+            animation.Finished += OnExitAnimationFinished;
+        }
+
+        private void OnExitAnimationFinished(object sender, EventArgs e)
+        {
+            Hide();
+        }
+
+        private void SetTheme(string path)
+        {
+            try
+            {
+                Theme theme = new Theme(path);
+                ThemeManager.ApplyTheme(theme);
+            }
+            catch (ArgumentNullException e)
+            {
+                Tizen.Log.Error(Resources.LogTag, "ArgumentNullException: " + e.ParamName);
+            }
+            catch (IOException e)
+            {
+                Tizen.Log.Error(Resources.LogTag, "IOException: " + e.Message);
+            }
+            catch (XamlParseException e)
+            {
+                Tizen.Log.Error(Resources.LogTag, "XamlParseException: " + e.Message);
+                if (e.XmlInfo != null)
+                {
+                    Tizen.Log.Error(Resources.LogTag, "XamlParseException, LineNo." + e.XmlInfo.LineNumber + " Pos: " + e.XmlInfo.LinePosition + " HasInfo: " + e.XmlInfo.HasLineInfo().ToString());
+                }
+            }
+        }
+        private void UpdateTheme(string platformThemeId)
+        {
+            if (platformThemeId == null)
+            {
+                Tizen.Log.Error(Resources.LogTag, "Platform theme id is null");
+                return;
+            }
+            if (platformThemeId.Equals(Resources.LightPlatformThemeId))
+            {
+                SetTheme(Resources.GetThemePath() + "light.xaml");
+            }
+            else if (platformThemeId.Equals(Resources.DarkPlatformThemeId))
+            {
+                SetTheme(Resources.GetThemePath() + "dark.xaml");
+            }
+        }
+
+        protected override void Dispose(DisposeTypes type)
+        {
+            if (Disposed)
+            {
+                return;
+            }
+            if (type == DisposeTypes.Explicit)
+            {
+                if(animation != null)
+                {
+                    animation.Stop();
+                    animation.Dispose();
+                    animation = null;
+                }
+                if (applicationsView != null)
+                {
+                    applicationsView.DeleteView();
+                    applicationsView = null;
+                    Remove(applicationsView);
+                }
+                if (quickAccessView != null)
+                {
+                    quickAccessView.DeleteView();
+                    quickAccessView = null;
+                    Remove(quickAccessView);
+                }
+                Window.Instance.GetDefaultLayer().Remove(this);
+            }
+            Tizen.Log.Info(Resources.LogTag, "MainViewDispose");
+            base.Dispose(type);
+        }
+
+        public void ShowView()
+        {
+            Show();
+            animation = new Animation(500);
+            animation.Play();
+            animation.AnimateTo(this, "PositionY", 0.SpToPx());
+        }
+
+        public void HideView()
+        {
+            HideAnimation();
+        }
+    }
+}
diff --git a/TrayApplication/Views/QuickAccessView.cs b/TrayApplication/Views/QuickAccessView.cs
new file mode 100644 (file)
index 0000000..4eb3419
--- /dev/null
@@ -0,0 +1,121 @@
+using System.Collections;
+using System.Collections.Generic;
+using Tizen.NUI;
+using Tizen.NUI.Components;
+using Tizen.NUI.BaseComponents;
+using Tizen.NUI.Binding;
+using TrayApplication.Common;
+
+namespace TrayApplication.Views
+{
+    public class QuickAccessView : View
+    {
+        private const int QuickAccessViewHeight = 124;
+        private const int IconSize = 76;
+        private List<Button> defaultButtons;
+
+        public static readonly BindableProperty AppListProperty = BindableProperty.Create(nameof(AppList), typeof(IEnumerable), typeof(QuickAccessView), null, propertyChanged: (bindable, oldValue, newValue) =>
+        {
+            QuickAccessView instance = (QuickAccessView)bindable;
+            if (oldValue != newValue)
+            {
+                if (oldValue != null)
+                {
+                    ((List<object>)oldValue).Clear();
+                }
+                if (newValue != null)
+                {
+                    instance.appList = (IEnumerable)newValue;
+                }
+                instance.UpdateButtons();
+            }
+        },
+        defaultValueCreator: (bindable) => ((QuickAccessView)bindable).appList);
+
+        public QuickAccessView() : base()
+        {
+            Name = "QuickAccessView";
+            WidthSpecification = LayoutParamPolicies.MatchParent;
+            HeightSpecification = QuickAccessViewHeight.SpToPx();
+            CornerRadius = new Vector4(0, 0, 20, 20);
+            Layout = new LinearLayout()
+            {
+                LinearOrientation = LinearLayout.Orientation.Horizontal,
+                HorizontalAlignment = HorizontalAlignment.Center,
+                VerticalAlignment = VerticalAlignment.Center,
+                CellPadding = new Size2D(16, 0).SpToPx()
+            };
+            defaultButtons = new List<Button>();
+            Tizen.Log.Info(Resources.LogTag, "QuickAccessView");
+        }
+
+        private IEnumerable appList;
+        public IEnumerable AppList
+        {
+            get => (IEnumerable)GetValue(AppListProperty);
+            set => SetValue(AppListProperty, value);
+        }
+
+        private Button CreateNewButton()
+        {
+            ButtonStyle buttonStyle = new ButtonStyle()
+            {
+                Icon = new ImageViewStyle(),
+                IsEnabled = true,
+                IsSelectable = true,
+            };
+            Button button = new Button(buttonStyle)
+            {
+                WidthSpecification = IconSize.SpToPx(),
+                HeightSpecification = IconSize.SpToPx()
+            };
+            return button;
+        }
+
+        private void UpdateButtons()
+        {
+            foreach (Button button in defaultButtons)
+            {
+                Remove(button);
+            }
+            defaultButtons.Clear();
+            foreach (var item in appList)
+            {
+                Button button = CreateNewButton();
+                Add(button);
+                defaultButtons.Add(button);
+                button.BindingContext = item;
+                button.Icon.SetBinding(ImageView.ResourceUrlProperty, "IconUrl");
+                button.SetBinding(Control.CommandProperty, "AppSelectCommand");
+            }
+            Tizen.Log.Info(Resources.LogTag, "Buttons Added");
+        }
+
+        protected override void Dispose(DisposeTypes type)
+        {
+            if (Disposed)
+            {
+                return;
+            }
+            if (type == DisposeTypes.Explicit)
+            {
+                while(defaultButtons.Count != 0)
+                {
+                    Button button = defaultButtons[0];
+                    defaultButtons.RemoveAt(0);
+                    Remove(button);
+                    button.Dispose();
+                }
+                defaultButtons.Clear();
+                defaultButtons = null;
+            }
+            Tizen.Log.Info(Resources.LogTag, "QuickAccessView Dispose");
+            base.Dispose(type);
+        }
+
+        public void DeleteView()
+        {
+            Dispose(DisposeTypes.Explicit);
+        }
+    }
+}
diff --git a/TrayApplication/res/images/dark/apps.png b/TrayApplication/res/images/dark/apps.png
new file mode 100644 (file)
index 0000000..4fbded1
Binary files /dev/null and b/TrayApplication/res/images/dark/apps.png differ
diff --git a/TrayApplication/res/images/dark/cross_button.png b/TrayApplication/res/images/dark/cross_button.png
new file mode 100644 (file)
index 0000000..3a984e7
Binary files /dev/null and b/TrayApplication/res/images/dark/cross_button.png differ
diff --git a/TrayApplication/res/images/dark/cross_button_selected.png b/TrayApplication/res/images/dark/cross_button_selected.png
new file mode 100644 (file)
index 0000000..42a99c0
Binary files /dev/null and b/TrayApplication/res/images/dark/cross_button_selected.png differ
diff --git a/TrayApplication/res/images/dark/home.png b/TrayApplication/res/images/dark/home.png
new file mode 100644 (file)
index 0000000..1371cb8
Binary files /dev/null and b/TrayApplication/res/images/dark/home.png differ
diff --git a/TrayApplication/res/images/dark/notifications.png b/TrayApplication/res/images/dark/notifications.png
new file mode 100644 (file)
index 0000000..4caa43b
Binary files /dev/null and b/TrayApplication/res/images/dark/notifications.png differ
diff --git a/TrayApplication/res/images/dark/power.png b/TrayApplication/res/images/dark/power.png
new file mode 100644 (file)
index 0000000..8e9d89f
Binary files /dev/null and b/TrayApplication/res/images/dark/power.png differ
diff --git a/TrayApplication/res/images/dark/settings.png b/TrayApplication/res/images/dark/settings.png
new file mode 100644 (file)
index 0000000..7aab130
Binary files /dev/null and b/TrayApplication/res/images/dark/settings.png differ
diff --git a/TrayApplication/res/images/dark/volume.png b/TrayApplication/res/images/dark/volume.png
new file mode 100644 (file)
index 0000000..240a2b7
Binary files /dev/null and b/TrayApplication/res/images/dark/volume.png differ
diff --git a/TrayApplication/res/images/light/apps.png b/TrayApplication/res/images/light/apps.png
new file mode 100644 (file)
index 0000000..007ea1f
Binary files /dev/null and b/TrayApplication/res/images/light/apps.png differ
diff --git a/TrayApplication/res/images/light/cross_button.png b/TrayApplication/res/images/light/cross_button.png
new file mode 100644 (file)
index 0000000..215a099
Binary files /dev/null and b/TrayApplication/res/images/light/cross_button.png differ
diff --git a/TrayApplication/res/images/light/cross_button_selected.png b/TrayApplication/res/images/light/cross_button_selected.png
new file mode 100644 (file)
index 0000000..b5afd49
Binary files /dev/null and b/TrayApplication/res/images/light/cross_button_selected.png differ
diff --git a/TrayApplication/res/images/light/home.png b/TrayApplication/res/images/light/home.png
new file mode 100644 (file)
index 0000000..b9c82f6
Binary files /dev/null and b/TrayApplication/res/images/light/home.png differ
diff --git a/TrayApplication/res/images/light/notifications.png b/TrayApplication/res/images/light/notifications.png
new file mode 100644 (file)
index 0000000..bcf5ee3
Binary files /dev/null and b/TrayApplication/res/images/light/notifications.png differ
diff --git a/TrayApplication/res/images/light/power.png b/TrayApplication/res/images/light/power.png
new file mode 100644 (file)
index 0000000..972bc42
Binary files /dev/null and b/TrayApplication/res/images/light/power.png differ
diff --git a/TrayApplication/res/images/light/settings.png b/TrayApplication/res/images/light/settings.png
new file mode 100644 (file)
index 0000000..b5d8e53
Binary files /dev/null and b/TrayApplication/res/images/light/settings.png differ
diff --git a/TrayApplication/res/images/light/volume.png b/TrayApplication/res/images/light/volume.png
new file mode 100644 (file)
index 0000000..512f3a1
Binary files /dev/null and b/TrayApplication/res/images/light/volume.png differ
diff --git a/TrayApplication/res/themes/dark.xaml b/TrayApplication/res/themes/dark.xaml
new file mode 100644 (file)
index 0000000..24ef708
--- /dev/null
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Theme
+xmlns="http://tizen.org/Tizen.NUI/2018/XAML"
+xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
+xmlns:c="clr-namespace:Tizen.NUI.Components;assembly=Tizen.NUI.Components"
+Id="DarkTheme">
+
+    <ViewStyle x:Key="AppItemBackGround" BackgroundColor="#16131A" />
+    <TextLabelStyle x:Key="AppItemLabel" TextColor="#FDFDFD" />
+
+    <c:ButtonStyle x:Key="CrossButton" ThemeChangeSensitive="true" IsSelectable="false" IsEnabled="true" BackgroundColor="Transparent">
+        <c:ButtonStyle.Icon>
+            <ImageViewStyle Size="48sp, 48sp">
+                <ImageViewStyle.ResourceUrl>
+                    <Selector x:TypeArguments="x:String" Normal="*Resource*/images/dark/cross_button.png" Pressed="*Resource*/images/dark/cross_button_selected.png" />
+                </ImageViewStyle.ResourceUrl>
+            </ImageViewStyle>
+        </c:ButtonStyle.Icon>
+    </c:ButtonStyle>
+
+</Theme>
\ No newline at end of file
diff --git a/TrayApplication/res/themes/light.xaml b/TrayApplication/res/themes/light.xaml
new file mode 100644 (file)
index 0000000..44ed732
--- /dev/null
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Theme
+xmlns="http://tizen.org/Tizen.NUI/2018/XAML"
+xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
+xmlns:c="clr-namespace:Tizen.NUI.Components;assembly=Tizen.NUI.Components"
+Id="LightTheme">
+
+    <ViewStyle x:Key="AppItemBackGround" BackgroundColor="#FAFAFA" />
+    <TextLabelStyle x:Key="AppItemLabel" TextColor="#090E21" />
+
+    <c:ButtonStyle x:Key="CrossButton" ThemeChangeSensitive="true" IsSelectable="false" IsEnabled="true" BackgroundColor="Transparent">
+        <c:ButtonStyle.Icon>
+            <ImageViewStyle Size="48sp, 48sp">
+                <ImageViewStyle.ResourceUrl>
+                    <Selector x:TypeArguments="x:String" Normal="*Resource*/images/light/cross_button.png" Pressed="*Resource*/images/light/cross_button_selected.png" />
+                </ImageViewStyle.ResourceUrl>
+            </ImageViewStyle>
+        </c:ButtonStyle.Icon>
+    </c:ButtonStyle>
+
+</Theme>
\ No newline at end of file
diff --git a/TrayApplication/shared/res/TrayApplication.png b/TrayApplication/shared/res/TrayApplication.png
new file mode 100644 (file)
index 0000000..9f3cb98
Binary files /dev/null and b/TrayApplication/shared/res/TrayApplication.png differ
diff --git a/TrayApplication/tizen-manifest.xml b/TrayApplication/tizen-manifest.xml
new file mode 100644 (file)
index 0000000..1c785b5
--- /dev/null
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest package="org.tizen.TrayApplication" version="1.0.0" api-version="6" xmlns="http://tizen.org/ns/packages">
+    <profile name="common" />
+    <ui-application appid="org.tizen.TrayApplication" exec="TrayApplication.dll" multiple="false" nodisplay="false" taskmanage="true" type="dotnet" launch_mode="single">
+        <label>TrayApplication</label>
+        <icon>TrayApplication.png</icon>
+        <metadata key="http://tizen.org/metadata/prefer_dotnet_aot" value="true" />
+        <splash-screens />
+    </ui-application>
+    <shortcut-list />
+    <privileges>
+        <privilege>http://tizen.org/privilege/windowsystem.admin</privilege>
+        <privilege>http://tizen.org/privilege/window.priority.set</privilege>
+        <privilege>http://tizen.org/privilege/appmanager.launch</privilege>
+        <privilege>http://tizen.org/privilege/systemsettings</privilege>
+        <privilege>http://tizen.org/privilege/content.write</privilege>
+        <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/packagemanager.info</privilege>
+    </privileges>
+    <dependencies />
+    <provides-appdefined-privileges />
+</manifest>
diff --git a/packaging/org.tizen.TrayApplication.spec b/packaging/org.tizen.TrayApplication.spec
new file mode 100644 (file)
index 0000000..a4dde1d
--- /dev/null
@@ -0,0 +1,36 @@
+Name:       org.tizen.TrayApplication
+Summary:    org.tizen.TrayApplication
+Version:    1.0.0
+Release:    1
+Group:      N/A
+License:    Apache-2.0
+Source0:    %{name}-%{version}.tar.gz
+
+ExclusiveArch:  %{ix86} %{arm} aarch64
+
+
+BuildRequires:  pkgconfig(libtzplatform-config)
+Requires(post):  /usr/bin/tpk-backend
+
+%define internal_name org.tizen.TrayApplication
+%define preload_tpk_path %{TZ_SYS_RO_APP}/.preload-tpk
+
+%description
+profile/iot/apps/dotnet/music-player
+This is application to access recent apps and device settings
+
+%prep
+%setup -q
+
+%build
+
+%install
+rm -rf %{buildroot}
+mkdir -p %{buildroot}/%{preload_tpk_path}
+install packaging/%{internal_name}-%{version}.tpk %{buildroot}/%{preload_tpk_path}/
+
+%post
+
+%files
+%defattr(-,root,root,-)
+%{preload_tpk_path}/*