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,258 @@
1
+ ---
2
+ name: exoplayer
3
+ description: >
4
+ ExoPlayer (Media3) setup and usage for advanced media playback on Android.
5
+ Load this skill when implementing audio/video streaming, HLS/DASH playback,
6
+ background audio with MediaSession, playlist management, or custom renderers.
7
+ ---
8
+
9
+ # ExoPlayer (Media3)
10
+
11
+ ## Overview
12
+ ExoPlayer, now part of AndroidX Media3, is the recommended media player for Android. It supports HTTP streaming (HLS, DASH, SmoothStreaming), local files, playlists, gapless audio, and deep MediaSession integration. It replaces `MediaPlayer` for all but the simplest use cases.
13
+
14
+ ---
15
+
16
+ ## Core Principles
17
+
18
+ - Use **Media3 ExoPlayer** — not the standalone ExoPlayer library (deprecated)
19
+ - Create one `ExoPlayer` instance per playback session — not per screen
20
+ - Use **MediaSession** for background audio and system/notification controls
21
+ - Release the player when done — `player.release()` frees all resources
22
+ - For background audio, use a `MediaSessionService` (foreground service)
23
+
24
+ ---
25
+
26
+ ## Setup
27
+
28
+ ```toml
29
+ [versions]
30
+ media3 = "1.4.0"
31
+
32
+ [libraries]
33
+ media3-exoplayer = { module = "androidx.media3:media3-exoplayer", version.ref = "media3" }
34
+ media3-exoplayer-hls = { module = "androidx.media3:media3-exoplayer-hls", version.ref = "media3" }
35
+ media3-ui = { module = "androidx.media3:media3-ui", version.ref = "media3" }
36
+ media3-session = { module = "androidx.media3:media3-session", version.ref = "media3" }
37
+ media3-datasource-okhttp = { module = "androidx.media3:media3-datasource-okhttp", version.ref = "media3" }
38
+ ```
39
+
40
+ ```kotlin
41
+ dependencies {
42
+ implementation(libs.media3.exoplayer)
43
+ implementation(libs.media3.exoplayer.hls)
44
+ implementation(libs.media3.ui)
45
+ implementation(libs.media3.session)
46
+ }
47
+ ```
48
+
49
+ ---
50
+
51
+ ## Basic Playback
52
+
53
+ ```kotlin
54
+ // ✅ Create and configure player
55
+ val player = ExoPlayer.Builder(context)
56
+ .setHandleAudioBecomingNoisy(true) // pause on headphone unplug
57
+ .setAudioAttributes(
58
+ AudioAttributes.Builder()
59
+ .setContentType(C.AUDIO_CONTENT_TYPE_MUSIC)
60
+ .setUsage(C.USAGE_MEDIA)
61
+ .build(),
62
+ true // handle audio focus automatically
63
+ )
64
+ .build()
65
+
66
+ // ✅ Set media item and play
67
+ val mediaItem = MediaItem.fromUri("https://example.com/audio.mp3")
68
+ player.setMediaItem(mediaItem)
69
+ player.prepare()
70
+ player.play()
71
+
72
+ // ✅ Local file
73
+ val mediaItem = MediaItem.fromUri(Uri.fromFile(File(context.filesDir, "audio.mp3")))
74
+
75
+ // ✅ HLS stream
76
+ val mediaItem = MediaItem.Builder()
77
+ .setUri("https://example.com/stream.m3u8")
78
+ .setMimeType(MimeTypes.APPLICATION_M3U8)
79
+ .build()
80
+ ```
81
+
82
+ ---
83
+
84
+ ## Playlist Management
85
+
86
+ ```kotlin
87
+ // ✅ Multiple media items
88
+ val playlist = listOf(
89
+ MediaItem.fromUri("https://example.com/track1.mp3"),
90
+ MediaItem.fromUri("https://example.com/track2.mp3"),
91
+ MediaItem.fromUri("https://example.com/track3.mp3")
92
+ )
93
+
94
+ player.setMediaItems(playlist)
95
+ player.prepare()
96
+ player.play()
97
+
98
+ // ✅ Navigate playlist
99
+ player.seekToNextMediaItem()
100
+ player.seekToPreviousMediaItem()
101
+ player.seekToMediaItem(index = 2)
102
+
103
+ // ✅ Repeat and shuffle
104
+ player.repeatMode = Player.REPEAT_MODE_ALL // repeat playlist
105
+ player.shuffleModeEnabled = true
106
+ ```
107
+
108
+ ---
109
+
110
+ ## Player Controls in Compose
111
+
112
+ ```kotlin
113
+ // ✅ PlayerView in Compose
114
+ @Composable
115
+ fun VideoPlayer(videoUri: Uri) {
116
+ val context = LocalContext.current
117
+
118
+ val player = remember {
119
+ ExoPlayer.Builder(context).build().apply {
120
+ setMediaItem(MediaItem.fromUri(videoUri))
121
+ prepare()
122
+ playWhenReady = true
123
+ }
124
+ }
125
+
126
+ DisposableEffect(Unit) {
127
+ onDispose { player.release() }
128
+ }
129
+
130
+ AndroidView(
131
+ factory = {
132
+ PlayerView(it).apply {
133
+ this.player = player
134
+ useController = true
135
+ }
136
+ },
137
+ modifier = Modifier.fillMaxWidth().aspectRatio(16f / 9f)
138
+ )
139
+ }
140
+ ```
141
+
142
+ ---
143
+
144
+ ## Player Listeners
145
+
146
+ ```kotlin
147
+ // ✅ Listen to playback state changes
148
+ player.addListener(object : Player.Listener {
149
+
150
+ override fun onPlaybackStateChanged(playbackState: Int) {
151
+ when (playbackState) {
152
+ Player.STATE_IDLE -> { /* not started */ }
153
+ Player.STATE_BUFFERING -> showBufferingIndicator()
154
+ Player.STATE_READY -> hideBufferingIndicator()
155
+ Player.STATE_ENDED -> onPlaybackEnded()
156
+ }
157
+ }
158
+
159
+ override fun onIsPlayingChanged(isPlaying: Boolean) {
160
+ updatePlayPauseButton(isPlaying)
161
+ }
162
+
163
+ override fun onPlayerError(error: PlaybackException) {
164
+ Log.e("ExoPlayer", "Playback error: ${error.message}")
165
+ showError(error.message)
166
+ }
167
+
168
+ override fun onMediaItemTransition(mediaItem: MediaItem?, reason: Int) {
169
+ updateNowPlayingUI(mediaItem)
170
+ }
171
+ })
172
+ ```
173
+
174
+ ---
175
+
176
+ ## Background Audio with MediaSession
177
+
178
+ ```kotlin
179
+ // ✅ MediaSessionService for background audio
180
+ @AndroidEntryPoint
181
+ class PlaybackService : MediaSessionService() {
182
+
183
+ private lateinit var player: ExoPlayer
184
+ private lateinit var mediaSession: MediaSession
185
+
186
+ override fun onCreate() {
187
+ super.onCreate()
188
+ player = ExoPlayer.Builder(this)
189
+ .setHandleAudioBecomingNoisy(true)
190
+ .build()
191
+
192
+ mediaSession = MediaSession.Builder(this, player)
193
+ .setCallback(MediaSessionCallback())
194
+ .build()
195
+ }
196
+
197
+ override fun onGetSession(controllerInfo: MediaSession.ControllerInfo): MediaSession =
198
+ mediaSession
199
+
200
+ override fun onDestroy() {
201
+ mediaSession.release()
202
+ player.release()
203
+ super.onDestroy()
204
+ }
205
+
206
+ private inner class MediaSessionCallback : MediaSession.Callback {
207
+ override fun onAddMediaItems(
208
+ mediaSession: MediaSession,
209
+ controller: MediaSession.ControllerInfo,
210
+ mediaItems: List<MediaItem>
211
+ ): ListenableFuture<List<MediaItem>> = Futures.immediateFuture(mediaItems)
212
+ }
213
+ }
214
+
215
+ // AndroidManifest.xml
216
+ // <service android:name=".PlaybackService"
217
+ // android:exported="true"
218
+ // android:foregroundServiceType="mediaPlayback">
219
+ // <intent-filter>
220
+ // <action android:name="androidx.media3.session.MediaSessionService"/>
221
+ // </intent-filter>
222
+ // </service>
223
+ ```
224
+
225
+ ---
226
+
227
+ ## Custom OkHttp Data Source
228
+
229
+ ```kotlin
230
+ // ✅ Use OkHttp for network requests (auth headers, custom interceptors)
231
+ val dataSourceFactory = OkHttpDataSource.Factory(okHttpClient)
232
+ .setDefaultRequestProperties(mapOf("Authorization" to "Bearer $token"))
233
+
234
+ val player = ExoPlayer.Builder(context)
235
+ .setMediaSourceFactory(
236
+ DefaultMediaSourceFactory(context).setDataSourceFactory(dataSourceFactory)
237
+ )
238
+ .build()
239
+ ```
240
+
241
+ ---
242
+
243
+ ## Anti-Patterns
244
+
245
+ - Creating a new `ExoPlayer` instance per screen — expensive, loses state on navigation
246
+ - Not calling `player.release()` — holds audio/video hardware
247
+ - Not setting `setHandleAudioBecomingNoisy(true)` — audio leaks to speaker on unplug
248
+ - Background audio without `MediaSessionService` — system kills playback
249
+ - Using legacy ExoPlayer library instead of Media3 — deprecated
250
+
251
+ ---
252
+
253
+ ## Related Skills
254
+ - `audio` — basic audio playback with MediaPlayer
255
+ - `video` — basic video playback
256
+ - `foreground-service` — required for background audio
257
+ - `notification` — media notification controls
258
+ - `lifecycle` — releasing player with lifecycle
@@ -0,0 +1,228 @@
1
+ ---
2
+ name: video
3
+ description: >
4
+ Android video playback and capture patterns.
5
+ Load this skill when playing local or streaming video, capturing video,
6
+ or handling video output on Android. For advanced playback use ExoPlayer.
7
+ ---
8
+
9
+ # Video
10
+
11
+ ## Overview
12
+ Android provides `VideoView` and `MediaPlayer` for simple local video playback, and `MediaRecorder` for video capture. For streaming, adaptive bitrate, or advanced playback, use ExoPlayer. This skill covers the foundational video APIs.
13
+
14
+ ---
15
+
16
+ ## Core Principles
17
+
18
+ - Use **ExoPlayer** for streaming video, adaptive bitrate (HLS/DASH), or any non-trivial playback
19
+ - Use `VideoView` only for simple local file playback with minimal customization
20
+ - Video capture requires **both** `CAMERA` and `RECORD_AUDIO` permissions
21
+ - Always **release** `MediaPlayer`/`MediaRecorder` — they hold exclusive hardware
22
+ - Handle **lifecycle** — pause video when app goes to background
23
+
24
+ ---
25
+
26
+ ## VideoView — Simple Playback
27
+
28
+ ```kotlin
29
+ // ✅ Play local video in XML layout
30
+ // layout/fragment_video.xml
31
+ // <VideoView android:id="@+id/videoView" ... />
32
+
33
+ // In Fragment
34
+ val videoView = binding.videoView
35
+ val mediaController = MediaController(requireContext())
36
+ mediaController.setAnchorView(videoView)
37
+
38
+ videoView.apply {
39
+ setMediaController(mediaController)
40
+ setVideoURI(Uri.parse("android.resource://${context.packageName}/${R.raw.sample_video}"))
41
+ setOnPreparedListener { start() }
42
+ setOnCompletionListener { /* handle completion */ }
43
+ setOnErrorListener { _, what, extra ->
44
+ Log.e("VideoView", "Error: what=$what extra=$extra")
45
+ true
46
+ }
47
+ requestFocus()
48
+ }
49
+ ```
50
+
51
+ ---
52
+
53
+ ## MediaPlayer — Programmatic Video Playback
54
+
55
+ ```kotlin
56
+ // ✅ VideoView alternative with more control
57
+ class VideoPlayer(private val context: Context) {
58
+
59
+ private var mediaPlayer: MediaPlayer? = null
60
+
61
+ fun playOnSurface(surface: Surface, videoUri: Uri) {
62
+ release()
63
+ mediaPlayer = MediaPlayer().apply {
64
+ setAudioAttributes(
65
+ AudioAttributes.Builder()
66
+ .setContentType(AudioAttributes.CONTENT_TYPE_MOVIE)
67
+ .setUsage(AudioAttributes.USAGE_MEDIA)
68
+ .build()
69
+ )
70
+ setDataSource(context, videoUri)
71
+ setSurface(surface)
72
+ setOnPreparedListener { start() }
73
+ prepareAsync()
74
+ }
75
+ }
76
+
77
+ fun pause() { mediaPlayer?.pause() }
78
+ fun resume() { mediaPlayer?.start() }
79
+
80
+ fun release() {
81
+ mediaPlayer?.release()
82
+ mediaPlayer = null
83
+ }
84
+
85
+ val currentPosition: Int get() = mediaPlayer?.currentPosition ?: 0
86
+ val duration: Int get() = mediaPlayer?.duration ?: 0
87
+ }
88
+ ```
89
+
90
+ ---
91
+
92
+ ## Video Capture with CameraX
93
+
94
+ ```kotlin
95
+ // ✅ Preferred — use CameraX VideoCapture use case
96
+ // See camerax skill for full setup
97
+
98
+ val recorder = Recorder.Builder()
99
+ .setQualitySelector(
100
+ QualitySelector.fromOrderedList(
101
+ listOf(Quality.FHD, Quality.HD, Quality.SD),
102
+ FallbackStrategy.lowerQualityOrHigherThan(Quality.SD)
103
+ )
104
+ )
105
+ .build()
106
+
107
+ val videoCapture = VideoCapture.withOutput(recorder)
108
+
109
+ // Start recording
110
+ var recording: Recording? = null
111
+
112
+ fun startRecording(context: Context, outputFile: File) {
113
+ recording = videoCapture.output
114
+ .prepareRecording(context, FileOutputOptions.Builder(outputFile).build())
115
+ .withAudioEnabled()
116
+ .start(ContextCompat.getMainExecutor(context)) { event ->
117
+ when (event) {
118
+ is VideoRecordEvent.Start -> onRecordingStarted()
119
+ is VideoRecordEvent.Finalize -> {
120
+ if (!event.hasError()) onRecordingSaved(event.outputResults.outputUri)
121
+ else onRecordingError(event.error)
122
+ }
123
+ }
124
+ }
125
+ }
126
+
127
+ fun stopRecording() {
128
+ recording?.stop()
129
+ recording = null
130
+ }
131
+ ```
132
+
133
+ ---
134
+
135
+ ## Video Capture with MediaRecorder (Legacy)
136
+
137
+ ```kotlin
138
+ // ✅ Use when CameraX is not available or Camera2 integration is needed
139
+ class LegacyVideoRecorder(private val context: Context) {
140
+
141
+ private var mediaRecorder: MediaRecorder? = null
142
+
143
+ fun startRecording(surface: Surface, outputFile: File) {
144
+ mediaRecorder = MediaRecorder(context).apply {
145
+ setAudioSource(MediaRecorder.AudioSource.MIC)
146
+ setVideoSource(MediaRecorder.VideoSource.SURFACE)
147
+ setOutputFormat(MediaRecorder.OutputFormat.MPEG_4)
148
+ setAudioEncoder(MediaRecorder.AudioEncoder.AAC)
149
+ setVideoEncoder(MediaRecorder.VideoEncoder.H264)
150
+ setVideoSize(1920, 1080)
151
+ setVideoFrameRate(30)
152
+ setVideoEncodingBitRate(10_000_000)
153
+ setOutputFile(outputFile.absolutePath)
154
+ prepare()
155
+ }
156
+ mediaRecorder?.start()
157
+ }
158
+
159
+ fun stopRecording() {
160
+ mediaRecorder?.apply {
161
+ stop()
162
+ release()
163
+ }
164
+ mediaRecorder = null
165
+ }
166
+ }
167
+ ```
168
+
169
+ ---
170
+
171
+ ## Thumbnail Generation
172
+
173
+ ```kotlin
174
+ // ✅ Generate video thumbnail
175
+ suspend fun getVideoThumbnail(context: Context, videoUri: Uri): Bitmap? {
176
+ return withContext(Dispatchers.IO) {
177
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
178
+ context.contentResolver.loadThumbnail(videoUri, Size(640, 360), null)
179
+ } else {
180
+ MediaMetadataRetriever().use { retriever ->
181
+ retriever.setDataSource(context, videoUri)
182
+ retriever.getFrameAtTime(0)
183
+ }
184
+ }
185
+ }
186
+ }
187
+ ```
188
+
189
+ ---
190
+
191
+ ## Lifecycle Handling
192
+
193
+ ```kotlin
194
+ // ✅ In Fragment — pause/resume with lifecycle
195
+ override fun onPause() {
196
+ super.onPause()
197
+ videoPlayer.pause()
198
+ }
199
+
200
+ override fun onResume() {
201
+ super.onResume()
202
+ videoPlayer.resume()
203
+ }
204
+
205
+ override fun onDestroyView() {
206
+ videoPlayer.release()
207
+ super.onDestroyView()
208
+ }
209
+ ```
210
+
211
+ ---
212
+
213
+ ## Anti-Patterns
214
+
215
+ - Using `VideoView` for streaming — no buffering control, poor UX; use ExoPlayer
216
+ - Not releasing `MediaPlayer`/`MediaRecorder` — hardware lock
217
+ - Video playback in background without a `ForegroundService` — system kills it
218
+ - Capturing video without checking both `CAMERA` and `RECORD_AUDIO` permissions
219
+ - Blocking main thread with `prepare()` — always use `prepareAsync()`
220
+
221
+ ---
222
+
223
+ ## Related Skills
224
+ - `exoplayer` — advanced video/audio playback
225
+ - `camerax` — video capture via CameraX
226
+ - `audio` — audio-only recording and playback
227
+ - `foreground-service` — background video playback
228
+ - `lifecycle` — releasing video resources on lifecycle events