Kotlin - Video Recording and Image Capture on Android using Camera Intents
Previous | Table of Contents | Next |
A Kotlin Android Picture-in-Picture Tutorial | Making Runtime Permission Requests in Android |
Many Android devices are equipped with at least one camera. There are a number of ways to allow the user to record video from within an Android application via these built-in cameras, but by far the easiest approach is to make use of a camera intent included with the Android operating system. This allows an application to invoke the standard Android video recording interface. When the user has finished recording, the intent will return to the application, passing through a reference to the media file containing the recorded video.
As will be demonstrated in this chapter, this approach allows video recording capabilities to be added to applications with just a few lines of code.
Checking for Camera Support
Before attempting to access the camera on an Android device, it is essential that defensive code be implemented to verify the presence of camera hardware. This is of particular importance since not all Android devices include a camera.
The presence or otherwise of a camera can be identified via a call to the PackageManager.hasSystemFeature() method. In order to check for the presence of a front-facing camera, the code needs to check for the presence of the PackageManager.FEATURE_CAMERA_FRONT feature. This can be encapsulated into the following convenience method:
private fun hasCamera(): Boolean { return packageManager.hasSystemFeature( PackageManager.FEATURE_CAMERA_ANY) }
The presence of a camera facing away from the device screen can be similarly verified using the PackageManager.FEATURE_CAMERA constant. A test for whether a device has any camera can be performed by referencing PackageManager.FEATURE_CAMERA_ANY.
Calling the Video Capture Intent
Use of the video capture intent involves, at a minimum, the implementation of code to call the intent activity and a method to handle the return from the activity. The Android built-in video recording intent is represented by MediaStore.ACTION_VIDEO_CAPTURE and may be launched as follows:
private val VIDEO_CAPTURE = 101 val intent = Intent(MediaStore.ACTION_VIDEO_CAPTURE) startActivityForResult(intent, VIDEO_CAPTURE)
When invoked in this way, the intent will place the recorded video into a file using a default location and file name.
When the user either completes or cancels the video recording session, the onActivityResult() method of the calling activity will be called. This method needs to check that the request code passed through as an argument matches that specified when the intent was launched, verify that the recording session was successful and extract the path of the video media file. The corresponding onActivityResult() method for the above intent launch code might, therefore, be implemented as follows:
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent) { val videoUri = data.data if (requestCode == VIDEO_CAPTURE) { if (resultCode == Activity.RESULT_OK) { Toast.makeText(this, "Video saved to:\n" + videoUri, Toast.LENGTH_LONG).show() } else if (resultCode == Activity.RESULT_CANCELED) { Toast.makeText(this, "Video recording cancelled.", Toast.LENGTH_LONG).show() } else { Toast.makeText(this, "Failed to record video", Toast.LENGTH_LONG).show() } } }
The above code example simply displays a toast message indicating the success of the recording intent session. In the event of a successful recording, the path to the stored video file is displayed.
When executed, the video capture intent (Figure 72-1) will launch and provide the user the opportunity to record video.
Calling the Image Capture Intent
In addition to the video capture intent, Android also includes an intent designed for taking still photos using the built-in camera, launched by referencing MediaStore.ACTION_IMAGE_CAPTURE:
private val VIDEO_CAPTURE = 102 val intent = Intent(MediaStore.ACTION_IMAGE_CAPTURE) startActivityForResult(intent, IMAGE_CAPTURE)
As with video capture, the intent may be passed the location and file name into which the image is to be stored, or left to use the default location and naming convention.
Creating an Android Studio Video Recording Project
In the remainder of this chapter, a very simple application will be created to demonstrate the use of the video capture intent. The application will consist of a single button which will launch the video capture intent. Once video has been recorded and the video capture intent dismissed, the application will simply display the path to the video file as a Toast message. The VideoPlayer application created in the previous chapter may then be modified to play back the recorded video.
Create a new project in Android Studio, entering CameraApp into the Application name field and ebookfrenzy.com as the Company Domain setting before clicking on the Next button.
On the form factors screen, enable the Phone and Tablet option and set the minimum SDK setting to API 14: Android 4.0 (IceCreamSandwich). Continue to proceed through the screens, requesting the creation of an Empty Activity named CameraAppActivity with a layout file named activity_camera_app.
Designing the User Interface Layout
Navigate to app -> res -> layout and double-click on the activity_camera_app.xml layout file to load it into the Layout Editor tool.
With the Layout Editor tool in Design mode, delete the default “Hello World!” text view and replace it with a Button view positioned in the center of the layout canvas. Change the text on the button to read “Record Video” and extract the text to a string resource. Also, assign an onClick property to the button so that it calls a method named startRecording when selected by the user:
Remaining within the Attributes tool window, change the ID to recordButton.
Checking for the Camera
Before attempting to launch the video capture intent, the application first needs to verify that the device on which it is running actually has a camera. For the purposes of this example, we will simply make use of the previously outlined hasCamera() method, this time checking for any camera type. In the event that a camera is not present, the Record Video button will be disabled.
Edit the CameraAppActivity.kt file and modify it as follows:
package com.ebookfrenzy.cameraapp import android.app.Activity import android.support.v7.app.AppCompatActivity import android.os.Bundle import android.content.pm.PackageManager import kotlinx.android.synthetic.main.activity_camera_app.* class CameraAppActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_camera_app) recordButton.isEnabled = hasCamera() } private fun hasCamera(): Boolean { return packageManager.hasSystemFeature( PackageManager.FEATURE_CAMERA_ANY) } }
Launching the Video Capture Intent
The objective is for the video capture intent to launch when the user selects the Record Video button. Since this is now configured to call a method named startRecording(), the next logical step is to implement this method within the CameraAppActivity.kt source file:
package com.ebookfrenzy.cameraapp import android.app.Activity import android.support.v7.app.AppCompatActivity import android.os.Bundle import android.content.pm.PackageManager import android.provider.MediaStore import android.content.Intent import android.view.View import android.app.Activity import kotlinx.android.synthetic.main.activity_camera_app.* class CameraAppActivity : AppCompatActivity() { private val VIDEO_CAPTURE = 101 fun startRecording(view: View) { val intent = Intent(MediaStore.ACTION_VIDEO_CAPTURE) startActivityForResult(intent, VIDEO_CAPTURE) } . . }
Handling the Intent Return
When control returns back from the intent to the application’s main activity, the onActivityResult() method will be called. All that this method needs to do for this example is verify the success of the video capture and display the path of the file into which the video has been stored:
. . import android.widget.Toast . . class CameraAppActivity : AppCompatActivity() { . . override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent) { val videoUri = data.data if (requestCode == VIDEO_CAPTURE) { if (resultCode == Activity.RESULT_OK) { Toast.makeText(this, "Video saved to:\n" + videoUri, Toast.LENGTH_LONG).show() } else if (resultCode == Activity.RESULT_CANCELED) { Toast.makeText(this, "Video recording cancelled.", Toast.LENGTH_LONG).show() } else { Toast.makeText(this, "Failed to record video", Toast.LENGTH_LONG).show() } } } . . }
Testing the Application
Compile and run the application on a physical Android device or emulator session, touch the record button and use the video capture intent to record some video. Once completed, stop the video recording. Play back the recording by selecting the play button on the screen. Finally, touch the Done (sometimes represented by a check mark) button on the screen to return to the CameraApp application. On returning, a Toast message should appear stating that the video has been stored in a specific location on the device (the exact location will differ from one device type to another) from where it can be moved, stored or played back depending on the requirements of the app.
Summary
Most Android tablet and smartphone devices include a camera that can be accessed by applications. While there are a number of different approaches to adding camera support to applications, the Android video and image capture intents provide a simple and easy solution to capturing video and images.
Previous | Table of Contents | Next |
A Kotlin Android Picture-in-Picture Tutorial | Making Runtime Permission Requests in Android |