1 /* 2 * Copyright (C) 2022 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.systemui.statusbar.pipeline.shared.data.repository 18 19 import android.content.Context 20 import androidx.annotation.ArrayRes 21 import androidx.annotation.VisibleForTesting 22 import com.android.systemui.Dumpable 23 import com.android.systemui.R 24 import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow 25 import com.android.systemui.dagger.SysUISingleton 26 import com.android.systemui.dagger.qualifiers.Application 27 import com.android.systemui.dump.DumpManager 28 import com.android.systemui.statusbar.phone.StatusBarIconController 29 import com.android.systemui.statusbar.pipeline.shared.ConnectivityInputLogger 30 import com.android.systemui.statusbar.pipeline.shared.data.model.ConnectivitySlot 31 import com.android.systemui.statusbar.pipeline.shared.data.model.ConnectivitySlots 32 import com.android.systemui.tuner.TunerService 33 import java.io.PrintWriter 34 import javax.inject.Inject 35 import kotlinx.coroutines.CoroutineScope 36 import kotlinx.coroutines.ExperimentalCoroutinesApi 37 import kotlinx.coroutines.channels.awaitClose 38 import kotlinx.coroutines.flow.SharingStarted 39 import kotlinx.coroutines.flow.StateFlow 40 import kotlinx.coroutines.flow.stateIn 41 42 /** 43 * Provides data related to the connectivity state that needs to be shared across multiple different 44 * types of connectivity (wifi, mobile, ethernet, etc.) 45 */ 46 interface ConnectivityRepository { 47 /** Observable for the current set of connectivity icons that should be force-hidden. */ 48 val forceHiddenSlots: StateFlow<Set<ConnectivitySlot>> 49 } 50 51 @OptIn(ExperimentalCoroutinesApi::class) 52 @SysUISingleton 53 class ConnectivityRepositoryImpl 54 @Inject 55 constructor( 56 private val connectivitySlots: ConnectivitySlots, 57 context: Context, 58 dumpManager: DumpManager, 59 logger: ConnectivityInputLogger, 60 @Application scope: CoroutineScope, 61 tunerService: TunerService, 62 ) : ConnectivityRepository, Dumpable { 63 init { 64 dumpManager.registerDumpable("ConnectivityRepository", this) 65 } 66 67 // The default set of hidden icons to use if we don't get any from [TunerService]. 68 private val defaultHiddenIcons: Set<ConnectivitySlot> = 69 context.resources 70 .getStringArray(DEFAULT_HIDDEN_ICONS_RESOURCE) 71 .asList() 72 .toSlotSet(connectivitySlots) 73 74 override val forceHiddenSlots: StateFlow<Set<ConnectivitySlot>> = <lambda>null75 conflatedCallbackFlow { 76 val callback = 77 object : TunerService.Tunable { 78 override fun onTuningChanged(key: String, newHideList: String?) { 79 if (key != HIDDEN_ICONS_TUNABLE_KEY) { 80 return 81 } 82 logger.logTuningChanged(newHideList) 83 84 val outputList = 85 newHideList?.split(",")?.toSlotSet(connectivitySlots) 86 ?: defaultHiddenIcons 87 trySend(outputList) 88 } 89 } 90 tunerService.addTunable(callback, HIDDEN_ICONS_TUNABLE_KEY) 91 92 awaitClose { tunerService.removeTunable(callback) } 93 } 94 .stateIn( 95 scope, 96 started = SharingStarted.WhileSubscribed(), 97 initialValue = defaultHiddenIcons 98 ) 99 dumpnull100 override fun dump(pw: PrintWriter, args: Array<out String>) { 101 pw.apply { println("defaultHiddenIcons=$defaultHiddenIcons") } 102 } 103 104 companion object { 105 @VisibleForTesting 106 internal const val HIDDEN_ICONS_TUNABLE_KEY = StatusBarIconController.ICON_HIDE_LIST 107 @VisibleForTesting 108 @ArrayRes 109 internal val DEFAULT_HIDDEN_ICONS_RESOURCE = R.array.config_statusBarIconsToExclude 110 111 /** Converts a list of string slot names to a set of [ConnectivitySlot] instances. */ Listnull112 private fun List<String>.toSlotSet( 113 connectivitySlots: ConnectivitySlots 114 ): Set<ConnectivitySlot> { 115 return this.filter { it.isNotBlank() } 116 .mapNotNull { connectivitySlots.getSlotFromName(it) } 117 .toSet() 118 } 119 } 120 } 121