The contract has been changed to return Boolean
instead of Bitmap
starting in androidx.activity version 1.2.0-alpha05. How can I use the Boolean
returned by the built in AndroidResultContracts.TakePicture()
contract to access and display the photo just taken by the user?

- 662
- 6
- 17
2 Answers
I am using
implementation 'androidx.activity:activity-ktx:1.2.0-alpha07'
implementation 'androidx.fragment:fragment-ktx:1.3.0-alpha07'
Here's my full sample code showing how to use the built-in Android Result Contract to take a photo from your application and display it in an ImageView.
Note: My solution uses View Binding
MainActivity
's layout XML included (1) a button defining onTakePhotoClick
as the onClick
event and (2) and ImageView to display the photo taken.
<Button
android:id="@+id/take_photo_button"
style="@style/Button"
android:drawableStart="@drawable/ic_camera_on"
android:onClick="onTakePhotoClick"
android:text="@string/button_take_photo"
app:layout_constraintTop_toBottomOf="@id/request_all_button" />
...
<ImageView
android:id="@+id/photo_preview"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
app:layout_constraintTop_toBottomOf="@id/take_video_button" />
In my MainActivity
I have done the following:
- Defined
imageUri: Uri?
which will be set to the uri of the image taken by theTakePicture()
contract. - Implemented
onTakePhotoClick()
to check for the necessary camera permissions before launching theTakePicture()
contract. - Defined
takePictureRegistration: ActivityResultLauncher
which will actually launch the request to take a photo on the device. WhenisSuccess
is returned astrue
then I know theimageUri
I previously defined now references the photo I just took. - Defined a
takePicture: Runnable
simply for code reuse. Note that the 2ndString
parameter passed to theFileProvider.getUriForFile(context, authority, file)
method will need to match theauthorities
attribute provided to the<provider>
in your app'sAndroidManifest.xml
. - For full transparency, I have also added the code showing how I use the ActivityResultContracts.RequestPermission() to request the user for runtime permissions to access the camera.
private var imageUri: Uri? = null
/**
* Function for onClick from XML
*
* Check if camera permission is granted, and if not, request it
* Once permission granted, launches camera to take photo
*/
fun onTakePhotoClick(view: View) {
if (!checkPermission(Manifest.permission.CAMERA)) {
// request camera permission first
onRequestCameraClick(callback = takePicture)
} else {
takePicture.run()
}
}
private val takePicture: Runnable = Runnable {
ImageUtils.createImageFile(applicationContext)?.also {
imageUri = FileProvider.getUriForFile(
applicationContext,
BuildConfig.APPLICATION_ID + ".fileprovider",
it
)
takePictureRegistration.launch(imageUri)
}
}
private val takePictureRegistration =
registerForActivityResult(ActivityResultContracts.TakePicture()) { isSuccess ->
if (isSuccess) {
mBinding.photoPreview.setImageURI(imageUri)
}
}
/**
* Function for onClick from XML
*
* Launches permission request for camera
*/
fun onRequestCameraClick(view: View? = null, callback: Runnable? = null) {
registerForActivityResult(ActivityResultContracts.RequestPermission()) { isGranted: Boolean ->
// update image
mBinding.iconCameraPermission.isEnabled = isGranted
val message = if (isGranted) {
"Camera permission has been granted!"
} else {
"Camera permission denied! :("
}
Toast.makeText(this, message, Toast.LENGTH_SHORT).show()
if (isGranted) {
callback?.run()
}
}.launch(Manifest.permission.CAMERA)
}
For full transparency the ImageUtils
utility class has the createImageFile()
method defined as follows and returns a File?
when given context. Note that I am using the external files directory as the storage directory for my FileProvider.
object ImageUtils {
lateinit var currentPhotoPath: String
@Throws(IOException::class)
fun createImageFile(context: Context): File? {
// Create an image file name
val timeStamp: String = SimpleDateFormat("yyyyMMdd_HHmmss", Locale.US).format(Date())
val storageDir: File? = context.getExternalFilesDir(Environment.DIRECTORY_PICTURES)
return File.createTempFile(
"JPEG_${timeStamp}_", /* prefix */
".jpg", /* suffix */
storageDir /* directory */
).apply {
// Save a file: path for use with ACTION_VIEW intents
currentPhotoPath = absolutePath
}
}
}
Don't forget to add the uses-permission
, uses-feature
and provider
tags to the AndroidManifest
.
Also make sure the authorities
attribute provided to the <provider>
matches the 2nd String parameter passed to FileProvider.getUriForFile(context, authority, file)
method. In my example, I have made my authority the package name + ".fileprovider". Read more about FileProvider
from Google's documentation.
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.captech.android_activity_results">
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-feature android:name="android.hardware.camera" />
<application
...
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="com.captech.android_activity_results.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
</provider>
</application>
</manifest>
My res/xml/file_paths
is shown below. Because I am using getExternalFilesDir()
, I am using the <external-files-path>
tags in the XML.
Note: If you are NOT using the external files directory, you may want to look up which FileProvider storage directory you want to specify in your XML tags here.
<?xml version="1.0" encoding="utf-8"?>
<paths>
<external-files-path
name="my_images"
path="/" />
</paths>
The result would display the imageUri
in the ImageView:

- 662
- 6
- 17
-
6You don't need the `CAMERA` permission to take a photo via an external app. That app is what needs that permission. It will throw a `SecurityException`, though, if it's listed in the manifest but not granted, so make sure to remove everything, if you change that. Also, you're not really using `WRITE_EXTERNAL_STORAGE`, since you're not requesting it, and you don't need it for `getExternalFilesDir()` anyway, so you could get rid of that, too. Just FYI. – Mike M. Aug 13 '20 at 21:39
-
6The fact that all of these parts are needed in order to simply get an image from the default camera app using this new and supposedly improved API is utterly absurd. Why does the API not have an option to autogenerate a temp Uri? Why is there no API to get a Bitmap where that is what's needed? Google, please fix this. – Ollie C Jan 27 '21 at 10:49
-
2Your code is cleaner than the code written in the official documentation about AndroidResultContract {which doesn't exist}, and the one written here https://developer.android.com/training/camera/photobasics?authuser=1 – Amr Apr 06 '21 at 09:32
I've been struggling with this same issue and only just came up with a (somewhat) tenable solution involving ContentResolver
.
The documentation leaves a lot to the imagination. A major concern with this approach is that the captured image URI has to be managed external to the ActivityResultContract
, which seems counterintuitive as the original question already points out.
I do not know of another way to insert media into the gallery that would solve that part of the problem, but I would absolutely love to see that solution.
// Placeholder Uri
var uri: Uri? = null
// ActivityResultContract for capturing an image
val takePicture =
registerForActivityResult(contract =
ActivityResultContracts.TakePicture()) { imageCaptured ->
if (imageCaptured) {
// Do stuff with your Uri here
}
}
...
fun myClickHandler() {
// Create a name for your image file
val filename = "${getTimeStamp("yyyyMMdd_HHmmss")}-$label.jpg"
// Get the correct media Uri for your Android build version
val imageUri =
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
MediaStore.Images.Media.getContentUri(
MediaStore.VOLUME_EXTERNAL_PRIMARY)
} else {
MediaStore.Audio.Media.EXTERNAL_CONTENT_URI
}
val imageDetails = ContentValues().apply {
put(MediaStore.Audio.Media.DISPLAY_NAME, filename)
}
// Try to create a Uri for your image file
activity.contentResolver.insert(imageUri, imageDetails).let {
// Save the generated Uri using our placeholder from before
uri = it
// Capture your image
takePicture.launch(uri)
} ?: run {
// Something went wrong
}
}

- 18,333
- 31
- 67
- 74

- 415
- 4
- 13