diff --git a/src/SamplesApp/SamplesApp.Droid/MainActivity.cs b/src/SamplesApp/SamplesApp.Droid/MainActivity.cs
index e0619c0c7c27..d42bf2987a36 100644
--- a/src/SamplesApp/SamplesApp.Droid/MainActivity.cs
+++ b/src/SamplesApp/SamplesApp.Droid/MainActivity.cs
@@ -8,6 +8,9 @@
using Microsoft.Identity.Client;
using Uno.UI.ViewManagement;
using Uno.AuthenticationBroker;
+using System.IO;
+using System.Threading;
+using Android.OS;
namespace SamplesApp.Droid
{
@@ -31,7 +34,8 @@ namespace SamplesApp.Droid
public class MainActivity : Windows.UI.Xaml.ApplicationActivity
{
private bool _onCreateEventInvoked = false;
-
+ private HandlerThread _pixelCopyHandlerThread;
+
public MainActivity()
{
ApplicationViewHelper.GetBaseActivityEvents().Create += OnCreateEvent;
@@ -61,6 +65,48 @@ protected override void OnStart()
[Export("GetDisplayScreenScaling")]
public string GetDisplayScreenScaling(string displayId) => App.GetDisplayScreenScaling(displayId);
+ ///
+ /// Returns a base64 encoded PNG file
+ ///
+ [Export("GetScreenshot")]
+ public string GetScreenshot(string displayId)
+ {
+ var rootView = Windows.UI.Xaml.Window.Current.MainContent as View;
+
+ var bitmap = Android.Graphics.Bitmap.CreateBitmap(rootView.Width, rootView.Height, Android.Graphics.Bitmap.Config.Argb8888);
+ var locationOfViewInWindow = new int[2];
+ rootView.GetLocationInWindow(locationOfViewInWindow);
+
+ var xCoordinate = locationOfViewInWindow[0];
+ var yCoordinate = locationOfViewInWindow[1];
+
+ var scope = new Android.Graphics.Rect(
+ xCoordinate,
+ yCoordinate,
+ xCoordinate + rootView.Width,
+ yCoordinate + rootView.Height
+ );
+
+ if (_pixelCopyHandlerThread == null)
+ {
+ _pixelCopyHandlerThread = new Android.OS.HandlerThread("ScreenshotHelper");
+ _pixelCopyHandlerThread.Start();
+ }
+
+ var listener = new PixelCopyListener();
+
+ // PixelCopy.Request returns the actual rendering of the screen location
+ // for the app, incliing OpenGL content.
+ PixelCopy.Request(Window, scope, bitmap, listener, new Android.OS.Handler(_pixelCopyHandlerThread.Looper));
+
+ listener.WaitOne();
+
+ using var memoryStream = new MemoryStream();
+ bitmap.Compress(Android.Graphics.Bitmap.CompressFormat.Png, 100, memoryStream);
+
+ return Convert.ToBase64String(memoryStream.ToArray());
+ }
+
[Export("SetFullScreenMode")]
public void SetFullScreenMode(bool fullscreen)
{
@@ -81,6 +127,21 @@ protected override void OnActivityResult(int requestCode, Result resultCode, And
base.OnActivityResult(requestCode, resultCode, data);
AuthenticationContinuationHelper.SetAuthenticationContinuationEventArgs(requestCode, resultCode, data);
}
+
+ class PixelCopyListener : Java.Lang.Object, PixelCopy.IOnPixelCopyFinishedListener
+ {
+ private ManualResetEvent _event = new ManualResetEvent(false);
+
+ public void WaitOne()
+ {
+ _event.WaitOne();
+ }
+
+ public void OnPixelCopyFinished(int copyResult)
+ {
+ _event.Set();
+ }
+ }
}
@@ -107,5 +168,6 @@ public class MsalActivity : BrowserTabActivity
public class WebAuthenticationBrokerActivity : WebAuthenticationBrokerActivityBase
{
}
+
}
diff --git a/src/SamplesApp/SamplesApp.UITests/Extensions/AppExtensions.cs b/src/SamplesApp/SamplesApp.UITests/Extensions/AppExtensions.cs
index d35d75cc749c..fe0ca03dfc34 100644
--- a/src/SamplesApp/SamplesApp.UITests/Extensions/AppExtensions.cs
+++ b/src/SamplesApp/SamplesApp.UITests/Extensions/AppExtensions.cs
@@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Drawing;
using System.Globalization;
+using System.IO;
using System.Linq;
using System.Text;
using Uno.UITest;
@@ -36,6 +37,26 @@ float GetScaling()
return 1f;
}
}
+#endif
+ }
+
+ public static FileInfo GetInAppScreenshot(this IApp app)
+ {
+#if IS_RUNTIME_UI_TESTS
+ return null;
+#else
+ var byte64Image = app.InvokeGeneric("browser:SampleRunner|GetScreenshot", "0")?.ToString();
+
+ var array = Convert.FromBase64String(byte64Image);
+
+ var outputFile = Path.GetTempFileName();
+ File.WriteAllBytes(outputFile, array);
+
+ var finalPath = Path.ChangeExtension(outputFile, ".png");
+
+ File.Move(outputFile, finalPath);
+
+ return new(finalPath);
#endif
}
}
diff --git a/src/SamplesApp/SamplesApp.UITests/SampleControlUITestBase.cs b/src/SamplesApp/SamplesApp.UITests/SampleControlUITestBase.cs
index d6ccdaf45f86..44c3fedd6153 100644
--- a/src/SamplesApp/SamplesApp.UITests/SampleControlUITestBase.cs
+++ b/src/SamplesApp/SamplesApp.UITests/SampleControlUITestBase.cs
@@ -185,8 +185,7 @@ public ScreenshotInfo TakeScreenshot(string stepName, ScreenshotOptions options)
}
var title = GetCurrentStepTitle(stepName);
-
- var fileInfo = _app.Screenshot(title);
+ var fileInfo = GetNativeScreenshot(title);
var fileNameWithoutExt = Path.GetFileNameWithoutExtension(fileInfo.Name);
if (fileNameWithoutExt != title)
@@ -219,6 +218,18 @@ public ScreenshotInfo TakeScreenshot(string stepName, ScreenshotOptions options)
return new ScreenshotInfo(fileInfo, stepName);
}
+ private FileInfo GetNativeScreenshot(string title)
+ {
+ if (AppInitializer.GetLocalPlatform() == Platform.Android)
+ {
+ return _app.GetInAppScreenshot();
+ }
+ else
+ {
+ return _app.Screenshot(title);
+ }
+ }
+
private static string GetCurrentStepTitle(string stepName) =>
$"{TestContext.CurrentContext.Test.Name}_{stepName}"
.Replace(" ", "_")
diff --git a/src/SamplesApp/SamplesApp.net6mobile/Android/MainActivity.Android.cs b/src/SamplesApp/SamplesApp.net6mobile/Android/MainActivity.Android.cs
index f94f7247b3d6..4ad56f2cda51 100644
--- a/src/SamplesApp/SamplesApp.net6mobile/Android/MainActivity.Android.cs
+++ b/src/SamplesApp/SamplesApp.net6mobile/Android/MainActivity.Android.cs
@@ -7,6 +7,8 @@
using Windows.UI.ViewManagement;
using Microsoft.Identity.Client;
using Uno.UI;
+using System.Threading;
+using Android.OS;
namespace SamplesApp.Droid
{
@@ -26,6 +28,8 @@ namespace SamplesApp.Droid
DataScheme = "uno-samples-test")]
public class MainActivity : Windows.UI.Xaml.ApplicationActivity
{
+ private HandlerThread _pixelCopyHandlerThread;
+
[Export("RunTest")]
public string RunTest(string metadataName) => App.RunTest(metadataName);
@@ -35,6 +39,49 @@ public class MainActivity : Windows.UI.Xaml.ApplicationActivity
[Export("GetDisplayScreenScaling")]
public string GetDisplayScreenScaling(string displayId) => App.GetDisplayScreenScaling(displayId);
+ ///
+ /// Returns a base64 encoded PNG file
+ ///
+ [Export("GetScreenshot")]
+ public string GetScreenshot(string displayId)
+ {
+ var rootView = Windows.UI.Xaml.Window.Current.MainContent as View;
+
+ var bitmap = Android.Graphics.Bitmap.CreateBitmap(rootView.Width, rootView.Height, Android.Graphics.Bitmap.Config.Argb8888);
+ var locationOfViewInWindow = new int[2];
+ rootView.GetLocationInWindow(locationOfViewInWindow);
+
+ var xCoordinate = locationOfViewInWindow[0];
+ var yCoordinate = locationOfViewInWindow[1];
+
+ var scope = new Android.Graphics.Rect(
+ xCoordinate,
+ yCoordinate,
+ xCoordinate + rootView.Width,
+ yCoordinate + rootView.Height
+ );
+
+ if (_pixelCopyHandlerThread == null)
+ {
+ _pixelCopyHandlerThread = new Android.OS.HandlerThread("ScreenshotHelper");
+ _pixelCopyHandlerThread.Start();
+ }
+
+ var listener = new PixelCopyListener();
+
+ // PixelCopy.Request returns the actual rendering of the screen location
+ // for the app, incliing OpenGL content.
+ PixelCopy.Request(Window, scope, bitmap, listener, new Android.OS.Handler(_pixelCopyHandlerThread.Looper));
+
+ listener.WaitOne();
+
+ using var memoryStream = new System.IO.MemoryStream();
+ bitmap.Compress(Android.Graphics.Bitmap.CompressFormat.Png, 100, memoryStream);
+
+ return Convert.ToBase64String(memoryStream.ToArray());
+ }
+
+
[Export("SetFullScreenMode")]
public void SetFullScreenMode(bool fullscreen)
{
@@ -57,6 +104,22 @@ protected override void OnActivityResult(int requestCode, Result resultCode, And
AuthenticationContinuationHelper.SetAuthenticationContinuationEventArgs(requestCode, resultCode, data);
#endif
}
+
+
+ class PixelCopyListener : Java.Lang.Object, PixelCopy.IOnPixelCopyFinishedListener
+ {
+ private ManualResetEvent _event = new ManualResetEvent(false);
+
+ public void WaitOne()
+ {
+ _event.WaitOne();
+ }
+
+ public void OnPixelCopyFinished(int copyResult)
+ {
+ _event.Set();
+ }
+ }
}
#if !NET6_0