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