/* * Copyright (c) 2023 Samsung Electronics Co., Ltd All Rights Reserved * * Licensed under the Apache License, Version 2.0 (the License); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an AS IS BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ using System; using System.Collections.Generic; using System.Linq; using System.IO; using Tizen.Applications; using System.ComponentModel; using System.Runtime.InteropServices; using System.Runtime.Loader; using System.Reflection; using System.Threading.Tasks; using System.Security.AccessControl; using SystemIO = System.IO; namespace Tizen.NUI { /// /// This class has the methods and events of the NUIGadgetManager. /// /// 10 [EditorBrowsable(EditorBrowsableState.Never)] public static class NUIGadgetManager { private static readonly Dictionary _gadgetInfos = new Dictionary(); private static readonly List _gadgets = new List(); static NUIGadgetManager() { IntPtr gadgetPkgIds = Interop.Libc.GetEnviornmentVariable("GADGET_PKGIDS"); if (gadgetPkgIds != IntPtr.Zero) { string packages = Marshal.PtrToStringAnsi(gadgetPkgIds); if (string.IsNullOrEmpty(packages)) { Log.Warn("There is no resource packages"); } else { foreach (string packageId in packages.Split(':').ToList()) { NUIGadgetInfo info = NUIGadgetInfo.CreateNUIGadgetInfo(packageId); if (info != null) { _gadgetInfos.Add(info.ResourceType, info); } } } } else { Log.Warn("Failed to get environment variable"); } var context = (CoreApplication)CoreApplication.Current; context.AppControlReceived += OnAppControlReceived; context.LowMemory += OnLowMemory; context.LowBattery += OnLowBattery; context.LocaleChanged += OnLocaleChanged; context.RegionFormatChanged += OnRegionFormatChanged; context.DeviceOrientationChanged += OnDeviceOrientationChanged; } private static void OnAppControlReceived(object sender, AppControlReceivedEventArgs args) { HandleAppControl(args); } private static void OnLowMemory(object sender, LowMemoryEventArgs args) { HandleEvents(NUIGadgetEventType.LowMemory, args); } private static void OnLowBattery(object sender, LowBatteryEventArgs args) { HandleEvents(NUIGadgetEventType.LowBattery, args); } private static void OnLocaleChanged(object sender, LocaleChangedEventArgs args) { HandleEvents(NUIGadgetEventType.LocaleChanged, args); } private static void OnRegionFormatChanged(object sender, RegionFormatChangedEventArgs args) { HandleEvents(NUIGadgetEventType.RegionFormatChanged, args); } private static void OnDeviceOrientationChanged(object sender, DeviceOrientationEventArgs args) { HandleEvents(NUIGadgetEventType.DeviceORientationChanged, args); } /// /// Occurs when the lifecycle of the NUIGadget is changed. /// /// 10 public static event EventHandler NUIGadgetLifecycleChanged; private static void OnNUIGadgetLifecycleChanged(object sender, NUIGadgetLifecycleChangedEventArgs args) { NUIGadgetLifecycleChanged?.Invoke(sender, args); if (args.State == NUIGadgetLifecycleState.Destroyed) { args.Gadget.LifecycleChanged -= OnNUIGadgetLifecycleChanged; _gadgets.Remove(args.Gadget); } } private static NUIGadgetInfo Find(string resourceType) { if (!_gadgetInfos.TryGetValue(resourceType, out NUIGadgetInfo info)) { throw new ArgumentException("Failed to find NUIGadgetInfo. resource type: " + resourceType); } return info; } /// /// Loads an assembly of the NUIGadget. /// /// The resource type of the NUIGadget package. /// Thrown when failed because of a invalid argument. /// Thrown when failed because of an invalid operation. /// 10 public static void Load(string resourceType) { Load(resourceType, true); } /// /// Loads an assembly of the NUIGadget. /// /// The resource type of the NUIGadget package. /// The flag if ture, use a default load context. Otherwise, use a new load context. /// Thrown when failed because of a invalid argument. /// Thrown when failed because of an invalid operation. /// 10 public static void Load(string resourceType, bool useDefaultContext) { if (string.IsNullOrEmpty(resourceType)) { throw new ArgumentException("Invalid argument"); } NUIGadgetInfo info = Find(resourceType); Load(info, useDefaultContext); } /// /// Unloads the loaded assembly of the NUIGadget. /// /// The resource type of the NUIGadget package. /// Thrown when failed because of a invalid argument. /// 10 public static void Unload(string resourceType) { if (string.IsNullOrEmpty(resourceType)) { throw new ArgumentException("Invalid argument"); } NUIGadgetInfo info = Find(resourceType); Unload(info); } private static void Unload(NUIGadgetInfo info) { if (info == null) { throw new ArgumentException("Invalid argument"); } lock (info) { if (info.NUIGadgetAssembly != null && info.NUIGadgetAssembly.IsLoaded) { info.NUIGadgetAssembly.Unload(); info.NUIGadgetAssembly = null; } } } private static void Load(NUIGadgetInfo info, bool useDefaultContext) { if (info == null) { throw new ArgumentException("Invalid argument"); } try { lock (info) { if (useDefaultContext) { if (info.Assembly == null) { Log.Warn("NUIGadget.Load(): " + info.ResourcePath + info.ExecutableFile + " ++"); info.Assembly = Assembly.Load(SystemIO.Path.GetFileNameWithoutExtension(info.ExecutableFile)); Log.Warn("NUIGadget.Load(): " + info.ResourcePath + info.ExecutableFile + " --"); } } else { if (info.NUIGadgetAssembly == null) { Log.Warn("NUIGadgetAssembly.Load(): " + info.ResourcePath + info.ExecutableFile + " ++"); info.NUIGadgetAssembly = new NUIGadgetAssembly(info.ResourcePath + info.ExecutableFile); info.NUIGadgetAssembly.Load(); Log.Warn("NUIGadgetAssembly.Load(): " + info.ResourcePath + info.ExecutableFile + " --"); } } } } catch (FileLoadException e) { throw new InvalidOperationException(e.Message); } catch (BadImageFormatException e) { throw new InvalidOperationException(e.Message); } } /// /// Adds a NUIGadget to the NUIGadgetManager. /// /// The resource type of the NUIGadget package. /// The class name of the NUIGadget. /// The NUIGadget object. /// Thrown when failed because of a invalid argument. /// Thrown when failed because of an invalid operation. /// 10 public static NUIGadget Add(string resourceType, string className) { return Add(resourceType, className, true); } /// /// Adds a NUIGadget to the NUIGadgetManager. /// /// The resource type of the NUIGadget package. /// The class name of the NUIGadget. /// The flag it true, use a default context. Otherwise, use a new load context. /// The NUIGadget object. /// Thrown when failed because of a invalid argument. /// Thrown when failed because of an invalid operation. /// 10 public static NUIGadget Add(string resourceType, string className, bool useDefaultContext) { if (string.IsNullOrEmpty(resourceType) || string.IsNullOrEmpty(className)) { throw new ArgumentException("Invalid argument"); } NUIGadgetInfo info = Find(resourceType); Load(info, useDefaultContext); NUIGadget gadget = useDefaultContext ? info.Assembly.CreateInstance(className, true) as NUIGadget : info.NUIGadgetAssembly.CreateInstance(className); if (gadget == null) { throw new InvalidOperationException("Failed to create instance. className: " + className); } gadget.NUIGadgetInfo = info; gadget.ClassName = className; gadget.NUIGadgetResourceManager = new NUIGadgetResourceManager(info); gadget.LifecycleChanged += OnNUIGadgetLifecycleChanged; if (!gadget.Create()) { throw new InvalidOperationException("The View MUST be created"); } _gadgets.Add(gadget); return gadget; } /// /// Gets the instance of the running NUIGadgets. /// /// The NUIGadget list. /// 10 public static IEnumerable GetGadgets() { return _gadgets; } /// /// Gets the information of the available NUIGadgets. /// /// /// This method only returns the available gadget informations, not all installed gadget informations. /// The resource package of the NUIGadget can set the allowed packages using "allowed-package". /// When executing an application, the platform mounts the resource package into the resource path of the application. /// /// The NUIGadgetInfo list. /// 10 public static IEnumerable GetGadgetInfos() { return _gadgetInfos.Values.ToList(); } /// /// Removes the NUIGadget from the NUIGadgetManager. /// /// The NUIGadget object. /// 10 public static void Remove(NUIGadget gadget) { if (gadget == null || !_gadgets.Contains(gadget)) { return; } if (gadget.State == NUIGadgetLifecycleState.Destroyed) { return; } _gadgets.Remove(gadget); CoreApplication.Post(() => { Log.Warn("ResourceType: " + gadget.NUIGadgetInfo.ResourceType + ", State: " + gadget.State); gadget.Finish(); }); } /// /// Removes all NUIGadgets from the NUIGadgetManager. /// /// 10 public static void RemoveAll() { for (int i = _gadgets.Count - 1; i >= 0; i--) { Remove(_gadgets[i]); } } /// /// Resumes the running NUIGadget. /// /// The NUIGadget object. /// 10 public static void Resume(NUIGadget gadget) { if (!_gadgets.Contains(gadget)) { return; } CoreApplication.Post(() => { Log.Warn("ResourceType: " + gadget.NUIGadgetInfo.ResourceType + ", State: " + gadget.State); gadget.Resume(); }); } /// /// Pauses the running NUIGadget. /// /// The NUIGadget object. /// 10 public static void Pause(NUIGadget gadget) { if (!_gadgets.Contains(gadget)) { return; } CoreApplication.Post(() => { Log.Warn("ResourceType: " + gadget.NUIGadgetInfo.ResourceType + ", State: " + gadget.State); gadget.Pause(); }); } /// /// Sends the appcontrol to the running NUIGadget. /// /// The NUIGadget object. /// The appcontrol object. /// Thrown when failed because of a invalid argument. /// Thrown when failed because the argument is null. /// 10 public static void SendAppControl(NUIGadget gadget, AppControl appControl) { if (gadget == null) { throw new ArgumentNullException(nameof(gadget)); } if (!_gadgets.Contains(gadget)) { throw new ArgumentException("Invalid argument"); } if (appControl == null) { throw new ArgumentNullException(nameof(appControl)); } gadget.HandleAppControlReceivedEvent(new AppControlReceivedEventArgs(new ReceivedAppControl(appControl.SafeAppControlHandle))); } internal static bool HandleAppControl(AppControlReceivedEventArgs args) { var extraData = args.ReceivedAppControl?.ExtraData; if (extraData == null||!extraData.TryGet("__K_GADGET_RES_TYPE", out string resourceType) || !extraData.TryGet("__K_GADGET_CLASS_NAME", out string className)) { return false; } foreach (NUIGadget gadget in _gadgets) { if (gadget.NUIGadgetInfo.ResourceType == resourceType && gadget.ClassName == className) { gadget.HandleAppControlReceivedEvent(args); return true; } } return false; } internal static void HandleEvents(NUIGadgetEventType eventType, EventArgs args) { foreach (NUIGadget gadget in _gadgets) { gadget.HandleEvents(eventType, args); } } } }