|
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Linq.Expressions;
using System.Net.Http;
using System.Reflection;
using System.Runtime.Versioning;
using System.Threading;
using System.Threading.Tasks;
using Android.App;
using Android.Content;
using Android.Content.Res;
using Android.OS;
using Android.Util;
using Android.Views;
using AndroidX.Core.Content;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Maui.Controls.Compatibility.Platform.Android;
using Microsoft.Maui.Controls.Internals;
using Microsoft.Maui.Graphics;
using AColor = Android.Graphics.Color;
using AndroidResource = Android.Resource;
using Size = Microsoft.Maui.Graphics.Size;
using Trace = System.Diagnostics.Trace;
namespace Microsoft.Maui.Controls.Compatibility
{
[Obsolete]
#pragma warning disable CA1815 // Override equals and operator equals on value types
public struct InitializationOptions
{
public struct EffectScope
#pragma warning restore CA1815 // Override equals and operator equals on value types
{
public string Name;
public ExportEffectAttribute[] Effects;
}
public InitializationOptions(Context activity, Bundle bundle, Assembly resourceAssembly)
{
this = default(InitializationOptions);
Activity = activity;
Bundle = bundle;
ResourceAssembly = resourceAssembly;
}
public Context Activity;
public Bundle Bundle;
public Assembly ResourceAssembly;
public HandlerAttribute[] Handlers;
public EffectScope[] EffectScopes;
public InitializationFlags Flags;
}
public static class Forms
{
const int TabletCrossover = 600;
// One per process; does not change, suitable for loading resources (e.g., ResourceProvider)
internal static Context ApplicationContext { get; private set; } = global::Android.App.Application.Context;
internal static IMauiContext MauiContext { get; private set; }
public static bool IsInitialized { get; private set; }
static bool _ColorButtonNormalSet;
static Color _ColorButtonNormal = null;
public static Color ColorButtonNormalOverride { get; set; }
public static float GetFontSizeNormal(Context context)
{
float size = 50;
// Android 5.0+
//this doesn't seem to work
using (var value = new TypedValue())
{
if (context.Theme.ResolveAttribute(AndroidResource.Attribute.TextSize, value, true))
{
size = value.Data;
}
}
return size;
}
public static Color GetColorButtonNormal(Context context)
{
if (!_ColorButtonNormalSet)
{
_ColorButtonNormal = GetButtonColor(context);
_ColorButtonNormalSet = true;
}
return _ColorButtonNormal;
}
[Obsolete]
public static void Init(IActivationState activationState, InitializationOptions? options = null) =>
Init(activationState.Context, options);
[Obsolete]
public static void Init(IMauiContext context, InitializationOptions? options = null)
{
Assembly resourceAssembly;
Profile.FrameBegin("Assembly.GetCallingAssembly");
resourceAssembly = Assembly.GetCallingAssembly();
Profile.FrameEnd("Assembly.GetCallingAssembly");
Profile.FrameBegin();
SetupInit(context, resourceAssembly, options);
Profile.FrameEnd();
}
[Obsolete]
public static void Init(IMauiContext context, Assembly resourceAssembly)
{
Profile.FrameBegin();
SetupInit(context, resourceAssembly, null);
Profile.FrameEnd();
}
public static void SetTitleBarVisibility(Activity activity, AndroidTitleBarVisibility visibility)
{
if (visibility == AndroidTitleBarVisibility.Never)
{
if (!activity.Window.Attributes.Flags.HasFlag(WindowManagerFlags.Fullscreen))
activity.Window.AddFlags(WindowManagerFlags.Fullscreen);
}
else
{
if (activity.Window.Attributes.Flags.HasFlag(WindowManagerFlags.Fullscreen))
activity.Window.ClearFlags(WindowManagerFlags.Fullscreen);
}
}
public static event EventHandler<ViewInitializedEventArgs> ViewInitialized;
internal static void SendViewInitialized(this VisualElement self, global::Android.Views.View nativeView)
{
EventHandler<ViewInitializedEventArgs> viewInitialized = ViewInitialized;
if (viewInitialized != null)
viewInitialized(self, new ViewInitializedEventArgs { View = self, NativeView = nativeView });
}
[Obsolete]
static bool IsInitializedRenderers;
// Once we get essentials/cg converted to using startup.cs
// we will delete all the renderer code inside this file
[Obsolete]
internal static void RenderersRegistered()
{
IsInitializedRenderers = true;
}
[Obsolete]
internal static void RegisterCompatRenderers(IMauiContext context, InitializationOptions? maybeOptions)
{
if (!IsInitializedRenderers)
{
IsInitializedRenderers = true;
if (maybeOptions.HasValue)
{
var options = maybeOptions.Value;
var handlers = options.Handlers;
var flags = options.Flags;
var effectScopes = options.EffectScopes;
//TODO: ExportCell?
//TODO: ExportFont
// renderers
Registrar.RegisterRenderers(handlers);
// effects
if (effectScopes != null)
{
for (var i = 0; i < effectScopes.Length; i++)
{
var effectScope = effectScopes[0];
Registrar.RegisterEffects(effectScope.Name, effectScope.Effects);
}
}
// css
Registrar.RegisterStylesheets(flags);
}
else
{
// Only need to do this once
Registrar.RegisterAll(new[] {
typeof(ExportRendererAttribute),
typeof(ExportCellAttribute),
typeof(ExportImageSourceHandlerAttribute),
typeof(ExportFontAttribute)
}, context?.Services?.GetService<IFontRegistrar>());
}
}
}
[Obsolete]
static void SetupInit(
IMauiContext context,
Assembly resourceAssembly,
InitializationOptions? maybeOptions = null
)
{
var activity = context.Context;
Profile.FrameBegin();
Registrar.RegisterRendererToHandlerShim(RendererToHandlerShim.CreateShim);
// Allow this multiple times to support the app and then the activity
ApplicationContext = activity.ApplicationContext;
MauiContext = context;
if (!IsInitialized)
{
// Only need to do this once
Profile.FramePartition("ResourceManager.Init");
ResourceManager.Init(resourceAssembly);
}
Profile.FramePartition("Color.SetAccent()");
// We want this to be updated when we have a new activity (e.g. on a configuration change)
// This could change if the UI mode changes (e.g., if night mode is enabled)
Application.AccentColor = GetAccentColor(activity);
_ColorButtonNormalSet = false;
// We want this to be updated when we have a new activity (e.g. on a configuration change)
// because AndroidPlatformServices needs a current activity to launch URIs from
Profile.FramePartition("Device.PlatformServices");
Device.DefaultRendererAssembly = typeof(Forms).Assembly;
Profile.FramePartition("RegisterAll");
if (maybeOptions?.Flags.HasFlag(InitializationFlags.SkipRenderers) != true)
RegisterCompatRenderers(context, maybeOptions);
Profile.FramePartition("Epilog");
if (ExpressionSearch.Default == null)
ExpressionSearch.Default = new AndroidExpressionSearch();
IsInitialized = true;
Profile.FrameEnd();
}
static Color GetAccentColor(Context context)
{
Color rc;
using (var value = new TypedValue())
{
if (context.Theme.ResolveAttribute(global::Android.Resource.Attribute.ColorAccent, value, true)) // Android 5.0+
{
rc = Color.FromUint((uint)value.Data);
}
else if (context.Theme.ResolveAttribute(context.Resources.GetIdentifier("colorAccent", "attr", context.PackageName), value, true)) // < Android 5.0
{
rc = Color.FromUint((uint)value.Data);
}
else // fallback to old code if nothing works (don't know if that ever happens)
{
// Hardcoded because could not get color from the theme drawable
// Holo dark light blue
rc = Color.FromArgb("#ff33b5e5");
}
}
return rc;
}
static Color GetButtonColor(Context context)
{
Color rc = ColorButtonNormalOverride;
if (ColorButtonNormalOverride == null)
{
using (var value = new TypedValue())
{
if (context.Theme.ResolveAttribute(global::Android.Resource.Attribute.ColorButtonNormal, value, true)) // Android 5.0+
{
rc = Color.FromUint((uint)value.Data);
}
else if (context.Theme.ResolveAttribute(context.Resources.GetIdentifier("colorButtonNormal", "attr", context.PackageName), value, true)) // < Android 5.0
{
rc = Color.FromUint((uint)value.Data);
}
}
}
return rc;
}
class AndroidExpressionSearch : ExpressionVisitor, IExpressionSearch
{
List<object> _results;
Type _targetType;
public List<T> FindObjects<T>(Expression expression) where T : class
{
_results = new List<object>();
_targetType = typeof(T);
Visit(expression);
return _results.Select(o => o as T).ToList();
}
protected override Expression VisitMember(MemberExpression node)
{
if (node.Expression is ConstantExpression && node.Member is FieldInfo)
{
object container = ((ConstantExpression)node.Expression).Value;
object value = ((FieldInfo)node.Member).GetValue(container);
if (_targetType.IsInstanceOfType(value))
_results.Add(value);
}
return base.VisitMember(node);
}
}
}
}
|