40

I am developing an portable App for Android and iOS. My current function is taking a Screenshot and use that image in the code. Therefor I have an Interface in the portable library.

public interface IFileSystemService
{
    string GetAppDataFolder();
}

I am taking the Screenshot also in the portable Library with the following code:

static public bool TakeScreenshot()
    {
        try
        {
            byte[] ScreenshotBytes = DependencyService.Get<Interface.IScreenshotManager>().TakeScreenshot();
            return true;
        }
        catch (Exception ex)
        {
        }
        return false;
    }

This either calls the Android or the iOS version.

Android:

class ScreenshotManagerAndroid : IScreenshotManager
{
    public static Activity Activity { get; set; }

    public byte[] TakeScreenshot()
    {

        if (Activity == null)
        {
            throw new Exception("You have to set ScreenshotManager.Activity in your Android project");
        }

        var view = Activity.Window.DecorView;
        view.DrawingCacheEnabled = true;

        Bitmap bitmap = view.GetDrawingCache(true);

        byte[] bitmapData;

        using (var stream = new MemoryStream())
        {
            bitmap.Compress(Bitmap.CompressFormat.Png, 0, stream);
            bitmapData = stream.ToArray();
        }

        return bitmapData;
    }

The question now is to get the current Activity from my app.

Lexu
  • 579
  • 1
  • 5
  • 14

5 Answers5

51

A better way would be to use the Standalone Current Activity Plugin or the Current Activity Property in the Xamarin Essentials Plugin. Then you could just do:

  • Standalone: CrossCurrentActivity.Current.Activity
  • Xamarin Essentials: Platform.CurrentActivity

If you do not want to use a plugin and you only have 1 Activity in your app, you could get away with assigning a static variable in MainActivity and referencing that where ever you needed it like this:

public class MainActivity : FormsApplicationActivity {
    public static Context Context;

    public MainActivity () {
        Context = this;
    }
}

If you needed Context within a custom renderer, you would want to use the Context passed into the constructor, like this:

public class MyEntryRenderer : EntryRenderer {

    private readonly Context _context;

    public MyEntryRenderer(Context context) : base(context) {
        _context = context;
    }

    // Now use _context or ((Activity)_context) any where you need to (just make sure you pass it into the base constructor)
}

The old deprecated way would be Context view = (Activity)Xamarin.Forms.Forms.Context

Xamarin automatically assigns the Activity to Forms.Context.

hvaughan3
  • 10,955
  • 5
  • 56
  • 76
33

Since the release of Xamarin 2.5, Xamarin.Forms.Forms.Context is obsolete. The Context can now be obtained as follows:

var currentContext = Android.App.Application.Context;
Hagbard
  • 3,430
  • 5
  • 28
  • 64
21
var activity = (Activity)Forms.Context;

or if you are using MainActivity

var activity = (MainActivity)Forms.Context;
Will Faulkner
  • 236
  • 1
  • 4
  • 1
    Yep! And I read your comment after posting mine originally and realising I overdid it. I have upvoted but it won't display – Will Faulkner Apr 07 '17 at 15:14
19

If you are using Xamarin Essentials 1.5 or higher, then you can use Platform.CurrentActivity. This is basically the equivalent of using the CurrentActivity plugin.

Ensure you initialise this correctly as per the instructions ie. in MainActivity OnCreate add the following line

Xamarin.Essentials.Platform.Init(this, savedInstanceState);
James Westgate
  • 11,306
  • 8
  • 61
  • 68
  • 4
    For anyone else that may be confused if they can't seem to find `Platform.CurrentActivity`, make sure you are on the latest Xamarin.Essentials. I was on 1.3 and couldn't see it, upgrading to 1.5 fixed the issue. – Jayden Meyer Mar 03 '20 at 01:40
0

I was trying to do something similar in Xamarin 5 and am having some luck in both my Android and iOS versions using

Shell.Current.CurrentPage 

So something happens like a screenshot or a login and that method (whatever it is) can fire a static event so that any interested activity can look for itself whether it's the active view or not, and if so consume the data (byte array etc.) transported by the event.

class FileChooserPage : ContentPage
{
    public FileChooserPage()
    {
        InitializeComponent();
        GoogleDriveService.Authenticated += GoogleDriveService_Authenticated;
    }

    private void GoogleDriveService_Authenticated(object sender, EventArgs e)
    {
        if (ReferenceEquals(this, Shell.Current.CurrentPage))
        {
            Populate(e);
        }
    }
}
IVSoftware
  • 5,732
  • 2
  • 12
  • 23