1 /*
2  * Copyright (C) 2023 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.settings.datausage
18 
19 import android.net.NetworkTemplate
20 import android.os.Bundle
21 import android.util.Range
22 import android.view.View
23 import android.view.accessibility.AccessibilityEvent
24 import android.widget.AdapterView
25 import android.widget.Spinner
26 import androidx.annotation.OpenForTesting
27 import androidx.lifecycle.LifecycleOwner
28 import com.android.settings.R
29 import com.android.settings.core.SubSettingLauncher
30 import com.android.settings.datausage.CycleAdapter.SpinnerInterface
31 import com.android.settings.datausage.lib.NetworkUsageData
32 import com.android.settingslib.spa.framework.util.collectLatestWithLifecycle
33 import kotlinx.coroutines.flow.Flow
34 
35 @OpenForTesting
36 open class DataUsageListHeaderController(
37     header: View,
38     template: NetworkTemplate,
39     sourceMetricsCategory: Int,
40     viewLifecycleOwner: LifecycleOwner,
41     cyclesFlow: Flow<List<NetworkUsageData>>,
42     private val updateSelectedCycle: (usageData: NetworkUsageData) -> Unit,
43 ) {
44     private val context = header.context
45 
46     private val configureButton: View = header.requireViewById(R.id.filter_settings)
47     private val cycleSpinner: Spinner = header.requireViewById(R.id.filter_spinner)
48 
49     private val cycleListener = object : AdapterView.OnItemSelectedListener {
onItemSelectednull50         override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
51             setSelectedCycle(position)
52         }
53 
onNothingSelectednull54         override fun onNothingSelected(parent: AdapterView<*>?) {
55             // ignored
56         }
57     }
58 
59     private val cycleAdapter = CycleAdapter(context, object : SpinnerInterface {
setAdapternull60         override fun setAdapter(cycleAdapter: CycleAdapter) {
61             cycleSpinner.adapter = cycleAdapter
62         }
63 
getSelectedItemnull64         override fun getSelectedItem() = cycleSpinner.selectedItem
65 
66         override fun setSelection(position: Int) {
67             cycleSpinner.setSelection(position)
68             if (cycleSpinner.onItemSelectedListener == null) {
69                 cycleSpinner.onItemSelectedListener = cycleListener
70             } else {
71                 setSelectedCycle(position)
72             }
73         }
74     })
75 
76     private var cycles: List<NetworkUsageData> = emptyList()
77 
78     init {
<lambda>null79         configureButton.setOnClickListener {
80             val args = Bundle().apply {
81                 putParcelable(DataUsageList.EXTRA_NETWORK_TEMPLATE, template)
82             }
83             SubSettingLauncher(context).apply {
84                 setDestination(BillingCycleSettings::class.java.name)
85                 setTitleRes(R.string.billing_cycle)
86                 setSourceMetricsCategory(sourceMetricsCategory)
87                 setArguments(args)
88             }.launch()
89         }
90         cycleSpinner.visibility = View.GONE
91         cycleSpinner.accessibilityDelegate = object : View.AccessibilityDelegate() {
sendAccessibilityEventnull92             override fun sendAccessibilityEvent(host: View, eventType: Int) {
93                 // Ignore TYPE_VIEW_SELECTED or TalkBack will speak for it at onResume.
94                 if (eventType == AccessibilityEvent.TYPE_VIEW_SELECTED) return
95                 super.sendAccessibilityEvent(host, eventType)
96             }
97         }
98 
<lambda>null99         cyclesFlow.collectLatestWithLifecycle(viewLifecycleOwner) {
100             cycles = it
101             updateCycleData()
102         }
103     }
104 
setConfigButtonVisiblenull105     open fun setConfigButtonVisible(visible: Boolean) {
106         configureButton.visibility = if (visible) View.VISIBLE else View.GONE
107     }
108 
updateCycleDatanull109     private fun updateCycleData() {
110         cycleAdapter.updateCycleList(cycles.map { Range(it.startTime, it.endTime) })
111         cycleSpinner.visibility = View.VISIBLE
112     }
113 
setSelectedCyclenull114     private fun setSelectedCycle(position: Int) {
115         cycles.getOrNull(position)?.let(updateSelectedCycle)
116     }
117 }
118