dGEN1 Terminal SDK
Android library for controlling the dGEN1 terminal screen and the 3x3 LED array via a clean, coroutine-based Kotlin API. Both subsystems communicate with hidden system services through reflection and gracefully no-op on non-dGEN1 hardware.
Table of Contents
Installation
Step 1. Add the JitPack repository to your project's settings.gradle.kts (inside the dependencyResolutionManagement block):
If your project uses a root
build.gradle.ktswithallprojects { repositories { ... } }instead, add the maven line there.
Step 2. Add the dependency to your app module's build.gradle.kts:
Running from source: If you've cloned or forked this repo, include the SDK module directly in
settings.gradle.kts:Then reference it from your app module:
Quick Start
Terminal Button
The terminal screen is a 428x142 pixel display on the back of the dGEN1 device. The SDK ships with pre-built button layouts that render as bitmaps and register touch handlers automatically.
Dual-Button Layouts
Single-Button Layouts
Each renders a full-width button and fires the callback on any tap:
Status Text
Display arbitrary text on a black background (no touch handler):
Dismiss
Restore the default system display (status bar) and remove touch handlers:
All
show*methods aresuspendfunctions. Call them from a coroutine scope (e.g.lifecycleScope.launch { ... }).
LED Matrix Patterns
The 3x3 LED array on the front of the device supports a library of built-in patterns. Each accepts an optional hex colour string — when omitted, the system accent colour is used.
Displaying Patterns
Display by Name
You can also display a pattern dynamically by its string name:
List Available Patterns
Flash Patterns
Flash patterns display a status indicator briefly (default 1 second), then automatically revert to the chad branding pattern. Useful for confirming actions like successful transactions or errors.
Practical Example: Transaction Flow
Custom LED Matrix Grid
Beyond predefined patterns, you have full control over individual LEDs in the 3x3 grid.
Grid Layout
Set a Single LED
Set All LEDs to One Colour
Custom 3x3 Pattern
Pass a 3x3 array of hex colour strings. Use "#000000" for off:
Adjust Brightness
Colour Format
The SDK accepts colours in any of these formats — they're normalised internally:
#RRGGBB
"#FF0000"
#AARRGGBB
"#FFFF0000"
0xRRGGBB
"0xFF0000"
0xAARRGGBB
"0xFFFF0000"
Building Custom Terminal Screens
The SDK ships with pre-built button layouts, but you can design your own terminal screen with custom buttons, icons, text, and touch regions. The terminal screen is 428x142 pixels — everything you show is an XML layout rendered into a bitmap.
How It Works
Create an XML layout sized to 428x142 px
Render it into a
BitmapusingLayoutRenderer(or manually)Push the bitmap to the terminal screen with
showOnDisplay()Register a touch handler to make regions interactive
Step 1: Create Your XML Layout
Create a layout file in your app's res/layout/ directory. The root must be 428px wide and 142px high with a black background to match the terminal screen:
Design tips:
Always use a
#000000background (OLED-friendly, matches the device)Use the included
@font/monomaniacfont for the authentic terminal aesthetic, or apply the@style/terminal_textstyleKeep text uppercase with letter spacing for readability at small sizes
Use the system accent colour for icons/labels (see Step 2)
The ConstraintLayout dependency is already included in the SDK
Step 2: Render the Layout to a Bitmap
Inflate your layout, apply the system accent colour, and convert it to a bitmap:
Shortcut: You can also use the SDK's built-in
LayoutRendereras a reference or extend it. The renderer interminal.rendereralready handles inflation, measuring, accent colouring, and bitmap conversion for the built-in layouts.
Step 3: Display It with Touch Handling
Push the bitmap to the terminal screen and register touch zones:
Step 4: Clean Up
Always dismiss your custom screen when leaving:
Full Example: Custom Approve/Reject Screen
Putting it all together in a ViewModel-driven flow:
Advanced: Three-Zone Touch Layout
You're not limited to a left/right split. Divide the 428px width into any number of zones:
Advanced: Programmatic Bitmap (No XML)
If you prefer to skip XML entirely, draw directly onto a Canvas:
Custom Bitmaps
For any fully custom content, render any Bitmap to the terminal screen:
You can also use the built-in LayoutRenderer to render the SDK's pre-built layouts manually:
Terminal Screen Power Control
Control the terminal screen power state directly:
Lifecycle Management
Proper lifecycle management prevents resource leaks and ensures the terminal screen returns to its default state when your app is backgrounded or destroyed.
Activity Lifecycle
Jetpack Compose Lifecycle
Use DisposableEffect tied to the composable lifecycle:
ViewModel Scoped Usage
If you use the SDK from a ViewModel, clean up in onCleared():
Architecture Patterns for Production Apps
For larger apps (like the ethOS Wallet Manager), structure your terminal interactions through a repository layer with dependency injection.
Repository Pattern
Wrap the SDK in a repository to decouple UI from hardware control and emit touch events as flows:
Dependency Injection with Hilt
Provide the SDK as a nullable singleton — it will be null on non-dGEN1 devices:
Collecting Events in a ViewModel
Screen-Aware Terminal Updates
Update the terminal screen as the user navigates between screens:
API Reference
TerminalSDK
display: TerminalDisplay?
Terminal screen controller (null if unavailable)
led: TerminalLED?
LED array controller (null if unavailable)
renderer: LayoutRenderer
Renders XML layouts to bitmaps for the terminal screen
isAvailable: Boolean
true if either display or LED is available
isDisplayAvailable: Boolean
true if the terminal screen is available
isLedAvailable: Boolean
true if the LED array is available
showQrOrSend(onQrCode, onSend)
Show QR/Send dual-button (suspend)
showSendNft(onQrCode, onSendNft)
Show QR/Send NFT dual-button (suspend)
showCopy(onCopy)
Show Copy button (suspend)
showCopiedAddress(onTap)
Show Copied confirmation (suspend)
showTopUp(onTopUp)
Show Top Up button (suspend)
showLog(onLog)
Show View on Explorer button (suspend)
showDetailLog(onDetailLog)
Show View TX in Explorer button (suspend)
showSwap(onSwap)
Show Swap button (suspend)
showBlackText(text)
Show text on black background (suspend)
showOnDisplay(bitmap, touchListener?)
Push any bitmap to the terminal screen (suspend)
dismissDisplay()
Restore default terminal screen, remove touch handlers (suspend)
destroy()
Release all resources — call in onDestroy()
TerminalLED
isAvailable: Boolean
Whether the LED subsystem is available
displayChad(color?)
Show ethOS branding pattern
displayPlus(color?) / displayMinus(color?)
Show +/− pattern
displaySend(color?) / displayReceive(color?)
Show arrow up/down pattern
displaySwap(color?) / displaySign(color?)
Show swap/sign pattern
displaySuccess(color?)
Show success checkmark
displayError(color?)
Show error cross
displayWarning(color?)
Show warning symbol
displayInfo(color?)
Show info symbol
displayPattern(name, color?)
Show pattern by string name
flashSuccess(color?, durationMs?)
Flash success then revert to chad
flashError(color?, durationMs?)
Flash error then revert to chad
flashWarning(color?, durationMs?)
Flash warning then revert to chad
flashInfo(color?, durationMs?)
Flash info then revert to chad
setColor(row, col, color)
Set single LED colour (row/col 0-2)
setColor(row, col, color, brightness)
Set single LED with brightness (0-8)
setAllColor(color, brightness?)
Set all LEDs to one colour
setCustomPattern(pattern, brightness?)
Set arbitrary 3x3 colour pattern
setBrightness(brightness)
Set global brightness (0-8)
applyBrightness(hexColor, brightnessPercent)
Adjust colour brightness (0-100%)
getAvailablePatterns(): List<String>
List all predefined pattern names
getSystemColor(): String?
Get cached system accent colour
refreshSystemColor()
Re-read the system accent colour
clear()
Turn off all LEDs
destroy()
Clear LEDs and cancel pending coroutines
TerminalDisplay
isAvailable(): Boolean
Whether the terminal screen is available (suspend)
isScreenOn(): Boolean
Check if terminal screen is on (suspend)
screenOn() / screenOff()
Power the terminal screen on/off (suspend)
refresh(bitmap, layerId): Boolean
Push a bitmap to a display layer (suspend)
resume(layerId)
Restore a display layer (suspend)
registerTouchListener(listener)
Register a touch callback
destroyTouchHandler()
Remove the current touch callback (suspend)
destroyTouchHandlerSync()
Remove touch callback synchronously
finish()
Restore status bar + destroy touch handler
Display Layer Constants
ID_STATUSBAR
System status bar layer
ID_INCOMINGCALL
Incoming call layer
ID_NOTIFICATIONS
Notification layer
ID_CLOCK
Clock layer
ID_GOOGLEBYE
Always-on display (AOD) layer
ID_PERSISTENT
Persistent layer (stays until replaced)
Requirements
Android API 33+ (minSdk)
dGEN1 device for hardware features — the SDK gracefully no-ops on standard Android devices
Kotlin Coroutines — display methods are suspend functions
Contributing
Fork or clone the repository
Open the project in Android Studio
The
appmodule is a demo app that exercises every SDK feature — run it on an dGEN1 device to testThe
TerminalSDKmodule is the library — make your changes thereSubmit a pull request
Project Structure
GitHub Repo:
Last updated