如何在Android Studio中获取设备屏幕唤醒时长及分周期总使用时长?
Hey there! Let's break down how to get screen wake duration and aggregated device usage stats by day/week/month/year in Android Studio, since UsageStats only gives app-specific data.
Before diving into code, you need to handle the special permission for usage stats:
- Add this to your
AndroidManifest.xml:<uses-permission android:name="android.permission.PACKAGE_USAGE_STATS" tools:ignore="ProtectedPermissions" /> - This permission can't be granted via regular runtime requests. You'll need to guide users to enable it manually in Settings:
fun checkUsageStatsPermission(context: Context): Boolean { val appOps = context.getSystemService(Context.APP_OPS_SERVICE) as AppOpsManager val mode = appOps.checkOpNoThrow( AppOpsManager.OPSTR_GET_USAGE_STATS, android.os.Process.myUid(), context.packageName ) return mode == AppOpsManager.MODE_ALLOWED } fun openUsageStatsSettings(context: Context) { val intent = Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS) context.startActivity(intent) }
To calculate how long the screen has been awake, we'll use UsageStatsManager to track EVENT_SCREEN_ON and EVENT_SCREEN_OFF events, then sum the time differences between each pair:
fun calculateTotalScreenWakeTime(context: Context): Long { val usageStatsManager = context.getSystemService(Context.USAGE_STATS_SERVICE) as UsageStatsManager val startTime = 0L // Start from device boot time, or set a custom start timestamp val endTime = System.currentTimeMillis() val events = usageStatsManager.queryEvents(startTime, endTime) var totalWakeTime = 0L var lastScreenOnTime = 0L while (events.hasNextEvent()) { val event = UsageEvents.Event() events.getNextEvent(event) when (event.eventType) { UsageEvents.Event.EVENT_SCREEN_ON -> { lastScreenOnTime = event.timeStamp } UsageEvents.Event.EVENT_SCREEN_OFF -> { if (lastScreenOnTime != 0L) { totalWakeTime += event.timeStamp - lastScreenOnTime lastScreenOnTime = 0L } } } } // Add time if screen is currently awake val powerManager = context.getSystemService(Context.POWER_SERVICE) as PowerManager if (powerManager.isInteractive && lastScreenOnTime != 0L) { totalWakeTime += System.currentTimeMillis() - lastScreenOnTime } return totalWakeTime // Returns duration in milliseconds }
To get stats for specific time intervals, we'll split the overall time range into chunks (days, weeks, etc.) and calculate wake time for each chunk:
Example: Daily Wake Stats
fun getDailyWakeStats(context: Context, startDate: Long, endDate: Long): Map<String, Long> { val dailyStats = mutableMapOf<String, Long>() val calendar = Calendar.getInstance().apply { timeInMillis = startDate set(Calendar.HOUR_OF_DAY, 0) set(Calendar.MINUTE, 0) set(Calendar.SECOND, 0) set(Calendar.MILLISECOND, 0) } var currentDayStart = calendar.timeInMillis val dateFormat = SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()) while (currentDayStart <= endDate) { val currentDayEnd = currentDayStart + 24 * 60 * 60 * 1000 - 1 // End of the day val dayKey = dateFormat.format(Date(currentDayStart)) val dayWakeTime = calculateWakeTimeForPeriod(context, currentDayStart, currentDayEnd) dailyStats[dayKey] = dayWakeTime // Move to next day calendar.add(Calendar.DAY_OF_MONTH, 1) currentDayStart = calendar.timeInMillis } return dailyStats } // Reusable function to calculate wake time for a specific time period private fun calculateWakeTimeForPeriod(context: Context, startTime: Long, endTime: Long): Long { val usageStatsManager = context.getSystemService(Context.USAGE_STATS_SERVICE) as UsageStatsManager val events = usageStatsManager.queryEvents(startTime, endTime) var totalWakeTime = 0L var lastScreenOnTime = 0L while (events.hasNextEvent()) { val event = UsageEvents.Event() events.getNextEvent(event) when (event.eventType) { UsageEvents.Event.EVENT_SCREEN_ON -> lastScreenOnTime = event.timeStamp UsageEvents.Event.EVENT_SCREEN_OFF -> { if (lastScreenOnTime != 0L) { totalWakeTime += event.timeStamp - lastScreenOnTime lastScreenOnTime = 0L } } } } // Handle case where screen is still awake at end of period if (endTime >= System.currentTimeMillis()) { val powerManager = context.getSystemService(Context.POWER_SERVICE) as PowerManager if (powerManager.isInteractive && lastScreenOnTime != 0L) { totalWakeTime += System.currentTimeMillis() - lastScreenOnTime } } return totalWakeTime }
Extending to Week/Month/Year
For weekly stats, adjust the calendar logic to increment Calendar.WEEK_OF_YEAR instead of DAY_OF_MONTH. Similarly, use Calendar.MONTH for monthly stats and Calendar.YEAR for yearly stats. Just make sure to set the start of each interval correctly (e.g., start of the week, start of the month).
- Compatibility:
UsageStatsManageris available from API 21 (Android 5.0). For older devices, you'll need alternative methods (like reading system logs, which is less reliable and requires more permissions). - Data Retention: System usage events aren't stored indefinitely. Older data (e.g., months back) might not be available depending on device settings.
- Definition of "Usage": This solution tracks screen wake time. If you need to measure overall device activity (even with screen off), you'd need to combine this with other metrics like CPU usage or idle state checks via
PowerManager.
内容的提问来源于stack exchange,提问作者Sai Shiva

