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 PTizen = Xamarin.Forms.Platform.Tizen;
18 using ElmSharp.Wearable;
19 using Tizen.Wearable.CircularUI.Forms;
21 namespace Xamarin.Forms
23 public enum StaticRegistrarStrategy
30 public enum PlatformType
36 public class InitializationOptions
38 public CoreApplication Context { get; set; }
39 public bool UseDeviceIndependentPixel { get; set; }
40 public HandlerAttribute[] Handlers { get; set; }
41 public Dictionary<Type, Func<IRegisterable>> CustomHandlers { get; set; } // for static registers
42 public Assembly[] Assemblies { get; set; }
43 public EffectScope[] EffectScopes { get; set; }
44 public InitializationFlags Flags { get; set; }
45 public StaticRegistrarStrategy StaticRegistarStrategy { get; set; }
46 public PlatformType PlatformType { get; set; }
47 public bool UseMessagingCenter { get; set; } = true;
48 public bool UseStyle { get; set; } = true;
49 public bool UseShell { get; set; } = true;
50 public bool UseVisual { get; set; } = true;
53 public struct EffectScope
56 public ExportEffectAttribute[] Effects;
59 public InitializationOptions(CoreApplication application)
61 Context = application;
64 public InitializationOptions(CoreApplication application, bool useDeviceIndependentPixel, HandlerAttribute[] handlers)
66 Context = application;
67 UseDeviceIndependentPixel = useDeviceIndependentPixel;
71 public InitializationOptions(CoreApplication application, bool useDeviceIndependentPixel, params Assembly[] assemblies)
73 Context = application;
74 UseDeviceIndependentPixel = useDeviceIndependentPixel;
75 Assemblies = assemblies;
78 public void UseStaticRegistrar(StaticRegistrarStrategy strategy, Dictionary<Type, Func<IRegisterable>> customHandlers = null, bool disableCss = false)
80 StaticRegistarStrategy = strategy;
81 CustomHandlers = customHandlers;
82 if (disableCss) // about 10ms
83 Flags = InitializationFlags.DisableCss;
87 public static class Forms
89 static Lazy<string> s_profile = new Lazy<string>(() =>
91 //TODO : Fix me if elm_config_profile_get() unavailable
92 return Elementary.GetProfile();
95 static Lazy<int> s_dpi = new Lazy<int>(() =>
98 if (s_profile.Value == "tv")
100 // Use fixed DPI value (72) if TV profile
103 TSystemInfo.TryGetValue<int>("http://tizen.org/feature/screen.dpi", out dpi);
107 static Lazy<double> s_elmScale = new Lazy<double>(() =>
109 // 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.
110 return s_dpi.Value / 72.0 / Elementary.GetScale();
113 class TizenDeviceInfo : DeviceInfo
115 readonly Size pixelScreenSize;
117 readonly Size scaledScreenSize;
119 readonly double scalingFactor;
121 readonly string profile;
123 public override Size PixelScreenSize
127 return this.pixelScreenSize;
131 public override Size ScaledScreenSize
135 return this.scaledScreenSize;
139 public override double ScalingFactor
143 return this.scalingFactor;
147 public string Profile
155 public TizenDeviceInfo() : this(getScreenWidth(), getScreenHeight())
159 static int getScreenWidth()
161 if (TSystemInfo.TryGetValue("http://tizen.org/feature/screen.width", out int width))
167 throw new InvalidOperationException("Can not get screen.Width");
170 static int getScreenHeight()
172 if (TSystemInfo.TryGetValue("http://tizen.org/feature/screen.height", out int height))
178 throw new InvalidOperationException("Can not get screen.Height");
181 TizenDeviceInfo(int width, int height)
183 pixelScreenSize = new Size(width, height);
185 scalingFactor = 1.0; // scaling is disabled, we're using pixels as Xamarin's geometry units
186 if (s_useDeviceIndependentPixel)
188 scalingFactor = s_dpi.Value / 160.0;
191 scaledScreenSize = new Size(width / scalingFactor, height / scalingFactor);
192 profile = s_profile.Value;
195 public TizenDeviceInfo RefreshByDIP()
197 return new TizenDeviceInfo((int)pixelScreenSize.Width, (int)pixelScreenSize.Height);
201 static bool s_useDeviceIndependentPixel = false;
203 static StaticRegistrarStrategy s_staticRegistrarStrategy = StaticRegistrarStrategy.None;
205 static PlatformType s_platformType = PlatformType.Defalut;
207 static bool s_useMessagingCenter = true;
209 public static event EventHandler<ViewInitializedEventArgs> ViewInitialized;
211 public static CoreApplication Context
217 public static EvasObject NativeParent
222 public static ELayout BaseLayout => NativeParent as ELayout;
224 public static CircleSurface CircleSurface
229 [EditorBrowsable(EditorBrowsableState.Never)]
230 public static Element RotaryFocusObject
235 public static bool IsInitialized
241 public static bool IsPreloaded
247 public static DeviceOrientation NaturalOrientation { get; } = GetDeviceOrientation();
249 public static StaticRegistrarStrategy StaticRegistrarStrategy => s_staticRegistrarStrategy;
251 public static PlatformType PlatformType => s_platformType;
253 public static bool UseMessagingCenter => s_useMessagingCenter;
255 internal static TizenTitleBarVisibility TitleBarVisibility
261 static DeviceOrientation GetDeviceOrientation()
265 TSystemInfo.TryGetValue<int>("http://tizen.org/feature/screen.width", out width);
266 TSystemInfo.TryGetValue<int>("http://tizen.org/feature/screen.height", out height);
270 return DeviceOrientation.Portrait;
274 return DeviceOrientation.Landscape;
278 internal static void SendViewInitialized(this VisualElement self, EvasObject nativeView)
280 EventHandler<ViewInitializedEventArgs> viewInitialized = Forms.ViewInitialized;
281 if (viewInitialized != null)
283 viewInitialized.Invoke(self, new ViewInitializedEventArgs
286 NativeView = nativeView
291 static IReadOnlyList<string> s_flags;
292 public static IReadOnlyList<string> Flags => s_flags ?? (s_flags = new string[0]);
294 public static void SetFlags(params string[] flags)
298 throw new InvalidOperationException($"{nameof(SetFlags)} must be called before {nameof(Init)}");
301 s_flags = (string[])flags.Clone();
302 if (s_flags.Contains("Profile"))
306 public static void SetTitleBarVisibility(TizenTitleBarVisibility visibility)
308 TitleBarVisibility = visibility;
311 public static TOut GetHandler<TOut>(Type type, params object[] args) where TOut : class, IRegisterable
313 if (s_staticRegistrarStrategy == StaticRegistrarStrategy.None)
315 // Find hander in internal registrar, that is using reflection (default).
316 return Internals.Registrar.Registered.GetHandler<TOut>(type, args);
320 // 1. Find hander in static registrar first
321 TOut ret = StaticRegistrar.Registered.GetHandler<TOut>(type, args);
323 // 2. If there is no handler, try to find hander in internal registrar, that is using reflection.
324 if (ret == null && s_staticRegistrarStrategy == StaticRegistrarStrategy.All)
326 ret = Internals.Registrar.Registered.GetHandler<TOut>(type, args);
332 public static TOut GetHandlerForObject<TOut>(object obj) where TOut : class, IRegisterable
334 if (s_staticRegistrarStrategy == StaticRegistrarStrategy.None)
336 // Find hander in internal registrar, that is using reflection (default).
337 return Internals.Registrar.Registered.GetHandlerForObject<TOut>(obj);
341 // 1. Find hander in static registrar first
342 TOut ret = StaticRegistrar.Registered.GetHandlerForObject<TOut>(obj);
344 // 2. If there is no handler, try to find hander in internal registrar, that is using reflection.
345 if (ret == null && s_staticRegistrarStrategy == StaticRegistrarStrategy.All)
347 ret = Internals.Registrar.Registered.GetHandlerForObject<TOut>(obj);
353 public static TOut GetHandlerForObject<TOut>(object obj, params object[] args) where TOut : class, IRegisterable
355 if (s_staticRegistrarStrategy == StaticRegistrarStrategy.None)
357 // Find hander in internal registrar, that is using reflection (default).
358 return Internals.Registrar.Registered.GetHandlerForObject<TOut>(obj, args);
362 // 1. Find hander in static registrar first without fallback handler.
363 TOut ret = StaticRegistrar.Registered.GetHandlerForObject<TOut>(obj, args);
365 // 2. If there is no handler, try to find hander in internal registrar, that is using reflection.
366 if (ret == null && s_staticRegistrarStrategy == StaticRegistrarStrategy.All)
368 ret = StaticRegistrar.Registered.GetHandlerForObject<TOut>(obj, args);
374 public static void Init(CoreApplication application)
376 Init(application, false);
379 public static void Init(CoreApplication application, bool useDeviceIndependentPixel)
381 s_useDeviceIndependentPixel = useDeviceIndependentPixel;
382 SetupInit(application);
385 public static void Init(InitializationOptions options)
387 SetupInit(Context, options);
390 static void SetupInit(CoreApplication application, InitializationOptions options = null)
392 Context = application;
396 Internals.Log.Listeners.Add(new XamarinLogListener());
397 if (System.Threading.SynchronizationContext.Current == null)
399 TizenSynchronizationContext.Initialize();
401 Elementary.Initialize();
402 Elementary.ThemeOverlay();
403 Utility.AppendGlobalFontPath(@"/usr/share/fonts");
405 Device.PlatformServices = new TizenPlatformServices();
406 if (Device.info != null)
408 ((TizenDeviceInfo)Device.info).Dispose();
412 Device.Info = new Forms.TizenDeviceInfo();
413 Device.SetFlags(s_flags);
415 else if (Device.info != null)
417 var info = ((TizenDeviceInfo)Device.info).RefreshByDIP();
418 ((TizenDeviceInfo)Device.info).Dispose();
422 string profile = ((TizenDeviceInfo)Device.Info).Profile;
423 if (profile == "mobile")
425 Device.SetIdiom(TargetIdiom.Phone);
427 else if (profile == "tv")
429 Device.SetIdiom(TargetIdiom.TV);
431 else if (profile == "desktop")
433 Device.SetIdiom(TargetIdiom.Desktop);
435 else if (profile == "wearable")
437 Device.SetIdiom(TargetIdiom.Watch);
441 Device.SetIdiom(TargetIdiom.Unsupported);
444 if (!Forms.IsInitialized && !Forms.IsPreloaded)
446 StaticRegistrar.RegisterHandlers(CircularUIForms.StaticHandlers);
447 CircularUIForms.RegisterDependencyService();
448 TizenPlatformServices.AppDomain.CurrentDomain.AddAssembly(Assembly.GetAssembly(typeof(Xamarin.Forms.View)));
451 if (!Forms.IsInitialized || Forms.IsPreloaded)
455 s_useDeviceIndependentPixel = options.UseDeviceIndependentPixel;
456 s_platformType = options.PlatformType;
457 s_useMessagingCenter = options.UseMessagingCenter;
458 OptionalFeatureValues.UseStyle = options.UseStyle;
459 OptionalFeatureValues.UseShell = options.UseShell;
460 OptionalFeatureValues.UseVisual = options.UseVisual;
462 if (options.Assemblies != null && options.Assemblies.Length > 0)
464 TizenPlatformServices.AppDomain.CurrentDomain.AddAssemblies(options.Assemblies);
468 if (options.Handlers != null)
470 Internals.Registrar.RegisterRenderers(options.Handlers);
474 // Add Xamarin.Forms.Core assembly by default to apply the styles.
475 if (!Forms.IsPreloaded)
477 TizenPlatformServices.AppDomain.CurrentDomain.AddAssembly(Assembly.GetAssembly(typeof(Xamarin.Forms.View)));
481 if (options.StaticRegistarStrategy != StaticRegistrarStrategy.None)
483 s_staticRegistrarStrategy = options.StaticRegistarStrategy;
484 StaticRegistrar.RegisterHandlers(options.CustomHandlers);
486 if (options.StaticRegistarStrategy == StaticRegistrarStrategy.All)
488 Registrar.RegisterAll(new Type[]
490 typeof(ExportRendererAttribute),
491 typeof(ExportImageSourceHandlerAttribute),
492 typeof(ExportCellAttribute),
493 typeof(ExportHandlerAttribute),
494 typeof(ExportFontAttribute)
500 // In .NETCore, AppDomain feature is not supported.
501 // The list of assemblies returned by AppDomain.GetAssemblies() method should be registered manually.
502 // The assembly of the executing application and referenced assemblies of it are added into the list here.
503 TizenPlatformServices.AppDomain.CurrentDomain.RegisterAssemblyRecursively(application.GetType().GetTypeInfo().Assembly);
505 Registrar.RegisterAll(new Type[]
507 typeof(ExportRendererAttribute),
508 typeof(ExportImageSourceHandlerAttribute),
509 typeof(ExportCellAttribute),
510 typeof(ExportHandlerAttribute),
511 typeof(ExportFontAttribute)
517 var effectScopes = options.EffectScopes;
518 if (effectScopes != null)
520 for (var i = 0; i < effectScopes.Length; i++)
522 var effectScope = effectScopes[i];
523 Internals.Registrar.RegisterEffects(effectScope.Name, effectScope.Effects);
528 var flags = options.Flags;
529 var noCss = (flags & InitializationFlags.DisableCss) != 0;
531 Internals.Registrar.RegisterStylesheets();
535 // In .NETCore, AppDomain feature is not supported.
536 // The list of assemblies returned by AppDomain.GetAssemblies() method should be registered manually.
537 // The assembly of the executing application and referenced assemblies of it are added into the list here.
538 TizenPlatformServices.AppDomain.CurrentDomain.RegisterAssemblyRecursively(application.GetType().GetTypeInfo().Assembly);
540 Registrar.RegisterAll(new Type[]
542 typeof(ExportRendererAttribute),
543 typeof(ExportImageSourceHandlerAttribute),
544 typeof(ExportCellAttribute),
545 typeof(ExportHandlerAttribute),
546 typeof(ExportFontAttribute)
551 Color.SetAccent(GetAccentColor(profile));
552 ExpressionSearch.Default = new TizenExpressionSearch();
553 IsInitialized = true;
556 static Color GetAccentColor(string profile)
558 // On Windows Phone, this is the complementary color chosen by the user.
559 // Good Windows Phone applications use this as part of their styling to provide a native look and feel.
560 // On iOS and Android this instance is set to a contrasting color that is visible on the default
561 // background but is not the same as the default text color.
566 // [Tizen_3.0]Basic_Interaction_GUI_[REF].xlsx Theme 001 (Default) 1st HSB: 188 70 80
567 return Color.FromRgba(61, 185, 204, 255);
569 return Color.FromRgba(15, 15, 15, 230);
571 // Theme A (Default) 1st HSB: 207 75 16
572 return Color.FromRgba(10, 27, 41, 255);
579 /// Converts the dp into pixel considering current DPI value.
582 /// Use this API if you want to get pixel size without scaling factor.
584 /// <param name="dp"></param>
585 /// <returns></returns>
586 public static int ConvertToPixel(double dp)
588 return (int)Math.Round(dp * s_dpi.Value / 160.0);
592 /// Converts the dp into pixel by using scaling factor.
595 /// Use this API if you want to get pixel size from dp by using scaling factor.
596 /// 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.
598 /// <param name="dp"></param>
599 /// <returns></returns>
600 public static int ConvertToScaledPixel(double dp)
602 return (int)Math.Round(dp * Device.Info.ScalingFactor);
606 /// Converts the pixel into dp value by using scaling factor.
609 /// 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.
611 /// <param name="pixel"></param>
612 /// <returns></returns>
613 public static double ConvertToScaledDP(int pixel)
615 return pixel / Device.Info.ScalingFactor;
619 /// Converts the pixel into dp value by using scaling factor.
622 /// 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.
624 /// <param name="pixel"></param>
625 /// <returns></returns>
626 public static double ConvertToScaledDP(double pixel)
628 return pixel / Device.Info.ScalingFactor;
632 /// Converts the sp into EFL's font size metric (EFL point).
634 /// <param name="sp"></param>
635 /// <returns></returns>
636 public static int ConvertToEflFontPoint(double sp)
638 return (int)Math.Round(sp * s_elmScale.Value);
642 /// Convert the EFL's point into sp.
644 /// <param name="eflPt"></param>
645 /// <returns></returns>
646 public static double ConvertToDPFont(int eflPt)
648 return eflPt / s_elmScale.Value;
652 /// Get the EFL's profile
654 /// <returns></returns>
655 public static string GetProfile()
657 return s_profile.Value;
660 // for internal use only
661 [EditorBrowsable(EditorBrowsableState.Never)]
662 public static EvasObject Preload()
664 var dummyApp = new DummyFormsApplication();
665 Init(dummyApp, false);
668 var locale = TSystemSetting.LocaleLanguage;
669 TSystemSetting.LocaleLanguageChanged += DummyHandler;
670 TSystemSetting.LocaleLanguageChanged -= DummyHandler;
671 void DummyHandler(object sender, System.EventArgs e) { }
677 typeof(NavigationPage),
679 typeof(ContentPresenter),
683 typeof(TemplatedView),
685 typeof(AbsoluteLayout),
686 typeof(RelativeLayout),
702 typeof(ActivityIndicator),
704 typeof(CarouselView),
705 typeof(CollectionView),
713 typeof(VisualElement),
717 typeof(NavigableElement),
720 typeof(TapGestureRecognizer),
721 typeof(PropertyCondition),
723 typeof(StructuredItemsView),
724 typeof(SearchHandler),
727 foreach (var type in types)
729 System.Runtime.CompilerServices.RuntimeHelpers.RunClassConstructor(type.TypeHandle);
732 PTizen.PreloadedWindow preloadedWindow = new PTizen.PreloadedWindow();
733 if (preloadedWindow.Window != null)
735 global::Xamarin.Forms.Platform.Tizen.Native.NativeFactory.PrecreateNatives(preloadedWindow.Window);
736 global::Tizen.Wearable.CircularUI.Forms.CircularUIForms.Preload(preloadedWindow.Window);
740 Console.WriteLine("PreloadedWindow is null");
742 return preloadedWindow.Window;
746 class TizenExpressionSearch : ExpressionVisitor, IExpressionSearch
748 List<object> _results;
751 public List<T> FindObjects<T>(Expression expression) where T : class
753 _results = new List<object>();
754 _targetType = typeof(T);
756 return _results.Select(o => o as T).ToList();
759 protected override Expression VisitMember(MemberExpression node)
761 if (node.Expression is ConstantExpression && node.Member is FieldInfo)
763 var container = ((ConstantExpression)node.Expression).Value;
764 var value = ((FieldInfo)node.Member).GetValue(container);
766 if (_targetType.IsInstanceOfType(value))
769 return base.VisitMember(node);
773 class DummyFormsApplication : FormsApplication { }