Merge "Refresh the DataUsageList when resume" into main

This commit is contained in:
Chaohui Wang
2023-10-16 05:16:55 +00:00
committed by Android (Google) Code Review
7 changed files with 33 additions and 58 deletions

View File

@@ -261,6 +261,7 @@ public class AppDataUsage extends DataUsageBaseFragment implements OnPreferenceC
return Unit.INSTANCE; return Unit.INSTANCE;
}); });
if (mCycles != null) { if (mCycles != null) {
Log.d(TAG, "setInitialCycles: " + mCycles + " " + mSelectedCycle);
controller.setInitialCycles(mCycles, mSelectedCycle); controller.setInitialCycles(mCycles, mSelectedCycle);
} }
} }

View File

@@ -17,9 +17,7 @@
package com.android.settings.datausage package com.android.settings.datausage
import android.content.Context import android.content.Context
import android.util.SparseBooleanArray
import androidx.annotation.OpenForTesting import androidx.annotation.OpenForTesting
import androidx.core.util.keyIterator
import androidx.lifecycle.Lifecycle import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
@@ -27,8 +25,6 @@ import androidx.lifecycle.repeatOnLifecycle
import androidx.preference.PreferenceGroup import androidx.preference.PreferenceGroup
import androidx.preference.PreferenceScreen import androidx.preference.PreferenceScreen
import com.android.settings.core.BasePreferenceController import com.android.settings.core.BasePreferenceController
import com.android.settings.datausage.lib.AppDataUsageRepository.Companion.getAppUid
import com.android.settings.datausage.lib.AppDataUsageRepository.Companion.getAppUidList
import com.android.settings.datausage.lib.AppPreferenceRepository import com.android.settings.datausage.lib.AppPreferenceRepository
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch

View File

@@ -55,9 +55,6 @@ open class DataUsageList : DataUsageBaseFragment(), MobileDataEnabledListener.Cl
@VisibleForTesting @VisibleForTesting
var subId = SubscriptionManager.INVALID_SUBSCRIPTION_ID var subId = SubscriptionManager.INVALID_SUBSCRIPTION_ID
// Spinner will keep the selected cycle even after paused, this only keeps the displayed cycle,
// which need be cleared when resumed.
private var lastDisplayedUsageData: NetworkUsageData? = null
private lateinit var usageAmount: Preference private lateinit var usageAmount: Preference
private var subscriptionInfoEntity: SubscriptionInfoEntity? = null private var subscriptionInfoEntity: SubscriptionInfoEntity? = null
private lateinit var dataUsageListAppsController: DataUsageListAppsController private lateinit var dataUsageListAppsController: DataUsageListAppsController
@@ -77,7 +74,7 @@ open class DataUsageList : DataUsageBaseFragment(), MobileDataEnabledListener.Cl
finish() finish()
return return
} }
billingCycleRepository = createBillingCycleRepository(); billingCycleRepository = createBillingCycleRepository()
if (!billingCycleRepository.isBandwidthControlEnabled()) { if (!billingCycleRepository.isBandwidthControlEnabled()) {
Log.w(TAG, "No bandwidth control; leaving") Log.w(TAG, "No bandwidth control; leaving")
finish() finish()
@@ -120,7 +117,6 @@ open class DataUsageList : DataUsageBaseFragment(), MobileDataEnabledListener.Cl
override fun onResume() { override fun onResume() {
super.onResume() super.onResume()
dataStateListener.start(subId) dataStateListener.start(subId)
lastDisplayedUsageData = null
updatePolicy() updatePolicy()
} }
@@ -188,11 +184,6 @@ open class DataUsageList : DataUsageBaseFragment(), MobileDataEnabledListener.Cl
* Updates the chart and detail data when initial loaded or selected cycle changed. * Updates the chart and detail data when initial loaded or selected cycle changed.
*/ */
private fun updateSelectedCycle(usageData: NetworkUsageData) { private fun updateSelectedCycle(usageData: NetworkUsageData) {
if (usageData == lastDisplayedUsageData) {
// Avoid duplicate update to avoid page flash.
return
}
lastDisplayedUsageData = usageData
Log.d(TAG, "showing cycle $usageData") Log.d(TAG, "showing cycle $usageData")
usageAmount.title = usageData.getDataUsedString(requireContext()) usageAmount.title = usageData.getDataUsedString(requireContext())

View File

@@ -45,7 +45,7 @@ open class DataUsageListHeaderController(
sourceMetricsCategory: Int, sourceMetricsCategory: Int,
viewLifecycleOwner: LifecycleOwner, viewLifecycleOwner: LifecycleOwner,
private val onCyclesLoad: (usageDataList: List<NetworkUsageData>) -> Unit, private val onCyclesLoad: (usageDataList: List<NetworkUsageData>) -> Unit,
private val onItemSelected: (usageData: NetworkUsageData) -> Unit, private val updateSelectedCycle: (usageData: NetworkUsageData) -> Unit,
private val repository: INetworkCycleDataRepository = private val repository: INetworkCycleDataRepository =
NetworkCycleDataRepository(header.context, template), NetworkCycleDataRepository(header.context, template),
) { ) {
@@ -53,6 +53,17 @@ open class DataUsageListHeaderController(
private val configureButton: View = header.requireViewById(R.id.filter_settings) private val configureButton: View = header.requireViewById(R.id.filter_settings)
private val cycleSpinner: Spinner = header.requireViewById(R.id.filter_spinner) private val cycleSpinner: Spinner = header.requireViewById(R.id.filter_spinner)
private val cycleListener = object : AdapterView.OnItemSelectedListener {
override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
setSelectedCycle(position)
}
override fun onNothingSelected(parent: AdapterView<*>?) {
// ignored
}
}
private val cycleAdapter = CycleAdapter(context, object : SpinnerInterface { private val cycleAdapter = CycleAdapter(context, object : SpinnerInterface {
override fun setAdapter(cycleAdapter: CycleAdapter) { override fun setAdapter(cycleAdapter: CycleAdapter) {
cycleSpinner.adapter = cycleAdapter cycleSpinner.adapter = cycleAdapter
@@ -62,21 +73,15 @@ open class DataUsageListHeaderController(
override fun setSelection(position: Int) { override fun setSelection(position: Int) {
cycleSpinner.setSelection(position) cycleSpinner.setSelection(position)
} if (cycleSpinner.onItemSelectedListener == null) {
}) cycleSpinner.onItemSelectedListener = cycleListener
private var cycles: List<NetworkUsageData> = emptyList() } else {
setSelectedCycle(position)
private val cycleListener = object : AdapterView.OnItemSelectedListener {
override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
if (0 <= position && position < cycleAdapter.count) {
cycles.getOrNull(position)?.let(onItemSelected)
} }
} }
})
override fun onNothingSelected(parent: AdapterView<*>?) { private var cycles: List<NetworkUsageData> = emptyList()
// ignored
}
}
init { init {
configureButton.setOnClickListener { configureButton.setOnClickListener {
@@ -114,11 +119,12 @@ open class DataUsageListHeaderController(
} }
private fun updateCycleData() { private fun updateCycleData() {
cycleSpinner.onItemSelectedListener = cycleListener
// calculate policy cycles based on available data
// generate cycle list based on policy and available history
cycleAdapter.updateCycleList(cycles.map { Range(it.startTime, it.endTime) }) cycleAdapter.updateCycleList(cycles.map { Range(it.startTime, it.endTime) })
cycleSpinner.visibility = View.VISIBLE cycleSpinner.visibility = View.VISIBLE
onCyclesLoad(cycles) onCyclesLoad(cycles)
} }
private fun setSelectedCycle(position: Int) {
cycles.getOrNull(position)?.let(updateSelectedCycle)
}
} }

View File

@@ -98,7 +98,7 @@ class AppDataUsageRepository(
private fun bindStats( private fun bindStats(
buckets: List<Bucket>, buckets: List<Bucket>,
profiles: MutableList<UserHandle>, profiles: List<UserHandle>,
knownItems: SparseArray<AppItem>, knownItems: SparseArray<AppItem>,
items: ArrayList<AppItem>, items: ArrayList<AppItem>,
) { ) {

View File

@@ -58,7 +58,7 @@ class NetworkCycleDataRepository(
return reverseBucketRange( return reverseBucketRange(
startTime = timeRange.lower, startTime = timeRange.lower,
endTime = timeRange.upper, endTime = timeRange.upper,
bucketSize = DateUtils.WEEK_IN_MILLIS * 4, step = DateUtils.WEEK_IN_MILLIS * 4,
) )
} }
@@ -76,7 +76,7 @@ class NetworkCycleDataRepository(
dailyUsage = bucketRange( dailyUsage = bucketRange(
startTime = startTime, startTime = startTime,
endTime = endTime, endTime = endTime,
bucketSize = NetworkCycleChartData.BUCKET_DURATION.inWholeMilliseconds, step = NetworkCycleChartData.BUCKET_DURATION.inWholeMilliseconds,
).queryUsage(), ).queryUsage(),
) )
} }
@@ -92,29 +92,10 @@ class NetworkCycleDataRepository(
usage = networkStatsRepository.querySummaryForDevice(range.lower, range.upper), usage = networkStatsRepository.querySummaryForDevice(range.lower, range.upper),
) )
private fun bucketRange(startTime: Long, endTime: Long, bucketSize: Long): List<Range<Long>> { private fun bucketRange(startTime: Long, endTime: Long, step: Long): List<Range<Long>> =
val buckets = mutableListOf<Range<Long>>() (startTime..endTime step step).zipWithNext(::Range)
var currentStart = startTime
while (currentStart < endTime) {
val bucketEnd = currentStart + bucketSize
buckets += Range(currentStart, bucketEnd)
currentStart = bucketEnd
}
return buckets
}
private fun reverseBucketRange( private fun reverseBucketRange(startTime: Long, endTime: Long, step: Long): List<Range<Long>> =
startTime: Long, (endTime downTo (startTime - step + 1) step step)
endTime: Long, .zipWithNext { bucketEnd, bucketStart -> Range(bucketStart, bucketEnd) }
bucketSize: Long,
): List<Range<Long>> {
val buckets = mutableListOf<Range<Long>>()
var currentEnd = endTime
while (currentEnd > startTime) {
val bucketStart = currentEnd - bucketSize
buckets += Range(bucketStart, currentEnd)
currentEnd = bucketStart
}
return buckets
}
} }

View File

@@ -69,7 +69,7 @@ class DataUsageListHeaderControllerTest {
sourceMetricsCategory = 0, sourceMetricsCategory = 0,
viewLifecycleOwner = testLifecycleOwner, viewLifecycleOwner = testLifecycleOwner,
onCyclesLoad = {}, onCyclesLoad = {},
onItemSelected = {}, updateSelectedCycle = {},
repository = repository, repository = repository,
) )