A Flutter + Kotlin Android app that auto-scrolls any app at your natural reading pace — hands-free.
ScrollMind learns how fast you read by watching you scroll through a sample article. It then drives the screen at exactly that pace using Android's Accessibility Service gesture API, so you can read without touching the screen.
- Reading speed training — scroll a sample article naturally; the app measures your pace across multiple read-pause-scroll cycles and computes a median rate
- Per-direction control — train Up and Down independently; the active direction is selectable from the home screen
- Video mode — auto-detects when the foreground app is playing audio and switches to a fixed swipe interval (default 15 s, configurable per app)
- Per-app video intervals — set a custom swipe timer (5–120 s) for specific apps like YouTube Shorts or Instagram Reels
- Floating overlay — translucent AssistiveTouch-style button while scrolling; tap to open pause/close menu, drag to reposition
- Quick Settings tile — toggle auto-scroll directly from the notification shade
- Automatic restart — overlay and scrolling restart automatically when you switch to a supported app
Flutter UI (Riverpod state)
↓ MethodChannel
MainActivity (Kotlin)
↓ SharedPreferences ←─────────────────────────┐
AutoScrollAccessibilityService │
├─ polls config every 250 ms │
├─ dispatches GestureDescription swipes │
└─ starts / stops FloatingOverlayService ───────┘
↓
User sees pause button floating over app
- Swipe covers 44% of the screen dimension (height for Up/Down)
- Fixed 300 ms gesture duration — natural feel
- Interval between gestures =
distance / readingSpeed × 1000(clamped 400 ms – 20 s)
- User scrolls through a long article naturally
- Each time the finger lifts for > 500 ms, a new drag segment begins
- Completion requires: ≥ 1 200 physical px scrolled AND ≥ 4 segments
- Per-cycle rate:
pixels[i] / (segmentStart[i+1] − segmentStart[i])(px/ms) - Final speed = median of all cycle rates × 1 000 (px/s), bounded [10–2 000]
Using the median makes the measurement robust to a single distraction pause or unusually fast swipe.
| Permission | Why |
|---|---|
| Accessibility service | Detect foreground app; dispatch scroll gestures |
| Display over other apps | Render the floating pause button |
| Foreground service | Keep the scroll loop alive in the background |
| Ignore battery optimizations | Prevent Android from killing the service |
| Query all packages | Populate the app-selection list |
All sensitive permissions must be granted manually by the user through system settings. The home screen shows a banner for each missing permission with a direct link.
| Screen | Purpose |
|---|---|
| Home | Trained speeds, permission banners, master on/off toggle, quick actions |
| Training | Scroll an article at your natural pace to calibrate speed |
| App Selection | Pick which apps trigger auto-scroll; set per-app video intervals |
| Settings | Permission management, reset training, about |
lib/
├── main.dart
├── router/app_router.dart
├── core/
│ ├── constants/app_constants.dart # thresholds, route names
│ └── theme/app_theme.dart
├── data/
│ ├── models/scroll_config.dart # data model + JSON serialisation
│ └── repositories/settings_repository.dart # SharedPreferences + MethodChannel
└── presentation/
├── providers/scroll_provider.dart # Riverpod notifiers
├── screens/ # home, training, app_selection, settings
└── widgets/ # luxury_card, direction_speed_card
android/app/src/main/kotlin/com/autoscroll/scrollmind/
├── MainActivity.kt # MethodChannel bridge
├── AutoScrollAccessibilityService.kt # scroll loop + gesture dispatch
├── FloatingOverlayService.kt # floating pause/close button
└── AutoScrollTileService.kt # Quick Settings tile
| Layer | Technology |
|---|---|
| UI | Flutter 3.41 |
| State | Riverpod 3 (AsyncNotifier) |
| Navigation | GoRouter |
| Persistence | SharedPreferences |
| Native bridge | MethodChannel |
| Background scroll | Android AccessibilityService + GestureDescription |
| Overlay | WindowManager TYPE_APPLICATION_OVERLAY |
| Min SDK | 24 (Android 7.0) |
| Target SDK | 35 (Android 15) |
# Install dependencies
flutter pub get
# Run debug on connected device
flutter run
# Build release APK
flutter build apk --release
# Build release AAB (Play Store)
flutter build appbundle --releaseFor production signing, add android/key.properties and a keystore file (excluded by android/.gitignore):
storePassword=YOUR_STORE_PASSWORD
keyPassword=YOUR_KEY_PASSWORD
keyAlias=YOUR_KEY_ALIAS
storeFile=autoscrollr-release.jksThe CI pipeline (.github/workflows/) runs flutter analyze + flutter test on every PR, and builds a release APK on every v*.*.* tag push.
- Open ScrollMind
- Tap Enable → grant Accessibility service
- Tap Grant → grant overlay permission
- Tap Fix → exempt from battery optimisation
- Tap 📱 Select Apps → choose which apps to scroll
- Tap a speed card → scroll the article at your natural reading pace
- Flip the master toggle — done
The floating button will appear over the selected app and auto-scroll will begin.
Two GitHub Actions workflows are included:
ci.yml— runs on every PR/push tomain:flutter analyze --fatal-infos+flutter testrelease.yml— runs onv*.*.*tags: builds release APK, uploads as artifact namedscrollmind-<version>.apk
To cut a release:
git tag v1.0.0
git push origin v1.0.0