using System;
using System.Collections.Generic;
using System.IO;
using System.IO.IsolatedStorage;
using System.Linq;
using System.Linq.Expressions;
using System.Net.Http;
using System.Reflection;
using System.Security.Cryptography;
using System.Text;
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 Xamarin.Forms.Internals;
using Xamarin.Forms.Platform.Android;
using Resource = Android.Resource;
using Trace = System.Diagnostics.Trace;
namespace Xamarin.Forms
{
public static class Forms
{
const int TabletCrossover = 600;
static bool? s_supportsProgress;
static bool? s_isLollipopOrNewer;
public static Context Context { get; internal set; }
public static bool IsInitialized { get; private set; }
internal static bool IsLollipopOrNewer
{
get
{
if (!s_isLollipopOrNewer.HasValue)
s_isLollipopOrNewer = (int)Build.VERSION.SdkInt >= 21;
return s_isLollipopOrNewer.Value;
}
}
internal static bool SupportsProgress
{
get
{
var activity = Context as Activity;
if (!s_supportsProgress.HasValue)
{
int progressCircularId = Context.Resources.GetIdentifier("progress_circular", "id", "android");
if (progressCircularId > 0 && activity != null)
s_supportsProgress = activity.FindViewById(progressCircularId) != null;
else
s_supportsProgress = true;
}
return s_supportsProgress.Value;
}
}
internal static AndroidTitleBarVisibility TitleBarVisibility { get; set; }
// Provide backwards compat for Forms.Init and AndroidActivity
// Why is bundle a param if never used?
public static void Init(Context activity, Bundle bundle)
{
Assembly resourceAssembly = Assembly.GetCallingAssembly();
SetupInit(activity, resourceAssembly);
}
public static void Init(Context activity, Bundle bundle, Assembly resourceAssembly)
{
SetupInit(activity, resourceAssembly);
}
///
/// Sets title bar visibility programmatically. Must be called after Xamarin.Forms.Forms.Init() method
///
/// Title bar visibility enum
public static void SetTitleBarVisibility(AndroidTitleBarVisibility visibility)
{
if((Activity)Context == null)
throw new NullReferenceException("Must be called after Xamarin.Forms.Forms.Init() method");
TitleBarVisibility = visibility;
if (TitleBarVisibility == AndroidTitleBarVisibility.Never)
{
if (!((Activity)Context).Window.Attributes.Flags.HasFlag(WindowManagerFlags.Fullscreen))
((Activity)Context).Window.AddFlags(WindowManagerFlags.Fullscreen);
}
else
{
if (((Activity)Context).Window.Attributes.Flags.HasFlag(WindowManagerFlags.Fullscreen))
((Activity)Context).Window.ClearFlags(WindowManagerFlags.Fullscreen);
}
}
public static event EventHandler ViewInitialized;
internal static void SendViewInitialized(this VisualElement self, global::Android.Views.View nativeView)
{
EventHandler viewInitialized = ViewInitialized;
if (viewInitialized != null)
viewInitialized(self, new ViewInitializedEventArgs { View = self, NativeView = nativeView });
}
static void SetupInit(Context activity, Assembly resourceAssembly)
{
Context = activity;
ResourceManager.Init(resourceAssembly);
Color.Accent = GetAccentColor();
if (!IsInitialized)
Log.Listeners.Add(new DelegateLogListener((c, m) => Trace.WriteLine(m, c)));
Device.PlatformServices = new AndroidPlatformServices();
// use field and not property to avoid exception in getter
if (Device.info != null)
{
((AndroidDeviceInfo)Device.info).Dispose();
Device.info = null;
}
Device.Info = new AndroidDeviceInfo(activity);
var ticker = Ticker.Default as AndroidTicker;
if (ticker != null)
ticker.Dispose();
Ticker.Default = new AndroidTicker();
if (!IsInitialized)
{
Registrar.RegisterAll(new[] { typeof(ExportRendererAttribute), typeof(ExportCellAttribute), typeof(ExportImageSourceHandlerAttribute) });
}
int minWidthDp = Context.Resources.Configuration.SmallestScreenWidthDp;
Device.Idiom = minWidthDp >= TabletCrossover ? TargetIdiom.Tablet : TargetIdiom.Phone;
if (ExpressionSearch.Default == null)
ExpressionSearch.Default = new AndroidExpressionSearch();
IsInitialized = true;
}
static Color GetAccentColor()
{
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)
{
// Detect if legacy device and use appropriate accent color
// Hardcoded because could not get color from the theme drawable
var sdkVersion = (int)Build.VERSION.SdkInt;
if (sdkVersion <= 10)
{
// legacy theme button pressed color
rc = Color.FromHex("#fffeaa0c");
}
else
{
// Holo dark light blue
rc = Color.FromHex("#ff33b5e5");
}
}
}
return rc;
}
class AndroidDeviceInfo : DeviceInfo
{
bool disposed;
readonly Context _formsActivity;
readonly Size _pixelScreenSize;
readonly double _scalingFactor;
Orientation _previousOrientation = Orientation.Undefined;
public AndroidDeviceInfo(Context formsActivity)
{
_formsActivity = formsActivity;
CheckOrientationChanged(_formsActivity.Resources.Configuration.Orientation);
// This will not be an implementation of IDeviceInfoProvider when running inside the context
// of layoutlib, which is what the Android Designer does.
if (_formsActivity is IDeviceInfoProvider)
((IDeviceInfoProvider) _formsActivity).ConfigurationChanged += ConfigurationChanged;
using (DisplayMetrics display = formsActivity.Resources.DisplayMetrics)
{
_scalingFactor = display.Density;
_pixelScreenSize = new Size(display.WidthPixels, display.HeightPixels);
ScaledScreenSize = new Size(_pixelScreenSize.Width / _scalingFactor, _pixelScreenSize.Width / _scalingFactor);
}
}
public override Size PixelScreenSize
{
get { return _pixelScreenSize; }
}
public override Size ScaledScreenSize { get; }
public override double ScalingFactor
{
get { return _scalingFactor; }
}
protected override void Dispose(bool disposing)
{
if (disposing && !disposed) {
disposed = true;
if (_formsActivity is IDeviceInfoProvider)
((IDeviceInfoProvider) _formsActivity).ConfigurationChanged -= ConfigurationChanged;
}
base.Dispose(disposing);
}
void CheckOrientationChanged(Orientation orientation)
{
if (!_previousOrientation.Equals(orientation))
CurrentOrientation = orientation.ToDeviceOrientation();
_previousOrientation = orientation;
}
void ConfigurationChanged(object sender, EventArgs e)
{
CheckOrientationChanged(_formsActivity.Resources.Configuration.Orientation);
}
}
class AndroidExpressionSearch : ExpressionVisitor, IExpressionSearch
{
List