android-sdd 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (176) hide show
  1. package/dist/index.js +143 -0
  2. package/package.json +27 -0
  3. package/skills/Android Ecosystem/Baseline Profile Generator/SKILL.md +277 -0
  4. package/skills/Android Ecosystem/Glance/SKILL.md +315 -0
  5. package/skills/Android Platform/Configuration/SKILL.md +201 -0
  6. package/skills/Android Platform/Filesystem/SKILL.md +216 -0
  7. package/skills/Android Platform/Lifecycle/SKILL.md +233 -0
  8. package/skills/Android Platform/Manifest/SKILL.md +226 -0
  9. package/skills/Android Platform/Process Death Recovery/SKILL.md +214 -0
  10. package/skills/Android Platform/Resources/SKILL.md +234 -0
  11. package/skills/Android Platform/SavedStateHandle/SKILL.md +217 -0
  12. package/skills/Android Platform/State Restoration/SKILL.md +210 -0
  13. package/skills/Architecture/Bounded Context/SKILL.md +207 -0
  14. package/skills/Architecture/Clean Architecture/SKILL.md +229 -0
  15. package/skills/Architecture/Domain Modeling/SKILL.md +236 -0
  16. package/skills/Architecture/Entity Design/SKILL.md +243 -0
  17. package/skills/Architecture/Feature Isolation/SKILL.md +216 -0
  18. package/skills/Architecture/MVI/SKILL.md +224 -0
  19. package/skills/Architecture/MVVM/SKILL.md +198 -0
  20. package/skills/Architecture/Modularization/SKILL.md +194 -0
  21. package/skills/Architecture/Offline First/SKILL.md +249 -0
  22. package/skills/Architecture/Repository Pattern/SKILL.md +216 -0
  23. package/skills/Architecture/Side Effect Management/SKILL.md +278 -0
  24. package/skills/Architecture/State Management/SKILL.md +229 -0
  25. package/skills/Architecture/Unidirectional Data Flow/SKILL.md +196 -0
  26. package/skills/Architecture/Use Case Design/SKILL.md +244 -0
  27. package/skills/Architecture/Value Object/SKILL.md +226 -0
  28. package/skills/Build Infrastructure/Build Orchestration/SKILL.md +257 -0
  29. package/skills/Build Infrastructure/Dependency Compatibility Resolver/SKILL.md +259 -0
  30. package/skills/Build Infrastructure/Environment Validator/SKILL.md +311 -0
  31. package/skills/Build System/Build Cache/SKILL.md +233 -0
  32. package/skills/Build System/Build Flavor Strategy/SKILL.md +171 -0
  33. package/skills/Build System/Build Variant/SKILL.md +215 -0
  34. package/skills/Build System/Convention Plugin/SKILL.md +288 -0
  35. package/skills/Build System/Dependency Management/SKILL.md +261 -0
  36. package/skills/Build System/Gradle/SKILL.md +284 -0
  37. package/skills/Build System/Incremental Build/SKILL.md +199 -0
  38. package/skills/Build System/KAPT/SKILL.md +198 -0
  39. package/skills/Build System/KSP/SKILL.md +263 -0
  40. package/skills/Build System/Module Dependency Graph Validation/SKILL.md +223 -0
  41. package/skills/Build System/Specialized/C++/SKILL.md +308 -0
  42. package/skills/Build System/Specialized/JNI/SKILL.md +306 -0
  43. package/skills/Build System/Specialized/NDK/SKILL.md +264 -0
  44. package/skills/Build System/Version Catalog/SKILL.md +304 -0
  45. package/skills/Concurrency/Background Processing/SKILL.md +185 -0
  46. package/skills/Concurrency/Channel/SKILL.md +207 -0
  47. package/skills/Concurrency/Coroutine/SKILL.md +200 -0
  48. package/skills/Concurrency/Flow/SKILL.md +179 -0
  49. package/skills/Concurrency/Mutex Strategy/SKILL.md +185 -0
  50. package/skills/Concurrency/SharedFlow/SKILL.md +171 -0
  51. package/skills/Concurrency/StateFlow/SKILL.md +175 -0
  52. package/skills/Concurrency/Structured Concurrency/SKILL.md +197 -0
  53. package/skills/Concurrency/Synchronization Policy/SKILL.md +192 -0
  54. package/skills/Core Language/Annotation Processing/SKILL.md +224 -0
  55. package/skills/Core Language/DSL/SKILL.md +186 -0
  56. package/skills/Core Language/Extension Functions Design/SKILL.md +191 -0
  57. package/skills/Core Language/Immutability/SKILL.md +156 -0
  58. package/skills/Core Language/KMP/SKILL.md +182 -0
  59. package/skills/Core Language/Kotlin/SKILL.md +187 -0
  60. package/skills/Core Language/Reactive State Management/SKILL.md +228 -0
  61. package/skills/Core Language/Reactive Streams/SKILL.md +235 -0
  62. package/skills/Core Language/Serialization/SKILL.md +191 -0
  63. package/skills/Data Layer/Cache Strategy/SKILL.md +261 -0
  64. package/skills/Data Layer/Conflict Resolution/SKILL.md +248 -0
  65. package/skills/Data Layer/DAO/SKILL.md +225 -0
  66. package/skills/Data Layer/DTO Mapping/SKILL.md +269 -0
  67. package/skills/Data Layer/DataStore/SKILL.md +264 -0
  68. package/skills/Data Layer/Database Versioning Strategy/SKILL.md +215 -0
  69. package/skills/Data Layer/Encrypted Database/SKILL.md +212 -0
  70. package/skills/Data Layer/File Storage/SKILL.md +247 -0
  71. package/skills/Data Layer/Indexing/SKILL.md +184 -0
  72. package/skills/Data Layer/Key-Value Store Strategy/SKILL.md +185 -0
  73. package/skills/Data Layer/Merge Strategy/SKILL.md +240 -0
  74. package/skills/Data Layer/Migration/SKILL.md +243 -0
  75. package/skills/Data Layer/Paging/SKILL.md +264 -0
  76. package/skills/Data Layer/Proto DataStore/SKILL.md +250 -0
  77. package/skills/Data Layer/Room/SKILL.md +244 -0
  78. package/skills/Data Layer/SQLite/SKILL.md +255 -0
  79. package/skills/Data Layer/Sync Engine/SKILL.md +268 -0
  80. package/skills/Dependency Injection/Dagger/SKILL.md +283 -0
  81. package/skills/Dependency Injection/Hilt/SKILL.md +345 -0
  82. package/skills/Dependency Injection/Koin/SKILL.md +282 -0
  83. package/skills/Developer Experience/Detekt/SKILL.md +272 -0
  84. package/skills/Developer Experience/Lint Rule/SKILL.md +281 -0
  85. package/skills/Google Ecosystem/Analytics/SKILL.md +281 -0
  86. package/skills/Google Ecosystem/Crashlytics/SKILL.md +234 -0
  87. package/skills/Google Ecosystem/Firebase/SKILL.md +200 -0
  88. package/skills/Google Ecosystem/Firebase Messaging/SKILL.md +266 -0
  89. package/skills/Media/Audio/SKILL.md +257 -0
  90. package/skills/Media/Camera/SKILL.md +229 -0
  91. package/skills/Media/CameraX/SKILL.md +295 -0
  92. package/skills/Media/ExoPlayer/SKILL.md +258 -0
  93. package/skills/Media/Video/SKILL.md +228 -0
  94. package/skills/Meta Skills/Domain Error Model/SKILL.md +238 -0
  95. package/skills/Meta Skills/Error Handling/SKILL.md +255 -0
  96. package/skills/Meta Skills/Error Mapping/SKILL.md +232 -0
  97. package/skills/Meta Skills/Failure Strategy/SKILL.md +294 -0
  98. package/skills/Meta Skills/Migration Strategy/SKILL.md +305 -0
  99. package/skills/Meta Skills/User Friendly Errors/SKILL.md +334 -0
  100. package/skills/Navigation/Deep Navigation/SKILL.md +209 -0
  101. package/skills/Navigation/Navigation/SKILL.md +215 -0
  102. package/skills/Navigation/Nested Navigation/SKILL.md +214 -0
  103. package/skills/Networking/API Contract/SKILL.md +220 -0
  104. package/skills/Networking/Authentication/SKILL.md +210 -0
  105. package/skills/Networking/Certificate Pinning/SKILL.md +167 -0
  106. package/skills/Networking/Fallback Strategy/SKILL.md +182 -0
  107. package/skills/Networking/Ktor/SKILL.md +219 -0
  108. package/skills/Networking/Multipart Upload/SKILL.md +213 -0
  109. package/skills/Networking/OkHttp/SKILL.md +193 -0
  110. package/skills/Networking/REST/SKILL.md +178 -0
  111. package/skills/Networking/Rate Limiting/SKILL.md +170 -0
  112. package/skills/Networking/Retrofit/SKILL.md +241 -0
  113. package/skills/Networking/Retry-Backoff/SKILL.md +181 -0
  114. package/skills/Networking/Server-Sent Events (SSE)/SKILL.md +196 -0
  115. package/skills/Networking/WebSocket/SKILL.md +224 -0
  116. package/skills/Observability/Crash Reporting/SKILL.md +219 -0
  117. package/skills/Observability/Logging/SKILL.md +168 -0
  118. package/skills/Observability/Metrics/SKILL.md +227 -0
  119. package/skills/Observability/Structured Logging/SKILL.md +234 -0
  120. package/skills/Performance/ANR Prevention/SKILL.md +192 -0
  121. package/skills/Performance/Allocation Optimization/SKILL.md +179 -0
  122. package/skills/Performance/App Startup/SKILL.md +183 -0
  123. package/skills/Performance/Baseline Profile/SKILL.md +205 -0
  124. package/skills/Performance/Battery Optimization/SKILL.md +192 -0
  125. package/skills/Performance/Benchmark/SKILL.md +182 -0
  126. package/skills/Performance/Bitmap Optimization/SKILL.md +178 -0
  127. package/skills/Performance/Compose Optimization/SKILL.md +187 -0
  128. package/skills/Performance/Heap Management/SKILL.md +184 -0
  129. package/skills/Performance/Macrobenchmark/SKILL.md +214 -0
  130. package/skills/Performance/Memory Leak Prevention/SKILL.md +218 -0
  131. package/skills/Performance/Rendering Performance/SKILL.md +205 -0
  132. package/skills/Performance/Startup Optimization/SKILL.md +219 -0
  133. package/skills/Security/Biometric/SKILL.md +224 -0
  134. package/skills/Security/Certificate Transparency/SKILL.md +158 -0
  135. package/skills/Security/Cryptography/SKILL.md +244 -0
  136. package/skills/Security/Encrypted Storage/SKILL.md +273 -0
  137. package/skills/Security/Frida Detection/SKILL.md +230 -0
  138. package/skills/Security/Hook Detection/SKILL.md +197 -0
  139. package/skills/Security/Keystore/SKILL.md +272 -0
  140. package/skills/Security/Network Security Config/SKILL.md +186 -0
  141. package/skills/Security/Obfuscation/SKILL.md +226 -0
  142. package/skills/Security/Proguard/SKILL.md +202 -0
  143. package/skills/Security/R8/SKILL.md +234 -0
  144. package/skills/Security/Reverse Engineering Resistance/SKILL.md +267 -0
  145. package/skills/Security/Root Detection/SKILL.md +220 -0
  146. package/skills/Security/Secure Networking/SKILL.md +220 -0
  147. package/skills/System Integration/AlarmManager/SKILL.md +182 -0
  148. package/skills/System Integration/App Widget/SKILL.md +182 -0
  149. package/skills/System Integration/Deep Link/SKILL.md +187 -0
  150. package/skills/System Integration/Foreground Service/SKILL.md +212 -0
  151. package/skills/System Integration/Notification/SKILL.md +237 -0
  152. package/skills/System Integration/WorkManager/SKILL.md +256 -0
  153. package/skills/System Integration/clipboard/SKILL.md +155 -0
  154. package/skills/System Integration/share-intent/SKILL.md +182 -0
  155. package/skills/Testing/Compose Testing/SKILL.md +296 -0
  156. package/skills/Testing/Espresso/SKILL.md +292 -0
  157. package/skills/Testing/Fake Data/SKILL.md +245 -0
  158. package/skills/Testing/Integration Testing/SKILL.md +288 -0
  159. package/skills/Testing/Mocking/SKILL.md +229 -0
  160. package/skills/Testing/Snapshot Testing/SKILL.md +259 -0
  161. package/skills/Testing/UI Testing/SKILL.md +293 -0
  162. package/skills/Testing/Unit Testing/SKILL.md +309 -0
  163. package/skills/UI System/Bottom Sheet Patterns/SKILL.md +279 -0
  164. package/skills/UI System/Compose/SKILL.md +296 -0
  165. package/skills/UI System/Compose Animation/SKILL.md +281 -0
  166. package/skills/UI System/Compose Multiplatform/SKILL.md +261 -0
  167. package/skills/UI System/Compose Navigation/SKILL.md +255 -0
  168. package/skills/UI System/Compose Performance/SKILL.md +274 -0
  169. package/skills/UI System/Design System/SKILL.md +217 -0
  170. package/skills/UI System/Empty State Strategy/SKILL.md +208 -0
  171. package/skills/UI System/Keyboard Navigation/SKILL.md +214 -0
  172. package/skills/UI System/Loading Strategy/SKILL.md +254 -0
  173. package/skills/UI System/Material 3/SKILL.md +279 -0
  174. package/skills/UI System/RTL/SKILL.md +179 -0
  175. package/src/index.ts +182 -0
  176. package/tsconfig.json +19 -0
@@ -0,0 +1,229 @@
1
+ ---
2
+ name: camera
3
+ description: >
4
+ Android Camera2 API usage and patterns.
5
+ Load this skill when accessing the camera directly via Camera2 API,
6
+ building custom camera experiences, or when CameraX doesn't meet requirements.
7
+ ---
8
+
9
+ # Camera (Camera2)
10
+
11
+ ## Overview
12
+ Camera2 is Android's low-level camera API providing full control over capture pipeline, exposure, focus, and output formats. It's complex but powerful. For most use cases, prefer CameraX — use Camera2 only when fine-grained control is required.
13
+
14
+ ---
15
+
16
+ ## Core Principles
17
+
18
+ - Camera2 is **complex and verbose** — use CameraX unless you need its specific capabilities
19
+ - Camera operations must run on a **background thread** — never on main thread
20
+ - Always **close** `CameraDevice` and `CameraCaptureSession` when done — resource leaks crash other apps
21
+ - Request permissions before accessing camera — `CAMERA` is a runtime permission
22
+ - Handle camera **disconnection and errors** — hardware can become unavailable
23
+
24
+ ---
25
+
26
+ ## When to Use Camera2 vs CameraX
27
+
28
+ | Need | Use |
29
+ |------|-----|
30
+ | Simple photo/video capture | CameraX |
31
+ | Preview + capture | CameraX |
32
+ | RAW capture | Camera2 |
33
+ | Manual exposure/ISO/shutter | Camera2 |
34
+ | Custom image processing pipeline | Camera2 |
35
+ | YUV frame access | Camera2 |
36
+ | Multi-camera (logical/physical) | Camera2 |
37
+
38
+ ---
39
+
40
+ ## Permission
41
+
42
+ ```kotlin
43
+ // AndroidManifest.xml
44
+ <uses-permission android:name="android.permission.CAMERA" />
45
+ <uses-feature android:name="android.hardware.camera" android:required="true" />
46
+
47
+ // ✅ Request at runtime
48
+ val requestPermissionLauncher = registerForActivityResult(
49
+ ActivityResultContracts.RequestPermission()
50
+ ) { isGranted ->
51
+ if (isGranted) openCamera()
52
+ else showPermissionDeniedMessage()
53
+ }
54
+
55
+ requestPermissionLauncher.launch(Manifest.permission.CAMERA)
56
+ ```
57
+
58
+ ---
59
+
60
+ ## Camera Manager — Enumerate Cameras
61
+
62
+ ```kotlin
63
+ // ✅ List available cameras
64
+ val cameraManager = context.getSystemService(CameraManager::class.java)
65
+
66
+ val cameraIds = cameraManager.cameraIdList
67
+ cameraIds.forEach { id ->
68
+ val characteristics = cameraManager.getCameraCharacteristics(id)
69
+ val facing = characteristics.get(CameraCharacteristics.LENS_FACING)
70
+ when (facing) {
71
+ CameraCharacteristics.LENS_FACING_BACK -> Log.d("Camera", "Back camera: $id")
72
+ CameraCharacteristics.LENS_FACING_FRONT -> Log.d("Camera", "Front camera: $id")
73
+ }
74
+ }
75
+
76
+ // ✅ Find back camera
77
+ fun findBackCamera(manager: CameraManager): String? {
78
+ return manager.cameraIdList.firstOrNull { id ->
79
+ manager.getCameraCharacteristics(id)
80
+ .get(CameraCharacteristics.LENS_FACING) == CameraCharacteristics.LENS_FACING_BACK
81
+ }
82
+ }
83
+ ```
84
+
85
+ ---
86
+
87
+ ## Opening Camera
88
+
89
+ ```kotlin
90
+ // ✅ Open camera on background thread
91
+ private lateinit var cameraDevice: CameraDevice
92
+ private val cameraThread = HandlerThread("CameraThread").also { it.start() }
93
+ private val cameraHandler = Handler(cameraThread.looper)
94
+
95
+ @SuppressLint("MissingPermission")
96
+ fun openCamera(cameraId: String) {
97
+ cameraManager.openCamera(cameraId, object : CameraDevice.StateCallback() {
98
+ override fun onOpened(camera: CameraDevice) {
99
+ cameraDevice = camera
100
+ createCaptureSession()
101
+ }
102
+
103
+ override fun onDisconnected(camera: CameraDevice) {
104
+ camera.close()
105
+ }
106
+
107
+ override fun onError(camera: CameraDevice, error: Int) {
108
+ camera.close()
109
+ // Handle error — show user message
110
+ }
111
+ }, cameraHandler)
112
+ }
113
+ ```
114
+
115
+ ---
116
+
117
+ ## Capture Session and Preview
118
+
119
+ ```kotlin
120
+ // ✅ Create capture session for preview
121
+ private lateinit var captureSession: CameraCaptureSession
122
+
123
+ fun createCaptureSession(surface: Surface) {
124
+ val targets = listOf(surface)
125
+
126
+ cameraDevice.createCaptureSession(
127
+ targets,
128
+ object : CameraCaptureSession.StateCallback() {
129
+ override fun onConfigured(session: CameraCaptureSession) {
130
+ captureSession = session
131
+ startPreview(surface)
132
+ }
133
+
134
+ override fun onConfigureFailed(session: CameraCaptureSession) {
135
+ // Handle configuration failure
136
+ }
137
+ },
138
+ cameraHandler
139
+ )
140
+ }
141
+
142
+ // ✅ Start repeating preview request
143
+ fun startPreview(surface: Surface) {
144
+ val previewRequest = cameraDevice
145
+ .createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW)
146
+ .apply {
147
+ addTarget(surface)
148
+ set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE)
149
+ set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON)
150
+ }
151
+ .build()
152
+
153
+ captureSession.setRepeatingRequest(previewRequest, null, cameraHandler)
154
+ }
155
+ ```
156
+
157
+ ---
158
+
159
+ ## Capture Photo
160
+
161
+ ```kotlin
162
+ // ✅ Capture still image
163
+ fun capturePhoto(imageReader: ImageReader) {
164
+ val captureRequest = cameraDevice
165
+ .createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE)
166
+ .apply {
167
+ addTarget(imageReader.surface)
168
+ set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE)
169
+ set(CaptureRequest.JPEG_ORIENTATION, getJpegOrientation())
170
+ }
171
+ .build()
172
+
173
+ captureSession.capture(captureRequest, object : CameraCaptureSession.CaptureCallback() {
174
+ override fun onCaptureCompleted(
175
+ session: CameraCaptureSession,
176
+ request: CaptureRequest,
177
+ result: TotalCaptureResult
178
+ ) {
179
+ // Photo captured
180
+ }
181
+ }, cameraHandler)
182
+ }
183
+
184
+ // ✅ Read image from ImageReader
185
+ imageReader.setOnImageAvailableListener({ reader ->
186
+ val image = reader.acquireLatestImage()
187
+ val buffer = image.planes[0].buffer
188
+ val bytes = ByteArray(buffer.remaining())
189
+ buffer.get(bytes)
190
+ image.close() // ✅ Always close image
191
+ savePhoto(bytes)
192
+ }, cameraHandler)
193
+ ```
194
+
195
+ ---
196
+
197
+ ## Cleanup
198
+
199
+ ```kotlin
200
+ // ✅ Always release camera resources
201
+ fun closeCamera() {
202
+ captureSession.close()
203
+ cameraDevice.close()
204
+ imageReader.close()
205
+ }
206
+
207
+ // ✅ Release in lifecycle
208
+ override fun onPause() {
209
+ super.onPause()
210
+ closeCamera()
211
+ }
212
+ ```
213
+
214
+ ---
215
+
216
+ ## Anti-Patterns
217
+
218
+ - Camera operations on the main thread — causes ANR
219
+ - Not closing CameraDevice on error/disconnect — blocks other apps from using camera
220
+ - Not closing Image from ImageReader — buffer pool exhaustion, new images drop
221
+ - Ignoring orientation — photos appear rotated
222
+ - Not handling permission denial gracefully — crashes without permission
223
+
224
+ ---
225
+
226
+ ## Related Skills
227
+ - `camerax` — high-level camera API (preferred)
228
+ - `manifest` — camera permission declaration
229
+ - `coroutine` — background thread management
@@ -0,0 +1,295 @@
1
+ ---
2
+ name: camerax
3
+ description: >
4
+ CameraX setup and usage for Android camera features.
5
+ Load this skill when implementing photo capture, video recording,
6
+ camera preview, QR scanning, or image analysis with CameraX.
7
+ ---
8
+
9
+ # CameraX
10
+
11
+ ## Overview
12
+ CameraX is Jetpack's high-level camera library built on Camera2. It handles lifecycle management, device compatibility, and camera session complexity automatically. It's the recommended approach for most camera use cases in Android.
13
+
14
+ ---
15
+
16
+ ## Core Principles
17
+
18
+ - CameraX is **lifecycle-aware** — bind to a LifecycleOwner, it handles open/close
19
+ - Use **use cases** to compose camera behavior — Preview, ImageCapture, VideoCapture, ImageAnalysis
20
+ - Maximum **3 use cases** can be active simultaneously — choose wisely
21
+ - CameraX handles **device compatibility** automatically — no per-device workarounds
22
+ - Always run image analysis on a **background executor**
23
+
24
+ ---
25
+
26
+ ## Setup
27
+
28
+ ```toml
29
+ [versions]
30
+ camerax = "1.3.4"
31
+
32
+ [libraries]
33
+ camerax-core = { module = "androidx.camera:camera-core", version.ref = "camerax" }
34
+ camerax-camera2 = { module = "androidx.camera:camera-camera2", version.ref = "camerax" }
35
+ camerax-lifecycle = { module = "androidx.camera:camera-lifecycle", version.ref = "camerax" }
36
+ camerax-video = { module = "androidx.camera:camera-video", version.ref = "camerax" }
37
+ camerax-view = { module = "androidx.camera:camera-view", version.ref = "camerax" }
38
+ camerax-extensions = { module = "androidx.camera:camera-extensions", version.ref = "camerax" }
39
+ ```
40
+
41
+ ```kotlin
42
+ dependencies {
43
+ implementation(libs.camerax.core)
44
+ implementation(libs.camerax.camera2)
45
+ implementation(libs.camerax.lifecycle)
46
+ implementation(libs.camerax.video)
47
+ implementation(libs.camerax.view)
48
+ }
49
+ ```
50
+
51
+ ---
52
+
53
+ ## Preview in Compose
54
+
55
+ ```kotlin
56
+ // ✅ CameraX Preview with Compose
57
+ @Composable
58
+ fun CameraPreview(
59
+ modifier: Modifier = Modifier,
60
+ onImageCaptured: (Uri) -> Unit
61
+ ) {
62
+ val context = LocalContext.current
63
+ val lifecycleOwner = LocalLifecycleOwner.current
64
+
65
+ val previewView = remember { PreviewView(context) }
66
+ val imageCapture = remember { ImageCapture.Builder().build() }
67
+
68
+ LaunchedEffect(Unit) {
69
+ val cameraProvider = ProcessCameraProvider.getInstance(context).await()
70
+
71
+ val preview = Preview.Builder().build().also {
72
+ it.setSurfaceProvider(previewView.surfaceProvider)
73
+ }
74
+
75
+ try {
76
+ cameraProvider.unbindAll()
77
+ cameraProvider.bindToLifecycle(
78
+ lifecycleOwner,
79
+ CameraSelector.DEFAULT_BACK_CAMERA,
80
+ preview,
81
+ imageCapture
82
+ )
83
+ } catch (e: Exception) {
84
+ Log.e("CameraX", "Use case binding failed", e)
85
+ }
86
+ }
87
+
88
+ Box(modifier = modifier) {
89
+ AndroidView(factory = { previewView }, modifier = Modifier.fillMaxSize())
90
+
91
+ Button(
92
+ onClick = { capturePhoto(context, imageCapture, onImageCaptured) },
93
+ modifier = Modifier.align(Alignment.BottomCenter).padding(16.dp)
94
+ ) {
95
+ Text("Capture")
96
+ }
97
+ }
98
+ }
99
+ ```
100
+
101
+ ---
102
+
103
+ ## Photo Capture
104
+
105
+ ```kotlin
106
+ // ✅ Capture photo to file
107
+ fun capturePhoto(
108
+ context: Context,
109
+ imageCapture: ImageCapture,
110
+ onImageCaptured: (Uri) -> Unit
111
+ ) {
112
+ val photoFile = File(
113
+ context.getExternalFilesDir(Environment.DIRECTORY_PICTURES),
114
+ "photo_${System.currentTimeMillis()}.jpg"
115
+ )
116
+
117
+ val outputOptions = ImageCapture.OutputFileOptions.Builder(photoFile).build()
118
+
119
+ imageCapture.takePicture(
120
+ outputOptions,
121
+ ContextCompat.getMainExecutor(context),
122
+ object : ImageCapture.OnImageSavedCallback {
123
+ override fun onImageSaved(output: ImageCapture.OutputFileResults) {
124
+ val savedUri = output.savedUri ?: Uri.fromFile(photoFile)
125
+ onImageCaptured(savedUri)
126
+ }
127
+
128
+ override fun onError(exception: ImageCaptureException) {
129
+ Log.e("CameraX", "Photo capture failed: ${exception.message}", exception)
130
+ }
131
+ }
132
+ )
133
+ }
134
+
135
+ // ✅ Capture to in-memory buffer (no file)
136
+ imageCapture.takePicture(
137
+ ContextCompat.getMainExecutor(context),
138
+ object : ImageCapture.OnImageCapturedCallback() {
139
+ override fun onCaptureSuccess(image: ImageProxy) {
140
+ val buffer = image.planes[0].buffer
141
+ val bytes = ByteArray(buffer.remaining())
142
+ buffer.get(bytes)
143
+ image.close() // ✅ Always close
144
+ processImage(bytes)
145
+ }
146
+
147
+ override fun onError(exception: ImageCaptureException) { }
148
+ }
149
+ )
150
+ ```
151
+
152
+ ---
153
+
154
+ ## Image Analysis (QR / ML)
155
+
156
+ ```kotlin
157
+ // ✅ Real-time frame analysis
158
+ val imageAnalysis = ImageAnalysis.Builder()
159
+ .setTargetResolution(Size(1280, 720))
160
+ .setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
161
+ .build()
162
+ .also { analysis ->
163
+ analysis.setAnalyzer(
164
+ Executors.newSingleThreadExecutor()
165
+ ) { imageProxy ->
166
+ analyzeFrame(imageProxy)
167
+ imageProxy.close() // ✅ Always close
168
+ }
169
+ }
170
+
171
+ // ✅ QR code scanning with ML Kit
172
+ fun analyzeFrame(imageProxy: ImageProxy) {
173
+ val mediaImage = imageProxy.image ?: return
174
+ val image = InputImage.fromMediaImage(mediaImage, imageProxy.imageInfo.rotationDegrees)
175
+
176
+ barcodeScanner.process(image)
177
+ .addOnSuccessListener { barcodes ->
178
+ barcodes.firstOrNull()?.rawValue?.let { value ->
179
+ onQrCodeDetected(value)
180
+ }
181
+ }
182
+ .addOnCompleteListener {
183
+ imageProxy.close()
184
+ }
185
+ }
186
+ ```
187
+
188
+ ---
189
+
190
+ ## Video Capture
191
+
192
+ ```kotlin
193
+ // ✅ Video recording
194
+ private var recording: Recording? = null
195
+
196
+ fun startRecording(
197
+ context: Context,
198
+ videoCapture: VideoCapture<Recorder>,
199
+ onVideoSaved: (Uri) -> Unit
200
+ ) {
201
+ val videoFile = File(
202
+ context.getExternalFilesDir(Environment.DIRECTORY_MOVIES),
203
+ "video_${System.currentTimeMillis()}.mp4"
204
+ )
205
+
206
+ recording = videoCapture.output
207
+ .prepareRecording(context, FileOutputOptions.Builder(videoFile).build())
208
+ .withAudioEnabled()
209
+ .start(ContextCompat.getMainExecutor(context)) { event ->
210
+ when (event) {
211
+ is VideoRecordEvent.Finalize -> {
212
+ if (!event.hasError()) {
213
+ onVideoSaved(event.outputResults.outputUri)
214
+ }
215
+ }
216
+ }
217
+ }
218
+ }
219
+
220
+ fun stopRecording() {
221
+ recording?.stop()
222
+ recording = null
223
+ }
224
+
225
+ // ✅ Setup VideoCapture use case
226
+ val recorder = Recorder.Builder()
227
+ .setQualitySelector(QualitySelector.from(Quality.HD))
228
+ .build()
229
+ val videoCapture = VideoCapture.withOutput(recorder)
230
+ ```
231
+
232
+ ---
233
+
234
+ ## Camera Selector
235
+
236
+ ```kotlin
237
+ // ✅ Select camera
238
+ CameraSelector.DEFAULT_BACK_CAMERA // main back camera
239
+ CameraSelector.DEFAULT_FRONT_CAMERA // selfie camera
240
+
241
+ // ✅ Custom selector
242
+ val cameraSelector = CameraSelector.Builder()
243
+ .requireLensFacing(CameraSelector.LENS_FACING_BACK)
244
+ .build()
245
+
246
+ // ✅ Switch camera
247
+ fun switchCamera(currentSelector: CameraSelector): CameraSelector =
248
+ if (currentSelector == CameraSelector.DEFAULT_BACK_CAMERA)
249
+ CameraSelector.DEFAULT_FRONT_CAMERA
250
+ else
251
+ CameraSelector.DEFAULT_BACK_CAMERA
252
+ ```
253
+
254
+ ---
255
+
256
+ ## Camera Controls
257
+
258
+ ```kotlin
259
+ // ✅ Tap to focus
260
+ fun tapToFocus(x: Float, y: Float, meteringPointFactory: MeteringPointFactory, camera: Camera) {
261
+ val point = meteringPointFactory.createPoint(x, y)
262
+ val action = FocusMeteringAction.Builder(point, FocusMeteringAction.FLAG_AF)
263
+ .setAutoCancelDuration(3, TimeUnit.SECONDS)
264
+ .build()
265
+ camera.cameraControl.startFocusAndMetering(action)
266
+ }
267
+
268
+ // ✅ Zoom
269
+ fun setZoom(camera: Camera, zoomRatio: Float) {
270
+ camera.cameraControl.setZoomRatio(zoomRatio)
271
+ }
272
+
273
+ // ✅ Torch
274
+ fun setTorch(camera: Camera, enabled: Boolean) {
275
+ camera.cameraControl.enableTorch(enabled)
276
+ }
277
+ ```
278
+
279
+ ---
280
+
281
+ ## Anti-Patterns
282
+
283
+ - Not closing `ImageProxy` in analysis — blocks future frames
284
+ - Binding more than 3 use cases simultaneously — exceeds hardware limits
285
+ - Running image analysis on the main executor — blocks UI
286
+ - Not handling `cameraProvider.unbindAll()` before rebinding — stale sessions
287
+ - Ignoring `ImageCapture.Builder.setTargetRotation()` — rotated photos
288
+
289
+ ---
290
+
291
+ ## Related Skills
292
+ - `camera` — Camera2 for advanced/custom use cases
293
+ - `lifecycle` — binding CameraX to lifecycle
294
+ - `compose` — CameraX in Compose with AndroidView
295
+ - `manifest` — camera permission setup