Skip to content

Feature Registry

sameerasw edited this page Aug 9, 2026 · 1 revision

📋 Feature Registry

The Feature Registry is the single source of truth for all features in Essentials. It defines every feature's metadata, permissions, and UI behavior in one centralized place.


File Location

app/src/main/java/com/sameerasw/essentials/domain/registry/
├── FeatureRegistry.kt     — All feature definitions
├── PermissionRegistry.kt  — Permission → feature mappings
└── SearchRegistry.kt      — Global search index entries

Feature Model

Every feature is an anonymous object extending the Feature abstract class:

object : Feature(
    id = "Feature name",
    title = R.string.feat_title,
    iconRes = R.drawable.rounded_icon_24,
    category = R.string.cat_system,
    description = R.string.feat_description,
    aboutDescription = R.string.about_desc_feature,
    permissionKeys = listOf("ACCESSIBILITY", "NOTIFICATION_LISTENER"),
    showToggle = true,
    hasMoreSettings = true,
    isVisibleInMain = true,
    isBeta = false,
    parentFeatureId = "Parent feature id",
    animationRes = R.raw.feature_animation,
    searchableSettings = listOf(
        SearchSetting(R.string.search_title, R.string.search_desc, "highlight_key")
    )
) {
    override fun isEnabled(viewModel: MainViewModel): Boolean = viewModel.isFeatureEnabled.value
    override fun isToggleEnabled(viewModel: MainViewModel, context: Context): Boolean = viewModel.isPermissionGranted.value
    override fun onToggle(viewModel: MainViewModel, context: Context, enabled: Boolean) = viewModel.setFeatureEnabled(enabled)
    override fun isDeviceSupported(context: Context): Boolean = true  // override for device-specific features
    override fun onClick(context: Context, viewModel: MainViewModel) { /* optional custom tap handler */ }
}

Feature Properties

Property Type Description
id String Unique identifier — used for parent-child linking and navigation
title @StringRes Int Display name (from strings.xml)
iconRes @DrawableRes Int Icon shown in the feature card
category @StringRes Int Category grouping (System, Interface, Connectivity, etc.)
description @StringRes Int Short description shown in the feature list
aboutDescription @StringRes Int? Longer description shown in the feature detail screen
permissionKeys List<String> Required permissions (maps to PermissionRegistry)
showToggle Boolean Whether to show an enable/disable toggle on the feature card
hasMoreSettings Boolean Whether to show a "Settings" button that opens a detail screen
isVisibleInMain Boolean Whether to show in the main features list (false = hidden helper feature)
isBeta Boolean Mark with a beta badge in the UI
parentFeatureId String? ID of the parent feature for grouping (null = top-level)
animationRes @RawRes Int? Lottie animation for the feature detail screen header
searchableSettings List<SearchSetting> Individual settings within this feature that are globally searchable

Feature Hierarchy

Features form a tree structure via parentFeatureId. The getFilteredFeatures() method recursively evaluates visibility — a child feature is only shown if its parent is also visible.

Display (parent)
├── Navigation (child of Display)
├── Essentials on Display (child of Display)
├── Always on Display (child of Display)
├── Status bar icons (child of Display)
├── Caffeinate (child of Display)
├── Text and animations (child of Display)
├── Screen refresh rate (child of Display, Pixel only)
├── Lock screen clock (child of Display, Pixel only)
├── Dynamic night light (child of Display)
├── Smart pixels (child of Display)
├── Other customizations (child of Display)
└── Pocket mode (child of Display, non-Pixel only)

Device Filtering

isDeviceSupported(context) is overridden for device-specific features:

// Pixel-only feature:
override fun isDeviceSupported(context: Context) = DeviceUtils.isGoogleDevice()

// Non-Pixel only:
override fun isDeviceSupported(context: Context) = !DeviceUtils.isGoogleDevice()

getFilteredFeatures(includeUnsupported = false) returns only supported features; passing true includes all regardless of device.


Permission Registry

PermissionRegistry maintains the reverse mapping: which features require each permission. This is used to show the affected features list in the permission request UI.

// Register a feature as requiring a permission:
PermissionRegistry.register("ACCESSIBILITY", R.string.feat_screen_off_widget_title)

// Query which features need a permission:
val featuresNeedingAccessibility = PermissionRegistry.getFeatures("ACCESSIBILITY")

Permission Keys

Key Android Permission / System
ACCESSIBILITY Accessibility Service enabled for Essentials
NOTIFICATION_LISTENER Notification Listener Service enabled
WRITE_SECURE_SETTINGS android.permission.WRITE_SECURE_SETTINGS (ADB)
WRITE_SETTINGS android.permission.WRITE_SETTINGS
SHIZUKU Shizuku binder authorized
ROOT su shell available
DRAW_OVERLAYS android.permission.SYSTEM_ALERT_WINDOW
USAGE_STATS Usage access granted
POST_NOTIFICATIONS android.permission.POST_NOTIFICATIONS
BLUETOOTH_CONNECT android.permission.BLUETOOTH_CONNECT
BLUETOOTH_SCAN android.permission.BLUETOOTH_SCAN
READ_PHONE_STATE android.permission.READ_PHONE_STATE
READ_CALENDAR android.permission.READ_CALENDAR
LOCATION android.permission.ACCESS_FINE_LOCATION
BACKGROUND_LOCATION android.permission.ACCESS_BACKGROUND_LOCATION
DEVICE_ADMIN Device Administrator activated
NOTIFICATION_POLICY android.permission.ACCESS_NOTIFICATION_POLICY

Search Registry

SearchRegistry enables global in-app search across all feature settings. Each SearchSetting inside a feature defines:

SearchSetting(
    title = R.string.search_setting_title,
    description = R.string.search_setting_desc,
    targetSettingHighlightKey = "unique_setting_key",  // used to scroll-to and highlight the setting
    keywordsRes = R.array.keywords_for_this_setting,    // optional keyword synonyms
    parentFeatureTitle = R.string.parent_feature_title  // optional breadcrumb
)

When a user searches, Essentials matches against title, description, and keyword arrays — then deep-links to the feature screen with the target setting highlighted.


Adding a New Feature

  1. Add a new object : Feature(...) entry to FeatureRegistry.ALL_FEATURES
  2. Register its permission mappings in PermissionRegistry (initPermissionRegistry())
  3. Add any searchable settings as SearchSetting entries in the feature's searchableSettings
  4. Create the corresponding UI composable in ui/features/<category>/
  5. Add strings to strings.xml for title, description, and any search entries
  6. Handle ViewModel state in MainViewModel (or the relevant sub-ViewModel)

Clone this wiki locally