Skip to content

Commit

Permalink
feat: Use in-app screenshots for android
Browse files Browse the repository at this point in the history
  • Loading branch information
jeromelaban committed Aug 24, 2022
1 parent 0cab04d commit cdaeda4
Show file tree
Hide file tree
Showing 4 changed files with 160 additions and 3 deletions.
64 changes: 63 additions & 1 deletion src/SamplesApp/SamplesApp.Droid/MainActivity.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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
{
Expand All @@ -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;
Expand Down Expand Up @@ -61,6 +65,48 @@ protected override void OnStart()
[Export("GetDisplayScreenScaling")]
public string GetDisplayScreenScaling(string displayId) => App.GetDisplayScreenScaling(displayId);

/// <summary>
/// Returns a base64 encoded PNG file
/// </summary>
[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)
{
Expand All @@ -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();
}
}
}


Expand All @@ -107,5 +168,6 @@ public class MsalActivity : BrowserTabActivity
public class WebAuthenticationBrokerActivity : WebAuthenticationBrokerActivityBase
{
}

}

21 changes: 21 additions & 0 deletions src/SamplesApp/SamplesApp.UITests/Extensions/AppExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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
}
}
Expand Down
15 changes: 13 additions & 2 deletions src/SamplesApp/SamplesApp.UITests/SampleControlUITestBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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(" ", "_")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
using Windows.UI.ViewManagement;
using Microsoft.Identity.Client;
using Uno.UI;
using System.Threading;
using Android.OS;

namespace SamplesApp.Droid
{
Expand All @@ -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);

Expand All @@ -35,6 +39,49 @@ public class MainActivity : Windows.UI.Xaml.ApplicationActivity
[Export("GetDisplayScreenScaling")]
public string GetDisplayScreenScaling(string displayId) => App.GetDisplayScreenScaling(displayId);

/// <summary>
/// Returns a base64 encoded PNG file
/// </summary>
[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)
{
Expand All @@ -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
Expand Down

0 comments on commit cdaeda4

Please sign in to comment.