A production-ready Android demo application showcasing Google's ML Kit on-device machine learning capabilities for barcode scanning and text recognition with 100% test coverage.
This project demonstrates how to implement ML Kit's scanner functionality in a modern Android application using:
- ML Kit Barcode Scanning: On-device barcode and QR code recognition
- ML Kit Text Recognition: On-device optical character recognition (OCR)
- Jetpack Compose: Modern Android UI framework
- CameraX: Camera functionality with lifecycle awareness
- Clean Architecture: Separation of concerns with MVVM pattern
- Hilt: Dependency injection for testability
- π± Real-time barcode scanning
- π·οΈ Multiple format support (QR, UPC, EAN, Code 128, etc.)
- π Format detection and display
- π― Visual scan area indicators
- πΎ Raw byte data access
- π Real-time text extraction from camera
- π Latin script support (English, Spanish, French, etc.)
- π Confidence scoring
- π± Optimized for mobile documents and signs
- π Continuous scanning mode
- π« No internet required - All processing happens on-device except for initial model download
- π¦ Automatic model downloads - ML Kit handles model management
- β‘ Real-time performance - Optimized for mobile devices
- π Privacy-first - Data never leaves the device
- π¨ Material 3 Design - Modern Android UI guidelines
- π§ͺ 100% Test Coverage - Enterprise-grade testing practices
- π± Modern Architecture - MVVM with Clean Architecture principles
app/
βββ data/
β βββ scanner/
β βββ MLKitBarcodeScanner.kt # Barcode scanning implementation
β βββ MLKitTextRecognizer.kt # Text recognition implementation
βββ domain/
β βββ model/
β βββ ScanResult.kt # Domain models
βββ presentation/
β βββ barcode/
β β βββ BarcodeScannerScreen.kt # Barcode UI
β β βββ BarcodeScannerViewModel.kt
β βββ text/
β β βββ TextRecognitionScreen.kt # Text recognition UI
β β βββ TextRecognitionViewModel.kt
β βββ home/
β β βββ HomeScreen.kt # Main navigation
β βββ components/
β βββ CameraPreview.kt # Reusable camera component
βββ di/
βββ AppModule.kt # Dependency injection
- Presentation Layer: Jetpack Compose UI with ViewModels
- Domain Layer: Business logic and models
- Data Layer: ML Kit integration and camera handling
- Android Studio Narwhal | 2025.1.3 or newer
- Android device/emulator with API 24+ (Android 7.0)
- Camera permission (requested automatically)
-
Clone the repository:
git clone https://github.com/iVamsi/MLKitShowcase.git cd MLKitShowcase -
Open the project in Android Studio
-
Sync the project to download dependencies
-
Run the app on a device or emulator
- The app will request camera permission on first launch
- ML Kit models will download automatically on first use
- No additional setup required!
- Tap "Barcode Scanner" on the home screen
- Point camera at any barcode or QR code
- Keep the barcode within the white frame
- Results appear automatically when detected
- View format type and extracted value
- Tap "Text Recognition" on the home screen
- Point camera at text (documents, signs, etc.)
- Keep text within the scanning frame
- Text is extracted and displayed in real-time
- View confidence scores and character counts
private val scannerOptions = BarcodeScannerOptions.Builder()
.setBarcodeFormats(
Barcode.FORMAT_QR_CODE,
Barcode.FORMAT_UPC_A,
Barcode.FORMAT_EAN_13,
// ... other formats
)
.build()
private val scanner: BarcodeScanner = BarcodeScanning.getClient(scannerOptions)private val textRecognizer: TextRecognizer =
TextRecognition.getClient(TextRecognizerOptions.DEFAULT_OPTIONS)val imageAnalysis = ImageAnalysis.Builder()
.setTargetResolution(Size(1280, 720))
.setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
.build()
imageAnalysis.setAnalyzer(ContextCompat.getMainExecutor(context), analyzer)The app uses Compose State with ViewModels to manage:
- Scanning states (scanning, success, error)
- Camera lifecycle
- Permission handling
- Results display
- Compile SDK: 36
- Min SDK: 24 (Android 7.0)
- Target SDK: 36
- Kotlin: 2.2.10
- Java: 21
- AGP: 8.13.0
// ML Kit - On-device Machine Learning
implementation("com.google.mlkit:text-recognition:16.0.1")
implementation("com.google.mlkit:barcode-scanning:17.3.0")
// CameraX - Modern Camera API
implementation("androidx.camera:camera-core:1.4.2")
implementation("androidx.camera:camera-camera2:1.4.2")
implementation("androidx.camera:camera-lifecycle:1.4.2")
implementation("androidx.camera:camera-view:1.4.2")
// Jetpack Compose - Modern UI Toolkit
implementation(platform("androidx.compose:compose-bom:2025.08.01"))
implementation("androidx.compose.ui:ui")
implementation("androidx.compose.ui:ui-graphics")
implementation("androidx.compose.ui:ui-tooling-preview")
implementation("androidx.compose.material3:material3")
implementation("androidx.compose.material:material-icons-extended")
// Navigation & Architecture
implementation("androidx.navigation:navigation-compose:2.9.3")
implementation("androidx.lifecycle:lifecycle-viewmodel-compose:2.9.3")
implementation("androidx.lifecycle:lifecycle-runtime-compose:2.9.3")
implementation("androidx.activity:activity-compose:1.10.1")
// Dependency Injection
implementation("com.google.dagger:hilt-android:2.57.1")
implementation("androidx.hilt:hilt-navigation-compose:1.2.0")
ksp("com.google.dagger:hilt-compiler:2.57.1")
// Permissions
implementation("com.google.accompanist:accompanist-permissions:0.37.3")
// Coroutines
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.10.2")- View: Jetpack Compose UI components
- ViewModel: Business logic and state management
- Model: Data classes and ML Kit integration
- Abstract data access behind repository interfaces
- Easy to test and modify data sources
- Clean separation of concerns
- Hilt provides dependencies
- Easy testing with mock objects
- Singleton scanners for performance
- Size: ~2MB on-device model
- Formats: 13 supported formats including QR, UPC, EAN, Code 128
- Performance: Real-time scanning at 30fps
- Accuracy: >95% for clear, well-lit barcodes
- Size: ~10MB on-device model
- Languages: Latin script (English, Spanish, French, German, Italian)
- Performance: ~100ms processing time per frame
- Accuracy: >90% for clear, well-lit text
- Models download automatically on first use
- Download happens in background
- Requires internet connection for initial download
- Models cached locally for offline use
This project demonstrates enterprise-grade testing practices with comprehensive test coverage across all layers of the application.
// Unit Testing Framework
testImplementation("junit:junit:4.13.2")
testImplementation("org.jetbrains.kotlin:kotlin-test:2.2.10")
// Mocking & Assertions
testImplementation("io.mockk:mockk:1.13.8")
testImplementation("com.google.truth:truth:1.1.4")
// Coroutines Testing
testImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.10.2")
testImplementation("androidx.arch.core:core-testing:2.2.0")
// Android Testing
testImplementation("org.robolectric:robolectric:4.11.1")
androidTestImplementation("androidx.test.ext:junit:1.3.0")
androidTestImplementation("androidx.test.espresso:espresso-core:3.7.0")
// Compose UI Testing
androidTestImplementation("androidx.compose.ui:ui-test-junit4:$compose_version")
androidTestImplementation("androidx.compose.ui:ui-test-manifest:$compose_version")
// Hilt Testing
androidTestImplementation("com.google.dagger:hilt-android-testing:2.57.1")
kspAndroidTest("com.google.dagger:hilt-compiler:2.57.1")
// Coverage Reporting
jacoco // JaCoCo 0.8.11- β
ScanResultTest.kt- All sealed class variants, equality, hashCode - β
BarcodeFormatTest.kt- Complete enum coverage and validation
- β
MLKitBarcodeScannerTest.kt- Scanner lifecycle, format conversion - β
MLKitTextRecognizerTest.kt- Text recognition states and behavior
- β
BarcodeScannerViewModelTest.kt- Complete state machine testing - β
TextRecognitionViewModelTest.kt- All UI state transitions - β
BarcodeScannerUiStateTest.kt- State class validation - β
TextRecognitionUiStateTest.kt- UI state verification
- β
AppModuleTest.kt- Hilt module validation and instance creation
- β
MLKitShowcaseApplicationTest.kt- App lifecycle and initialization
- β
HomeScreenTest.kt- Compose UI interactions, navigation, accessibility
- β
ColorTest.kt- Theme colors, alpha values, light/dark variants
# Run all unit tests
./gradlew testDebugUnitTest
# Run all instrumentation tests
./gradlew connectedAndroidTest
# Run tests with coverage
./gradlew testDebugUnitTest jacocoTestReport# Generate coverage report
./gradlew jacocoTestReport
# Verify 100% coverage requirement
./gradlew jacocoTestCoverageVerification
# View coverage report
open app/build/reports/jacoco/jacocoTestReport/html/index.html# Domain model tests
./gradlew testDebugUnitTest --tests "*domain*"
# ViewModel tests
./gradlew testDebugUnitTest --tests "*ViewModel*"
# UI tests
./gradlew connectedAndroidTest --tests "*Screen*"
# ML Kit integration tests
./gradlew testDebugUnitTest --tests "*MLKit*"- β Given-When-Then structure for readability
- β Descriptive test names explaining intent
- β Comprehensive mocking with MockK
- β Coroutines testing with test dispatchers
- β Flow testing with channels and test flows
- β Truth assertions for readable error messages
- β Edge case coverage for error handling
- β State transition testing for ViewModels
- β Lifecycle-aware testing for Android components
-
Barcode Scanning:
- Multiple format detection (QR, UPC, EAN, Code 128)
- Format conversion accuracy
- Scanning state management
- Error handling and recovery
-
Text Recognition:
- Text filtering (meaningful vs. short text)
- Confidence score handling
- Continuous scanning behavior
- Latin script recognition
-
UI Interactions:
- Navigation between screens
- Permission request flows
- Camera lifecycle management
- Result display and formatting
-
Architecture Validation:
- Dependency injection correctness
- State management consistency
- Clean architecture boundaries
- Proper separation of concerns
# GitHub Actions Example
- name: Run Unit Tests
run: ./gradlew testDebugUnitTest
- name: Generate Coverage Report
run: ./gradlew jacocoTestReport
- name: Verify Coverage
run: ./gradlew jacocoTestCoverageVerification
- name: Run UI Tests
run: ./gradlew connectedAndroidTest- Frame Rate Limiting: Process every 3rd frame to reduce CPU usage
- Resolution Optimization: Use 1280x720 for balance of speed/accuracy
- Memory Management: Proper ImageProxy cleanup
- Background Processing: ML Kit processing on background threads
- Battery Usage: ~5% per hour of continuous scanning
- Memory Usage: ~50MB RAM during active scanning
- CPU Usage: ~15-20% on mid-range devices
- β All processing happens on-device
- β No data sent to servers
- β No data stored permanently
- β Camera feed not recorded
- β Results cleared on app exit
CAMERA: Required for camera accessINTERNET: Only for initial model download
Camera won't start
- Ensure camera permission is granted
- Check if another app is using camera
- Restart the app
ML Kit models not downloading
- Ensure internet connection for first use
- Clear app data and restart
- Check device storage space
Poor scanning accuracy
- Ensure good lighting
- Hold device steady
- Clean camera lens
- Get closer to target
App crashes on startup
- Update Google Play Services
- Clear app cache
- Reinstall the app
This project is licensed under the Apache License 2.0 - see the LICENSE file for details.
- Google ML Kit team for the excellent on-device ML capabilities
- Android Jetpack team for Compose and CameraX
- Material Design team for the design system
- Open source community for inspiration and guidance