Android camera app with Xamarin.Android

android camera xamarin

Hi everyone. A few days ago I was willing to implement camera functionalities in my Xamarin.Android application, as usual I went around to get info how to implement this on the internet, and here is a small sample which demonstrate how to build a simple camera app with Xamarin.Android which captures an image and saves it on your mobile device. Most of the knowledge I used in building this sample is gotten from this documentation.

Here is the code for this app.

Subscribe to the mailing list

Cool Coders

How we will proceed.

  • Create the project and set it up for the app.
  • Add permissions.
  • Implement the camera functionality.
  • Polish up the sample application.

Create the project and set it up

  • Using Visual Studio, create a new Android project.
  • Add a FrameLayout to your Main.axml file.
<FrameLayout
            android:id="@+id/content_frame"
            android:layout_width="match_parent"
            android:layout_height="match_parent"/>
  • Create a new fragment, name CameraFeedFragment
  • Create a view for this fragment and attach this view to the fragment created in my case I named it CameraFragmentLayout.axml .
  • Inside the Fragment’s View add the following views.
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:minWidth="25px"
    android:minHeight="25px">
  
    <FrameLayout
        android:id="@+id/camera_preview"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:layout_weight="1">
    </FrameLayout>

  <Button
      android:text="Snap"
      android:layout_width="match_parent"
      android:layout_height="35.0dp"
      android:gravity="center"
      android:layout_alignParentBottom="true"
      android:id="@+id/snapButton" />
  
</RelativeLayout>
  • Inside the onCreate method of the MainActivity class, add the camera fragment to the frame layout as follows.
FragmentManager.BeginTransaction()
              .Replace(Resource.Id.content_frame, new CameraFragment())
              .Commit();

Adding permissions to the manifest file

To access certain functionalities of our mobile phones, we need permissions as we know all. These permissions are requested in the manifest of our application. This is done as follows.

<uses-feature android:name="android.hardware.camera" />
  <uses-feature android:name="android.hardware.camera" android:required="false" />
  <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
  <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
  <uses-permission android:name="android.permission.CAMERA" />

Here, we are requesting permissions to access the camera, read and write to the phone’s external storage.

Cool Coders

Implementing the Camera functionality

Camera preview

We are going to create a View which will display the images directly seen from the camera into our app. This view will inherit from the SurfaceView class. This view will also serve as call-back when the view is created, destroyed …

Here is its implementation

public class CameraPreview : SurfaceView, ISurfaceHolderCallback
    {
        Android.Hardware.Camera _camera;
        static bool _stopped;

        public CameraPreview(Context context, Android.Hardware.Camera camera) : base(context)
        {
            _camera = camera;
            _camera.SetDisplayOrientation(90);

            //Surface holder callback is set so theat SurfaceChanged, Created, destroy... 
            //Could be called from here.
            Holder.AddCallback(this);
            // deprecated but required on Android versions less than 3.0
            Holder.SetType(SurfaceType.PushBuffers);
        }

        public void SurfaceChanged(ISurfaceHolder holder, [GeneratedEnum] Format format, int width, int height)
        {
            if (Holder.Surface == null)
            {
                return;
            }
            
            try
            {
                _camera.StopPreview();
            }
            catch (Exception)
            {
                // ignore: tried to stop a non-existent preview
            }

            try
            {
                // start preview with new settings
                _camera.SetPreviewDisplay(Holder);
                _camera.StartPreview();
            }
            catch (Exception e)
            {
                Log.Debug("", "Error starting camera preview: " + e.Message);
            }
        }

        public void SurfaceCreated(ISurfaceHolder holder)
        {
            try
            {
                _camera.SetPreviewDisplay(holder);
                _camera.StartPreview();
            }
            catch (IOException e)
            {
                throw e;
            }
        }

        public void SurfaceDestroyed(ISurfaceHolder holder)
        {
            //You could handle release of camera and holder here, but I did it already in the CameraFragment.
        }
    }
Picture callback

After taking a picture with the camera, there is a class which we will implement which will serve as callback and it is in tehis calss that the picture taken will be saved. This class will inherit from Camera.IPictureCallback. Here is its implementation.

public class CameraPictureCallBack : Java.Lang.Object, Camera.IPictureCallback
    {
        const string APP_NAME = "SimpleCameraApp";
        Context _context;

        public CameraPictureCallBack(Context cont)
        {
            _context = cont;
        }

        /// <summary>
        /// Callback when the picture is taken by the Camera
        /// </summary>
        /// <param name="data"></param>
        /// <param name="camera"></param>
        public void OnPictureTaken(byte[] data, Camera camera)
        {
            try
            {
                string fileName = Uri.Parse("test.jpg").LastPathSegment;
                var os = _context.OpenFileOutput(fileName, FileCreationMode.Private);
                System.IO.BinaryWriter binaryWriter = new System.IO.BinaryWriter(os);
                binaryWriter.Write(data);
                binaryWriter.Close();

                //We start the camera preview back since after taking a picture it freezes
                camera.StartPreview();
            }
            catch (System.Exception e)
            {
                Log.Debug(APP_NAME, "File not found: " + e.Message);
            }
        }
    }
The camera fragment

Let’s come back to the camera fragment where every thign is coordinated, we will add a button to the layout of this fragment in my case, this button has an id of snapButton. This button when pressed will take the picture.

  • Add the Camera Preview we created to the frame layout in the fragment’s layout. this is done as follows :
/// <summary>
        /// Set the Camera Preview, and pass it the current device's Camera
        /// </summary>
        private void SetCameraPreview()
        {
            _frameLayout.AddView(new CameraPreview(Activity, _camera));
        }
  • When the snap button is clicked, here is the code which should be executed
    _camera.StartPreview();
    _camera.TakePicture(null, null, new CameraPictureCallBack(Activity));

    Here is the complete code for the Camera fragment.

    public class CameraFragment : Fragment
        {
            Camera _camera;
            CameraPreview _camPreview;
            FrameLayout _frameLayout;
    
            public override void OnCreate(Bundle savedInstanceState)
            {
                base.OnCreate(savedInstanceState);
            }
    
            public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
            {
                var ignor = base.OnCreateView(inflater, container, savedInstanceState);
                var view = inflater.Inflate(Resource.Layout.CameraFragmentLayout, container, false);
    
                var snapButton = view.FindViewById<Button>(Resource.Id.snapButton);
                snapButton.BringToFront();
                snapButton.Click += SnapButtonClick; ;
    
                _camera = SetUpCamera();
                _frameLayout = view.FindViewById<FrameLayout>(Resource.Id.camera_preview);
                SetCameraPreview();
    
                return view;
            }
    
            /// <summary>
            /// Take a picture.
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private void SnapButtonClick(object sender, EventArgs e)
            {
                try
                {
                    _camera.StartPreview();
                    _camera.TakePicture(null, null, new CameraPictureCallBack(Activity));
                }
                catch (Exception ex)
                {
                    throw;
                }
            }
    
    
            /// <summary>
            /// Set the Camera Preview, and pass it the current device's Camera
            /// </summary>
            private void SetCameraPreview()
            {
                _frameLayout.AddView(new CameraPreview(Activity, _camera));
            }
    
            /// <summary>
            /// Get an instace of the current hardware camera of the device
            /// </summary>
            /// <returns></returns>
            Camera SetUpCamera()
            {
                Camera c = null;
                try
                {
                    c = Camera.Open();
                }
                catch (Exception e)
                {
                    Log.Debug("", "Device camera not available now.");
                }
    
                return c;
            }
        }
    Let’s handle a few more issues

    You may have noticed while running the app that the camera causes a bug when the app is paused, or the fragment  is destroyed, this is because the  camera should be released and  this is done as follows.

  • public override void OnDestroy()
           {
               _camera.StopPreview();
               _camera.Release();
               _cameraReleased = true;
               base.OnDestroy();
           }
    
           public override void OnResume()
           {
               if(_cameraReleased)
               {
                   _camera.Reconnect();
                   _camera.StartPreview();
                   _cameraReleased = false;
               }
               base.OnResume();
           }

    Here is the code for this app.

Here is what the app should look like.

Screen shot of the sample app

Cool Coders

IIf you liked this post, or it was useful to you, please 👍 like it, share it on twitter, facebook or other social media… in case you want to get updated on any new useful post, follow me on twitter  and like my page on facebook.

Want to know how to build a smart android app which can understand natural language with LUIS and Xamarin.Android ? Check This Post

Want to know how to create a cross platform mobile app for your bot ? Check This Post 

Follow me on social media and stay updated

3 Replies to “Android camera app with Xamarin.Android”

  1. Hi I’ve downloaded this and loaded the project into Xamarin. This told me that the ‘Camera’ command was obsolete. Please can you advise which version of Android you were running it under?

  2. I ran the sample on Android 4 4.2 Kitkat and Android 6 Marshmallow. And it functions well, as seen on the screen shot at the end of the tutorial.
    What issue do you have precisely ? Your IDE sends you warning about the camera being deprecated ? the code is crashing ?

  3. Thank you.
    When building, the message the camera class is obsolete is displayed, followed by a lot of similar messages (using Nougat 7.1). The application is not built and therefor cannot run.

    Do you have plans to upgrade it to the later versions of Android? The Class for the Camera must have been replaced.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.