Skip to content

Commit 111affb

Browse files
committed
perf: [Android] Improve DisplayInformation performance
1 parent 54ad32f commit 111affb

File tree

1 file changed

+115
-140
lines changed

1 file changed

+115
-140
lines changed

src/Uno.UWP/Graphics/Display/DisplayInformation.Android.cs

Lines changed: 115 additions & 140 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#if __ANDROID__
2+
#nullable enable
23
using System;
34
using Android.App;
45
using Android.Content;
@@ -11,7 +12,10 @@ namespace Windows.Graphics.Display
1112
{
1213
public sealed partial class DisplayInformation
1314
{
14-
private static DisplayInformation _instance;
15+
private static DisplayInformation? _instance;
16+
17+
private DisplayMetricsCache _cachedDisplayMetrics;
18+
private SurfaceOrientation _cachedRotation;
1519

1620
private static DisplayInformation InternalGetForCurrentView()
1721
{
@@ -39,6 +43,11 @@ static partial void SetOrientationPartial(DisplayOrientations orientations)
3943
}
4044
}
4145

46+
partial void Initialize()
47+
{
48+
RefreshDisplayMetricsCache();
49+
}
50+
4251
public DisplayOrientations CurrentOrientation => GetCurrentOrientation();
4352

4453

@@ -51,61 +60,21 @@ static partial void SetOrientationPartial(DisplayOrientations orientations)
5160

5261

5362
public uint ScreenHeightInRawPixels
54-
{
55-
get
56-
{
57-
using (var realDisplayMetrics = CreateRealDisplayMetrics())
58-
{
59-
return (uint)realDisplayMetrics.HeightPixels;
60-
}
61-
}
62-
}
63+
=> (uint)_cachedDisplayMetrics.HeightPixels;
6364

6465
public uint ScreenWidthInRawPixels
65-
{
66-
get
67-
{
68-
using (var realDisplayMetrics = CreateRealDisplayMetrics())
69-
{
70-
return (uint)realDisplayMetrics.WidthPixels;
71-
}
72-
}
73-
}
74-
66+
=> (uint)_cachedDisplayMetrics.WidthPixels;
67+
7568
public double RawPixelsPerViewPixel
76-
{
77-
get
78-
{
79-
using (var realDisplayMetrics = CreateRealDisplayMetrics())
80-
{
81-
return 1.0f * (int)realDisplayMetrics.DensityDpi / (int)DisplayMetricsDensity.Default;
82-
}
83-
}
84-
}
69+
=> 1.0f * (int)_cachedDisplayMetrics.DensityDpi / (int)DisplayMetricsDensity.Default;
8570

8671
public float LogicalDpi
87-
{
88-
get
89-
{
90-
using (var realDisplayMetrics = CreateRealDisplayMetrics())
91-
{
92-
// DisplayMetrics of 1.0 matches 100%, or UWP's default 96.0 DPI.
93-
// https://stuff.mit.edu/afs/sipb/project/android/docs/reference/android/util/DisplayMetrics.html#density
94-
return realDisplayMetrics.Density * BaseDpi;
95-
}
96-
}
97-
}
72+
// DisplayMetrics of 1.0 matches 100%, or UWP's default 96.0 DPI.
73+
// https://stuff.mit.edu/afs/sipb/project/android/docs/reference/android/util/DisplayMetrics.html#density
74+
=> _cachedDisplayMetrics.Density * BaseDpi;
9875

9976
public ResolutionScale ResolutionScale
100-
{
101-
get
102-
{
103-
using (var realDisplayMetrics = CreateRealDisplayMetrics())
104-
{
105-
return (ResolutionScale)(int)(realDisplayMetrics.Density * 100);
106-
}
107-
}
108-
}
77+
=> (ResolutionScale)(int)(_cachedDisplayMetrics.Density * 100);
10978

11079
/// <summary>
11180
/// Gets the raw dots per inch (DPI) along the x axis of the display monitor.
@@ -115,15 +84,7 @@ public ResolutionScale ResolutionScale
11584
/// defaults to 0 if not set
11685
/// </remarks>
11786
public float RawDpiX
118-
{
119-
get
120-
{
121-
using (var realDisplayMetrics = CreateRealDisplayMetrics())
122-
{
123-
return realDisplayMetrics.Xdpi;
124-
}
125-
}
126-
}
87+
=> _cachedDisplayMetrics.Xdpi;
12788

12889
/// <summary>
12990
/// Gets the raw dots per inch (DPI) along the y axis of the display monitor.
@@ -133,15 +94,7 @@ public float RawDpiX
13394
/// defaults to 0 if not set
13495
/// </remarks>
13596
public float RawDpiY
136-
{
137-
get
138-
{
139-
using (var realDisplayMetrics = CreateRealDisplayMetrics())
140-
{
141-
return realDisplayMetrics.Ydpi;
142-
}
143-
}
144-
}
97+
=> _cachedDisplayMetrics.Ydpi;
14598

14699
/// <summary>
147100
/// Diagonal size of the display in inches.
@@ -154,13 +107,10 @@ public double? DiagonalSizeInInches
154107
{
155108
get
156109
{
157-
using (var realDisplayMetrics = CreateRealDisplayMetrics())
158-
{
159-
var x = Math.Pow((uint)realDisplayMetrics.WidthPixels / realDisplayMetrics.Xdpi, 2);
160-
var y = Math.Pow((uint)realDisplayMetrics.HeightPixels / realDisplayMetrics.Ydpi, 2);
161-
var screenInches = Math.Sqrt(x + y);
162-
return screenInches;
163-
}
110+
var x = Math.Pow((uint)_cachedDisplayMetrics.WidthPixels / _cachedDisplayMetrics.Xdpi, 2);
111+
var y = Math.Pow((uint)_cachedDisplayMetrics.HeightPixels / _cachedDisplayMetrics.Ydpi, 2);
112+
var screenInches = Math.Sqrt(x + y);
113+
return screenInches;
164114
}
165115
}
166116

@@ -175,13 +125,13 @@ private DisplayOrientations GetNativeOrientation()
175125
{
176126
using (var windowManager = CreateWindowManager())
177127
{
178-
var orientation = ContextHelper.Current.Resources.Configuration.Orientation;
128+
var orientation = ContextHelper.Current.Resources!.Configuration!.Orientation;
179129
if (orientation == Android.Content.Res.Orientation.Undefined)
180130
{
181131
return DisplayOrientations.None;
182132
}
183133

184-
var rotation = windowManager.DefaultDisplay.Rotation;
134+
var rotation = _cachedRotation;
185135
bool isLandscape;
186136
switch (rotation)
187137
{
@@ -208,94 +158,119 @@ private DisplayOrientations GetCurrentOrientation()
208158
{
209159
using (var windowManager = CreateWindowManager())
210160
{
211-
var rotation = windowManager.DefaultDisplay.Rotation;
212-
using (var displayMetrics = new DisplayMetrics())
213-
{
214-
#pragma warning disable 618
215-
windowManager.DefaultDisplay.GetMetrics(displayMetrics);
216-
#pragma warning restore 618
217-
218-
int width = displayMetrics.WidthPixels;
219-
int height = displayMetrics.HeightPixels;
161+
int width = _cachedDisplayMetrics.WidthPixels;
162+
int height = _cachedDisplayMetrics.HeightPixels;
220163

221-
if (width == height)
222-
{
223-
//square device, can't tell orientation
224-
return DisplayOrientations.None;
225-
}
164+
if (width == height)
165+
{
166+
//square device, can't tell orientation
167+
return DisplayOrientations.None;
168+
}
226169

227-
if (NativeOrientation == DisplayOrientations.Portrait)
228-
{
229-
switch (rotation)
230-
{
231-
case SurfaceOrientation.Rotation0:
232-
return DisplayOrientations.Portrait;
233-
case SurfaceOrientation.Rotation90:
234-
return DisplayOrientations.Landscape;
235-
case SurfaceOrientation.Rotation180:
236-
return DisplayOrientations.PortraitFlipped;
237-
case SurfaceOrientation.Rotation270:
238-
return DisplayOrientations.LandscapeFlipped;
239-
default:
240-
//invalid rotation
241-
return DisplayOrientations.None;
242-
}
243-
}
244-
else if (NativeOrientation == DisplayOrientations.Landscape)
170+
if (NativeOrientation == DisplayOrientations.Portrait)
171+
{
172+
switch (_cachedRotation)
245173
{
246-
//device is landscape or square
247-
switch (rotation)
248-
{
249-
case SurfaceOrientation.Rotation0:
250-
return DisplayOrientations.Landscape;
251-
case SurfaceOrientation.Rotation90:
252-
return DisplayOrientations.Portrait;
253-
case SurfaceOrientation.Rotation180:
254-
return DisplayOrientations.LandscapeFlipped;
255-
case SurfaceOrientation.Rotation270:
256-
return DisplayOrientations.PortraitFlipped;
257-
default:
258-
//invalid rotation
259-
return DisplayOrientations.None;
260-
}
174+
case SurfaceOrientation.Rotation0:
175+
return DisplayOrientations.Portrait;
176+
case SurfaceOrientation.Rotation90:
177+
return DisplayOrientations.Landscape;
178+
case SurfaceOrientation.Rotation180:
179+
return DisplayOrientations.PortraitFlipped;
180+
case SurfaceOrientation.Rotation270:
181+
return DisplayOrientations.LandscapeFlipped;
182+
default:
183+
//invalid rotation
184+
return DisplayOrientations.None;
261185
}
262-
else
186+
}
187+
else if (NativeOrientation == DisplayOrientations.Landscape)
188+
{
189+
//device is landscape or square
190+
switch (_cachedRotation)
263191
{
264-
//fallback
265-
return DisplayOrientations.None;
192+
case SurfaceOrientation.Rotation0:
193+
return DisplayOrientations.Landscape;
194+
case SurfaceOrientation.Rotation90:
195+
return DisplayOrientations.Portrait;
196+
case SurfaceOrientation.Rotation180:
197+
return DisplayOrientations.LandscapeFlipped;
198+
case SurfaceOrientation.Rotation270:
199+
return DisplayOrientations.PortraitFlipped;
200+
default:
201+
//invalid rotation
202+
return DisplayOrientations.None;
266203
}
267204
}
205+
else
206+
{
207+
//fallback
208+
return DisplayOrientations.None;
209+
}
268210
}
269211
}
270212

271213
private IWindowManager CreateWindowManager()
272214
{
273-
return ContextHelper.Current.GetSystemService(Context.WindowService).JavaCast<IWindowManager>();
274-
}
275-
276-
private DisplayMetrics CreateRealDisplayMetrics()
277-
{
278-
var displayMetrics = new DisplayMetrics();
279-
using (var windowManager = CreateWindowManager())
215+
if(ContextHelper.Current.GetSystemService(Context.WindowService) is { } windowService)
280216
{
281-
windowManager.DefaultDisplay.GetRealMetrics(displayMetrics);
217+
return windowService.JavaCast<IWindowManager>();;
282218
}
283-
return displayMetrics;
219+
220+
throw new InvalidOperationException("Failed to get the system Window Service");
284221
}
285222

286223
partial void StartOrientationChanged()
224+
=> _lastKnownOrientation = CurrentOrientation;
225+
226+
partial void StartDpiChanged()
227+
=> _lastKnownDpi = LogicalDpi;
228+
229+
internal void HandleConfigurationChange()
287230
{
288-
_lastKnownOrientation = CurrentOrientation;
231+
RefreshDisplayMetricsCache();
232+
OnDisplayMetricsChanged();
289233
}
290234

291-
partial void StartDpiChanged()
235+
private void RefreshDisplayMetricsCache()
292236
{
293-
_lastKnownDpi = LogicalDpi;
237+
var displayMetrics = new DisplayMetrics();
238+
using (var windowManager = CreateWindowManager())
239+
{
240+
if (windowManager.DefaultDisplay is { } defaultDisplay)
241+
{
242+
defaultDisplay.GetRealMetrics(displayMetrics);
243+
244+
_cachedDisplayMetrics = new DisplayMetricsCache(displayMetrics);
245+
_cachedRotation = windowManager.DefaultDisplay.Rotation;
246+
}
247+
else
248+
{
249+
throw new InvalidOperationException("Failed to get the default display information");
250+
}
251+
}
294252
}
295253

296-
internal void HandleConfigurationChange()
254+
private class DisplayMetricsCache
297255
{
298-
OnDisplayMetricsChanged();
256+
public DisplayMetricsCache(DisplayMetrics displayMetric)
257+
{
258+
Density = displayMetric.Density;
259+
DensityDpi = displayMetric.DensityDpi;
260+
HeightPixels = displayMetric.HeightPixels;
261+
ScaledDensity = displayMetric.ScaledDensity;
262+
WidthPixels = displayMetric.WidthPixels;
263+
Xdpi = displayMetric.Xdpi;
264+
Ydpi = displayMetric.Ydpi;
265+
}
266+
267+
public float Density { get; }
268+
public DisplayMetricsDensity DensityDpi { get; }
269+
public int HeightPixels { get; }
270+
public float ScaledDensity { get; }
271+
public int WidthPixels { get; }
272+
public float Xdpi { get; }
273+
public float Ydpi { get; }
299274
}
300275
}
301276
}

0 commit comments

Comments
 (0)