How to Implement Material You Dynamic Colors in a Custom Android Keyboard
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 (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 and 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:
// 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/:
<!-- 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) 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, QWERTYKeyboardView.kt, and TabletKeyboardView.kt) handles the actual resource switching:
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:
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 (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():
// 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_MASKto 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.xmllayouts insetPopupViewTheme()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 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 and 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) without requiring an Activity restart or layout reinflation.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →