SkillAgentSearch skills...

Triggerx

TriggerX is a modular, developer-friendly alarm execution library for Android.

Install / Use

/learn @meticha/Triggerx

README

TriggerX

triggerx-banner.png

<p align="center"> <a href="https://central.sonatype.com/artifact/com.meticha/triggerx"> <img src="https://img.shields.io/maven-central/v/com.meticha/triggerx.svg?label=Maven%20Central" alt="Maven Central"> </a> <img src="https://img.shields.io/badge/Jetpack%20Compose-Supported-4285F4?logo=android" alt="Jetpack Compose Supported"> <img src="https://img.shields.io/badge/Kotlin-2.1.20-blueviolet?logo=kotlin" alt="Kotlin Version"> <a href="https://github.com/Meticha/TriggerX/blob/main/LICENSE"> <img src="https://img.shields.io/github/license/Meticha/TriggerX.svg" alt="license"> </a> <a href="https://androidweekly.net/issues/issue-678"><img alt="Android Weekly" src="https://androidweekly.net/issues/issue-678/badge" height="20px"/></a> <a href="https://github.com/Meticha/TriggerX/stargazers"> <img src="https://img.shields.io/github/stars/Meticha/TriggerX.svg?style=social" alt="GitHub stars"> </a> <a href="https://opensource.org/licenses/Apache-2.0"> <img alt="License" src="https://img.shields.io/badge/License-Apache%202.0-blue.svg"/> </a> </p>

TriggerX is a modular, developer-friendly alarm execution library for Android.

See the full documentation

It simplifies scheduling exact alarms and showing user-facing UIs at a specific time, even when your app has been killed or without you managing foreground-service boilerplate, wake-locks, or lock-screen flags.

Example

<p> <img src="triggerx_example.gif" alt="TriggerX Example" height="500"> </p>

📌 What does TriggerX do?

| | | |-----------------------------------------------------------------------------------|----------------------------------------------------------------------| | ⏰ Exact alarms that work in Doze (API 25+) | 🔓 Lock-screen activity automatically shown when the alarm fires | | 🔑 Handles permissions: exact alarm, battery optimisations, overlay, notification | 📱 Wakes the device, starts a foreground service, then stops it | | 🔄 Fetches fresh data at alarm time via suspend provider (Room, API, …) | 🎨 Lets you build the UI in Jetpack Compose |

Think of TriggerX as an execution layer that runs a piece of UI logic at the right time and hides the system details.


✅ When should you use TriggerX?

| | | |---------------------------------------------------------------------------------|-----------------------------------------------------------------| | 📅 You need to show a UI (reminder, alert, action screen) at a given time | 🔄 The UI needs live data from DB, cache, or API | | 🧹 You want to avoid edge-case handling for Doze, foreground services, or flags | 🎯 You want a consistent alarm solution across Android versions |


📦 Installation

<details> <summary>Version catalogs</summary>
[versions]
triggerx = "latest-version"

[dependencies]
triggerx = { module = "com.meticha:triggerx", version.ref = "triggerx" }
</details> <details> <summary>Gradle DSL</summary>
dependencies {
    implementation("com.meticha:triggerx:latest-version")
}
</details>

🚀 Quick Start

0. Add these permission in your AndroidManifest.xml file:


<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />

    <!-- Permissions for scheduling exact alarms -->
<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM" />

<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>

1. Initialize in your Application class

class MyApplication : Application() {
    override fun onCreate() {
        super.onCreate()

        TriggerX.init(this) {

            /* UI that opens when the alarm fires */
            activityClass = MyAlarmActivity::class.java

            /* Foreground-service notification */
            useDefaultNotification(
                title = "Alarm running",
                message = "Tap to open",
                channelName = "Alarm Notifications"
            )

            /* Optional: Provide up-to-date data right before the UI opens */
            alarmDataProvider = object : TriggerXDataProvider {
                override suspend fun provideData(alarmId: Int, alarmType: String): Bundle {
                    return when (alarmType) {
                        "MEETING" -> {
                            val meeting = meetingRepository.getMeeting(alarmId)
                            return bundleOf(
                                "title" to meeting?.title,
                                "location" to meeting?.location
                            )
                        }

                        else -> bundleOf()
                    }
                }
            }
        }
    }
}

2. Ask for the permission

The library provides a composable helper to request permissions so that you don't have to manage this manually. However, the library provides the functionality to request permissions manually if you want to follow that path

@Composable
fun HomeScreen(
    viewModel: HomeViewModel = hiltViewModel()
) {
    val context = LocalContext.current
    val permissionState = rememberAppPermissionState()
    val coroutines = rememberCoroutineScope()

    Scaffold { paddingValues ->
        Column(
            modifier = Modifier
                .fillMaxSize()
                .padding(paddingValues)
                .padding(16.dp),
            verticalArrangement = Arrangement.Center,
            horizontalAlignment = Alignment.CenterHorizontally
        ) {
            ElevatedButton(
                onClick = {
                    coroutines.launch {
                        if (permissionState.allRequiredGranted()) {
                            viewModel.scheduleOneMinuteAlarm(context)
                        } else {
                            permissionState.requestPermission()
                        }
                    }
                }
            ) {
                Text("Schedule Activity")
            }
        }
    }
}

3. Schedule an alarm

val inFiveMinutes = Calendar.getInstance().apply {
    add(Calendar.MINUTE, 5)
}.timeInMillis


TriggerXAlarmScheduler().scheduleAlarm(
    context = this,
    alarmId = 1,
    type = "MEETING",
    triggerAtMillis = inFiveMinutes
)

💡 You can schedule many alarms with different alarmId / alarmType.

🧩 Create your Alarm UI

class AppAlarmActivity : TriggerXActivity() {

    @Composable
    override fun AlarmContent() {
        val bundle = remember { intent?.getBundleExtra("ALARM_DATA") }
        val title = bundle?.getString("title") ?: "empty title"
        val location = bundle?.getString("location")
        Box(
            modifier = Modifier.fillMaxSize()
        ) {
            Column(
                modifier = Modifier
                    .fillMaxSize()
                    .background(
                        color = Color.White,
                        shape = RoundedCornerShape(32.dp)
                    )
                    .padding(32.dp),
                verticalArrangement = Arrangement.Center,
                horizontalAlignment = Alignment.CenterHorizontally
            ) {
                Icon(
                    imageVector = Icons.Default.Notifications,
                    contentDescription = "Trigger Icon",
                    tint = Color(0xFF111111),
                    modifier = Modifier.size(80.dp)
                )

                Spacer(modifier = Modifier.height(24.dp))

                Text(
                    text = title,
                    fontSize = 42.sp,
                    fontWeight = FontWeight.Bold,
                    color = Color(0xFF111111)
                )

                Spacer(modifier = Modifier.height(12.dp))

                Text(
                    text = location ?: "empty location",
                    fontSize = 20.sp,
                    fontWeight = FontWeight.Medium,
                    color = Color(0xFF333333),
                    textAlign = TextAlign.Center
                )
            }
        }
    }
}

What the base class handles for you:

  • 🔓 Shows over lock-screen
  • 📱 Turns screen on
  • ⚙️ Chooses correct flags per Android version
  • 📦 Receives & parses Bundle (“ALARM_DATA”)

🔐 Permissions

TriggerX includes a Composable helper to request what it needs.

@Composable
fun HomeScreen(
    viewModel: HomeViewModel = hiltViewModel()
) {
    val context = LocalContext.current
    val permissionState = rememberAppPermissionState()
    val coroutines = rememberCoroutineScope()


    Scaffold { paddingValues ->
        Column(
            modifier = Modifier
                .fillMaxSize()
                .padding(paddingValues)
                .padding(16.dp),
            verticalArrangement = Arrangement.Center,
            horizontalAlignment = Alignment.CenterHorizontally
        ) {
            ElevatedButton(
                onClick = {
                    coroutines.launch {
                        if (permissionState.allRequiredGranted()) {
                            viewModel.scheduleOneMinuteAlarm(
                                context
                            )
                        } else {
                            permissionState.requestPermission()
                        }
                    }
                }
            ) {
                Text("Schedule Activity")
            }
        }
    }
}

Covered automatically:

| Permission |

View on GitHub
GitHub Stars101
CategoryDevelopment
Updated14d ago
Forks4

Languages

Kotlin

Security Score

100/100

Audited on Mar 13, 2026

No findings