pooya mahmoodi
pooya mahmoodi

Reputation: 93

Problem with screen capturing in Xamarin-Android

I've created a program for capturing the screen of my device. This program is include of 2 part. The main class and the service class. Capturing operation is performed in the service class. I have to send Main Activity context to service class via Dependency Service . Here is the MainActivity class:

     protected override void OnCreate(Bundle savedInstanceState)
        {
            Xamarin.Forms.Forms.Init(this, savedInstanceState);
            Xamarin.Forms.DependencyService.Register<A_Service.ScreenshotService>();
            Xamarin.Forms.DependencyService.Get<A_Service.ScreenshotService>().SetActivity(this);
            base.OnCreate(savedInstanceState);
            Xamarin.Essentials.Platform.Init(this, savedInstanceState);
            SetContentView(Resource.Layout.activity_main);
            StartRecordButton = (Button)FindViewById(Resource.Id.btnStartRecord);
            StopRecordButton = (Button)FindViewById(Resource.Id.btnStopRecord);

            StartRecordButton.Click += (sender, e) => {
                StartService(intent);
            };
            StopRecordButton.Click += (sender, e) => {
                StopService(intent);
            };

            Android.Support.V7.Widget.Toolbar toolbar = FindViewById<Android.Support.V7.Widget.Toolbar>(Resource.Id.toolbar);
            SetSupportActionBar(toolbar);

            intent = new Intent(this, typeof(A_Service));
        }

And here is the Service class:

    namespace AndroidService
{
    [Service]
    public class A_Service : Android.App.Service
    {
        private interface IScreenshotService
        {
            byte[] Capture();
        }

        public class ScreenshotService : IScreenshotService, IDisposable
        {
            public Activity _currentActivity;

            public void SetActivity(Activity activity)
            {
                _currentActivity = activity;
            }
            public byte[] Capture()
            {
                Android.Views.View rootView;
                rootView= _currentActivity.Window.DecorView.RootView;
                using (var screenshot = Bitmap.CreateBitmap(rootView.Width, rootView.Height, Bitmap.Config.Argb8888))
                {
                    var canvas = new Canvas(screenshot);
                    rootView.Draw(canvas);
                    using(var stream=new MemoryStream())
                    {
                        screenshot.Compress(Bitmap.CompressFormat.Png, 90, stream);
                        return stream.ToArray();
                    }
                }  
            }

            public void Dispose()
            {
                this.Dispose();
            }
        }

        public override void OnCreate()
        {
            Toast.MakeText(this, "Service is created ...", ToastLength.Long).Show();
        }

        [return: GeneratedEnum]
        public override StartCommandResult OnStartCommand(Intent intent, [GeneratedEnum] StartCommandFlags flags, int startId)
        {
            Toast.MakeText(this, "سرویس استارت شد", ToastLength.Short).Show();
           
            Task.Run(() =>
            {
                StartCapturing();
            });
            return StartCommandResult.Sticky;
        }

        protected void StartCapturing()
        {
            bool d = true;
            int StartSecond = DateTime.Now.Hour * 3600 + DateTime.Now.Minute * 60 + DateTime.Now.Second;
            int StopSecond;
            using(var snpshot=new ScreenshotService())
            {
                var sShot = snpshot.Capture();
                SavePhoto(sShot);
            }

            while (d)
            {
                StopSecond = DateTime.Now.Hour * 3600 + DateTime.Now.Minute * 60 + DateTime.Now.Second;
                int secDiff = System.Math.Abs(StopSecond - StartSecond);
                if (secDiff == 5) d = false;
            }
        }
        
        public bool SavePhoto(byte[] data)
        {
            string filePath = FullPath("Image");
            try
            {
                using (FileOutputStream bitmapFile = new FileOutputStream(filePath))
                {
                    var buffer = ByteBuffer.Allocate(data.Length);
                    //fos.Write(new byte[buffer.Remaining()]); 
                    byte[] bmpData = new byte[data.Length];
                    buffer.Position(0); //or buffer.Flip();
                    buffer.Get(bmpData, 0, buffer.Remaining());
                    bitmapFile.Write(bmpData);
                    bitmapFile.Close();
                }
            }
            catch
            {
                return false;
            }
            return true;
        }
    }
}

The problem is that after running the program and start the service , on second line of Service class in Capture method the value of "_currentActivity" is became NULL.("ScreenshotService" class)

Upvotes: 0

Views: 164

Answers (1)

Jarvan Zhang
Jarvan Zhang

Reputation: 1013

When using DependencyService, the interface should be created in the shared project and don't create the interface inside a class. Please set the public keyword for the interface so that it could be available in the native platform.

How to use the DependencyService, you could following the steps:

1.Create an interface in the shared project

namespace AndroidService
{
    public interface IScreenshotService
    {
        byte[] Capture();
    }
}

2.Implement the interface on each platform register the platform implementation.

[assembly: Dependency(typeof(ScreenshotService))]
namespace AndroidService.Droid
{
    public class ScreenshotService : IScreenshotService
    {
        public byte[] Capture()
        {
            //
            return xx;
        }
    }
}

2.Then consume the function in the shared project.

var data = DependencyService.Get<IScreenshotService>().Capture();

Check the docs:
DependencyService Introduction and DependencyService Registration and Resolution

Upvotes: 1

Related Questions