/
ContextExtensions.cs
176 lines (140 loc) · 4.99 KB
/
ContextExtensions.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
using System;
using System.Runtime.CompilerServices;
using Android.Content;
using Android.Util;
using Android.Views.InputMethods;
using AApplicationInfoFlags = Android.Content.PM.ApplicationInfoFlags;
using AActivity = Android.App.Activity;
#if __ANDROID_29__
using AndroidX.Fragment.App;
using AndroidX.AppCompat.App;
using AFragmentManager = AndroidX.Fragment.App.FragmentManager;
#else
using AFragmentManager = Android.Support.V4.App.FragmentManager;
using Android.Support.V4.App;
using Android.Support.V7.App;
#endif
namespace Xamarin.Forms.Platform.Android
{
public static class ContextExtensions
{
// Caching this display density here means that all pixel calculations are going to be based on the density
// of the first Context these extensions are run against. That's probably fine, but if we run into a
// situation where subsequent activities can be launched with a different display density from the intial
// activity, we'll need to remove this cached value or cache it in a Dictionary<Context, float>
static float s_displayDensity = float.MinValue;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double FromPixels(this Context self, double pixels)
{
SetupMetrics(self);
return pixels / s_displayDensity;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Size FromPixels(this Context context, double width, double height)
{
return new Size(context.FromPixels(width), context.FromPixels(height));
}
public static void HideKeyboard(this Context self, global::Android.Views.View view)
{
var service = (InputMethodManager)self.GetSystemService(Context.InputMethodService);
// service may be null in the context of the Android Designer
if (service != null)
service.HideSoftInputFromWindow(view.WindowToken, HideSoftInputFlags.None);
}
public static void ShowKeyboard(this Context self, global::Android.Views.View view)
{
var service = (InputMethodManager)self.GetSystemService(Context.InputMethodService);
// Can happen in the context of the Android Designer
if (service != null)
service.ShowSoftInput(view, ShowFlags.Implicit);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static float ToPixels(this Context self, double dp)
{
SetupMetrics(self);
return (float)Math.Ceiling(dp * s_displayDensity);
}
public static bool HasRtlSupport(this Context self) =>
(self.ApplicationInfo.Flags & AApplicationInfoFlags.SupportsRtl) == AApplicationInfoFlags.SupportsRtl;
public static int TargetSdkVersion(this Context self) =>
(int)self.ApplicationInfo.TargetSdkVersion;
internal static double GetThemeAttributeDp(this Context self, int resource)
{
using (var value = new TypedValue())
{
if (!self.Theme.ResolveAttribute(resource, value, true))
return -1;
var pixels = (double)TypedValue.ComplexToDimension(value.Data, self.Resources.DisplayMetrics);
return self.FromPixels(pixels);
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
static void SetupMetrics(Context context)
{
if (s_displayDensity != float.MinValue)
return;
using (DisplayMetrics metrics = context.Resources.DisplayMetrics)
s_displayDensity = metrics.Density;
}
public static AActivity GetActivity(this Context context)
{
if (context == null)
return null;
if (context is AActivity activity)
return activity;
if (context is ContextWrapper contextWrapper)
return contextWrapper.BaseContext.GetActivity();
return null;
}
internal static Context GetThemedContext(this Context context)
{
if (context == null)
return null;
if (context.IsDesignerContext())
return context;
if (context is AppCompatActivity activity)
return activity.SupportActionBar.ThemedContext;
if (context is ContextWrapper contextWrapper)
return contextWrapper.BaseContext.GetThemedContext();
return null;
}
static bool? _isDesignerContext;
internal static bool IsDesignerContext(this Context context)
{
if (_isDesignerContext.HasValue)
return _isDesignerContext.Value;
context.SetDesignerContext();
return _isDesignerContext.Value;
}
internal static void SetDesignerContext(this Context context)
{
if (_isDesignerContext.HasValue)
return;
if (context == null)
_isDesignerContext = false;
else if ($"{context}".Contains("com.android.layoutlib.bridge.android.BridgeContext"))
_isDesignerContext = true;
else
_isDesignerContext = false;
}
internal static void SetDesignerContext(global::Android.Views.View view)
{
_isDesignerContext = view.IsInEditMode;
}
internal static bool IsDesignerContext(this global::Android.Views.View view)
{
if (!_isDesignerContext.HasValue)
SetDesignerContext(view);
return _isDesignerContext.Value;
}
public static AFragmentManager GetFragmentManager(this Context context)
{
if (context == null)
return null;
var activity = context.GetActivity();
if (activity is FragmentActivity fa)
return fa.SupportFragmentManager;
return null;
}
}
}