2 using System.Collections.Generic;
3 using System.ComponentModel;
5 using System.Linq.Expressions;
6 using System.Reflection;
7 using Xamarin.Forms.Internals;
8 using Xamarin.Forms.Platform.Tizen;
10 using Tizen.Applications;
11 using TSystemInfo = Tizen.System.Information;
12 using TSystemSetting = Tizen.System.SystemSettings;
13 using EWindow = ElmSharp.Window;
14 using ELayout = ElmSharp.Layout;
15 using DeviceOrientation = Xamarin.Forms.Internals.DeviceOrientation;
16 using Xamarin.Forms.PlatformConfiguration.TizenSpecific;
17 using ElmSharp.Wearable;
18 using Tizen.Wearable.CircularUI.Forms;
20 namespace Xamarin.Forms
22 public enum StaticRegistrarStrategy
29 public enum PlatformType
35 public class InitializationOptions
37 public CoreApplication Context { get; set; }
38 public bool UseDeviceIndependentPixel { get; set; }
39 public HandlerAttribute[] Handlers { get; set; }
40 public Dictionary<Type, Func<IRegisterable>> CustomHandlers { get; set; } // for static registers
41 public Assembly[] Assemblies { get; set; }
42 public EffectScope[] EffectScopes { get; set; }
43 public InitializationFlags Flags { get; set; }
44 public StaticRegistrarStrategy StaticRegistarStrategy { get; set; }
45 public PlatformType PlatformType { get; set; }
46 public bool UseMessagingCenter { get; set; } = true;
47 public bool UseStyle { get; set; } = true;
48 public bool UseShell { get; set; } = true;
49 public bool UseVisual { get; set; } = true;
52 public struct EffectScope
55 public ExportEffectAttribute[] Effects;
58 public InitializationOptions(CoreApplication application)
60 Context = application;
63 public InitializationOptions(CoreApplication application, bool useDeviceIndependentPixel, HandlerAttribute[] handlers)
65 Context = application;
66 UseDeviceIndependentPixel = useDeviceIndependentPixel;
70 public InitializationOptions(CoreApplication application, bool useDeviceIndependentPixel, params Assembly[] assemblies)
72 Context = application;
73 UseDeviceIndependentPixel = useDeviceIndependentPixel;
74 Assemblies = assemblies;
77 public void UseStaticRegistrar(StaticRegistrarStrategy strategy, Dictionary<Type, Func<IRegisterable>> customHandlers = null, bool disableCss = false)
79 StaticRegistarStrategy = strategy;
80 CustomHandlers = customHandlers;
81 if (disableCss) // about 10ms
82 Flags = InitializationFlags.DisableCss;
86 public static class Forms
88 static Lazy<string> s_profile = new Lazy<string>(() =>
90 //TODO : Fix me if elm_config_profile_get() unavailable
91 return Elementary.GetProfile();
94 static Lazy<int> s_dpi = new Lazy<int>(() =>
97 if (s_profile.Value == "tv")
99 // Use fixed DPI value (72) if TV profile
102 TSystemInfo.TryGetValue<int>("http://tizen.org/feature/screen.dpi", out dpi);
106 static Lazy<double> s_elmScale = new Lazy<double>(() =>
108 // 72.0 is from EFL which is using fixed DPI value (72.0) to determine font size internally. Thus, we are restoring the size by deviding the DPI by 72.0 here.
109 return s_dpi.Value / 72.0 / Elementary.GetScale();
112 class TizenDeviceInfo : DeviceInfo
114 readonly Size pixelScreenSize;
116 readonly Size scaledScreenSize;
118 readonly double scalingFactor;
120 readonly string profile;
122 public override Size PixelScreenSize
126 return this.pixelScreenSize;
130 public override Size ScaledScreenSize
134 return this.scaledScreenSize;
138 public override double ScalingFactor
142 return this.scalingFactor;
146 public string Profile
154 public TizenDeviceInfo() : this(getScreenWidth(), getScreenHeight())
158 static int getScreenWidth()
160 if (TSystemInfo.TryGetValue("http://tizen.org/feature/screen.width", out int width))
166 throw new InvalidOperationException("Can not get screen.Width");
169 static int getScreenHeight()
171 if (TSystemInfo.TryGetValue("http://tizen.org/feature/screen.height", out int height))
177 throw new InvalidOperationException("Can not get screen.Height");
180 TizenDeviceInfo(int width, int height)
182 pixelScreenSize = new Size(width, height);
184 scalingFactor = 1.0; // scaling is disabled, we're using pixels as Xamarin's geometry units
185 if (s_useDeviceIndependentPixel)
187 scalingFactor = s_dpi.Value / 160.0;
190 scaledScreenSize = new Size(width / scalingFactor, height / scalingFactor);
191 profile = s_profile.Value;
194 public TizenDeviceInfo RefreshByDIP()
196 return new TizenDeviceInfo((int)pixelScreenSize.Width, (int)pixelScreenSize.Height);
200 static bool s_useDeviceIndependentPixel = false;
202 static StaticRegistrarStrategy s_staticRegistrarStrategy = StaticRegistrarStrategy.None;
204 static PlatformType s_platformType = PlatformType.Defalut;
206 static bool s_useMessagingCenter = true;
208 public static event EventHandler<ViewInitializedEventArgs> ViewInitialized;
210 public static CoreApplication Context
216 public static EvasObject NativeParent
221 public static ELayout BaseLayout => NativeParent as ELayout;
223 public static CircleSurface CircleSurface
228 [EditorBrowsable(EditorBrowsableState.Never)]
229 public static Element RotaryFocusObject
234 public static bool IsInitialized
240 public static bool IsPreloaded
246 public static DeviceOrientation NaturalOrientation { get; } = GetDeviceOrientation();
248 public static StaticRegistrarStrategy StaticRegistrarStrategy => s_staticRegistrarStrategy;
250 public static PlatformType PlatformType => s_platformType;
252 public static bool UseMessagingCenter => s_useMessagingCenter;
254 internal static TizenTitleBarVisibility TitleBarVisibility
260 static DeviceOrientation GetDeviceOrientation()
264 TSystemInfo.TryGetValue<int>("http://tizen.org/feature/screen.width", out width);
265 TSystemInfo.TryGetValue<int>("http://tizen.org/feature/screen.height", out height);
269 return DeviceOrientation.Portrait;
273 return DeviceOrientation.Landscape;
277 internal static void SendViewInitialized(this VisualElement self, EvasObject nativeView)
279 EventHandler<ViewInitializedEventArgs> viewInitialized = Forms.ViewInitialized;
280 if (viewInitialized != null)
282 viewInitialized.Invoke(self, new ViewInitializedEventArgs
285 NativeView = nativeView
290 static IReadOnlyList<string> s_flags;
291 public static IReadOnlyList<string> Flags => s_flags ?? (s_flags = new string[0]);
293 public static void SetFlags(params string[] flags)
297 throw new InvalidOperationException($"{nameof(SetFlags)} must be called before {nameof(Init)}");
300 s_flags = (string[])flags.Clone();
301 if (s_flags.Contains("Profile"))
305 public static void SetTitleBarVisibility(TizenTitleBarVisibility visibility)
307 TitleBarVisibility = visibility;
310 public static TOut GetHandler<TOut>(Type type, params object[] args) where TOut : class, IRegisterable
312 if (s_staticRegistrarStrategy == StaticRegistrarStrategy.None)
314 // Find hander in internal registrar, that is using reflection (default).
315 return Internals.Registrar.Registered.GetHandler<TOut>(type, args);
319 // 1. Find hander in static registrar first
320 TOut ret = StaticRegistrar.Registered.GetHandler<TOut>(type, args);
322 // 2. If there is no handler, try to find hander in internal registrar, that is using reflection.
323 if (ret == null && s_staticRegistrarStrategy == StaticRegistrarStrategy.All)
325 ret = Internals.Registrar.Registered.GetHandler<TOut>(type, args);
331 public static TOut GetHandlerForObject<TOut>(object obj) where TOut : class, IRegisterable
333 if (s_staticRegistrarStrategy == StaticRegistrarStrategy.None)
335 // Find hander in internal registrar, that is using reflection (default).
336 return Internals.Registrar.Registered.GetHandlerForObject<TOut>(obj);
340 // 1. Find hander in static registrar first
341 TOut ret = StaticRegistrar.Registered.GetHandlerForObject<TOut>(obj);
343 // 2. If there is no handler, try to find hander in internal registrar, that is using reflection.
344 if (ret == null && s_staticRegistrarStrategy == StaticRegistrarStrategy.All)
346 ret = Internals.Registrar.Registered.GetHandlerForObject<TOut>(obj);
352 public static TOut GetHandlerForObject<TOut>(object obj, params object[] args) where TOut : class, IRegisterable
354 if (s_staticRegistrarStrategy == StaticRegistrarStrategy.None)
356 // Find hander in internal registrar, that is using reflection (default).
357 return Internals.Registrar.Registered.GetHandlerForObject<TOut>(obj, args);
361 // 1. Find hander in static registrar first without fallback handler.
362 TOut ret = StaticRegistrar.Registered.GetHandlerForObject<TOut>(obj, args);
364 // 2. If there is no handler, try to find hander in internal registrar, that is using reflection.
365 if (ret == null && s_staticRegistrarStrategy == StaticRegistrarStrategy.All)
367 ret = StaticRegistrar.Registered.GetHandlerForObject<TOut>(obj, args);
373 public static void Init(CoreApplication application)
375 Init(application, false);
378 public static void Init(CoreApplication application, bool useDeviceIndependentPixel)
380 s_useDeviceIndependentPixel = useDeviceIndependentPixel;
381 SetupInit(application);
384 public static void Init(InitializationOptions options)
386 SetupInit(Context, options);
389 static void SetupInit(CoreApplication application, InitializationOptions options = null)
391 Context = application;
395 Internals.Log.Listeners.Add(new XamarinLogListener());
396 if (System.Threading.SynchronizationContext.Current == null)
398 TizenSynchronizationContext.Initialize();
400 Elementary.Initialize();
401 Elementary.ThemeOverlay();
402 Utility.AppendGlobalFontPath(@"/usr/share/fonts");
404 Device.PlatformServices = new TizenPlatformServices();
405 if (Device.info != null)
407 ((TizenDeviceInfo)Device.info).Dispose();
411 Device.Info = new Forms.TizenDeviceInfo();
412 Device.SetFlags(s_flags);
414 else if (Device.info != null)
416 var info = ((TizenDeviceInfo)Device.info).RefreshByDIP();
417 ((TizenDeviceInfo)Device.info).Dispose();
421 string profile = ((TizenDeviceInfo)Device.Info).Profile;
422 if (profile == "mobile")
424 Device.SetIdiom(TargetIdiom.Phone);
426 else if (profile == "tv")
428 Device.SetIdiom(TargetIdiom.TV);
430 else if (profile == "desktop")
432 Device.SetIdiom(TargetIdiom.Desktop);
434 else if (profile == "wearable")
436 Device.SetIdiom(TargetIdiom.Watch);
440 Device.SetIdiom(TargetIdiom.Unsupported);
443 if (!Forms.IsInitialized && !Forms.IsPreloaded)
445 StaticRegistrar.RegisterHandlers(CircularUIForms.StaticHandlers);
446 CircularUIForms.RegisterDependencyService();
447 TizenPlatformServices.AppDomain.CurrentDomain.AddAssembly(Assembly.GetAssembly(typeof(Xamarin.Forms.View)));
450 if (!Forms.IsInitialized || Forms.IsPreloaded)
454 s_useDeviceIndependentPixel = options.UseDeviceIndependentPixel;
455 s_platformType = options.PlatformType;
456 s_useMessagingCenter = options.UseMessagingCenter;
457 OptionalFeatureValues.UseStyle = options.UseStyle;
458 OptionalFeatureValues.UseShell = options.UseShell;
459 OptionalFeatureValues.UseVisual = options.UseVisual;
461 if (options.Assemblies != null && options.Assemblies.Length > 0)
463 TizenPlatformServices.AppDomain.CurrentDomain.AddAssemblies(options.Assemblies);
467 if (options.Handlers != null)
469 Internals.Registrar.RegisterRenderers(options.Handlers);
473 // Add Xamarin.Forms.Core assembly by default to apply the styles.
474 if (!Forms.IsPreloaded)
476 TizenPlatformServices.AppDomain.CurrentDomain.AddAssembly(Assembly.GetAssembly(typeof(Xamarin.Forms.View)));
480 if (options.StaticRegistarStrategy != StaticRegistrarStrategy.None)
482 s_staticRegistrarStrategy = options.StaticRegistarStrategy;
483 StaticRegistrar.RegisterHandlers(options.CustomHandlers);
485 if (options.StaticRegistarStrategy == StaticRegistrarStrategy.All)
487 Registrar.RegisterAll(new Type[]
489 typeof(ExportRendererAttribute),
490 typeof(ExportImageSourceHandlerAttribute),
491 typeof(ExportCellAttribute),
492 typeof(ExportHandlerAttribute),
493 typeof(ExportFontAttribute)
499 // In .NETCore, AppDomain feature is not supported.
500 // The list of assemblies returned by AppDomain.GetAssemblies() method should be registered manually.
501 // The assembly of the executing application and referenced assemblies of it are added into the list here.
502 TizenPlatformServices.AppDomain.CurrentDomain.RegisterAssemblyRecursively(application.GetType().GetTypeInfo().Assembly);
504 Registrar.RegisterAll(new Type[]
506 typeof(ExportRendererAttribute),
507 typeof(ExportImageSourceHandlerAttribute),
508 typeof(ExportCellAttribute),
509 typeof(ExportHandlerAttribute),
510 typeof(ExportFontAttribute)
516 var effectScopes = options.EffectScopes;
517 if (effectScopes != null)
519 for (var i = 0; i < effectScopes.Length; i++)
521 var effectScope = effectScopes[i];
522 Internals.Registrar.RegisterEffects(effectScope.Name, effectScope.Effects);
527 var flags = options.Flags;
528 var noCss = (flags & InitializationFlags.DisableCss) != 0;
530 Internals.Registrar.RegisterStylesheets();
534 // In .NETCore, AppDomain feature is not supported.
535 // The list of assemblies returned by AppDomain.GetAssemblies() method should be registered manually.
536 // The assembly of the executing application and referenced assemblies of it are added into the list here.
537 TizenPlatformServices.AppDomain.CurrentDomain.RegisterAssemblyRecursively(application.GetType().GetTypeInfo().Assembly);
539 Registrar.RegisterAll(new Type[]
541 typeof(ExportRendererAttribute),
542 typeof(ExportImageSourceHandlerAttribute),
543 typeof(ExportCellAttribute),
544 typeof(ExportHandlerAttribute),
545 typeof(ExportFontAttribute)
550 Color.SetAccent(GetAccentColor(profile));
551 ExpressionSearch.Default = new TizenExpressionSearch();
552 IsInitialized = true;
555 static Color GetAccentColor(string profile)
557 // On Windows Phone, this is the complementary color chosen by the user.
558 // Good Windows Phone applications use this as part of their styling to provide a native look and feel.
559 // On iOS and Android this instance is set to a contrasting color that is visible on the default
560 // background but is not the same as the default text color.
565 // [Tizen_3.0]Basic_Interaction_GUI_[REF].xlsx Theme 001 (Default) 1st HSB: 188 70 80
566 return Color.FromRgba(61, 185, 204, 255);
568 return Color.FromRgba(15, 15, 15, 230);
570 // Theme A (Default) 1st HSB: 207 75 16
571 return Color.FromRgba(10, 27, 41, 255);
578 /// Converts the dp into pixel considering current DPI value.
581 /// Use this API if you want to get pixel size without scaling factor.
583 /// <param name="dp"></param>
584 /// <returns></returns>
585 public static int ConvertToPixel(double dp)
587 return (int)Math.Round(dp * s_dpi.Value / 160.0);
591 /// Converts the dp into pixel by using scaling factor.
594 /// Use this API if you want to get pixel size from dp by using scaling factor.
595 /// If the scaling factor is 1.0 by user setting, the same value is returned. This is mean that user doesn't want to pixel independent metric.
597 /// <param name="dp"></param>
598 /// <returns></returns>
599 public static int ConvertToScaledPixel(double dp)
601 return (int)Math.Round(dp * Device.Info.ScalingFactor);
605 /// Converts the pixel into dp value by using scaling factor.
608 /// If the scaling factor is 1.0 by user setting, the same value is returned. This is mean that user doesn't want to pixel independent metric.
610 /// <param name="pixel"></param>
611 /// <returns></returns>
612 public static double ConvertToScaledDP(int pixel)
614 return pixel / Device.Info.ScalingFactor;
618 /// Converts the pixel into dp value by using scaling factor.
621 /// If the scaling factor is 1.0 by user setting, the same value is returned. This is mean that user doesn't want to pixel independent metric.
623 /// <param name="pixel"></param>
624 /// <returns></returns>
625 public static double ConvertToScaledDP(double pixel)
627 return pixel / Device.Info.ScalingFactor;
631 /// Converts the sp into EFL's font size metric (EFL point).
633 /// <param name="sp"></param>
634 /// <returns></returns>
635 public static int ConvertToEflFontPoint(double sp)
637 return (int)Math.Round(sp * s_elmScale.Value);
641 /// Convert the EFL's point into sp.
643 /// <param name="eflPt"></param>
644 /// <returns></returns>
645 public static double ConvertToDPFont(int eflPt)
647 return eflPt / s_elmScale.Value;
651 /// Get the EFL's profile
653 /// <returns></returns>
654 public static string GetProfile()
656 return s_profile.Value;
659 // for internal use only
660 [EditorBrowsable(EditorBrowsableState.Never)]
661 public static EvasObject Preload()
663 var dummyApp = new DummyFormsApplication();
664 Init(dummyApp, false);
667 EWindow eWindow = null;
668 ELayout eLayout = null;
669 CircleSurface eCircleSurface = null;
670 var typeWin = typeof(EWindow);
671 var methodInfo = typeWin.GetMethod("CreateWindow", BindingFlags.NonPublic | BindingFlags.Static);
672 if (methodInfo != null)
674 eWindow = (EWindow)methodInfo.Invoke(null, new object[] { "FormsWindow" });
675 eLayout = (ELayout)eWindow.GetType().GetProperty("BaseLayout")?.GetValue(eWindow);
676 eCircleSurface = (CircleSurface)eWindow.GetType().GetProperty("BaseCircleSurface")?.GetValue(eWindow);
679 PreloadedWindow preloadedWindow = null;
680 if (eWindow != null && eLayout != null)
682 preloadedWindow = new PreloadedWindow(eWindow, eLayout, eCircleSurface);
686 preloadedWindow = new PreloadedWindow();
689 var locale = TSystemSetting.LocaleLanguage;
690 TSystemSetting.LocaleLanguageChanged += DummyHandler;
691 TSystemSetting.LocaleLanguageChanged -= DummyHandler;
692 void DummyHandler(object sender, System.EventArgs e) { }
698 typeof(NavigationPage),
700 typeof(ContentPresenter),
704 typeof(TemplatedView),
706 typeof(AbsoluteLayout),
707 typeof(RelativeLayout),
723 typeof(ActivityIndicator),
725 typeof(CarouselView),
726 typeof(CollectionView),
734 typeof(VisualElement),
738 typeof(NavigableElement),
741 typeof(TapGestureRecognizer),
742 typeof(PropertyCondition),
744 typeof(StructuredItemsView),
745 typeof(SearchHandler),
748 foreach (var type in types)
750 System.Runtime.CompilerServices.RuntimeHelpers.RunClassConstructor(type.TypeHandle);
752 global::Xamarin.Forms.Platform.Tizen.Native.NativeFactory.PrecreateNatives(preloadedWindow.Window);
753 global::Tizen.Wearable.CircularUI.Forms.CircularUIForms.Preload(preloadedWindow.Window);
755 return preloadedWindow.Window;
759 class TizenExpressionSearch : ExpressionVisitor, IExpressionSearch
761 List<object> _results;
764 public List<T> FindObjects<T>(Expression expression) where T : class
766 _results = new List<object>();
767 _targetType = typeof(T);
769 return _results.Select(o => o as T).ToList();
772 protected override Expression VisitMember(MemberExpression node)
774 if (node.Expression is ConstantExpression && node.Member is FieldInfo)
776 var container = ((ConstantExpression)node.Expression).Value;
777 var value = ((FieldInfo)node.Member).GetValue(container);
779 if (_targetType.IsInstanceOfType(value))
782 return base.VisitMember(node);
786 class DummyFormsApplication : FormsApplication { }