ShizuStore

Blink

character-flat

1.1.0 · GitHub

Download APK
Productivity Android 14+ 4 months ago GPL-3.0
29 ShizuStore
688 GitHub
23 Stars
1 MB Size

More about this app

A persistent, highly customizable 20-20-20 rule eye-care timer that uses Shizuku to whitelist itself from Android's battery optimizations

Blink

A bulletproof 20-20-20 rule timer for Android that actually works.

Blink is a persistent eye-care daemon that reminds you to rest your eyes every 20 minutes. Unlike other timer apps, it uses exact alarms and a foreground service to survive Android's aggressive battery optimizations — your timer fires on time, every time, even during Doze mode.

When it's time, a beautiful fullscreen overlay appears on top of whatever you're doing (no app switching, no interruptions) and counts down 20 seconds for you to look at something 20 feet away.


✨ Features

Core

Feature Description
Exact Alarms Uses AlarmManager.setExactAndAllowWhileIdle — fires during deep sleep & Doze
Foreground Service Persistent specialUse FGS with live countdown notification
True Overlay TYPE_APPLICATION_OVERLAY floats on top of all apps without replacing them
Smart Screen Detection Pauses on screen off, resets after >20s lock, resumes on short locks
Boot Receiver Optional auto-start when device reboots

Customization

Feature Description
3 Overlay Styles Expressive (animated rings, ripple waves, orbital dots), Calm (smooth arc, gentle glow), Minimal (clean progress circle)
Dynamic M3 Theming Colors pulled from your wallpaper via dynamicColorScheme()
Alert Modes Choose between: Overlay only, Notification only, or Both
Adjustable Timers Work: 1–60 min, Rest: 10–60 sec
Overlay Opacity 30–100% transparency
Dismissable Mode Optional close button (red FAB) during rest overlay
Landscape Support Responsive layout adapts to orientation

Battery & Reliability

Feature Description
Shizuku Integration Optional — auto-whitelists app from battery optimization via cmd deviceidle whitelist
Battery Optimization Built-in toggle to request unrestricted battery access
START_STICKY Service restarts itself if killed by the OS
Watchdog Alarm 5-minute exact alarm verifies service liveness, restarts if dead
Direct Boot Starts on LOCKED_BOOT_COMPLETED before device unlock
OEM Guides Per-manufacturer battery settings instructions (Xiaomi, Samsung, OPPO, Vivo, etc.)

📦 Download

→ Latest Release

Build Size Description
blink-v1.1.0-release.apk ~1.8 MB Signed, R8-minified release build
blink-v1.1.0-debug.apk ~10 MB Debug build with logging

See CHANGELOG.md for release notes.

Requirements

  • Android 14+ (API 34)
  • Display over other apps permission (for the overlay)
  • Notification permission
  • Exact alarm permission

🏗️ Architecture

┌─────────────────────────────────────────────────┐
│  MainActivity (Jetpack Compose / M3)            │
│  ├── Timer Ring (segmented arc, 60fps)          │
│  ├── Start/Stop FAB                             │
│  └── Settings FAB → SettingsScreen              │
├─────────────────────────────────────────────────┤
│  EyeCareService (Foreground Service)            │
│  ├── AlarmManager (exact, idle-safe)            │
│  ├── BroadcastReceiver (SCREEN_ON/OFF)          │
│  ├── Countdown coroutine (1s tick)              │
│  └── Persistent notification (live countdown)   │
├─────────────────────────────────────────────────┤
│  RestOverlayService (TYPE_APPLICATION_OVERLAY)  │
│  ├── ComposeView in WindowManager               │
│  ├── 3 style composables (Expressive/Calm/Min) │
│  ├── 60fps raw progress (no animateFloatAsState)│
│  └── Vibration at start + end                   │
├─────────────────────────────────────────────────┤
│  ShizukuUtils → cmd deviceidle whitelist        │
│  BootReceiver → auto-start on reboot            │
│  AlarmReceiver → wakes EyeCareService           │
│  PrefsManager → SharedPreferences wrapper       │
└─────────────────────────────────────────────────┘

Key Design Decisions

  • No WorkManager — too imprecise for 20-minute intervals. AlarmManager.setExactAndAllowWhileIdle is the only reliable option.
  • True overlay, not Activity — TYPE_APPLICATION_OVERLAY stays on top without replacing the current app. Activities would force-switch context.
  • ComposeView in Service — requires setting all three tree owners (LifecycleOwner, SavedStateRegistryOwner, ViewModelStoreOwner) manually.
  • Raw 16ms countdown — animateFloatAsState on an already-updating mutableState causes jitter. Direct delay(16) loop gives smooth ~60fps arc animation.
  • R8 on debug builds — material-icons-extended is ~30MB unshrinked. R8 tree-shakes unused icons down to <2MB.

🔨 Build

# Debug
./gradlew assembleDebug

# Release (requires signing key)
./gradlew assembleRelease

Tech Stack

  • Language: Kotlin 2.1
  • UI: Jetpack Compose + Material 3 (Dynamic Color)
  • Min SDK: 34 (Android 14)
  • Build: Gradle 8.9, AGP 8.7.3, Compose BOM 2024.12.01
  • Dependencies: Shizuku 13.1.5, Coroutines 1.8.1

📄 License

GNU General Public License v3.

Close

How Shizuku is used

Can whitelist itself from battery optimization via `cmd deviceidle whitelist` through Shizuku.

This is an AI-assisted analysis of Shizuku-related usages in the app's public source code. It is best effort, so it may not catch every single usage.

How this app uses Shizuku

Blink uses Shizuku to keep its eye care timers reliable in the background.

  • Exempt from battery optimization: adds itself to the system idle whitelist with the cmd deviceidle whitelist shell command through Shizuku so reminders continue on schedule, and checks whether it is already whitelisted the same way.

Android APIs or commands used

  • cmd deviceidle whitelist

Notable details

Battery exemption can also be requested through the standard system prompt without Shizuku.

Close

Changelog

What's new for version 1.1.0

v1.1.0

Reliability Improvements Service calls startForeground() in onCreate() — closes the empty-process kill window Timer state persisted across OS-initiated restarts (no longer cleared in onDestroy) Watchdog alarm fires every 5 minutes via setExactAndAllowWhileIdle to auto-restart dead service Direct boot support (LOCKED_BOOT_COMPLETED) — service starts before device unlock AlarmReceiver independently restarts service if found dead

UX Improvements OEM-specific battery settings guide (Xiaomi, Samsung, OPPO/Realme/OnePlus, Vivo, Motorola, Huawei, ASUS, Nokia) Each OEM guide includes auto-start whitelist steps and force-stop warning Shizuku is now fully optional — app works without it (only used for one-tap battery whitelist)

Housekeeping Package renamed from com.eyecare.daemon to com.cflat.blink License: GNU General Public License v3

Close

Permissions

12 permissions requested

  • android.permission.POST_NOTIFICATIONS
  • android.permission.FOREGROUND_SERVICE
  • android.permission.FOREGROUND_SERVICE_SPECIAL_USE
  • android.permission.SCHEDULE_EXACT_ALARM
  • android.permission.USE_EXACT_ALARM
  • android.permission.RECEIVE_BOOT_COMPLETED
  • android.permission.VIBRATE
  • android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS
  • android.permission.SYSTEM_ALERT_WINDOW
  • android.permission.USE_FULL_SCREEN_INTENT
  • com.cflat.blink.DYNAMIC_RECEIVER_NOT_EXPORTED_PERMISSION
  • moe.shizuku.manager.permission.API_V23
Close