Image Upload
Camera Access
Photo Gallery
User Interface
Android Development

Allow user to select camera or gallery for image

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

On Android, the clean way to let a user choose between the camera and the gallery is to present both options explicitly and handle each path with the Activity Result API. That keeps lifecycle handling cleaner than the old onActivityResult style and makes permission setup easier to reason about.

Show the Choice First

The user experience is usually best when the app presents a clear choice such as:

  • Take Photo
  • Choose from Gallery

That can be a dialog, bottom sheet, or action sheet. The important part is separating the two input sources before launching anything.

Use Modern Activity Result Contracts

For gallery selection, PickVisualMedia is a good modern choice. For camera capture, TakePicture is a clean contract when you provide a writable destination Uri.

kotlin
1class ImageActivity : AppCompatActivity() {
2    private var pendingPhotoUri: Uri? = null
3
4    private val pickImage = registerForActivityResult(
5        ActivityResultContracts.PickVisualMedia()
6    ) { uri ->
7        if (uri != null) {
8            imageView.setImageURI(uri)
9        }
10    }
11
12    private val takePhoto = registerForActivityResult(
13        ActivityResultContracts.TakePicture()
14    ) { success ->
15        if (success) {
16            pendingPhotoUri?.let { imageView.setImageURI(it) }
17        }
18    }
19}

This is easier to maintain than a single callback with several request codes.

To open the gallery:

kotlin
pickImage.launch(
    PickVisualMediaRequest(ActivityResultContracts.PickVisualMedia.ImageOnly)
)

To launch the camera, prepare a destination Uri first, usually with FileProvider:

kotlin
1val file = File.createTempFile("photo_", ".jpg", cacheDir)
2pendingPhotoUri = FileProvider.getUriForFile(
3    this,
4    "com.example.app.fileprovider",
5    file
6)
7
8takePhoto.launch(pendingPhotoUri)

The camera path is different from the gallery path because the camera app needs a place to write the captured image.

Configure FileProvider and Permissions

The gallery path is relatively simple on modern Android because the photo picker can often avoid broad storage permissions. Camera capture still needs a correctly configured FileProvider.

In AndroidManifest.xml:

xml
1<provider
2    android:name="androidx.core.content.FileProvider"
3    android:authorities="com.example.app.fileprovider"
4    android:exported="false"
5    android:grantUriPermissions="true">
6    <meta-data
7        android:name="android.support.FILE_PROVIDER_PATHS"
8        android:resource="@xml/file_paths" />
9</provider>

And in res/xml/file_paths.xml:

xml
<paths>
    <cache-path name="images" path="." />
</paths>

Without FileProvider, many camera launches fail because your app cannot safely expose a raw filesystem path.

Keep Image Acquisition Separate From Upload Logic

A useful design rule is to end the camera or gallery flow with a stable Uri, not an immediate upload. Once you have the Uri, the rest of the app can:

  • preview the image
  • crop or resize it
  • validate size or format
  • upload it later

This separation makes the code easier to test and gives the user a chance to confirm the image before committing to upload.

Handle Device Capability Gracefully

Not every device or profile will have a usable camera path at the moment you ask for it. It is worth checking capabilities and degrading gracefully. If camera capture is unavailable, show only the gallery option instead of presenting a choice that will fail after the user taps it.

That small check improves reliability and avoids turning a simple image picker into a permission or device-support bug report.

Common Pitfalls

  • Using deprecated onActivityResult patterns in new Android code.
  • Launching the camera without first creating a writable Uri.
  • Forgetting to declare and configure FileProvider.
  • Requesting broad storage permissions when the modern photo picker would avoid them.
  • Mixing image capture and upload logic into one callback until the code becomes hard to reuse.

Summary

  • Let the user explicitly choose camera or gallery first.
  • Use the Activity Result API instead of old request-code callbacks.
  • Use PickVisualMedia for gallery selection.
  • Use TakePicture with a FileProvider Uri for camera capture.
  • Keep image acquisition separate from later preview, editing, or upload steps.

Course illustration
Course illustration

All Rights Reserved.