/* * Copyright (C) 2023 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.settings.datausage.lib import android.app.usage.NetworkStats import android.app.usage.NetworkStatsManager import android.content.Context import android.net.NetworkTemplate import android.util.Log import android.util.Range class NetworkStatsRepository(context: Context, private val template: NetworkTemplate) { private val networkStatsManager = context.getSystemService(NetworkStatsManager::class.java)!! fun queryAggregateForUid( range: Range, uid: Int, state: Int = NetworkStats.Bucket.STATE_ALL, ): NetworkUsageData? = try { networkStatsManager.queryDetailsForUidTagState( template, range.lower, range.upper, uid, NetworkStats.Bucket.TAG_NONE, state, ).convertToBuckets().aggregate() } catch (e: Exception) { Log.e(TAG, "Exception queryDetailsForUidTagState", e) null } fun queryDetailsForDevice(): List = try { networkStatsManager.queryDetailsForDevice(template, Long.MIN_VALUE, Long.MAX_VALUE) .convertToBuckets() } catch (e: Exception) { Log.e(TAG, "Exception queryDetailsForDevice", e) emptyList() } fun getTimeRange(): Range? = queryDetailsForDevice().aggregate()?.timeRange fun querySummaryForDevice(startTime: Long, endTime: Long): Long = try { networkStatsManager.querySummaryForDevice(template, startTime, endTime).bytes } catch (e: Exception) { Log.e(TAG, "Exception querySummaryForDevice", e) 0 } fun queryBuckets(startTime: Long, endTime: Long): List = try { networkStatsManager.querySummary(template, startTime, endTime).convertToBuckets() } catch (e: Exception) { Log.e(TAG, "Exception querySummary", e) emptyList() } companion object { private const val TAG = "NetworkStatsRepository" val AllTimeRange = Range(Long.MIN_VALUE, Long.MAX_VALUE) data class Bucket( val uid: Int, val bytes: Long, val state: Int = NetworkStats.Bucket.STATE_ALL, val startTimeStamp: Long, val endTimeStamp: Long, ) fun List.aggregate(): NetworkUsageData? = when { isEmpty() -> null else -> NetworkUsageData( startTime = minOf { it.startTimeStamp }, endTime = maxOf { it.endTimeStamp }, usage = sumOf { it.bytes }, ) } fun List.filterTime(startTime: Long, endTime: Long): List = filter { it.startTimeStamp >= startTime && it.endTimeStamp <= endTime } private fun NetworkStats.convertToBuckets(): List = use { val buckets = mutableListOf() val bucket = NetworkStats.Bucket() while (getNextBucket(bucket)) { if (bucket.bytes > 0) { buckets += Bucket( uid = bucket.uid, bytes = bucket.bytes, state = bucket.state, startTimeStamp = bucket.startTimeStamp, endTimeStamp = bucket.endTimeStamp, ) } } buckets } private val NetworkStats.Bucket.bytes: Long get() = rxBytes + txBytes } }