Take photos with Camera and store in an ImageView

<< RETURN: Coding / Android / Coding with Android Studio

Introduction

If you just want to capture an image with the Camera and store it in your Android App for future or immediate use, you can achieve this by starting an activity with an intent that has the following action, "android.media.action.IMAGE_CAPTURE"

Camera interfacing application in action

Full Sample Code

The code for the following files are displayed in this section: MainActivity.kt, activity_main.xml, and AndroidManifest.xml.

MainActivity.kt
package com.example.androidlab

import android.content.Intent
import android.content.pm.PackageManager
import android.graphics.Bitmap
import android.os.Build
import android.os.Bundle
import android.provider.MediaStore
import android.widget.Button
import android.widget.ImageView
import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat


class MainActivity : AppCompatActivity() {

    private lateinit var button: Button
    private lateinit var imageView: ImageView
    private val CAMERA_PERMISSION_CODE = 1
    private lateinit var cameraActivityResultLauncher: ActivityResultLauncher<Intent>

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        button = findViewById(R.id.button)
        imageView = findViewById(R.id.imageView)

        registerActivityResultLauncher()

        button.setOnClickListener {
            if (ContextCompat.checkSelfPermission(
                    applicationContext,
                    android.Manifest.permission.CAMERA
                ) == PackageManager.PERMISSION_GRANTED
            ) {
                val intent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
                cameraActivityResultLauncher.launch(intent)
            } else {
                ActivityCompat.requestPermissions(
                    this@MainActivity,
                    arrayOf(android.Manifest.permission.CAMERA),
                    CAMERA_PERMISSION_CODE
                )
            }
        }
    }

    override fun onRequestPermissionsResult(
        requestCode: Int,
        permissions: Array<String?>,
        grantResults: IntArray
    ) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults)
        if (requestCode == CAMERA_PERMISSION_CODE) {
            if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                val intent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
                cameraActivityResultLauncher.launch(intent)
            }
        }
    }

    private fun registerActivityResultLauncher() {
        cameraActivityResultLauncher = registerForActivityResult(
            ActivityResultContracts.StartActivityForResult()
        ) { resultCamera ->
            val resultCode = resultCamera.resultCode
            val data = resultCamera.data
            if (resultCode == RESULT_OK && data != null) {
                val extras = data.extras

                val imageBitmap: Bitmap? = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
                    extras!!.getParcelable("data", Bitmap::class.java)
                } else {
                    extras!!["data"] as Bitmap?
                }

                imageView.setImageBitmap(imageBitmap)
            }
        }
    }

}
Kotlin
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="58dp"
        android:text="Capture"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/imageView" />

    <ImageView
        android:id="@+id/imageView"
        android:layout_width="237dp"
        android:layout_height="227dp"
        android:background="@color/black"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:srcCompat="@android:drawable/ic_menu_camera" />

</androidx.constraintlayout.widget.ConstraintLayout>
XML
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">

    <uses-feature android:name="android.hardware.camera" android:required="true" />

    <uses-permission android:name="android.permission.CAMERA" />

    <application
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.AndroidLab"
        tools:targetApi="31">
        <activity
            android:name=".MainActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>


</manifest>
XML

Code Breakdown

Step 1 – Update your manifest XML file

XML
<uses-feature android:name="android.hardware.camera" android:required="true" />

<uses-permission android:name="android.permission.CAMERA" />
XML

In-between your <manifest> tag and above (outside) the <application> tag, add the above two lines to tell the device that your application require permissions to the Camera.

Step 2 – Add Permission Checks

Within the code logic of any user interface element (i.e. buttons), add the programming logic to check if Camera permissions were granted, and grant them if they were not already done so.

Kotlin
if (ContextCompat.checkSelfPermission(
        applicationContext,
        android.Manifest.permission.CAMERA
    ) == PackageManager.PERMISSION_GRANTED
) {
    val intent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
    cameraActivityResultLauncher.launch(intent)
} else {
    ActivityCompat.requestPermissions(
        this@MainActivity,
        arrayOf(android.Manifest.permission.CAMERA),
        CAMERA_PERMISSION_CODE
    )
}
Kotlin

This simple if-else block uses ContextCompat.checkSelfPermission(@NonNull Context context, @NonNull String permission) to decide whether or not to request for permissions. If permissions wasn’t granted, the application will request for it. At this point, users will encounter a prompt asking them if they will allow the application to take pictures and record video. Note that this will only happen the first time this application is used, or when the camera permission is not granted for this application.

Step 3 – Add Permission Result and Activity Result Launcher

So what happens when after you grant the permission? It needs to start the default camera application, take a picture, and return the resulting image data.

First of, lets declare the ActivityResultLauncher variable.

Kotlin
private val CAMERA_PERMISSION_CODE = 1
private lateinit var cameraActivityResultLauncher: ActivityResultLauncher<Intent>
Kotlin

Note that the camera permission code is used to identify the permission request and launch the correct ActivityResultLauncher.

Then, override the onRequestPermissionsResult function. We want it to launch the Camera application after the permission has been granted.

Kotlin
override fun onRequestPermissionsResult(
    requestCode: Int,
    permissions: Array<String?>,
    grantResults: IntArray
) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults)
    if (requestCode == CAMERA_PERMISSION_CODE) {
        if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
            val intent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
            cameraActivityResultLauncher.launch(intent)
        }
    }
}
Kotlin

Last but not least, add the ActivityResultLauncher code to the button (or to the relevant UI element).

Kotlin
val intent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
cameraActivityResultLauncher.launch(intent)
Kotlin

Step 4 – Register the ActivityResultLauncher

Kotlin
private fun registerActivityResultLauncher() {
    cameraActivityResultLauncher = registerForActivityResult(
        ActivityResultContracts.StartActivityForResult()
    ) { resultCamera ->
        val resultCode = resultCamera.resultCode
        val data = resultCamera.data
        if (resultCode == RESULT_OK && data != null) {
            val extras = data.extras

            val imageBitmap: Bitmap? = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
                extras!!.getParcelable("data", Bitmap::class.java)
            } else {
                extras!!["data"] as Bitmap?
            }

            imageView.setImageBitmap(imageBitmap)
        }
    }
}
Kotlin

Registering this ActivityResultLauncher with the StartActivityForResult() contract, tells your application that any intent launched with this ActivityResultLauncher will return to this section of code. Upon proper result return, the acquired image bitmap is used to fill the ImageView.

Next Up

Once you’re done, you can also check out Taking Photos with Camera Previews. (TBD)