Android quickstart
Install the Video Mobile SDK and apply your first image correction on Android.
This guide walks you through installing the Video Mobile SDK in your Android project and applying your first image correction.
Prerequisites
Before you begin, ensure you have:
- Android Studio Arctic Fox (2020.3.1) or later
- Android SDK with API level 21 or higher
- Your API key and certificate from EyeQ
- A physical Android device for testing (recommended over emulator)
Install the SDK
Follow these steps to add the Video Mobile SDK to your Android project.
Step 1: Add the SDK to your project
- In Android Studio, switch to Project view (drop-down menu at top-left of Project panel, it may show Android by default).
- Right-click on the
appfolder and select New → Directory. - Name it
libsnotlib, always remember the 's'. - Copy
pfcdynamic-sdk-debug.aarinto the newly-createdapp/libs/folder.
Your project structure should look like this:
your-project/
├── app/
│ ├── libs/
│ │ └── pfcdynamic-sdk-debug.aar
│ ├── src/
│ └── build.gradle.kts
├── build.gradle.kts
└── settings.gradle.ktsIf the libs folder doesn't appear in Android Studio, then make sure you're in Project view, not Android view. You can also create libs via terminal:
mkdir app/libs
cp /path/to/pfcdynamic-sdk-debug.aar app/libs/Step 2: Configure Gradle
Add the following to your app-level build.gradle.kts (Module :app):
android {
// Prevent compression of model files
androidResources {
noCompress.addAll(listOf("pnn", "pnne"))
}
}
dependencies {
// Include AAR files from libs directory
implementation(fileTree("libs") { include("*.jar", "*.aar") })
// TensorFlow Lite dependencies (with exclusion to fix namespace conflict)
implementation("org.tensorflow:tensorflow-lite:2.17.0")
implementation("org.tensorflow:tensorflow-lite-gpu:2.17.0")
// Required for lifecycleScope
implementation(libs.androidx.lifecycle.runtime.ktx)
// AppCompat (required for AppCompatActivity)
implementation(libs.androidx.appcompat)
}Step 3: Update AndroidManifest.xml
Add the tools namespace and tools:replace attribute to resolve potential manifest merge conflicts:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<application
android:name=".App"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:theme="@style/Theme.YourApp"
tools:replace="android:allowBackup">
<!-- Your activities here -->
</application>
</manifest>Step 4: Configure theme for AppCompatActivity
If you're using AppCompatActivity (recommended), then your theme must extend an AppCompat theme. Update res/values/themes.xml:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="Theme.YourApp" parent="Theme.AppCompat.Light.DarkActionBar">
<item name="colorPrimary">@color/purple_500</item>
<item name="colorPrimaryDark">@color/purple_700</item>
<item name="colorAccent">@color/teal_200</item>
</style>
</resources>If your project was created with Jetpack Compose, then it might use a Material3 theme (Theme.Material3.*), which is incompatible with AppCompatActivity. Either update the theme as shown above, or use ComponentActivity instead of AppCompatActivity in your MainActivity.
Step 5: Sync your project
Choose one of the following methods to sync your project to download dependencies and configure the SDK:
- Click Sync Now in the banner that appears at the top of the editor, or
- Go to File → Sync Project with Gradle Files, or
- Press Ctrl+Shift+O (Windows/Linux)
Initialize the SDK
Create an Application class to hold a singleton instance of DynamicProcessor, set your license, and initialize the processor.
Step 1: Create App.kt
Create a new file at app/src/main/java/your/package/name/App.kt:
package com.example.yourapp // Replace with your package name
import android.app.Application
import photos.eyeq.dynamic.DynamicProcessor
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
class App : Application() {
companion object {
lateinit var dynamicProcessor: DynamicProcessor
private set
var isInitialized = false
private set
}
override fun onCreate() {
super.onCreate()
dynamicProcessor = DynamicProcessor(this)
// Set license - replace with your credentials
dynamicProcessor.setLicence(
apiKey = "your_api_key",
cert = "your_certificate",
recreate = false
)
// Initialize on background thread. This might take a few seconds.
CoroutineScope(Dispatchers.IO).launch {
dynamicProcessor.init(useGpu = true)
isInitialized = true
}
}
}Step 2: Register in AndroidManifest.xml
Make sure your AndroidManifest.xml includes android:name=".App" in the <application> tag (shown in Step 3 above).
Parameters reference
| Parameter | Description |
|---|---|
apiKey | Your API key from EyeQ. |
cert | Your certificate string (use escaped backslashes: \\). |
recreate | Set true if updating certificate at runtime. |
useGpu | true for GPU acceleration (faster), false for CPU fallback. |
Initialization might take a few seconds. Always run init() on a background thread to avoid freezing the UI.
The isInitialized flag helps you check if the SDK is ready before processing.
GPU inference is faster on most devices. If you encounter issues, then try setting useGpu = false to fall back to CPU processing.
Process your first image
Once the SDK is initialized, you can process images. This example shows a before/after comparison so you can verify the processing worked.
Step 1: Add a test image
Add any photo to your project:
- Find or download a photo, a
.jpgor.png. - Rename it to
sample.jpgorsample.png. - Copy it to
app/src/main/res/drawable/.
For best results, use a photo of a person or landscape. The SDK enhances colors, exposure, and details; the effects are more visible on underexposed or dull images.
Step 2: Create the layout
Create a layout with two ImageViews to show before and after. Create or replace res/layout/activity_main.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="16dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Original"
android:textSize="16sp"
android:textStyle="bold" />
<ImageView
android:id="@+id/originalImage"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:scaleType="centerCrop" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="Processed"
android:textSize="16sp"
android:textStyle="bold" />
<ImageView
android:id="@+id/processedImage"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:scaleType="centerCrop" />
<TextView
android:id="@+id/statusText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="Initializing..." />
</LinearLayout>Step 3: Process and display
Replace your MainActivity.kt with the following code. This loads the original image, waits for the SDK to initialize, processes the image, and displays both versions for comparison:
package com.example.yourapp // Replace with your package name
import android.graphics.BitmapFactory
import android.os.Bundle
import android.widget.ImageView
import android.widget.TextView
import androidx.activity.ComponentActivity
import androidx.lifecycle.lifecycleScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val originalImageView = findViewById<ImageView>(R.id.originalImage)
val processedImageView = findViewById<ImageView>(R.id.processedImage)
val statusText = findViewById<TextView>(R.id.statusText)
// Load the original image
val bitmap = BitmapFactory.decodeResource(resources, R.drawable.sample)
originalImageView.setImageBitmap(bitmap)
lifecycleScope.launch {
// Wait for SDK to initialize
statusText.text = "Initializing SDK..."
while (!App.isInitialized) {
delay(100)
}
statusText.text = "Processing image..."
try {
val result = withContext(Dispatchers.IO) {
App.dynamicProcessor.processImage(bitmap, strength = 1.0f)
}
// Display the processed result
processedImageView.setImageBitmap(result)
statusText.text = "Done! Compare the images above."
} catch (e: Exception) {
statusText.text = "Error: ${e.message}"
}
}
}
}What to expect
When you run the app, you'll see:
- Top image: Your original unprocessed photo
- Bottom image: The same photo after SDK processing
- Status text: Shows "Initializing SDK..." → "Processing image..." → "Done!"
The processed image should show improved colors, better exposure, and enhanced details compared to the original.
VIDEO-SDK Version 1.0.0.23 built from aa5eef97017e23db1d3051b079500606825ef474 on 5-6-2023.
Copyright © 2026 EyeQ Imaging Inc. All rights reserved.