Add a AutoAddInteractor
This is meant to replace the old AutoTileManager. It works with a collection of AutoAddable, so adding new rules for tiles that need to be added is easier to do. Fixes: 278577795 Test: atest com.android.systemui.qs.pipeline Flag: QS_PIPELINE_AUTO_ADD Change-Id: Iee7e70f90034c5bb773a515660f88548d5a0aa86
This commit is contained in:
@@ -161,7 +161,9 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, P
|
|||||||
// finishes before creating any tiles.
|
// finishes before creating any tiles.
|
||||||
tunerService.addTunable(this, TILES_SETTING);
|
tunerService.addTunable(this, TILES_SETTING);
|
||||||
// AutoTileManager can modify mTiles so make sure mTiles has already been initialized.
|
// AutoTileManager can modify mTiles so make sure mTiles has already been initialized.
|
||||||
mAutoTiles = autoTiles.get();
|
if (!mFeatureFlags.isEnabled(Flags.QS_PIPELINE_AUTO_ADD)) {
|
||||||
|
mAutoTiles = autoTiles.get();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,22 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2023 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.qs.pipeline.dagger
|
||||||
|
|
||||||
|
import javax.inject.Qualifier
|
||||||
|
|
||||||
|
/** A [LogBuffer] for the QS pipeline to track auto-added tiles */
|
||||||
|
@Qualifier @MustBeDocumented @Retention(AnnotationRetention.RUNTIME) annotation class QSAutoAddLog
|
||||||
@@ -16,13 +16,40 @@
|
|||||||
|
|
||||||
package com.android.systemui.qs.pipeline.dagger
|
package com.android.systemui.qs.pipeline.dagger
|
||||||
|
|
||||||
|
import com.android.systemui.dagger.SysUISingleton
|
||||||
|
import com.android.systemui.log.LogBuffer
|
||||||
|
import com.android.systemui.log.LogBufferFactory
|
||||||
import com.android.systemui.qs.pipeline.data.repository.AutoAddRepository
|
import com.android.systemui.qs.pipeline.data.repository.AutoAddRepository
|
||||||
import com.android.systemui.qs.pipeline.data.repository.AutoAddSettingRepository
|
import com.android.systemui.qs.pipeline.data.repository.AutoAddSettingRepository
|
||||||
|
import com.android.systemui.qs.pipeline.domain.model.AutoAddable
|
||||||
|
import com.android.systemui.qs.pipeline.shared.logging.QSPipelineLogger
|
||||||
import dagger.Binds
|
import dagger.Binds
|
||||||
import dagger.Module
|
import dagger.Module
|
||||||
|
import dagger.Provides
|
||||||
|
import dagger.multibindings.Multibinds
|
||||||
|
|
||||||
@Module
|
@Module(
|
||||||
|
includes =
|
||||||
|
[
|
||||||
|
BaseAutoAddableModule::class,
|
||||||
|
]
|
||||||
|
)
|
||||||
abstract class QSAutoAddModule {
|
abstract class QSAutoAddModule {
|
||||||
|
|
||||||
@Binds abstract fun bindAutoAddRepository(impl: AutoAddSettingRepository): AutoAddRepository
|
@Binds abstract fun bindAutoAddRepository(impl: AutoAddSettingRepository): AutoAddRepository
|
||||||
|
|
||||||
|
@Multibinds abstract fun providesAutoAddableSet(): Set<AutoAddable>
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
/**
|
||||||
|
* Provides a logging buffer for all logs related to the new Quick Settings pipeline to log
|
||||||
|
* auto added tiles.
|
||||||
|
*/
|
||||||
|
@Provides
|
||||||
|
@SysUISingleton
|
||||||
|
@QSAutoAddLog
|
||||||
|
fun provideQSAutoAddLogBuffer(factory: LogBufferFactory): LogBuffer {
|
||||||
|
return factory.create(QSPipelineLogger.AUTO_ADD_TAG, maxSize = 100, systrace = false)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,5 +19,5 @@ import java.lang.annotation.Retention
|
|||||||
import java.lang.annotation.RetentionPolicy
|
import java.lang.annotation.RetentionPolicy
|
||||||
import javax.inject.Qualifier
|
import javax.inject.Qualifier
|
||||||
|
|
||||||
/** A {@link LogBuffer} for the new QS Pipeline for logging changes to the set of current tiles. */
|
/** A [LogBuffer] for the new QS Pipeline for logging changes to the set of current tiles. */
|
||||||
@Qualifier @MustBeDocumented @Retention(RetentionPolicy.RUNTIME) annotation class QSTileListLog
|
@Qualifier @MustBeDocumented @Retention(RetentionPolicy.RUNTIME) annotation class QSTileListLog
|
||||||
|
|||||||
@@ -0,0 +1,123 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2023 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.qs.pipeline.domain.interactor
|
||||||
|
|
||||||
|
import com.android.systemui.Dumpable
|
||||||
|
import com.android.systemui.dagger.SysUISingleton
|
||||||
|
import com.android.systemui.dagger.qualifiers.Application
|
||||||
|
import com.android.systemui.dump.DumpManager
|
||||||
|
import com.android.systemui.qs.pipeline.data.repository.AutoAddRepository
|
||||||
|
import com.android.systemui.qs.pipeline.domain.model.AutoAddSignal
|
||||||
|
import com.android.systemui.qs.pipeline.domain.model.AutoAddTracking
|
||||||
|
import com.android.systemui.qs.pipeline.domain.model.AutoAddable
|
||||||
|
import com.android.systemui.qs.pipeline.shared.logging.QSPipelineLogger
|
||||||
|
import com.android.systemui.util.asIndenting
|
||||||
|
import com.android.systemui.util.indentIfPossible
|
||||||
|
import java.io.PrintWriter
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean
|
||||||
|
import javax.inject.Inject
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.coroutineScope
|
||||||
|
import kotlinx.coroutines.flow.collectLatest
|
||||||
|
import kotlinx.coroutines.flow.emptyFlow
|
||||||
|
import kotlinx.coroutines.flow.filterIsInstance
|
||||||
|
import kotlinx.coroutines.flow.merge
|
||||||
|
import kotlinx.coroutines.flow.stateIn
|
||||||
|
import kotlinx.coroutines.flow.take
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Collects the signals coming from all registered [AutoAddable] and adds/removes tiles accordingly.
|
||||||
|
*/
|
||||||
|
@SysUISingleton
|
||||||
|
class AutoAddInteractor
|
||||||
|
@Inject
|
||||||
|
constructor(
|
||||||
|
private val autoAddables: Set<@JvmSuppressWildcards AutoAddable>,
|
||||||
|
private val repository: AutoAddRepository,
|
||||||
|
private val dumpManager: DumpManager,
|
||||||
|
private val qsPipelineLogger: QSPipelineLogger,
|
||||||
|
@Application private val scope: CoroutineScope,
|
||||||
|
) : Dumpable {
|
||||||
|
|
||||||
|
private val initialized = AtomicBoolean(false)
|
||||||
|
|
||||||
|
/** Start collection of signals following the user from [currentTilesInteractor]. */
|
||||||
|
fun init(currentTilesInteractor: CurrentTilesInteractor) {
|
||||||
|
if (!initialized.compareAndSet(false, true)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
dumpManager.registerNormalDumpable(TAG, this)
|
||||||
|
|
||||||
|
scope.launch {
|
||||||
|
currentTilesInteractor.userId.collectLatest { userId ->
|
||||||
|
coroutineScope {
|
||||||
|
val previouslyAdded = repository.autoAddedTiles(userId).stateIn(this)
|
||||||
|
|
||||||
|
autoAddables
|
||||||
|
.map { addable ->
|
||||||
|
val autoAddSignal = addable.autoAddSignal(userId)
|
||||||
|
when (val lifecycle = addable.autoAddTracking) {
|
||||||
|
is AutoAddTracking.Always -> autoAddSignal
|
||||||
|
is AutoAddTracking.Disabled -> emptyFlow()
|
||||||
|
is AutoAddTracking.IfNotAdded -> {
|
||||||
|
if (lifecycle.spec !in previouslyAdded.value) {
|
||||||
|
autoAddSignal.filterIsInstance<AutoAddSignal.Add>().take(1)
|
||||||
|
} else {
|
||||||
|
emptyFlow()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.merge()
|
||||||
|
.collect { signal ->
|
||||||
|
when (signal) {
|
||||||
|
is AutoAddSignal.Add -> {
|
||||||
|
if (signal.spec !in previouslyAdded.value) {
|
||||||
|
currentTilesInteractor.addTile(signal.spec, signal.position)
|
||||||
|
qsPipelineLogger.logTileAutoAdded(
|
||||||
|
userId,
|
||||||
|
signal.spec,
|
||||||
|
signal.position
|
||||||
|
)
|
||||||
|
repository.markTileAdded(userId, signal.spec)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
is AutoAddSignal.Remove -> {
|
||||||
|
currentTilesInteractor.removeTiles(setOf(signal.spec))
|
||||||
|
qsPipelineLogger.logTileAutoRemoved(userId, signal.spec)
|
||||||
|
repository.unmarkTileAdded(userId, signal.spec)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun dump(pw: PrintWriter, args: Array<out String>) {
|
||||||
|
with(pw.asIndenting()) {
|
||||||
|
println("AutoAddables:")
|
||||||
|
indentIfPossible { autoAddables.forEach { println(it.description) } }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val TAG = "AutoAddInteractor"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -125,6 +125,7 @@ interface CurrentTilesInteractor : ProtoDumpable {
|
|||||||
class CurrentTilesInteractorImpl
|
class CurrentTilesInteractorImpl
|
||||||
@Inject
|
@Inject
|
||||||
constructor(
|
constructor(
|
||||||
|
autoAddInteractor: AutoAddInteractor,
|
||||||
private val tileSpecRepository: TileSpecRepository,
|
private val tileSpecRepository: TileSpecRepository,
|
||||||
private val installedTilesComponentRepository: InstalledTilesComponentRepository,
|
private val installedTilesComponentRepository: InstalledTilesComponentRepository,
|
||||||
private val userRepository: UserRepository,
|
private val userRepository: UserRepository,
|
||||||
@@ -172,6 +173,10 @@ constructor(
|
|||||||
if (featureFlags.isEnabled(Flags.QS_PIPELINE_NEW_HOST)) {
|
if (featureFlags.isEnabled(Flags.QS_PIPELINE_NEW_HOST)) {
|
||||||
startTileCollection()
|
startTileCollection()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (featureFlags.isEnabled(Flags.QS_PIPELINE_AUTO_ADD)) {
|
||||||
|
autoAddInteractor.init(this)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@OptIn(ExperimentalCoroutinesApi::class)
|
@OptIn(ExperimentalCoroutinesApi::class)
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ package com.android.systemui.qs.pipeline.shared.logging
|
|||||||
import android.annotation.UserIdInt
|
import android.annotation.UserIdInt
|
||||||
import com.android.systemui.log.LogBuffer
|
import com.android.systemui.log.LogBuffer
|
||||||
import com.android.systemui.log.LogLevel
|
import com.android.systemui.log.LogLevel
|
||||||
|
import com.android.systemui.qs.pipeline.dagger.QSAutoAddLog
|
||||||
import com.android.systemui.qs.pipeline.dagger.QSTileListLog
|
import com.android.systemui.qs.pipeline.dagger.QSTileListLog
|
||||||
import com.android.systemui.qs.pipeline.shared.TileSpec
|
import com.android.systemui.qs.pipeline.shared.TileSpec
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
@@ -32,10 +33,12 @@ class QSPipelineLogger
|
|||||||
@Inject
|
@Inject
|
||||||
constructor(
|
constructor(
|
||||||
@QSTileListLog private val tileListLogBuffer: LogBuffer,
|
@QSTileListLog private val tileListLogBuffer: LogBuffer,
|
||||||
|
@QSAutoAddLog private val tileAutoAddLogBuffer: LogBuffer,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val TILE_LIST_TAG = "QSTileListLog"
|
const val TILE_LIST_TAG = "QSTileListLog"
|
||||||
|
const val AUTO_ADD_TAG = "QSAutoAddableLog"
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -136,6 +139,31 @@ constructor(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun logTileAutoAdded(userId: Int, spec: TileSpec, position: Int) {
|
||||||
|
tileAutoAddLogBuffer.log(
|
||||||
|
AUTO_ADD_TAG,
|
||||||
|
LogLevel.DEBUG,
|
||||||
|
{
|
||||||
|
int1 = userId
|
||||||
|
int2 = position
|
||||||
|
str1 = spec.toString()
|
||||||
|
},
|
||||||
|
{ "Tile $str1 auto added for user $int1 at position $int2" }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun logTileAutoRemoved(userId: Int, spec: TileSpec) {
|
||||||
|
tileAutoAddLogBuffer.log(
|
||||||
|
AUTO_ADD_TAG,
|
||||||
|
LogLevel.DEBUG,
|
||||||
|
{
|
||||||
|
int1 = userId
|
||||||
|
str1 = spec.toString()
|
||||||
|
},
|
||||||
|
{ "Tile $str1 auto removed for user $int1" }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
/** Reasons for destroying an existing tile. */
|
/** Reasons for destroying an existing tile. */
|
||||||
enum class TileDestroyedReason(val readable: String) {
|
enum class TileDestroyedReason(val readable: String) {
|
||||||
TILE_REMOVED("Tile removed from current set"),
|
TILE_REMOVED("Tile removed from current set"),
|
||||||
|
|||||||
@@ -140,6 +140,7 @@ public class QSTileHostTest extends SysuiTestCase {
|
|||||||
mFeatureFlags = new FakeFeatureFlags();
|
mFeatureFlags = new FakeFeatureFlags();
|
||||||
|
|
||||||
mFeatureFlags.set(Flags.QS_PIPELINE_NEW_HOST, false);
|
mFeatureFlags.set(Flags.QS_PIPELINE_NEW_HOST, false);
|
||||||
|
mFeatureFlags.set(Flags.QS_PIPELINE_AUTO_ADD, false);
|
||||||
|
|
||||||
mMainExecutor = new FakeExecutor(new FakeSystemClock());
|
mMainExecutor = new FakeExecutor(new FakeSystemClock());
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,201 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2023 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.qs.pipeline.domain.interactor
|
||||||
|
|
||||||
|
import android.testing.AndroidTestingRunner
|
||||||
|
import androidx.test.filters.SmallTest
|
||||||
|
import com.android.systemui.SysuiTestCase
|
||||||
|
import com.android.systemui.coroutines.collectLastValue
|
||||||
|
import com.android.systemui.dump.DumpManager
|
||||||
|
import com.android.systemui.qs.pipeline.data.repository.FakeAutoAddRepository
|
||||||
|
import com.android.systemui.qs.pipeline.domain.autoaddable.FakeAutoAddable
|
||||||
|
import com.android.systemui.qs.pipeline.domain.model.AutoAddTracking
|
||||||
|
import com.android.systemui.qs.pipeline.domain.model.AutoAddable
|
||||||
|
import com.android.systemui.qs.pipeline.shared.TileSpec
|
||||||
|
import com.android.systemui.qs.pipeline.shared.logging.QSPipelineLogger
|
||||||
|
import com.android.systemui.util.mockito.any
|
||||||
|
import com.android.systemui.util.mockito.whenever
|
||||||
|
import com.google.common.truth.Truth.assertThat
|
||||||
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
|
import kotlinx.coroutines.test.TestScope
|
||||||
|
import kotlinx.coroutines.test.runCurrent
|
||||||
|
import kotlinx.coroutines.test.runTest
|
||||||
|
import org.junit.Before
|
||||||
|
import org.junit.Test
|
||||||
|
import org.junit.runner.RunWith
|
||||||
|
import org.mockito.ArgumentMatchers.anyInt
|
||||||
|
import org.mockito.Mock
|
||||||
|
import org.mockito.Mockito.inOrder
|
||||||
|
import org.mockito.Mockito.never
|
||||||
|
import org.mockito.Mockito.verify
|
||||||
|
import org.mockito.MockitoAnnotations
|
||||||
|
|
||||||
|
@SmallTest
|
||||||
|
@RunWith(AndroidTestingRunner::class)
|
||||||
|
@OptIn(ExperimentalCoroutinesApi::class)
|
||||||
|
class AutoAddInteractorTest : SysuiTestCase() {
|
||||||
|
private val testScope = TestScope()
|
||||||
|
|
||||||
|
private val autoAddRepository = FakeAutoAddRepository()
|
||||||
|
|
||||||
|
@Mock private lateinit var dumpManager: DumpManager
|
||||||
|
@Mock private lateinit var currentTilesInteractor: CurrentTilesInteractor
|
||||||
|
@Mock private lateinit var logger: QSPipelineLogger
|
||||||
|
private lateinit var underTest: AutoAddInteractor
|
||||||
|
|
||||||
|
@Before
|
||||||
|
fun setUp() {
|
||||||
|
MockitoAnnotations.initMocks(this)
|
||||||
|
|
||||||
|
whenever(currentTilesInteractor.userId).thenReturn(MutableStateFlow(USER))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun autoAddable_alwaysTrack_addSignal_tileAddedAndMarked() =
|
||||||
|
testScope.runTest {
|
||||||
|
val fakeAutoAddable = FakeAutoAddable(SPEC, AutoAddTracking.Always)
|
||||||
|
val autoAddedTiles by collectLastValue(autoAddRepository.autoAddedTiles(USER))
|
||||||
|
|
||||||
|
underTest = createInteractor(setOf(fakeAutoAddable))
|
||||||
|
|
||||||
|
val position = 3
|
||||||
|
fakeAutoAddable.sendAddSignal(USER, position)
|
||||||
|
runCurrent()
|
||||||
|
|
||||||
|
verify(currentTilesInteractor).addTile(SPEC, position)
|
||||||
|
assertThat(autoAddedTiles).contains(SPEC)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun autoAddable_alwaysTrack_addThenRemoveSignal_tileAddedAndRemoved() =
|
||||||
|
testScope.runTest {
|
||||||
|
val fakeAutoAddable = FakeAutoAddable(SPEC, AutoAddTracking.Always)
|
||||||
|
val autoAddedTiles by collectLastValue(autoAddRepository.autoAddedTiles(USER))
|
||||||
|
|
||||||
|
underTest = createInteractor(setOf(fakeAutoAddable))
|
||||||
|
|
||||||
|
val position = 3
|
||||||
|
fakeAutoAddable.sendAddSignal(USER, position)
|
||||||
|
runCurrent()
|
||||||
|
fakeAutoAddable.sendRemoveSignal(USER)
|
||||||
|
runCurrent()
|
||||||
|
|
||||||
|
val inOrder = inOrder(currentTilesInteractor)
|
||||||
|
inOrder.verify(currentTilesInteractor).addTile(SPEC, position)
|
||||||
|
inOrder.verify(currentTilesInteractor).removeTiles(setOf(SPEC))
|
||||||
|
assertThat(autoAddedTiles).doesNotContain(SPEC)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun autoAddable_alwaysTrack_addSignalWhenAddedPreviously_noop() =
|
||||||
|
testScope.runTest {
|
||||||
|
val fakeAutoAddable = FakeAutoAddable(SPEC, AutoAddTracking.Always)
|
||||||
|
autoAddRepository.markTileAdded(USER, SPEC)
|
||||||
|
runCurrent()
|
||||||
|
|
||||||
|
underTest = createInteractor(setOf(fakeAutoAddable))
|
||||||
|
|
||||||
|
val position = 3
|
||||||
|
fakeAutoAddable.sendAddSignal(USER, position)
|
||||||
|
runCurrent()
|
||||||
|
|
||||||
|
verify(currentTilesInteractor, never()).addTile(SPEC, position)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun autoAddable_disabled_noInteractionsWithCurrentTilesInteractor() =
|
||||||
|
testScope.runTest {
|
||||||
|
val fakeAutoAddable = FakeAutoAddable(SPEC, AutoAddTracking.Disabled)
|
||||||
|
val autoAddedTiles by collectLastValue(autoAddRepository.autoAddedTiles(USER))
|
||||||
|
|
||||||
|
underTest = createInteractor(setOf(fakeAutoAddable))
|
||||||
|
|
||||||
|
val position = 3
|
||||||
|
fakeAutoAddable.sendAddSignal(USER, position)
|
||||||
|
runCurrent()
|
||||||
|
fakeAutoAddable.sendRemoveSignal(USER)
|
||||||
|
runCurrent()
|
||||||
|
|
||||||
|
verify(currentTilesInteractor, never()).addTile(any(), anyInt())
|
||||||
|
verify(currentTilesInteractor, never()).removeTiles(any())
|
||||||
|
assertThat(autoAddedTiles).doesNotContain(SPEC)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun autoAddable_trackIfNotAdded_removeSignal_noop() =
|
||||||
|
testScope.runTest {
|
||||||
|
val fakeAutoAddable = FakeAutoAddable(SPEC, AutoAddTracking.IfNotAdded(SPEC))
|
||||||
|
runCurrent()
|
||||||
|
|
||||||
|
underTest = createInteractor(setOf(fakeAutoAddable))
|
||||||
|
|
||||||
|
fakeAutoAddable.sendRemoveSignal(USER)
|
||||||
|
runCurrent()
|
||||||
|
|
||||||
|
verify(currentTilesInteractor, never()).addTile(any(), anyInt())
|
||||||
|
verify(currentTilesInteractor, never()).removeTiles(any())
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun autoAddable_trackIfNotAdded_addSignalWhenPreviouslyAdded_noop() =
|
||||||
|
testScope.runTest {
|
||||||
|
val fakeAutoAddable = FakeAutoAddable(SPEC, AutoAddTracking.IfNotAdded(SPEC))
|
||||||
|
autoAddRepository.markTileAdded(USER, SPEC)
|
||||||
|
runCurrent()
|
||||||
|
|
||||||
|
underTest = createInteractor(setOf(fakeAutoAddable))
|
||||||
|
|
||||||
|
fakeAutoAddable.sendAddSignal(USER)
|
||||||
|
runCurrent()
|
||||||
|
|
||||||
|
verify(currentTilesInteractor, never()).addTile(any(), anyInt())
|
||||||
|
verify(currentTilesInteractor, never()).removeTiles(any())
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun autoAddable_trackIfNotAdded_addSignal_addedAndMarked() =
|
||||||
|
testScope.runTest {
|
||||||
|
val fakeAutoAddable = FakeAutoAddable(SPEC, AutoAddTracking.IfNotAdded(SPEC))
|
||||||
|
val autoAddedTiles by collectLastValue(autoAddRepository.autoAddedTiles(USER))
|
||||||
|
|
||||||
|
underTest = createInteractor(setOf(fakeAutoAddable))
|
||||||
|
|
||||||
|
val position = 3
|
||||||
|
fakeAutoAddable.sendAddSignal(USER, position)
|
||||||
|
runCurrent()
|
||||||
|
|
||||||
|
verify(currentTilesInteractor).addTile(SPEC, position)
|
||||||
|
assertThat(autoAddedTiles).contains(SPEC)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createInteractor(autoAddables: Set<AutoAddable>): AutoAddInteractor {
|
||||||
|
return AutoAddInteractor(
|
||||||
|
autoAddables,
|
||||||
|
autoAddRepository,
|
||||||
|
dumpManager,
|
||||||
|
logger,
|
||||||
|
testScope.backgroundScope
|
||||||
|
)
|
||||||
|
.apply { init(currentTilesInteractor) }
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val SPEC = TileSpec.create("spec")
|
||||||
|
private val USER = 10
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -83,6 +83,8 @@ class CurrentTilesInteractorImplTest : SysuiTestCase() {
|
|||||||
|
|
||||||
@Mock private lateinit var customTileStatePersister: CustomTileStatePersister
|
@Mock private lateinit var customTileStatePersister: CustomTileStatePersister
|
||||||
|
|
||||||
|
@Mock private lateinit var autoAddInteractor: AutoAddInteractor
|
||||||
|
|
||||||
@Mock private lateinit var userTracker: UserTracker
|
@Mock private lateinit var userTracker: UserTracker
|
||||||
|
|
||||||
@Mock private lateinit var logger: QSPipelineLogger
|
@Mock private lateinit var logger: QSPipelineLogger
|
||||||
@@ -100,6 +102,7 @@ class CurrentTilesInteractorImplTest : SysuiTestCase() {
|
|||||||
MockitoAnnotations.initMocks(this)
|
MockitoAnnotations.initMocks(this)
|
||||||
|
|
||||||
featureFlags.set(Flags.QS_PIPELINE_NEW_HOST, true)
|
featureFlags.set(Flags.QS_PIPELINE_NEW_HOST, true)
|
||||||
|
featureFlags.set(Flags.QS_PIPELINE_AUTO_ADD, true)
|
||||||
|
|
||||||
userRepository.setUserInfos(listOf(USER_INFO_0, USER_INFO_1))
|
userRepository.setUserInfos(listOf(USER_INFO_0, USER_INFO_1))
|
||||||
|
|
||||||
@@ -107,6 +110,7 @@ class CurrentTilesInteractorImplTest : SysuiTestCase() {
|
|||||||
|
|
||||||
underTest =
|
underTest =
|
||||||
CurrentTilesInteractorImpl(
|
CurrentTilesInteractorImpl(
|
||||||
|
autoAddInteractor = autoAddInteractor,
|
||||||
tileSpecRepository = tileSpecRepository,
|
tileSpecRepository = tileSpecRepository,
|
||||||
installedTilesComponentRepository = installedTilesPackageRepository,
|
installedTilesComponentRepository = installedTilesPackageRepository,
|
||||||
userRepository = userRepository,
|
userRepository = userRepository,
|
||||||
@@ -647,6 +651,11 @@ class CurrentTilesInteractorImplTest : SysuiTestCase() {
|
|||||||
assertThat(tiles!![1].spec).isEqualTo(CUSTOM_TILE_SPEC)
|
assertThat(tiles!![1].spec).isEqualTo(CUSTOM_TILE_SPEC)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun autoAddInteractor_initted() {
|
||||||
|
verify(autoAddInteractor).init(underTest)
|
||||||
|
}
|
||||||
|
|
||||||
private fun QSTile.State.fillIn(state: Int, label: CharSequence, secondaryLabel: CharSequence) {
|
private fun QSTile.State.fillIn(state: Int, label: CharSequence, secondaryLabel: CharSequence) {
|
||||||
this.state = state
|
this.state = state
|
||||||
this.label = label
|
this.label = label
|
||||||
|
|||||||
@@ -0,0 +1,42 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2023 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.qs.pipeline.data.repository
|
||||||
|
|
||||||
|
import com.android.systemui.qs.pipeline.shared.TileSpec
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
|
|
||||||
|
class FakeAutoAddRepository : AutoAddRepository {
|
||||||
|
|
||||||
|
private val autoAddedTilesPerUser = mutableMapOf<Int, MutableStateFlow<Set<TileSpec>>>()
|
||||||
|
|
||||||
|
override fun autoAddedTiles(userId: Int): Flow<Set<TileSpec>> {
|
||||||
|
return getFlow(userId)
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun markTileAdded(userId: Int, spec: TileSpec) {
|
||||||
|
if (spec == TileSpec.Invalid) return
|
||||||
|
with(getFlow(userId)) { value = value.toMutableSet().apply { add(spec) } }
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun unmarkTileAdded(userId: Int, spec: TileSpec) {
|
||||||
|
with(getFlow(userId)) { value = value.toMutableSet().apply { remove(spec) } }
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getFlow(userId: Int): MutableStateFlow<Set<TileSpec>> =
|
||||||
|
autoAddedTilesPerUser.getOrPut(userId) { MutableStateFlow(emptySet()) }
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user