← Back to Tutorials
Chapter 13
Multimedia & Graphics
MediaPlayer
class AudioPlayer(private val context: Context) {
private var mediaPlayer: MediaPlayer? = null
fun playFromUrl(url: String) {
mediaPlayer = MediaPlayer().apply {
setDataSource(url)
setOnPreparedListener { start() }
setOnErrorListener { _, _, _ -> false }
prepareAsync()
}
}
fun playFromResource(resId: Int) {
mediaPlayer = MediaPlayer.create(context, resId)
mediaPlayer?.start()
}
fun pause() {
mediaPlayer?.pause()
}
fun resume() {
mediaPlayer?.start()
}
fun stop() {
mediaPlayer?.stop()
mediaPlayer?.release()
mediaPlayer = null
}
fun getCurrentPosition(): Int = mediaPlayer?.currentPosition ?: 0
}
Camera API
// CameraX (modern camera API)
// build.gradle.kts
// implementation("androidx.camera:camera-camera2:1.3.0")
// implementation("androidx.camera:camera-lifecycle:1.3.0")
// implementation("androidx.camera:camera-view:1.3.0")
class CameraActivity : AppCompatActivity() {
private lateinit var imageCapture: ImageCapture
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_camera)
val cameraProviderFuture = ProcessCameraProvider.getInstance(this)
cameraProviderFuture.addListener({
val cameraProvider = cameraProviderFuture.get()
val preview = Preview.Builder().build()
imageCapture = ImageCapture.Builder()
.setCaptureMode(ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY)
.build()
val cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA
cameraProvider.bindToLifecycle(this, cameraSelector, preview, imageCapture)
}, ContextCompat.getMainExecutor(this))
// Take photo
findViewById<Button>(R.id.captureBtn).setOnClickListener {
val photoFile = File(externalMediaDirs[0],
"photo_${System.currentTimeMillis()}.jpg")
val outputOptions = ImageCapture.OutputFileOptions.Builder(photoFile).build()
imageCapture.takePicture(outputOptions, ContextCompat.getMainExecutor(this),
object : ImageCapture.OnImageSavedCallback {
override fun onImageSaved(output: ImageCapture.OutputFileResults) {
Toast.makeText(this@CameraActivity, "Photo saved!", Toast.LENGTH_SHORT).show()
}
override fun onError(exc: ImageCaptureException) {
Toast.makeText(this@CameraActivity, "Error: ${exc.message}", Toast.LENGTH_SHORT).show()
}
})
}
}
}
Custom Canvas Drawing
class CustomCanvasView(context: Context, attrs: AttributeSet?) : View(context, attrs) {
private val paint = Paint().apply {
isAntiAlias = true
style = Paint.Style.FILL
}
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
// Draw background
canvas.drawColor(Color.WHITE)
// Draw circle
paint.color = Color.parseColor("#43a047")
canvas.drawCircle(200f, 200f, 100f, paint)
// Draw rectangle
paint.color = Color.parseColor("#1E88E5")
canvas.drawRect(50f, 350f, 350f, 500f, paint)
// Draw text
paint.color = Color.BLACK
paint.textSize = 40f
canvas.drawText("Hello Canvas!", 50f, 600f, paint)
// Draw line
paint.strokeWidth = 8f
paint.style = Paint.Style.STROKE
canvas.drawLine(50f, 650f, 350f, 650f, paint)
// Draw path
val path = Path().apply {
moveTo(100f, 700f)
lineTo(200f, 750f)
lineTo(300f, 700f)
close()
}
paint.style = Paint.Style.FILL
paint.color = Color.parseColor("#FFC107")
canvas.drawPath(path, paint)
}
}
Image Effects with Bitmap
fun applySepiaEffect(bitmap: Bitmap): Bitmap {
val result = bitmap.copy(Bitmap.Config.ARGB_8888, true)
val canvas = Canvas(result)
val paint = Paint()
val sepiaFilter = ColorMatrix(floatArrayOf(
0.393f, 0.769f, 0.189f, 0f, 0f,
0.349f, 0.686f, 0.168f, 0f, 0f,
0.272f, 0.534f, 0.131f, 0f, 0f,
0f, 0f, 0f, 1f, 0f
))
paint.colorFilter = ColorMatrixColorFilter(sepiaFilter)
canvas.drawBitmap(bitmap, 0f, 0f, paint)
return result
}
Animations
// View animation
view.animate()
.translationX(200f)
.translationY(100f)
.alpha(0.5f)
.scaleX(1.5f)
.scaleY(1.5f)
.rotation(360f)
.setDuration(1000)
.setInterpolator(AccelerateDecelerateInterpolator())
.withEndAction { println("Animation done") }
.start()
// Lottie animations (JSON-based)
// implementation("com.airbnb.android:lottie:6.3.0")
<com.airbnb.lottie.LottieAnimationView
android:id="@+id/animationView"
android:layout_width="200dp"
android:layout_height="200dp"
app:lottie_rawRes="@raw/loading_animation"
app:lottie_loop="true"
app:lottie_autoPlay="true" />
Exercise: Create a photo editor app. Use CameraX to capture a photo, display it in an ImageView, and provide three filters: sepia, grayscale, and invert colors using Bitmap color matrix effects. Add a Lottie loading animation while processing the image.
← Previous: Networking & APIs
Back to Index
Next: Sensors & Hardware →