| 📱 Min SDK | 🏗️ Architecture | 💾 Database | ⚙️ Background | 🔒 Privacy | 🎨 UI |
|---|---|---|---|---|---|
| Android 7.0 | MVVM | Room SQLite | WorkManager | Local-only | Material Design 3 |
| # | Section | # | Section |
|---|---|---|---|
| 01 | 📖 About MinST | 07 | 🏗️ Architecture |
| 02 | ✨ Features | 08 | 🚀 Installation |
| 03 | 🎯 Accurate Usage Tracking | 09 | 🎯 How It Works |
| 04 | 🔔 Break Reminder System | 10 | 🤝 Contributing |
| 05 | 📊 App Analytics | 11 | 🔐 Privacy & Security |
| 06 | 🎯 App Limits & Alerts | 12 | 🗺️ Roadmap |
MinST (Minimize Screen Time) is a sophisticated digital wellbeing application that helps you build healthier relationships with your devices. Unlike basic screen time trackers, MinST provides precision tracking, intelligent break reminders, and actionable insights to genuinely transform your digital habits.
| Why MinST? | What It Delivers | |
|---|---|---|
| 🎯 | Precision Tracking | Measures only active foreground time using Android's native UsageStatsManager API |
| 🔔 | Smart Break Reminders | Context-aware notifications that pause during home screen or when using MinST itself |
| 📊 | Deep Analytics | Comprehensive insights including usage trends, streaks, forecasts, and behavioral patterns |
| 🎨 | Modern Design | Beautiful Material Design 3 interface with glassmorphic effects and smooth animations |
| 🔒 | Privacy First | All data stored locally on your device with zero telemetry or tracking |
MinST employs a custom-built event processing engine that analyzes UsageEvents from Android's system APIs to calculate precise foreground time.
📐 Technical Details
// Core tracking implementation in UsageStatsHelper.java
public static HashMap<String, ProcessedUsageStats> getProcessedUsageStats(
Context context, long start, long end) {
// Query raw usage events from the system
UsageEvents usageEvents = usm.queryEvents(start, end);
// Process MOVE_TO_FOREGROUND and MOVE_TO_BACKGROUND events
// to calculate accurate foreground duration
while (usageEvents.hasNextEvent()) {
// Calculate time spent in each app
// Handle edge cases (apps active at window boundaries)
// Implement 30-second debounce for launch counting
}
return usageStatsMap;
}Key Features:
- Only counts time when apps are actively visible on screen
- Handles edge cases (apps active before/after measurement window)
- 30-second debounce prevents inflated launch counts
- Real-time updates every 5 seconds in Usage Timeline
- Automatically filters out system apps and MinST itself
A state-based overlay notification system that helps you take mindful breaks without being intrusive.
graph TD
A[TrackingService Started] --> B{Reminders Active?}
B -->|No| C[Background Mode<br/>5-min checks]
B -->|Yes| D[Fast Polling Mode<br/>15-sec checks]
D --> E{Get Foreground App}
E --> F{Is Ignored App?}
F -->|Yes<br/>Home/MinST| G[Timer Paused<br/>Time preserved]
F -->|No| H[Add Time to Session]
H --> I{Time ≥ Interval?}
I -->|No| D
I -->|Yes| J[Show Overlay]
J --> K[User Action]
K -->|Dismiss| L[Reset Timer]
K -->|Snooze| M[Pause for Snooze Duration]
K -->|View Stats| N[Open Usage Activity]
L --> D
M --> D
N --> D
G --> D
| Step | Behaviour |
|---|---|
| 1 | Fast Polling (15s): When reminders are active, checks current foreground app every 15 seconds |
| 2 | Cumulative Timer: Tracks total active usage across all non-ignored apps |
| 3 | Smart Pausing: Timer pauses on home screen or when using MinST, preserves progress |
| 4 | Overlay Display: Shows non-intrusive notification bar at configured interval (default: 1 hour) |
| 5 | User Actions: Snooze (1 min default), View Stats, or Dismiss |
// TrackingService.java - Core timer logic
private void updateOverlayTimer() {
String foregroundApp = UsageStatsHelper.getCurrentForegroundPackage(this);
if (foregroundApp != null && !ignoredPackages.contains(foregroundApp)) {
long delta = System.currentTimeMillis() - lastCheckTimestamp;
cumulativeSessionTime += delta;
if (cumulativeSessionTime >= Prefs.getInterval(this)) {
showOverlay(); // Display break reminder
cumulativeSessionTime = 0L;
}
}
// Timer pauses for ignored apps
}Each app gets a dedicated detail page with multi-dimensional insights.
| 📊 Today's Snapshot | 📈 Weekly Overview | 📉 Trend Analysis | 🎯 Deeper Insights |
|---|---|---|---|
| Total foreground usage | 7-day daily average | Day-over-day comparison | Usage rank among all apps |
| Launch count (debounced) | Busiest day identification | Week-over-week comparison | Consecutive usage streak |
| Last used timestamp | Total average (if >7 days data) | Color-coded indicators (↑ red, ↓ green) | Average session length |
| Usage pattern (weekday/weekend) | |||
| End-of-day forecast (after 10 AM) | |||
| Late night usage (after 10 PM) |
Visual Analytics:
- 7-Day Bar Chart — Daily usage comparison
- 30+ Day Line Chart — Extended trend visualization
- Dynamic Toggle — Switch between chart views based on data availability
Set custom daily time limits for specific apps with real-time tracking and smart notifications.
sequenceDiagram
participant User
participant UI as SetGoalsActivity
participant DB as Room Database
participant Service as TrackingService
participant System as Android System
User->>UI: Select app & set limit
UI->>DB: Save AppGoalEntity
Note over DB: dailyGoalMillis<br/>usageAtTimeOfSet
DB-->>UI: Limit saved
loop Every 5 minutes
Service->>System: Query today's usage
System-->>Service: Usage data
Service->>DB: Load all goals
DB-->>Service: Goal list
Service->>Service: Compare usage vs limits
alt Limit exceeded
Service->>User: Send notification
Service->>DB: Mark as notified (today)
end
end
| Feature | Detail |
|---|---|
| 🛡️ Smart Validation | Warns if limit is below current usage |
| 🎨 Visual Feedback | Color-coded progress bars (green → orange → red) |
| 🔄 Daily Reset | Notification flags reset at midnight automatically |
| 📐 Grid Layout | 3-column display of all apps with real-time status |
Proactive alerts when your usage of an app today exceeds yesterday's usage.
Notification Criteria — all must be true:
boolean shouldNotify =
todayUsage > yesterdayUsage &&
todayUsage > TimeUnit.MINUTES.toMillis(5) && // Meaningful today
yesterdayUsage > TimeUnit.MINUTES.toMillis(1) && // Was used yesterday
!isSystemApp(packageName) &&
!alreadyNotifiedToday.contains(packageName);| Step | Detail |
|---|---|
| 1 | Yesterday's Cache: Loaded once per day from Room database |
| 2 | Live Comparison: Today's usage fetched from UsageStatsManager every 5 minutes |
| 3 | Smart Filtering: System apps and previously notified apps excluded |
| 4 | Notification: Displays comparison (e.g., "Today: 2h 30m | Yesterday: 1h 45m") |
All usage data is automatically saved to a local SQLite database for long-term analysis.
Database Schema:
-- Room Database (AppDatabase.java)
CREATE TABLE app_goals (
packageName TEXT PRIMARY KEY,
dailyGoalMillis INTEGER,
usageAtTimeOfSet INTEGER
);
CREATE TABLE daily_usage (
packageName TEXT,
date TEXT, -- Format: YYYY-MM-DD
usageTime INTEGER,
PRIMARY KEY (packageName, date)
);Automated Data Collection:
graph LR
A[First App Launch] --> B[DataSaveWorker<br/>Queues 6 OneTimeRequests]
B --> C[Import Past 6 Days<br/>from UsageStatsManager]
C --> D[Save to Database]
E[Every Day at Midnight] --> F[PeriodicWorkRequest<br/>DataSaveWorker]
F --> G[Query Yesterday's Usage]
G --> H[Save to Database]
style A fill:#4CAF50
style E fill:#2196F3
style D fill:#FF9800
style H fill:#FF9800
| Detail | Implementation |
|---|---|
| 📥 Initial Import | Past 6 days imported on first launch (2-minute delay to avoid blocking setup) |
| 🕛 Daily Saves | WorkManager runs at midnight to save yesterday's data |
| ⚡ Efficient Queries | Room's @MapInfo annotation enables fast Map<String, Long> retrieval |
| 🔐 Data Integrity | REPLACE conflict strategy ensures data consistency |
Break Reminder Settings Configure interval, snooze duration with quick preset options |
Individual App Limits Set per-app usage limits with color-coded progress indicators |
MinST follows clean architecture principles with clear separation of concerns across four distinct layers.
| Core Technologies | Key Libraries | ||
|---|---|---|---|
| Language | Java | MPAndroidChart | Data visualization |
| Min SDK | 24 (Android 7.0) | Material Components | UI framework |
| Architecture | MVVM + Clean Architecture | Flexbox Layout | Flexible UI layouts |
| Database | Room Persistence Library | AndroidX Libraries | Jetpack components |
| Background Tasks | WorkManager | RecyclerView | Efficient list rendering |
| Dependency Injection | Manual (Lightweight) |
graph TB
subgraph PresentationLayer["📱 Presentation Layer"]
A1["MainActivity"]
A2["UsageStatsActivity"]
A3["AppDetailActivity"]
A4["SetGoalsActivity"]
A5["SettingsActivity"]
end
subgraph DomainLayer["🧠 Domain Layer"]
B1["AppUsageCache<br/>(Singleton)"]
B2["UsageStatsHelper<br/>(Static Methods)"]
B3["Prefs<br/>(Settings Manager)"]
end
subgraph DataLayer["💾 Data Layer"]
C1[("Room Database<br/>AppDatabase")]
C2["SharedPreferences<br/>(App State)"]
C3["UsageStatsManager<br/>(Android System)"]
end
subgraph ServiceLayer["⚙️ Service Layer"]
D1["TrackingService<br/>(Foreground Service)"]
D2["ScreenStateReceiver<br/>(Broadcast Receiver)"]
D3["DataSaveWorker<br/>(WorkManager)"]
D4["TrackingWorker<br/>(Watchdog)"]
end
A1 --> B1
A2 --> B1
A3 --> B2
A4 --> C1
A5 --> B3
B1 --> B2
B2 --> C3
D1 --> B2
D1 --> C1
D1 --> C2
D2 --> D1
D3 --> C3
D3 --> C1
D4 --> D1
style A1 fill:#4CAF50,stroke:#2E7D32,stroke-width:3px,color:#000
style A2 fill:#4CAF50,stroke:#2E7D32,stroke-width:3px,color:#000
style A3 fill:#4CAF50,stroke:#2E7D32,stroke-width:3px,color:#000
style A4 fill:#4CAF50,stroke:#2E7D32,stroke-width:3px,color:#000
style A5 fill:#4CAF50,stroke:#2E7D32,stroke-width:3px,color:#000
style B1 fill:#2196F3,stroke:#1565C0,stroke-width:3px,color:#000
style B2 fill:#2196F3,stroke:#1565C0,stroke-width:3px,color:#000
style B3 fill:#2196F3,stroke:#1565C0,stroke-width:3px,color:#000
style C1 fill:#FF9800,stroke:#E65100,stroke-width:3px,color:#000
style C2 fill:#FF9800,stroke:#E65100,stroke-width:3px,color:#000
style C3 fill:#FF9800,stroke:#E65100,stroke-width:3px,color:#000
style D1 fill:#9C27B0,stroke:#6A1B9A,stroke-width:3px,color:#fff
style D2 fill:#9C27B0,stroke:#6A1B9A,stroke-width:3px,color:#fff
style D3 fill:#9C27B0,stroke:#6A1B9A,stroke-width:3px,color:#fff
style D4 fill:#9C27B0,stroke:#6A1B9A,stroke-width:3px,color:#fff
style PresentationLayer fill:#E8F5E9,stroke:#4CAF50,stroke-width:2px,color:#000
style DomainLayer fill:#E3F2FD,stroke:#2196F3,stroke-width:2px,color:#000
style DataLayer fill:#FFF3E0,stroke:#FF9800,stroke-width:2px,color:#000
style ServiceLayer fill:#F3E5F5,stroke:#9C27B0,stroke-width:2px,color:#000
// Dual-mode operation
public class TrackingService extends Service {
// Background Mode (default): 5-minute checks for notifications
private boolean areFastChecksActive = true;
// Reminder Mode (user-activated): 15-second checks for overlay timer
private boolean areRemindersActive = false;
private void performChecks() {
// Update overlay timer if reminders active
if (areRemindersActive) updateOverlayTimer();
// Run notification checks every 5 minutes
if (shouldRunFullCheck()) runFullNotificationChecks();
// Schedule next check (15s or 5min based on mode)
long delay = areRemindersActive ? 15_000L : 300_000L;
handler.postDelayed(checkRunnable, delay);
}
}// Singleton cache with 30-second validity
public class AppUsageCache {
private List<AppUsageModel> filteredList = new ArrayList<>();
private long lastUpdatedTimestamp = 0;
private static final long CACHE_VALIDITY_MS = 30_000L;
public void getFilteredList(Context context, AppListCallback callback) {
// Return cached data if fresh
if (isCacheFresh()) {
callback.onAppListReady(new ArrayList<>(filteredList));
return;
}
// Otherwise refresh asynchronously
refreshCache(context, callback);
}
}@Database(entities = {AppGoalEntity.class, DailyUsageEntity.class},
version = 1, exportSchema = false)
public abstract class AppDatabase extends RoomDatabase {
public abstract GoalDao goalDao();
public abstract UsageDao usageDao();
// Thread-safe singleton instance
private static volatile AppDatabase INSTANCE;
}| Requirement | Detail |
|---|---|
| 📱 Android Version | Android 7.0 (API 24) or higher |
| 💽 Storage | Minimum 50MB free space |
Step 1 — Download APK
- Visit the Releases page
- Download the latest
MinST-vX.X.X.apk
Step 2 — Install
- Enable "Install from Unknown Sources" in Settings
- Open the downloaded APK and follow installation prompts
Step 3 — Grant Permissions
| Permission | Purpose | Required |
|---|---|---|
| Usage Access | Read app usage data | ✅ Yes |
| Display Over Other Apps | Show break reminders | ✅ Yes |
| Activity Recognition | Detect screen state | ✅ Yes |
| Notifications | Send usage alerts | ✅ Yes |
Step 4 — Optimize Battery Settings (Recommended)
- Navigate to:
Settings → Battery → Battery Optimization - Find MinST and select
"Don't optimize" - This ensures reliable alert delivery
# Clone repository
git clone https://github.com/kumarpiyushraj/MinST-Minimize-Screen-Time.git
cd MinST-Minimize-Screen-Time
# Open in Android Studio
# File > Open > Select project directory
# Build APK
./gradlew assembleRelease
# Install on connected device
./gradlew installReleasesequenceDiagram
participant User
participant MainActivity
participant System as Android System
participant Service as TrackingService
participant Worker as DataSaveWorker
participant DB as Database
User->>MainActivity: Launch app
MainActivity->>User: Show permission screen
User->>System: Grant all permissions
System-->>MainActivity: Permissions granted
MainActivity->>Worker: Queue 6 OneTimeRequests<br/>(Import past 6 days)
MainActivity->>Service: Start TrackingService
MainActivity->>Worker: Schedule daily<br/>PeriodicWorkRequest
Note over Worker,DB: 2-minute delay
Worker->>System: Query usage for each past day
System-->>Worker: Historical usage data
Worker->>DB: Save to daily_usage table
Service->>Service: Begin 5-minute<br/>background checks
sequenceDiagram
participant User
participant MainActivity
participant Service as TrackingService
participant System as UsageStatsManager
participant Overlay
User->>MainActivity: Tap central ring
MainActivity->>MainActivity: Set isReminderActive=true
MainActivity->>Service: Send START_REMINDERS action
Service->>Service: Switch to fast polling (15s)
loop Every 15 seconds
Service->>System: getCurrentForegroundPackage()
System-->>Service: Current app name
alt App is NOT ignored
Service->>Service: Add 15s to cumulative timer
alt Timer >= Interval
Service->>Overlay: Show break reminder
Overlay-->>User: Display notification
User->>Overlay: Dismiss/Snooze/View Stats
Overlay->>Service: Reset timer
end
else App IS ignored (Home/MinST)
Service->>Service: Pause timer<br/>(preserve progress)
end
end
graph LR
A["📱 UsageStatsActivity<br/>Opens"] --> B["💾 AppUsageCache<br/>Check cache"]
B -->|"✅ Fresh"| C["⚡ Return cached data<br/>(< 30 seconds old)"]
B -->|"🔄 Stale"| D["🔃 Background refresh"]
D --> E["🔍 UsageStatsHelper<br/>Query today's events"]
E --> F["⚙️ Process events<br/>Calculate foreground time"]
F --> G["🎯 Filter & sort apps<br/>Exclude system apps"]
G --> H["💾 Update cache<br/>Set timestamp"]
H --> I["📤 Return to UI"]
I --> J["📊 Display in<br/>RecyclerView"]
J --> K["🔄 Refresh every 5s<br/>while visible"]
style A fill:#4CAF50,stroke:#2E7D32,stroke-width:3px,color:#000,font-weight:bold
style B fill:#2196F3,stroke:#1565C0,stroke-width:3px,color:#000,font-weight:bold
style C fill:#66BB6A,stroke:#2E7D32,stroke-width:3px,color:#000,font-weight:bold
style D fill:#42A5F5,stroke:#1565C0,stroke-width:3px,color:#000,font-weight:bold
style E fill:#2196F3,stroke:#1565C0,stroke-width:3px,color:#000,font-weight:bold
style F fill:#42A5F5,stroke:#1565C0,stroke-width:3px,color:#000,font-weight:bold
style G fill:#64B5F6,stroke:#1565C0,stroke-width:3px,color:#000,font-weight:bold
style H fill:#FF9800,stroke:#E65100,stroke-width:3px,color:#000,font-weight:bold
style I fill:#FFB74D,stroke:#E65100,stroke-width:3px,color:#000,font-weight:bold
style J fill:#4CAF50,stroke:#2E7D32,stroke-width:3px,color:#000,font-weight:bold
style K fill:#66BB6A,stroke:#2E7D32,stroke-width:3px,color:#000,font-weight:bold
Contributions are welcome! Here's how you can help make MinST even better.
| Way to Contribute | Description |
|---|---|
| 🐛 Report Bugs | Open an issue with detailed reproduction steps |
| 💡 Suggest Features | Describe use cases and expected behavior |
| 🔧 Submit Pull Requests | Fix bugs or implement new features |
| 📖 Improve Documentation | Clarify instructions or add examples |
| 🌍 Translate | Help make MinST accessible worldwide |
# Fork and clone
git clone https://github.com/YOUR_USERNAME/MinST-Minimize-Screen-Time.git
cd MinST-Minimize-Screen-Time
# Add upstream remote
git remote add upstream https://github.com/kumarpiyushraj/MinST-Minimize-Screen-Time.git
# Create feature branch
git checkout -b feature/amazing-feature
# Make changes and commit
git commit -m "Add amazing feature"
# Push to your fork
git push origin feature/amazing-feature
# Open Pull Request on GitHub- Follow Java Code Conventions
- Use meaningful variable names (avoid single letters except for loops)
- Add comments for complex logic
- Keep methods focused (single responsibility)
- Write unit tests for new features
- Code follows Java style guidelines
- All existing tests pass
- New tests added for new features
- Documentation updated (README, code comments)
- No lint warnings
- Commit messages are clear and descriptive
- Screenshots included for UI changes
MinST is designed with privacy as a core principle.
| Principle | Detail |
|---|---|
| 🔒 Local-First | All data stored on your device |
| 🚫 Zero Tracking | No analytics, telemetry, or user profiling |
| 🔐 Encrypted Storage | Sensitive data protected at rest |
| 📵 Offline Functionality | Full features without internet connection |
| 🔓 Open Source | Code available for public audit |
MinST collects only the following data, stored locally on your device:
| Data Type | Purpose | Storage Location |
|---|---|---|
| App usage times | Calculate screen time | Room Database |
| App launch counts | Track session frequency | Calculated on-demand |
| User preferences | Remember settings | SharedPreferences |
| Daily usage goals | Enforce limits | Room Database |
MinST never: sends data to external servers · accesses your personal files · reads your messages or calls · tracks your location · shares data with third parties
📦 Version 1.1 — Next Release
- Focus Mode with scheduled automation
- Dark mode improvements
- Export usage reports as CSV/PDF
- Widget for quick stats on home screen
📦 Version 1.2
- Wear OS companion app
- AI-powered usage insights
- Social challenges with friends
- Integration with productivity apps (Todoist, Notion)
🚀 Version 2.0 — Future Vision
- Cross-platform support (iOS, desktop)
- Website/browser usage tracking (requires extension)
- Mental health integration (mood tracking)
- Enterprise/education editions
MinST is a digital wellbeing tool designed to assist users in managing their screen time. It is not a replacement for professional help if you're struggling with technology addiction. For serious concerns, please consult a mental health professional.
The app requires sensitive permissions to function properly. All data is stored locally and never transmitted without explicit consent. Review the Privacy Policy for complete details.
| Acknowledgment | |
|---|---|
| 🤝 | Android Development Community — For excellent libraries and resources |
| 🎨 | Material Design Team — For beautiful, accessible design guidelines |
| 💬 | Stack Overflow Community — For invaluable problem-solving assistance |
| 🌟 | Open Source Contributors — Everyone who has helped improve MinST |
Built with ❤️ for mindful living · Java · Android · Material Design 3
© 2025 Kumar Piyush Raj · GitHub @kumarpiyushraj




