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
[zc4wp_za2]
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.
1 2 3 4 | <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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | <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.
1 2 3 | 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.
1 2 3 4 5 | <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.
[zc4wp_za2]
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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 | 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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | 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 :
1 2 3 4 5 6 7 | /// <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 executed12_camera.StartPreview();_camera.TakePicture(null, null, new CameraPictureCallBack(Activity));
Here is the complete code for the Camera fragment.12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273public 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.
- 123456789101112131415161718public 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.
[zc4wp_za2]
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
Rob
Doumer
Rob
Seylan
Ripcoid