Merge "[SB Refactor] Create the callback collector object for the new pipeline and have the processor connect to it." into tm-qpr-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
22affe07b4
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright (C) 2022 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.systemui.statusbar.pipeline
|
||||
|
||||
import com.android.systemui.statusbar.pipeline.repository.NetworkCapabilityInfo
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
|
||||
/**
|
||||
* Interface exposing a flow for raw connectivity information. Clients should collect on
|
||||
* [rawConnectivityInfoFlow] to get updates on connectivity information.
|
||||
*
|
||||
* Note: [rawConnectivityInfoFlow] should be a *hot* flow, so that we only create one instance of it
|
||||
* and all clients get references to the same flow.
|
||||
*
|
||||
* This will be used for the new status bar pipeline to compile information we need to display some
|
||||
* of the icons in the RHS of the status bar.
|
||||
*/
|
||||
interface ConnectivityInfoCollector {
|
||||
val rawConnectivityInfoFlow: StateFlow<RawConnectivityInfo>
|
||||
}
|
||||
|
||||
/**
|
||||
* An object containing all of the raw connectivity information.
|
||||
*
|
||||
* Importantly, all the information in this object should not be processed at all (i.e., the data
|
||||
* that we receive from callbacks should be piped straight into this object and not be filtered,
|
||||
* manipulated, or processed in any way). Instead, any listeners on
|
||||
* [ConnectivityInfoCollector.rawConnectivityInfoFlow] can do the processing.
|
||||
*
|
||||
* This allows us to keep all the processing in one place which is beneficial for logging and
|
||||
* debugging purposes.
|
||||
*/
|
||||
data class RawConnectivityInfo(
|
||||
val networkCapabilityInfo: Map<Int, NetworkCapabilityInfo> = emptyMap(),
|
||||
)
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright (C) 2022 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.systemui.statusbar.pipeline
|
||||
|
||||
import com.android.systemui.dagger.SysUISingleton
|
||||
import com.android.systemui.dagger.qualifiers.Application
|
||||
import com.android.systemui.statusbar.pipeline.repository.NetworkCapabilitiesRepo
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import javax.inject.Inject
|
||||
import kotlinx.coroutines.flow.SharingStarted.Companion.Lazily
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
|
||||
/**
|
||||
* The real implementation of [ConnectivityInfoCollector] that will collect information from all the
|
||||
* relevant connectivity callbacks and compile it into [rawConnectivityInfoFlow].
|
||||
*/
|
||||
@SysUISingleton
|
||||
class ConnectivityInfoCollectorImpl @Inject constructor(
|
||||
networkCapabilitiesRepo: NetworkCapabilitiesRepo,
|
||||
@Application scope: CoroutineScope,
|
||||
) : ConnectivityInfoCollector {
|
||||
override val rawConnectivityInfoFlow: StateFlow<RawConnectivityInfo> =
|
||||
// TODO(b/238425913): Collect all the separate flows for individual raw information into
|
||||
// this final flow.
|
||||
networkCapabilitiesRepo.dataStream
|
||||
.map {
|
||||
RawConnectivityInfo(networkCapabilityInfo = it)
|
||||
}
|
||||
.stateIn(scope, started = Lazily, initialValue = RawConnectivityInfo())
|
||||
}
|
||||
@@ -19,7 +19,15 @@ package com.android.systemui.statusbar.pipeline
|
||||
import android.content.Context
|
||||
import com.android.systemui.CoreStartable
|
||||
import com.android.systemui.dagger.SysUISingleton
|
||||
import com.android.systemui.dagger.qualifiers.Application
|
||||
import com.android.systemui.statusbar.pipeline.repository.NetworkCapabilityInfo
|
||||
import javax.inject.Inject
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.SharingStarted.Companion.Lazily
|
||||
import kotlinx.coroutines.flow.emptyFlow
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
|
||||
/**
|
||||
* A processor that transforms raw connectivity information that we get from callbacks and turns it
|
||||
@@ -27,20 +35,43 @@ import javax.inject.Inject
|
||||
*
|
||||
* This will be used for the new status bar pipeline to calculate the list of icons that should be
|
||||
* displayed in the RHS of the status bar.
|
||||
*
|
||||
* Anyone can listen to [processedInfoFlow] to get updates to the processed data.
|
||||
*/
|
||||
@SysUISingleton
|
||||
class ConnectivityInfoProcessor @Inject constructor(
|
||||
connectivityInfoCollector: ConnectivityInfoCollector,
|
||||
context: Context,
|
||||
private val statusBarPipelineFlags: StatusBarPipelineFlags,
|
||||
@Application private val scope: CoroutineScope,
|
||||
statusBarPipelineFlags: StatusBarPipelineFlags,
|
||||
) : CoreStartable(context) {
|
||||
// Note: This flow will not start running until a client calls `collect` on it, which means that
|
||||
// [connectivityInfoCollector]'s flow will also not start anything until that `collect` call
|
||||
// happens.
|
||||
val processedInfoFlow: Flow<ProcessedConnectivityInfo> =
|
||||
if (!statusBarPipelineFlags.isNewPipelineEnabled())
|
||||
emptyFlow()
|
||||
else connectivityInfoCollector.rawConnectivityInfoFlow
|
||||
.map { it.process() }
|
||||
.stateIn(
|
||||
scope,
|
||||
started = Lazily,
|
||||
initialValue = ProcessedConnectivityInfo()
|
||||
)
|
||||
|
||||
override fun start() {
|
||||
if (statusBarPipelineFlags.isNewPipelineEnabled()) {
|
||||
init()
|
||||
}
|
||||
}
|
||||
|
||||
/** Initializes this processor and everything it depends on. */
|
||||
private fun init() {
|
||||
// TODO(b/238425913): Register all the connectivity callbacks here.
|
||||
private fun RawConnectivityInfo.process(): ProcessedConnectivityInfo {
|
||||
// TODO(b/238425913): Actually process the raw info into meaningful data.
|
||||
return ProcessedConnectivityInfo(this.networkCapabilityInfo)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An object containing connectivity info that has been processed into data that can be directly
|
||||
* used by the status bar (and potentially other SysUI areas) to display icons.
|
||||
*/
|
||||
data class ProcessedConnectivityInfo(
|
||||
val networkCapabilityInfo: Map<Int, NetworkCapabilityInfo> = emptyMap(),
|
||||
)
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
package com.android.systemui.statusbar.pipeline.dagger
|
||||
|
||||
import com.android.systemui.CoreStartable
|
||||
import com.android.systemui.statusbar.pipeline.ConnectivityInfoCollector
|
||||
import com.android.systemui.statusbar.pipeline.ConnectivityInfoCollectorImpl
|
||||
import com.android.systemui.statusbar.pipeline.ConnectivityInfoProcessor
|
||||
import dagger.Binds
|
||||
import dagger.Module
|
||||
@@ -30,4 +32,9 @@ abstract class StatusBarPipelineModule {
|
||||
@IntoMap
|
||||
@ClassKey(ConnectivityInfoProcessor::class)
|
||||
abstract fun bindConnectivityInfoProcessor(cip: ConnectivityInfoProcessor): CoreStartable
|
||||
|
||||
@Binds
|
||||
abstract fun provideConnectivityInfoCollector(
|
||||
impl: ConnectivityInfoCollectorImpl
|
||||
): ConnectivityInfoCollector
|
||||
}
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Copyright (C) 2022 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.systemui.statusbar.pipeline
|
||||
|
||||
import android.net.NetworkCapabilities
|
||||
import android.testing.AndroidTestingRunner
|
||||
import androidx.test.filters.SmallTest
|
||||
import com.android.systemui.SysuiTestCase
|
||||
import com.android.systemui.statusbar.pipeline.repository.NetworkCapabilityInfo
|
||||
import com.android.systemui.util.mockito.mock
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.CoroutineStart
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.InternalCoroutinesApi
|
||||
import kotlinx.coroutines.cancel
|
||||
import kotlinx.coroutines.flow.collect
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import kotlinx.coroutines.yield
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.mockito.Mockito.`when` as whenever
|
||||
|
||||
@OptIn(InternalCoroutinesApi::class)
|
||||
@SmallTest
|
||||
@RunWith(AndroidTestingRunner::class)
|
||||
class ConnectivityInfoProcessorTest : SysuiTestCase() {
|
||||
|
||||
private val statusBarPipelineFlags = mock<StatusBarPipelineFlags>()
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
whenever(statusBarPipelineFlags.isNewPipelineEnabled()).thenReturn(true)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun collectorInfoUpdated_processedInfoAlsoUpdated() = runBlocking {
|
||||
// GIVEN a processor hooked up to a collector
|
||||
val scope = CoroutineScope(Dispatchers.Unconfined)
|
||||
val collector = FakeConnectivityInfoCollector()
|
||||
val processor = ConnectivityInfoProcessor(
|
||||
collector,
|
||||
context,
|
||||
scope,
|
||||
statusBarPipelineFlags,
|
||||
)
|
||||
|
||||
var mostRecentValue: ProcessedConnectivityInfo? = null
|
||||
val job = launch(start = CoroutineStart.UNDISPATCHED) {
|
||||
processor.processedInfoFlow.collect {
|
||||
mostRecentValue = it
|
||||
}
|
||||
}
|
||||
|
||||
// WHEN the collector emits a value
|
||||
val networkCapabilityInfo = mapOf(
|
||||
10 to NetworkCapabilityInfo(mock(), NetworkCapabilities.Builder().build())
|
||||
)
|
||||
collector.emitValue(RawConnectivityInfo(networkCapabilityInfo))
|
||||
// Because our job uses [CoroutineStart.UNDISPATCHED], it executes in the same thread as
|
||||
// this test. So, our test needs to yield to let the job run.
|
||||
// Note: Once we upgrade our Kotlin coroutines testing library, we won't need this.
|
||||
yield()
|
||||
|
||||
// THEN the processor receives it
|
||||
assertThat(mostRecentValue?.networkCapabilityInfo).isEqualTo(networkCapabilityInfo)
|
||||
|
||||
job.cancel()
|
||||
scope.cancel()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright (C) 2022 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.systemui.statusbar.pipeline
|
||||
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
|
||||
/**
|
||||
* A test-friendly implementation of [ConnectivityInfoCollector] that just emits whatever value it
|
||||
* receives in [emitValue].
|
||||
*/
|
||||
class FakeConnectivityInfoCollector : ConnectivityInfoCollector {
|
||||
private val _rawConnectivityInfoFlow = MutableStateFlow(RawConnectivityInfo())
|
||||
override val rawConnectivityInfoFlow = _rawConnectivityInfoFlow.asStateFlow()
|
||||
|
||||
suspend fun emitValue(value: RawConnectivityInfo) {
|
||||
_rawConnectivityInfoFlow.emit(value)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user