Android Desktop Features Kotlin Samples

Android Kotlin desktop-like features examples including file dialogs, message boxes, and system tray (notifications)

Key Facts

Category
Kotlin
Items
3
Format Families
sample

Sample Overview

Android Kotlin desktop-like features examples including file dialogs, message boxes, and system tray (notifications) This sample set belongs to Kotlin and can be used to test related workflows inside Elysia Tools.

💻 Message Boxes kotlin

🟢 simple ⭐⭐⭐

Show alert dialogs, confirmation prompts, toast messages, and snackbars

⏱️ 20 min 🏷️ kotlin, android, ui, dialogs
Prerequisites: Basic Kotlin, Android SDK
// Android Kotlin Message Box Examples
// Using AlertDialog, Toast, and Snackbar

// 1. Alert Dialogs
class AlertDialogHelper(private val activity: AppCompatActivity) {

    // Simple alert dialog
    fun showAlert(title: String, message: String) {
        AlertDialog.Builder(activity)
            .setTitle(title)
            .setMessage(message)
            .setPositiveButton("OK") { dialog, which ->
                println("OK clicked")
            }
            .show()
    }

    // Alert with callback
    fun showAlertWithCallback(
                    title: String,
                    message: String,
                    onOkClicked: () -> Unit
    ) {
        AlertDialog.Builder(activity)
            .setTitle(title)
            .setMessage(message)
            .setPositiveButton("OK") { dialog, which ->
                onOkClicked()
            }
            .show()
    }

    // Confirmation dialog
    fun showConfirmDialog(
                    title: String,
                    message: String,
                    onConfirm: () -> Unit,
                    onCancel: () -> Unit = {}
    ) {
        AlertDialog.Builder(activity)
            .setTitle(title)
            .setMessage(message)
            .setPositiveButton("Yes") { dialog, which ->
                onConfirm()
            }
            .setNegativeButton("No") { dialog, which ->
                onCancel()
            }
            .show()
    }

    // Dialog with icon
    fun showAlertWithIcon(
                    title: String,
                    message: String,
                    iconId: Int
    ) {
        AlertDialog.Builder(activity)
            .setTitle(title)
            .setMessage(message)
            .setIcon(iconId)
            .setPositiveButton("OK", null)
            .show()
    }

    // Dialog with neutral button
    fun showThreeButtonDialog(
                    title: String,
                    message: String,
                    onPositive: () -> Unit = {},
                    onNegative: () -> Unit = {},
                    onNeutral: () -> Unit = {}
    ) {
        AlertDialog.Builder(activity)
            .setTitle(title)
            .setMessage(message)
            .setPositiveButton("Yes") { _, _ -> onPositive() }
            .setNegativeButton("No") { _, _ -> onNegative() }
            .setNeutralButton("Cancel") { _, _ -> onNeutral() }
            .show()
    }
}

// 2. Input Dialogs
class InputDialogHelper(private val activity: AppCompatActivity) {

    // Single input dialog
    fun showInputDialog(
                    title: String,
                    hint: String,
                    onConfirm: (String) -> Unit
    ) {
        val input = EditText(activity)
        input.hint = hint

        AlertDialog.Builder(activity)
            .setTitle(title)
            .setView(input)
            .setPositiveButton("OK") { dialog, which ->
                val text = input.text.toString()
                onConfirm(text)
            }
            .setNegativeButton("Cancel", null)
            .show()
    }

    // Multi-input dialog
    fun showMultiInputDialog(
                    title: String,
                    fields: List<InputField>,
                    onConfirm: (Map<String, String>) -> Unit
    ) {
        val container = activity.layoutInflater
            .inflate(android.R.layout.select_dialog_multiselect, null) as ViewGroup

        val inputs = mutableMapOf<String, EditText>()

        for (field in fields) {
            val layout = activity.layoutInflater.inflate(
                android.R.layout.simple_list_item_1,
                container,
                false
            ) as ViewGroup

            val label = EditText(activity)
            label.hint = field.hint
            label.inputType = field.inputType

            container.addView(label)
            inputs[field.key] = label
        }

        AlertDialog.Builder(activity)
            .setTitle(title)
            .setView(container)
            .setPositiveButton("OK") { _, _ ->
                val values = inputs.mapValues { it.text.toString() }
                onConfirm(values)
            }
            .setNegativeButton("Cancel", null)
            .show()
    }

    // Password input dialog
    fun showPasswordDialog(
                    title: String,
                    hint: String = "Enter password",
                    onConfirm: (String) -> Unit
    ) {
        val input = EditText(activity)
        input.hint = hint
        input.inputType = android.text.InputType.TYPE_CLASS_TEXT or
                         android.text.InputType.TYPE_TEXT_VARIATION_PASSWORD

        AlertDialog.Builder(activity)
            .setTitle(title)
            .setView(input)
            .setPositiveButton("OK") { _, _ ->
                onConfirm(input.text.toString())
            }
            .setNegativeButton("Cancel", null)
            .show()
    }

    // Data class for input field
    data class InputField(
        val key: String,
        val hint: String,
        val inputType: Int = android.text.InputType.TYPE_CLASS_TEXT
    )
}

// 3. List Dialogs
class ListDialogHelper(private val activity: AppCompatActivity) {

    // Single choice list
    fun showSingleChoiceList(
                    title: String,
                    items: List<String>,
                    onSelected: (Int) -> Unit
    ) {
        var selectedItem = 0

        AlertDialog.Builder(activity)
            .setTitle(title)
            .setSingleChoiceItems(items.toTypedArray(), selectedItem) { dialog, which ->
                selectedItem = which
            }
            .setPositiveButton("OK") { dialog, which ->
                onSelected(selectedItem)
            }
            .setNegativeButton("Cancel", null)
            .show()
    }

    // Multi-choice list
    fun showMultiChoiceList(
                    title: String,
                    items: List<String>,
                    onSelected: (Set<Int>) -> Unit
    ) {
        val selectedItems = mutableSetOf<Int>()

        AlertDialog.Builder(activity)
            .setTitle(title)
            .setMultiChoiceItems(items.toTypedArray(), null) { dialog, which, isChecked ->
                if (isChecked) {
                    selectedItems.add(which)
                } else {
                    selectedItems.remove(which)
                }
            }
            .setPositiveButton("OK") { dialog, which ->
                onSelected(selectedItems)
            }
            .setNegativeButton("Cancel", null)
            .show()
    }

    // Simple list dialog
    fun showListDialog(
                    title: String,
                    items: List<String>,
                    onSelected: (String) -> Unit
    ) {
        AlertDialog.Builder(activity)
            .setTitle(title)
            .setItems(items.toTypedArray()) { dialog, which ->
                onSelected(items[which])
            }
            .show()
    }
}

// 4. Toast Messages
class ToastHelper(private val context: Context) {

    // Short toast
    fun showShort(message: String) {
        Toast.makeText(context, message, Toast.LENGTH_SHORT).show()
    }

    // Long toast
    fun showLong(message: String) {
        Toast.makeText(context, message, Toast.LENGTH_LONG).show()
    }

    // Custom duration toast
    fun showCustom(message: String, durationMs: Int) {
        val toast = Toast.makeText(context, message, Toast.LENGTH_SHORT)
        toast.duration = durationMs
        toast.show()
    }

    // Toast with position
    fun showWithPosition(
                    message: String,
                    gravity: Int,
                    xOffset: Int,
                    yOffset: Int
    ) {
        val toast = Toast.makeText(context, message, Toast.LENGTH_SHORT)
        toast.setGravity(gravity, xOffset, yOffset)
        toast.show()
    }

    // Custom view toast
    fun showCustomView(message: String) {
        val inflater = LayoutInflater.from(context)
        val layout = inflater.inflate(android.R.layout.simple_list_item_1, null)

        // Assuming there's a TextView in the layout
        // val textView = layout.findViewById<TextView>(android.R.id.text1)
        // textView.text = message

        val toast = Toast(context)
        toast.view = layout
        toast.duration = Toast.LENGTH_SHORT
        toast.show()
    }
}

// 5. Snackbar
class SnackbarHelper {

    // Show simple snackbar
    fun show(view: View, message: String) {
        Snackbar.make(view, message, Snackbar.LENGTH_SHORT).show()
    }

    // Show long snackbar
    fun showLong(view: View, message: String) {
        Snackbar.make(view, message, Snackbar.LENGTH_LONG).show()
    }

    // Snackbar with action
    fun showWithAction(
                    view: View,
                    message: String,
                    actionText: String,
                    onActionClicked: () -> Unit
    ) {
        Snackbar.make(view, message, Snackbar.LENGTH_LONG)
            .setAction(actionText) {
                onActionClicked()
            }
            .show()
    }

    // Indefinite snackbar
    fun showIndefinite(view: View, message: String) {
        Snackbar.make(view, message, Snackbar.LENGTH_INDEFINITE)
            .setAction("Dismiss") { }
            .show()
    }

    // Custom snackbar with callback
    fun showWithCallback(
                    view: View,
                    message: String,
                    onDismissed: () -> Unit
    ) {
        val snackbar = Snackbar.make(view, message, Snackbar.LENGTH_SHORT)

        snackbar.addCallback(object : Snackbar.Callback() {
            override fun onDismissed(transientBottomBar: Snackbar, event: Int) {
                onDismissed()
            }
        })

        snackbar.show()
    }

    // Snackbar with custom styling
    fun showStyled(view: View, message: String, backgroundColor: Int) {
        val snackbar = Snackbar.make(view, message, Snackbar.LENGTH_SHORT)

        snackbar.view.setBackgroundColor(backgroundColor)
        snackbar.show()
    }
}

// 6. Progress Dialogs
class ProgressDialogHelper(private val activity: AppCompatActivity) {

    // Simple progress dialog
    fun showProgressDialog(title: String, message: String): AlertDialog {
        val builder = AlertDialog.Builder(activity)

        val inflater = activity.layoutInflater
        val dialogView = inflater.inflate(android.R.layout.select_dialog_item, null)

        builder.setTitle(title)
            .setMessage(message)
            .setView(dialogView)
            .setCancelable(false)

        val dialog = builder.create()
        dialog.show()

        return dialog
    }

    // Indeterminate progress
    fun showIndeterminateProgress(title: String, message: String): AlertDialog {
        return showProgressDialog(title, message)
    }

    // Horizontal progress dialog
    fun showHorizontalProgress(
                    title: String,
                    message: String,
                    max: Int
    ): AlertDialog {
        val builder = AlertDialog.Builder(activity)

        val progressBar = android.widget.ProgressBar(activity, null, android.R.attr.progressBarStyleHorizontal)
        progressBar.max = max

        builder.setTitle(title)
            .setView(progressBar)
            .setCancelable(false)

        val dialog = builder.create()
        dialog.show()

        return dialog
    }
}

// Main demonstration
fun demonstrateMessageBoxes(activity: AppCompatActivity) {
    println("=== Android Kotlin Message Box Examples ===\n")

    // 1. Alert dialogs
    println("--- 1. Alert Dialogs ---")
    val alertDialogHelper = AlertDialogHelper(activity)

    alertDialogHelper.showAlert("Information", "This is an alert dialog")
    alertDialogHelper.showAlertWithCallback("Notice", "Operation completed") {
        println("Callback executed")
    }

    alertDialogHelper.showConfirmDialog(
        "Confirm",
        "Are you sure you want to continue?",
        onConfirm = { println("User confirmed") },
        onCancel = { println("User cancelled") }
    )

    // 2. Input dialogs
    println("\n--- 2. Input Dialogs ---")
    val inputDialogHelper = InputDialogHelper(activity)

    inputDialogHelper.showInputDialog("Enter Name", "Name") { name ->
        println("Entered name: $name")
    }

    inputDialogHelper.showPasswordDialog("Password") { password ->
        println("Password entered: ${password.length} chars")
    }

    // 3. List dialogs
    println("\n--- 3. List Dialogs ---")
    val listDialogHelper = ListDialogHelper(activity)

    val items = listOf("Option 1", "Option 2", "Option 3", "Option 4")

    listDialogHelper.showSingleChoiceList("Choose an option", items) { index ->
        println("Selected: ${items[index]}")
    }

    listDialogHelper.showListDialog("Select item", items) { item ->
        println("Selected: $item")
    }

    // 4. Toast messages
    println("\n--- 4. Toast Messages ---")
    val toastHelper = ToastHelper(activity)

    toastHelper.showShort("Short toast message")
    toastHelper.showLong("Long toast message")
    toastHelper.showWithPosition(
        "Positioned toast",
        android.view.Gravity.BOTTOM or android.view.Gravity.END,
        0,
        100
    )

    // 5. Snackbar
    println("\n--- 5. Snackbar ---")
    // Note: Snackbar requires a View as anchor
    println("Snackbar examples:")
    println("  - show(): Simple snackbar")
    println("  - showLong(): Long duration snackbar")
    println("  - showWithAction(): With action button")
    println("  - showIndefinite(): Until dismissed")
    println("  - showStyled(): Custom styling")

    // 6. Progress dialogs
    println("\n--- 6. Progress Dialogs ---")
    val progressDialogHelper = ProgressDialogHelper(activity)

    val progressDialog = progressDialogHelper.showIndeterminateProgress(
        "Loading",
        "Please wait..."
    )

    // Simulate loading
    activity.runOnUiThread {
        // In real app, dismiss when operation completes
        // progressDialog.dismiss()
    }

    println("\n=== All Message Box Examples Completed ===")
}

💻 File Dialogs kotlin

🟡 intermediate ⭐⭐⭐⭐

Open file picker, save file dialog, and directory selection using Storage Access Framework

⏱️ 30 min 🏷️ kotlin, android, ui, dialogs
Prerequisites: Intermediate Kotlin, Android SDK
// Android Kotlin File Dialog Examples
// Using Storage Access Framework and Intent

import android.app.Activity
import android.app.AlertDialog
import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.PendingIntent
import android.content.Context
import android.content.DialogInterface
import android.content.Intent
import android.graphics.BitmapFactory
import android.graphics.Color
import android.net.Uri
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.EditText
import android.widget.Toast
import android.os.Bundle
import android.os.Build
import android.provider.DocumentsContract
import android.provider.OpenableColumns
import android.content.ContentResolver
import android.database.Cursor
import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat
import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.contract.ActivityResultContracts
import androidx.fragment.app.Fragment
import androidx.appcompat.app.AppCompatActivity
import com.google.android.material.snackbar.Snackbar

// 1. Open File Dialog
class OpenFileDialogHelper(private val activity: AppCompatActivity) {

    // Create open file launcher
    private val openFileLauncher = activity.registerForActivityResult(
        ActivityResultContracts.StartActivityForResult()
    ) { result ->
        if (result.resultCode == Activity.RESULT_OK) {
            result.data?.data?.also { uri ->
                handleFileSelected(uri)
            }
        }
    }

    // Open single file
    fun openFile(mimeType: String = "*/*") {
        val intent = Intent(Intent.ACTION_OPEN_DOCUMENT).apply {
            addCategory(Intent.CATEGORY_OPENABLE)
            type = mimeType
            putExtra(Intent.EXTRA_TITLE, "Select a file")
        }

        openFileLauncher.launch(intent)
    }

    // Open multiple files
    private val openMultipleFilesLauncher = activity.registerForActivityResult(
        ActivityResultContracts.StartActivityForResult()
    ) { result ->
        if (result.resultCode == Activity.RESULT_OK) {
            result.data?.let { intent ->
                val clipData = intent.clipData

                if (clipData != null) {
                    for (i in 0 until clipData.itemCount) {
                        val uri = clipData.getItemAt(i).uri
                        handleFileSelected(uri)
                    }
                } else {
                    intent.data?.also { uri ->
                        handleFileSelected(uri)
                    }
                }
            }
        }
    }

    fun openMultipleFiles(mimeType: String = "*/*") {
        val intent = Intent(Intent.ACTION_OPEN_DOCUMENT).apply {
            addCategory(Intent.CATEGORY_OPENABLE)
            type = mimeType
            putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true)
        }

        openMultipleFilesLauncher.launch(intent)
    }

    // Open specific file types
    fun openImage() {
        openFile("image/*")
    }

    fun openPdf() {
        openFile("application/pdf")
    }

    fun openTextFile() {
        openFile("text/*")
    }

    // Handle selected file
    private fun handleFileSelected(uri: Uri) {
        val fileName = getFileName(uri)
        val fileSize = getFileSize(uri)

        println("File selected: $fileName")
        println("Size: $fileSize bytes")
        println("URI: $uri")

        // Read file content
        val content = readFileContent(uri)
        println("Content preview: ${content?.take(100)}...")
    }

    // Get file name
    private fun getFileName(uri: Uri): String? {
        var result: String? = null

        if (uri.scheme == "content") {
            val cursor: Cursor? = activity.contentResolver.query(
                uri,
                null,
                null,
                null,
                null
            )

            cursor?.use {
                if (it.moveToFirst()) {
                    val index = it.getColumnIndex(OpenableColumns.DISPLAY_NAME)
                    if (index >= 0) {
                        result = it.getString(index)
                    }
                }
            }
        }

        if (result == null) {
            result = uri.path
            val cut = result?.lastIndexOf('/')
            if (cut != -1) {
                result = result?.substring(cut!! + 1)
            }
        }

        return result
    }

    // Get file size
    private fun getFileSize(uri: Uri): Long {
        val cursor: Cursor? = activity.contentResolver.query(
            uri,
            arrayOf(OpenableColumns.SIZE),
            null,
            null,
            null
        )

        cursor?.use {
            if (it.moveToFirst()) {
                val sizeIndex = it.getColumnIndex(OpenableColumns.SIZE)
                if (sizeIndex >= 0 && !it.isNull(sizeIndex)) {
                    return it.getLong(sizeIndex)
                }
            }
        }

        return 0L
    }

    // Read file content
    private fun readFileContent(uri: Uri): String? {
        return try {
            activity.contentResolver.openInputStream(uri)?.bufferedReader()?.use { it.readText() }
        } catch (e: Exception) {
            println("Error reading file: ${e.message}")
            null
        }
    }
}

// 2. Save File Dialog
class SaveFileDialogHelper(private val activity: AppCompatActivity) {

    private val saveFileLauncher = activity.registerForActivityResult(
        ActivityResultContracts.StartActivityForResult()
    ) { result ->
        if (result.resultCode == Activity.RESULT_OK) {
            result.data?.data?.also { uri ->
                handleFileSaved(uri)
            }
        }
    }

    // Create new file
    fun createFile(fileName: String, mimeType: String = "text/plain") {
        val intent = Intent(Intent.ACTION_CREATE_DOCUMENT).apply {
            addCategory(Intent.CATEGORY_OPENABLE)
            type = mimeType
            putExtra(Intent.EXTRA_TITLE, fileName)
        }

        saveFileLauncher.launch(intent)
    }

    // Save text content
    fun saveTextFile(fileName: String, content: String) {
        val intent = Intent(Intent.ACTION_CREATE_DOCUMENT).apply {
            addCategory(Intent.CATEGORY_OPENABLE)
            type = "text/plain"
            putExtra(Intent.EXTRA_TITLE, fileName)
        }

        saveFileLauncher.launch(Intent.createChooser(intent, "Save file"))
    }

    // Save image
    fun saveImageFile(fileName: String) {
        createFile(fileName, "image/png")
    }

    // Handle file saved
    private fun handleFileSaved(uri: Uri) {
        // Take persistable permission
        val takeFlags = Intent.FLAG_GRANT_READ_URI_PERMISSION or
                         Intent.FLAG_GRANT_WRITE_URI_PERMISSION

        activity.contentResolver.takePersistableUriPermission(uri, takeFlags)

        println("File saved: $uri")

        // Write content to file
        try {
            activity.contentResolver.openOutputStream(uri)?.use { outputStream ->
                val content = "Sample content written at ${java.util.Date()}"
                outputStream.write(content.toByteArray())
            }

            println("Content written successfully")
        } catch (e: Exception) {
            println("Error writing file: ${e.message}")
        }
    }

    // Write bytes to file
    fun writeToFile(uri: Uri, data: ByteArray): Boolean {
        return try {
            activity.contentResolver.openOutputStream(uri)?.use { outputStream ->
                outputStream.write(data)
                outputStream.flush()
            }

            true
        } catch (e: Exception) {
            println("Error writing: ${e.message}")
            false
        }
    }
}

// 3. Directory Selection
class DirectoryPickerHelper(private val activity: AppCompatActivity) {

    private val directoryPickerLauncher = activity.registerForActivityResult(
        ActivityResultContracts.StartActivityForResult()
    ) { result ->
        if (result.resultCode == Activity.RESULT_OK) {
            result.data?.data?.also { uri ->
                handleDirectorySelected(uri)
            }
        }
    }

    // Open directory picker
    fun openDirectory() {
        val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE).apply {
            putExtra(DocumentsContract.EXTRA_INITIAL_URI, null)
        }

        directoryPickerLauncher.launch(intent)
    }

    // Handle directory selected
    private fun handleDirectorySelected(uri: Uri) {
        // Take persistable permission
        val takeFlags = Intent.FLAG_GRANT_READ_URI_PERMISSION or
                         Intent.FLAG_GRANT_WRITE_URI_PERMISSION

        activity.contentResolver.takePersistableUriPermission(uri, takeFlags)

        println("Directory selected: $uri")

        // List files in directory
        listFilesInDirectory(uri)
    }

    // List files in directory
    private fun listFilesInDirectory(directoryUri: Uri) {
        val childrenUri = DocumentsContract.buildChildDocumentsUriUsingTree(
            directoryUri,
            DocumentsContract.getDocumentId(directoryUri)
        )

        val cursor: Cursor? = activity.contentResolver.query(
            childrenUri,
            arrayOf(
                DocumentsContract.Document.COLUMN_DISPLAY_NAME,
                DocumentsContract.Document.COLUMN_MIME_TYPE
            ),
            null,
            null,
            null
        )

        cursor?.use {
            println("Files in directory:")
            while (it.moveToNext()) {
                val nameIndex = it.getColumnIndex(DocumentsContract.Document.COLUMN_DISPLAY_NAME)
                val mimeIndex = it.getColumnIndex(DocumentsContract.Document.COLUMN_MIME_TYPE)

                val name = it.getString(nameIndex)
                val mimeType = it.getString(mimeIndex)

                println("  - $name ($mimeType)")
            }
        }
    }

    // Create subdirectory
    fun createSubdirectory(parentUri: Uri, directoryName: String): Uri? {
        return try {
            val documentUri = DocumentsContract.createDocument(
                activity.contentResolver,
                parentUri,
                DocumentsContract.Document.MIME_TYPE_DIR,
                directoryName
            )

            documentUri
        } catch (e: Exception) {
            println("Error creating directory: ${e.message}")
            null
        }
    }
}

// 4. Advanced File Operations
class AdvancedFileOperations(private val activity: AppCompatActivity) {

    // Open file with custom filter
    fun openWithFilter(mimeTypes: List<String>) {
        val intent = Intent(Intent.ACTION_OPEN_DOCUMENT).apply {
            addCategory(Intent.CATEGORY_OPENABLE)
            type = if (mimeTypes.size == 1) mimeTypes[0] else "*/*"

            if (mimeTypes.size > 1) {
                putExtra(Intent.EXTRA_MIME_TYPES, mimeTypes.toTypedArray())
            }
        }

        activity.startActivityForResult(intent, 1001)
    }

    // Get file metadata
    fun getFileMetadata(uri: Uri): FileMetadata? {
        val cursor: Cursor? = activity.contentResolver.query(
            uri,
            arrayOf(
                OpenableColumns.DISPLAY_NAME,
                OpenableColumns.SIZE,
                OpenableColumns.MIME_TYPE
            ),
            null,
            null,
            null
        )

        return cursor?.use {
            if (it.moveToFirst()) {
                val nameIndex = it.getColumnIndex(OpenableColumns.DISPLAY_NAME)
                val sizeIndex = it.getColumnIndex(OpenableColumns.SIZE)
                val mimeIndex = it.getColumnIndex(OpenableColumns.MIME_TYPE)

                FileMetadata(
                    name = it.getString(nameIndex),
                    size = it.getLong(sizeIndex),
                    mimeType = it.getString(mimeIndex)
                )
            } else {
                null
            }
        }
    }

    // File metadata data class
    data class FileMetadata(
        val name: String,
        val size: Long,
        val mimeType: String
    )
}

// 5. Recent Documents
class RecentDocuments(private val activity: AppCompatActivity) {

    // Get recent files
    fun getRecentDocuments(): List<Uri> {
        val recentUris = mutableListOf<Uri>()

        // Query recent documents
        val projection = arrayOf(
            OpenableColumns.DISPLAY_NAME,
            OpenableColumns.DATE_MODIFIED
        )

        val cursor: Cursor? = activity.contentResolver.query(
            android.provider.MediaStore.Files.getContentUri("external"),
            projection,
            null,
            null,
            "${OpenableColumns.DATE_MODIFIED} DESC LIMIT 10"
        )

        cursor?.use {
            val idIndex = it.getColumnIndex(android.provider.BaseColumns._ID)

            while (it.moveToNext()) {
                val id = it.getLong(idIndex)
                val contentUri = android.provider.MediaStore.Files.getContentUri("external", id)
                recentUris.add(contentUri)
            }
        }

        return recentUris
    }
}

// Main demonstration
fun demonstrateFileDialogs(activity: AppCompatActivity) {
    println("=== Android Kotlin File Dialog Examples ===\n")

    // 1. Open file dialog
    println("--- 1. Open File Dialog ---")
    val openDialogHelper = OpenFileDialogHelper(activity)

    println("Opening file dialog...")
    openDialogHelper.openFile()

    println("\nOpening image picker...")
    openDialogHelper.openImage()

    println("\nOpening multiple files...")
    openDialogHelper.openMultipleFiles()

    // 2. Save file dialog
    println("\n--- 2. Save File Dialog ---")
    val saveDialogHelper = SaveFileDialogHelper(activity)

    println("Creating new file...")
    saveDialogHelper.createFile("example.txt", "text/plain")

    println("\nSaving text file...")
    saveDialogHelper.saveTextFile("note.txt", "Sample content")

    // 3. Directory picker
    println("\n--- 3. Directory Picker ---")
    val directoryPicker = DirectoryPickerHelper(activity)

    println("Opening directory picker...")
    directoryPicker.openDirectory()

    // 4. Advanced operations
    println("\n--- 4. Advanced Operations ---")
    val advancedOps = AdvancedFileOperations(activity)

    println("Opening with multiple MIME type filters...")
    advancedOps.openWithFilter(listOf("image/*", "video/*", "audio/*"))

    // 5. Recent documents
    println("\n--- 5. Recent Documents ---")
    val recentDocs = RecentDocuments(activity)

    println("Getting recent documents...")
    val recent = recentDocs.getRecentDocuments()
    println("Found ${recent.size} recent documents")

    println("\n=== All File Dialog Examples Completed ===")
}

💻 System Tray (Notifications) kotlin

🟡 intermediate ⭐⭐⭐⭐

Display notifications in system tray/status bar with various options

⏱️ 30 min 🏷️ kotlin, android, notifications, ui
Prerequisites: Intermediate Kotlin, Android SDK
// Android Kotlin Notification Examples
// Using NotificationManager and NotificationCompat

// 1. Basic Notification
class BasicNotificationHelper(private val context: Context) {

    companion object {
        private const val CHANNEL_ID = "basic_channel"
        private const val NOTIFICATION_ID = 1001
    }

    private val notificationManager = NotificationManagerCompat.from(context)

    init {
        createNotificationChannel()
    }

    // Create notification channel (required for Android O+)
    private fun createNotificationChannel() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            val channel = NotificationChannel(
                CHANNEL_ID,
                "Basic Notifications",
                NotificationManager.IMPORTANCE_DEFAULT
            ).apply {
                description = "Basic notification channel"
                enableLights(true)
                lightColor = Color.BLUE
            }

            val manager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
            manager.createNotificationChannel(channel)
        }
    }

    // Show simple notification
    fun showNotification(title: String, message: String) {
        val builder = NotificationCompat.Builder(context, CHANNEL_ID)
            .setSmallIcon(android.R.drawable.ic_dialog_info)
            .setContentTitle(title)
            .setContentText(message)
            .setPriority(NotificationCompat.PRIORITY_DEFAULT)
            .setAutoCancel(true)

        notificationManager.notify(NOTIFICATION_ID, builder.build())
    }

    // Show notification with large text
    fun showNotificationWithLargeText(title: String, message: String) {
        val builder = NotificationCompat.Builder(context, CHANNEL_ID)
            .setSmallIcon(android.R.drawable.ic_dialog_info)
            .setContentTitle(title)
            .setContentText(message)
            .setStyle(
                NotificationCompat.BigTextStyle()
                    .bigText(message)
            )
            .setPriority(NotificationCompat.PRIORITY_DEFAULT)
            .setAutoCancel(true)

        notificationManager.notify(NOTIFICATION_ID, builder.build())
    }
}

// 2. Notification with Actions
class ActionNotificationHelper(private val context: Context) {

    companion object {
        private const val CHANNEL_ID = "action_channel"
        private const val NOTIFICATION_ID = 1002
    }

    private val notificationManager = NotificationManagerCompat.from(context)

    init {
        createNotificationChannel()
    }

    private fun createNotificationChannel() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            val channel = NotificationChannel(
                CHANNEL_ID,
                "Action Notifications",
                NotificationManager.IMPORTANCE_HIGH
            ).apply {
                description = "Notifications with action buttons"
            }

            val manager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
            manager.createNotificationChannel(channel)
        }
    }

    // Notification with action button
    fun showNotificationWithAction(
                    title: String,
                    message: String,
                    actionText: String,
                    actionIntent: PendingIntent
    ) {
        val builder = NotificationCompat.Builder(context, CHANNEL_ID)
            .setSmallIcon(android.R.drawable.ic_dialog_info)
            .setContentTitle(title)
            .setContentText(message)
            .setPriority(NotificationCompat.PRIORITY_HIGH)
            .addAction(
                android.R.drawable.ic_menu_send,
                actionText,
                actionIntent
            )
            .setAutoCancel(true)

        notificationManager.notify(NOTIFICATION_ID, builder.build())
    }

    // Multiple actions
    fun showNotificationWithMultipleActions(
                    title: String,
                    message: String,
                    actions: List<NotificationAction>
    ) {
        val builder = NotificationCompat.Builder(context, CHANNEL_ID)
            .setSmallIcon(android.R.drawable.ic_dialog_info)
            .setContentTitle(title)
            .setContentText(message)
            .setPriority(NotificationCompat.PRIORITY_HIGH)

        actions.forEach { action ->
            builder.addAction(action.icon, action.title, action.pendingIntent)
        }

        builder.setAutoCancel(true)
        notificationManager.notify(NOTIFICATION_ID, builder.build())
    }

    // Data class for notification action
    data class NotificationAction(
        val icon: Int,
        val title: String,
        val pendingIntent: PendingIntent
    )
}

// 3. Progress Notification
class ProgressNotificationHelper(private val context: Context) {

    companion object {
        private const val CHANNEL_ID = "progress_channel"
        private const val NOTIFICATION_ID = 1003
    }

    private val notificationManager = NotificationManagerCompat.from(context)

    init {
        createNotificationChannel()
    }

    private fun createNotificationChannel() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            val channel = NotificationChannel(
                CHANNEL_ID,
                "Progress Notifications",
                NotificationManager.IMPORTANCE_LOW
            )

            val manager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
            manager.createNotificationChannel(channel)
        }
    }

    // Show indeterminate progress
    fun showIndeterminateProgress(title: String, message: String) {
        val builder = NotificationCompat.Builder(context, CHANNEL_ID)
            .setSmallIcon(android.R.drawable.ic_dialog_info)
            .setContentTitle(title)
            .setContentText(message)
            .setPriority(NotificationCompat.PRIORITY_LOW)
            .setOngoing(true)
            .setProgress(0, 0, true)

        notificationManager.notify(NOTIFICATION_ID, builder.build())
    }

    // Show determinate progress
    fun showProgress(title: String, message: String, max: Int, progress: Int) {
        val builder = NotificationCompat.Builder(context, CHANNEL_ID)
            .setSmallIcon(android.R.drawable.ic_dialog_info)
            .setContentTitle(title)
            .setContentText(message)
            .setPriority(NotificationCompat.PRIORITY_LOW)
            .setOngoing(true)
            .setProgress(max, progress, false)

        notificationManager.notify(NOTIFICATION_ID, builder.build())
    }

    // Update progress
    fun updateProgress(max: Int, progress: Int, message: String? = null) {
        val builder = NotificationCompat.Builder(context, CHANNEL_ID)
            .setSmallIcon(android.R.drawable.ic_dialog_info)
            .setContentTitle("Downloading")
            .setContentText(message ?: "$progress%")
            .setOngoing(true)
            .setProgress(max, progress, false)

        notificationManager.notify(NOTIFICATION_ID, builder.build())
    }

    // Complete progress
    fun completeProgress(title: String, message: String) {
        val builder = NotificationCompat.Builder(context, CHANNEL_ID)
            .setSmallIcon(android.R.drawable.ic_dialog_info)
            .setContentTitle(title)
            .setContentText(message)
            .setProgress(0, 0, false)
            .setOngoing(false)
            .setAutoCancel(true)

        notificationManager.notify(NOTIFICATION_ID, builder.build())
    }
}

// 4. Rich Notification with Image
class RichNotificationHelper(private val context: Context) {

    companion object {
        private const val CHANNEL_ID = "rich_channel"
        private const val NOTIFICATION_ID = 1004
    }

    private val notificationManager = NotificationManagerCompat.from(context)

    init {
        createNotificationChannel()
    }

    private fun createNotificationChannel() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            val channel = NotificationChannel(
                CHANNEL_ID,
                "Rich Notifications",
                NotificationManager.IMPORTANCE_HIGH
            ).apply {
                description = "Rich notifications with images"
            }

            val manager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
            manager.createNotificationChannel(channel)
        }
    }

    // Big picture notification
    fun showBigPictureNotification(
                    title: String,
                    message: String,
                    imageBitmap: android.graphics.Bitmap
    ) {
        val builder = NotificationCompat.Builder(context, CHANNEL_ID)
            .setSmallIcon(android.R.drawable.ic_dialog_info)
            .setContentTitle(title)
            .setContentText(message)
            .setLargeIcon(imageBitmap)
            .setStyle(
                NotificationCompat.BigPictureStyle()
                    .bigPicture(imageBitmap)
                    .bigLargeIcon(null)
            )
            .setPriority(NotificationCompat.PRIORITY_HIGH)
            .setAutoCancel(true)

        notificationManager.notify(NOTIFICATION_ID, builder.build())
    }

    // Inbox style notification
    fun showInboxNotification(
                    title: String,
                    contentTitle: String,
                    lines: List<String>
    ) {
        val builder = NotificationCompat.Builder(context, CHANNEL_ID)
            .setSmallIcon(android.R.drawable.ic_dialog_info)
            .setContentTitle(title)
            .setContentText(contentTitle)
            .setStyle(
                NotificationCompat.InboxStyle()
                    .setSummaryText("${lines.size} new messages")
                    .addLine(lines[0])
            )
            .setPriority(NotificationCompat.PRIORITY_HIGH)

        // Add remaining lines
        for (i in 1 until minOf(lines.size, 5)) {
            builder.setStyle(
                NotificationCompat.InboxStyle()
                    .setSummaryText("${lines.size} new messages")
                    .addLine(lines[i])
            )
        }

        builder.setAutoCancel(true)
        notificationManager.notify(NOTIFICATION_ID, builder.build())
    }
}

// 5. Notification Groups
class GroupNotificationHelper(private val context: Context) {

    companion object {
        private const val CHANNEL_ID = "group_channel"
        private const val GROUP_ID = "notification_group"
        private const val SUMMARY_ID = 1005
    }

    private val notificationManager = NotificationManagerCompat.from(context)

    init {
        createNotificationChannel()
    }

    private fun createNotificationChannel() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            val channel = NotificationChannel(
                CHANNEL_ID,
                "Group Notifications",
                NotificationManager.IMPORTANCE_HIGH
            )

            val manager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
            manager.createNotificationChannel(channel)
        }
    }

    // Show grouped notifications
    fun showGroupedNotifications(
                    notifications: List<GroupedNotification>
    ) {
        // Show individual notifications
        notifications.forEach { notification ->
            val builder = NotificationCompat.Builder(context, CHANNEL_ID)
                .setSmallIcon(android.R.drawable.ic_dialog_info)
                .setContentTitle(notification.title)
                .setContentText(notification.message)
                .setGroup(GROUP_ID)
                .setAutoCancel(true)

            notificationManager.notify(notification.id, builder.build())
        }

        // Show summary notification
        val summaryBuilder = NotificationCompat.Builder(context, CHANNEL_ID)
            .setSmallIcon(android.R.drawable.ic_dialog_info)
            .setContentTitle("Group Summary")
            .setContentText("${notifications.size} notifications")
            .setGroup(GROUP_ID)
            .setGroupSummary(true)
            .setAutoCancel(true)

        notificationManager.notify(SUMMARY_ID, summaryBuilder.build())
    }

    // Data class for grouped notification
    data class GroupedNotification(
        val id: Int,
        val title: String,
        val message: String
    )
}

// 6. Notification Manager
class UnifiedNotificationManager(private val context: Context) {

    private val basicHelper = BasicNotificationHelper(context)
    private val actionHelper = ActionNotificationHelper(context)
    private val progressHelper = ProgressNotificationHelper(context)
    private val richHelper = RichNotificationHelper(context)
    private val groupHelper = GroupNotificationHelper(context)

    // Show simple notification
    fun notify(title: String, message: String) {
        basicHelper.showNotification(title, message)
    }

    // Show notification with action
    fun notifyWithAction(
                    title: String,
                    message: String,
                    actionText: String,
                    actionIntent: PendingIntent
    ) {
        actionHelper.showNotificationWithAction(title, message, actionText, actionIntent)
    }

    // Show progress
    fun showProgress(title: String, message: String, max: Int, progress: Int) {
        progressHelper.showProgress(title, message, max, progress)
    }

    // Cancel all notifications
    fun cancelAll() {
        val manager = NotificationManagerCompat.from(context)
        manager.cancelAll()
    }

    // Cancel specific notification
    fun cancel(id: Int) {
        val manager = NotificationManagerCompat.from(context)
        manager.cancel(id)
    }
}

// Main demonstration
fun demonstrateSystemTray(context: Context, activity: AppCompatActivity) {
    println("=== Android Kotlin Notification Examples ===\n")

    // 1. Basic notifications
    println("--- 1. Basic Notifications ---")
    val basicHelper = BasicNotificationHelper(context)

    basicHelper.showNotification(
        "Basic Notification",
        "This is a simple notification"
    )

    basicHelper.showNotificationWithLargeText(
        "Long Notification",
        "This is a notification with a very long message that " +
        "should be displayed using the big text style in the notification drawer."
    )

    // 2. Action notifications
    println("\n--- 2. Action Notifications ---")
    val actionHelper = ActionNotificationHelper(context)

    // Create pending intent
    val intent = Intent(context, activity::class.java)
    val pendingIntent = PendingIntent.getActivity(
        context,
        0,
        intent,
        PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
    )

    actionHelper.showNotificationWithAction(
        "Action Notification",
        "Click to perform action",
        "Reply",
        pendingIntent
    )

    // 3. Progress notifications
    println("\n--- 3. Progress Notifications ---")
    val progressHelper = ProgressNotificationHelper(context)

    progressHelper.showIndeterminateProgress("Indeterminate", "Working...")

    // Simulate progress
    val max = 100
    for (i in 0..100 step 10) {
        progressHelper.updateProgress(max, i, "Download: $i%")
    }

    progressHelper.completeProgress("Complete", "Download finished!")

    // 4. Rich notifications
    println("\n--- 4. Rich Notifications ---")
    val richHelper = RichNotificationHelper(context)

    // Note: In real usage, you'd have actual bitmap
    println("Rich notification types:")
    println("  - Big picture style")
    println("  - Inbox style")
    println("  - Messaging style")

    // 5. Group notifications
    println("\n--- 5. Group Notifications ---")
    val groupHelper = GroupNotificationHelper(context)

    val notifications = listOf(
        GroupNotificationHelper.GroupedNotification(
            1,
            "Message 1",
            "First message"
        ),
        GroupNotificationHelper.GroupedNotification(
            2,
            "Message 2",
            "Second message"
        ),
        GroupNotificationHelper.GroupedNotification(
            3,
            "Message 3",
            "Third message"
        )
    )

    groupHelper.showGroupedNotifications(notifications)

    // 6. Unified manager
    println("\n--- 6. Unified Notification Manager ---")
    val unifiedManager = UnifiedNotificationManager(context)

    println("Unified manager provides:")
    println("  - notify(): Simple notifications")
    println("  - notifyWithAction(): With action buttons")
    println("  - showProgress(): Progress notifications")
    println("  - cancelAll(): Cancel all notifications")

    println("\n=== All Notification Examples Completed ===")
}