Skip to content

contentauth/c2pa-android-example

C2PA Android example app

The c2pa-android-example repository contains a prototype Android application demonstrating how to capture photos and videos, embed Content Credentials, and then sign them.

The app is built using modern Android development practices with Jetpack Compose and CameraX.

Key Features

  • Photo and video capture: Uses CameraX for a robust camera implementation.
  • C2PA signing: Signs captured media with RSA keys to create a C2PA manifest, ensuring content authenticity.
  • In-place signing: Correctly handles modern Android Scoped Storage by signing files from content:// URIs in-place using a temporary file strategy.
  • Location tagging: Fetches the device's current location and embeds it into the C2PA manifest.
  • Video recording control: Supports starting, pausing, resuming, and stopping video recordings, with the UI reacting to the current state.
  • Runtime permissions: Gracefully handles camera, audio, and location permissions.

Tech stack and core libraries

  • UI: 100% Jetpack Compose for a declarative and modern UI.
  • Architecture: MVVM (Model-View-ViewModel).
  • Dependency Injection: Hilt for managing dependencies.
  • Camera: CameraX for camera operations, including preview, image capture, and video capture.
  • Content Authenticity: C2PA Android Library for creating and embedding authenticity manifests.
  • Asynchronicity: Kotlin Coroutines and Flow for managing background tasks and reactive data streams.
  • Permissions: Accompanist Permissions for a clean, composable-based permissions handling flow.
  • Location: Google Play Services Fused Location Provider for accurate and efficient location fetching.
  • Image Loading: Coil for displaying the thumbnail preview.
  • MapLibre Compose: For showing location of captured media.

Project Architecture

The application's logic is centered around a few key files that demonstrate a clean separation of concerns.

UI layer (/ui)

CameraScreen.kt:

The main entry point for the camera UI that handles all runtime permission requests (Camera, Audio, Location):

  • Displays either a permission request screen or the main CameraCaptureScreen that:
    • Observes state from CameraViewModel (recordingState, thumbPreviewUri).
    • Displays the CameraXViewfinder for the live camera preview. Provides IconButton controls for taking photos, starting/pausing/resuming/stopping video, and navigating to a media preview.
    • The thumbnail preview dynamically updates by observing StateFlow of the thumbPreviewUri.

ViewModel layer (/ui)

CameraViewModel.kt:

The core of the application's logic; acts as the bridge between the UI and the data/domain layers and:

  • Manages the camera's lifecycle via bindToCamera.
  • Handles user actions like takePhoto() and captureVideo().
  • Manages the recording state through the RecordingState sealed class, exposing it as a StateFlow for the UI to observe.
  • Fetches the device's location using getCurrentLocation() before a capture.
  • After a capture is saved, it triggers the signMediaFile() function.

C2PA signing logic (/c2pa_signing)

Utils.kt:

Contains the signMediaFile() function, which is the heart of the content signing process:

  • Scoped Storage Solution: To sign a file from a content:// URI, it first creates a temporary file in the app's cache, signs that file in-place, and then writes the modified (signed) file back to the original URI.
  • Constructs the C2PA manifest, adding claims for the action (c2pa.created), software agent, and location data.
  • Configures the SignerInfo object using RSA keys stored locally as PEM files.

General utilities (/utils)

Utils.kt:

  • getOrGenerateKeyPair(), saveKeyToPem(), etc.: A set of functions for generating an RSA KeyPair and saving it to disk in the standard PEM format.
  • readPemString(): A robust function to read PEM files, correctly stripping headers/footers.
  • getCurrentLocation(): A suspend function that uses the Fused Location Provider to fetch the device's location one time.
  • getMediaFlow(): A function that queries the Android MediaStore to retrieve all photos and videos created by the app, exposing them as a Kotlin Flow.

About

Example app that uses c2pa-android to add Content Credentials

Topics

Resources

License

Code of conduct

Contributing

Security policy

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors 2

  •  
  •  

Languages