# How to Implement Material You Dynamic Colors in a Custom Android Keyboard

> Learn how to implement Material You dynamic colors in your custom Android keyboard. Easily adapt key backgrounds to user wallpaper using theme-attribute drawables.

- Repository: [Kazu/japanesekeyboard](https://github.com/kazumaproject/japanesekeyboard)
- Tags: tutorial
- Published: 2026-03-05

---

**Enable the `isDynamicColorEnabled` flag in your keyboard view and use theme-attribute drawables like `?attr/colorSurface` to automatically adapt key backgrounds to the user's wallpaper palette.**

The Japanese Keyboard project demonstrates a production-ready approach to Material You integration in a custom Android keyboard. By storing a boolean flag and detecting night mode, the keyboard swaps drawable resources at runtime to match the dynamic color palette while maintaining fallback support for static themes.

## Core Architecture for Material You Support

### The Theme Flag Pattern

The implementation centers on a boolean flag stored in each keyboard view subclass. In [`TenKey.kt`](https://github.com/kazumaproject/japanesekeyboard/blob/main/TenKey.kt) (lines 61-66), the view maintains an `isDynamicColorEnabled` property that persists across configuration changes. This flag is passed to internal theming methods to determine whether to load Material You resources or static drawables.

The same pattern appears in [`QWERTYKeyboardView.kt`](https://github.com/kazumaproject/japanesekeyboard/blob/main/QWERTYKeyboardView.kt) and [`TabletKeyboardView.kt`](https://github.com/kazumaproject/japanesekeyboard/blob/main/TabletKeyboardView.kt), ensuring consistent behavior across ten-key, QWERTY, and tablet layouts.

### Night Mode Detection

Material You requires separate light and dark palettes. The repository detects night mode inside `applyKeyboardTheme()` by checking the configuration:

```kotlin
// TenKey.kt lines 19-21
val isNightMode = (context.resources.configuration.uiMode and 
    Configuration.UI_MODE_NIGHT_MASK) == Configuration.UI_MODE_NIGHT_YES

```

This boolean drives the selection between `*_material.xml` (dark) and `*_material_light.xml` (light) drawable variants.

## Implementing Dynamic Color Drawables

### Creating Theme-Aware XML Resources

The key to Material You integration is using theme attributes instead of hardcoded colors. The repository defines separate drawable files for dark and light modes in `core/src/main/res/drawable/`:

```xml
<!-- ten_keys_center_bg_material.xml (dark variant) -->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item 
        android:id="@+id/background"
        android:drawable="@drawable/rounded_key_background"
        android:tint="?attr/colorSurface" />
</layer-list>

```

The light variant ([`ten_keys_center_bg_material_light.xml`](https://github.com/kazumaproject/japanesekeyboard/blob/main/ten_keys_center_bg_material_light.xml)) uses the same structure but is selected when `isNightMode` is false. By referencing `?attr/colorSurface`, the drawable automatically resolves to the Material You surface color derived from the user's wallpaper.

### Runtime Drawable Swapping

The `setMaterialYouTheme()` method (defined in [`TenKey.kt`](https://github.com/kazumaproject/japanesekeyboard/blob/main/TenKey.kt), [`QWERTYKeyboardView.kt`](https://github.com/kazumaproject/japanesekeyboard/blob/main/QWERTYKeyboardView.kt), and [`TabletKeyboardView.kt`](https://github.com/kazumaproject/japanesekeyboard/blob/main/TabletKeyboardView.kt)) handles the actual resource switching:

```kotlin
private fun setMaterialYouTheme(isDarkMode: Boolean, isDynamicColorEnable: Boolean) {
    if (!isDynamicColorEnable) {
        // Fallback to static black tint for special keys
        ImageViewCompat.setImageTintList(
            binding.keyEnter,
            ColorStateList.valueOf(ContextCompat.getColor(context, R.color.black))
        )
        return
    }

    // Select appropriate Material You resource
    val centerRes = if (isDarkMode)
        R.drawable.ten_keys_center_bg_material
    else
        R.drawable.ten_keys_center_bg_material_light

    // Apply to all main keys
    listOf(binding.key1, binding.key2, binding.key3, binding.key4, binding.key5,
           binding.key6, binding.key7, binding.key8, binding.key9, binding.key0)
        .forEach { btn ->
            btn.background = ContextCompat.getDrawable(context, centerRes)?.mutate()
        }
}

```

This approach ensures that enabling or disabling Material You requires only a boolean toggle, with no layout inflation changes.

## Applying Material You to Keyboard Popups

Key preview popups (the small windows that appear when a key is pressed) also support dynamic colors. The `setPopupViewTheme()` method inflates Material You layouts when the flag is enabled:

```kotlin
if (isDynamicColorsEnable) {
    val activeBinding = PopupLayoutActiveMaterialBinding.inflate(inflater, null, false)
    popupWindowActive = PopupWindow(activeBinding.root, width, height, false)
    // ... configure popup
}

```

The layout file [`popup_layout_active_material.xml`](https://github.com/kazumaproject/japanesekeyboard/blob/main/popup_layout_active_material.xml) (located in `tenkey/src/main/res/layout/`) uses the same theme-attribute tinting strategy as the main keys, ensuring the preview popup matches the keyboard's dynamic palette.

## Public API for Theme Switching

To expose Material You control to your Input Method Service (IME) or settings Activity, implement a public method like `applyKeyboardTheme()`:

```kotlin
// Example call from an InputMethodService
val tenKey = TenKey(this, null)

tenKey.applyKeyboardTheme(
    themeMode = "default",               // "default" triggers Material You when enabled
    currentNightMode = resources.configuration.uiMode,
    isDynamicColorEnabled = true,        // Enable Material You
    customBgColor = Color.WHITE,         // Ignored for "default" mode
    customKeyColor = Color.LTGRAY,       // Ignored for "default" mode
    customSpecialKeyColor = Color.GRAY,  // Ignored for "default" mode
    customKeyTextColor = Color.BLACK,    // Ignored for "default" mode
    customSpecialKeyTextColor = Color.BLACK,
    liquidGlassEnable = false,
    customBorderEnable = false,
    customBorderColor = Color.BLACK,
    liquidGlassKeyAlphaEnable = 255,
    borderWidth = 0
)

```

This method stores the flag, computes night mode, and delegates to `setMaterialYouTheme()` and `setPopupViewTheme()`, ensuring all UI elements update atomically.

## Summary

- **Store a boolean flag** (`isDynamicColorEnabled`) in your keyboard view to persist the Material You state across configuration changes.
- **Detect night mode** using `Configuration.UI_MODE_NIGHT_MASK` to select between light and dark dynamic color palettes.
- **Use theme attributes** (`?attr/colorSurface`, `?attr/colorOnSurface`) in XML drawables so the system resolves Material You colors at runtime.
- **Swap drawables programmatically** via `setMaterialYouTheme()` to toggle between Material You resources and static fallbacks without reinflating layouts.
- **Apply to popups** by inflating `*_material.xml` layouts in `setPopupViewTheme()` when the flag is enabled.
- **Expose a public API** like `applyKeyboardTheme()` so your IME or settings can control the feature.

## Frequently Asked Questions

### How do I enable Material You colors in a custom Android keyboard view?

Call the public `applyKeyboardTheme()` method on your keyboard view instance with `isDynamicColorEnabled = true`. Ensure you pass the current night mode configuration so the view can select the correct light or dark palette. According to the Japanese Keyboard source code, this stores the flag and triggers `setMaterialYouTheme()` to swap the background drawables.

### What XML attributes make a keyboard key drawable use Material You colors?

Use `?attr/colorSurface` or `?attr/colorOnSurface` as the `android:tint` value in your `<layer-list>` drawable XML. The Japanese Keyboard project defines [`ten_keys_center_bg_material.xml`](https://github.com/kazumaproject/japanesekeyboard/blob/main/ten_keys_center_bg_material.xml) with `android:tint="?attr/colorSurface"`, allowing the system to substitute the user's dynamic wallpaper-derived color at runtime.

### How does the keyboard handle both light and dark Material You themes?

The repository maintains separate drawable files for dark and light modes (e.g., [`ten_keys_center_bg_material.xml`](https://github.com/kazumaproject/japanesekeyboard/blob/main/ten_keys_center_bg_material.xml) and [`ten_keys_center_bg_material_light.xml`](https://github.com/kazumaproject/japanesekeyboard/blob/main/ten_keys_center_bg_material_light.xml)). The `setMaterialYouTheme()` method checks `isNightMode` and loads the appropriate resource, ensuring the keyboard matches the system theme automatically.

### Can I toggle Material You on and off without restarting the keyboard?

Yes. The Japanese Keyboard implementation uses a boolean flag and runtime drawable swapping. When you call `applyKeyboardTheme()` with `isDynamicColorEnabled = false`, the view immediately falls back to static drawables ([`ten_keys_center_bg.xml`](https://github.com/kazumaproject/japanesekeyboard/blob/main/ten_keys_center_bg.xml)) without requiring an Activity restart or layout reinflation.