Merge "Fixes quick affordance visibility bug." into tm-qpr-dev am: 7e09869954 am: 1846a65ace

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/19485352

Change-Id: I5c74897307ff321d90d31defee5ecd39085de3eb
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
Alejandro Nijamkin
2022-08-02 22:28:21 +00:00
committed by Automerger Merge Worker
14 changed files with 245 additions and 212 deletions

View File

@@ -17,14 +17,12 @@
package com.android.systemui.keyguard.data.quickaffordance
import android.content.Context
import com.android.systemui.R
import com.android.systemui.animation.ActivityLaunchAnimator
import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging
import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
import com.android.systemui.containeddrawable.ContainedDrawable
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.qrcodescanner.controller.QRCodeScannerController
import javax.inject.Inject
import kotlinx.coroutines.channels.awaitClose
@@ -35,12 +33,9 @@ import kotlinx.coroutines.flow.Flow
class QrCodeScannerKeyguardQuickAffordanceConfig
@Inject
constructor(
@Application context: Context,
private val controller: QRCodeScannerController,
) : KeyguardQuickAffordanceConfig {
private val appContext = context.applicationContext
override val state: Flow<KeyguardQuickAffordanceConfig.State> = conflatedCallbackFlow {
val callback =
object : QRCodeScannerController.Callback {

View File

@@ -29,32 +29,59 @@ import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCall
import com.android.systemui.containeddrawable.ContainedDrawable
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.statusbar.policy.KeyguardStateController
import com.android.systemui.statusbar.policy.KeyguardStateControllerExt.isKeyguardShowing
import com.android.systemui.wallet.controller.QuickAccessWalletController
import javax.inject.Inject
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flowOf
/** Quick access wallet quick affordance data source. */
@SysUISingleton
class QuickAccessWalletKeyguardQuickAffordanceConfig
@Inject
constructor(
private val keyguardStateController: KeyguardStateController,
private val walletController: QuickAccessWalletController,
private val activityStarter: ActivityStarter,
) : KeyguardQuickAffordanceConfig {
override val state: Flow<KeyguardQuickAffordanceConfig.State> =
keyguardStateController
.isKeyguardShowing(TAG)
.flatMapLatest { isKeyguardShowing ->
stateInternal(isKeyguardShowing)
override val state: Flow<KeyguardQuickAffordanceConfig.State> = conflatedCallbackFlow {
val callback =
object : QuickAccessWalletClient.OnWalletCardsRetrievedCallback {
override fun onWalletCardsRetrieved(response: GetWalletCardsResponse?) {
trySendWithFailureLogging(
state(
isFeatureEnabled = walletController.isWalletEnabled,
hasCard = response?.walletCards?.isNotEmpty() == true,
tileIcon = walletController.walletClient.tileIcon,
),
TAG,
)
}
override fun onWalletCardRetrievalError(error: GetWalletCardsError?) {
Log.e(TAG, "Wallet card retrieval error, message: \"${error?.message}\"")
trySendWithFailureLogging(
KeyguardQuickAffordanceConfig.State.Hidden,
TAG,
)
}
}
walletController.setupWalletChangeObservers(
callback,
QuickAccessWalletController.WalletChangeEvent.WALLET_PREFERENCE_CHANGE,
QuickAccessWalletController.WalletChangeEvent.DEFAULT_PAYMENT_APP_CHANGE
)
walletController.updateWalletPreference()
walletController.queryWalletCards(callback)
awaitClose {
walletController.unregisterWalletChangeObservers(
QuickAccessWalletController.WalletChangeEvent.WALLET_PREFERENCE_CHANGE,
QuickAccessWalletController.WalletChangeEvent.DEFAULT_PAYMENT_APP_CHANGE
)
}
}
override fun onQuickAffordanceClicked(
animationController: ActivityLaunchAnimator.Controller?,
): KeyguardQuickAffordanceConfig.OnClickedResult {
@@ -66,53 +93,6 @@ constructor(
return KeyguardQuickAffordanceConfig.OnClickedResult.Handled
}
private fun stateInternal(
isKeyguardShowing: Boolean
): Flow<KeyguardQuickAffordanceConfig.State> {
if (!isKeyguardShowing) {
return flowOf(KeyguardQuickAffordanceConfig.State.Hidden)
}
return conflatedCallbackFlow {
val callback =
object : QuickAccessWalletClient.OnWalletCardsRetrievedCallback {
override fun onWalletCardsRetrieved(response: GetWalletCardsResponse?) {
trySendWithFailureLogging(
state(
isFeatureEnabled = walletController.isWalletEnabled,
hasCard = response?.walletCards?.isNotEmpty() == true,
tileIcon = walletController.walletClient.tileIcon,
),
TAG,
)
}
override fun onWalletCardRetrievalError(error: GetWalletCardsError?) {
Log.e(TAG, "Wallet card retrieval error, message: \"${error?.message}\"")
trySendWithFailureLogging(
KeyguardQuickAffordanceConfig.State.Hidden,
TAG,
)
}
}
walletController.setupWalletChangeObservers(
callback,
QuickAccessWalletController.WalletChangeEvent.WALLET_PREFERENCE_CHANGE,
QuickAccessWalletController.WalletChangeEvent.DEFAULT_PAYMENT_APP_CHANGE
)
walletController.updateWalletPreference()
walletController.queryWalletCards(callback)
awaitClose {
walletController.unregisterWalletChangeObservers(
QuickAccessWalletController.WalletChangeEvent.WALLET_PREFERENCE_CHANGE,
QuickAccessWalletController.WalletChangeEvent.DEFAULT_PAYMENT_APP_CHANGE
)
}
}
}
private fun state(
isFeatureEnabled: Boolean,
hasCard: Boolean,

View File

@@ -21,6 +21,7 @@ import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCall
import com.android.systemui.common.data.model.Position
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.statusbar.policy.KeyguardStateController
import javax.inject.Inject
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
@@ -49,6 +50,15 @@ interface KeyguardRepository {
*/
val clockPosition: StateFlow<Position>
/**
* Observable for whether the keyguard is showing.
*
* Note: this is also `true` when the lock-screen is occluded with an `Activity` "above" it in
* the z-order (which is not really above the system UI window, but rather - the lock-screen
* becomes invisible to reveal the "occluding activity").
*/
val isKeyguardShowing: Flow<Boolean>
/**
* Observable for whether we are in doze state.
*
@@ -91,6 +101,7 @@ class KeyguardRepositoryImpl
@Inject
constructor(
statusBarStateController: StatusBarStateController,
keyguardStateController: KeyguardStateController,
) : KeyguardRepository {
private val _animateBottomAreaDozingTransitions = MutableStateFlow(false)
override val animateBottomAreaDozingTransitions =
@@ -102,6 +113,29 @@ constructor(
private val _clockPosition = MutableStateFlow(Position(0, 0))
override val clockPosition = _clockPosition.asStateFlow()
override val isKeyguardShowing: Flow<Boolean> = conflatedCallbackFlow {
val callback =
object : KeyguardStateController.Callback {
override fun onKeyguardShowingChanged() {
trySendWithFailureLogging(
keyguardStateController.isShowing,
TAG,
"updated isKeyguardShowing"
)
}
}
keyguardStateController.addCallback(callback)
// Adding the callback does not send an initial update.
trySendWithFailureLogging(
keyguardStateController.isShowing,
TAG,
"initial isKeyguardShowing"
)
awaitClose { keyguardStateController.removeCallback(callback) }
}
override val isDozing: Flow<Boolean> = conflatedCallbackFlow {
val callback =
object : StatusBarStateController.StateListener {

View File

@@ -30,7 +30,8 @@ interface KeyguardRepositoryModule {
impl: KeyguardQuickAffordanceRepositoryImpl
): KeyguardQuickAffordanceRepository
@Binds fun keyguardQuickAffordanceConfigs(
@Binds
fun keyguardQuickAffordanceConfigs(
impl: KeyguardQuickAffordanceConfigsImpl
): KeyguardQuickAffordanceConfigs
}

View File

@@ -0,0 +1,39 @@
/*
* 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.keyguard.domain.usecase
import com.android.systemui.keyguard.data.repository.KeyguardRepository
import javax.inject.Inject
import kotlinx.coroutines.flow.Flow
/**
* Use-case for observing whether the keyguard is currently being shown.
*
* Note: this is also `true` when the lock-screen is occluded with an `Activity` "above" it in the
* z-order (which is not really above the system UI window, but rather - the lock-screen becomes
* invisible to reveal the "occluding activity").
*/
class ObserveIsKeyguardShowingUseCase
@Inject
constructor(
private val repository: KeyguardRepository,
) {
operator fun invoke(): Flow<Boolean> {
return repository.isKeyguardShowing
}
}

View File

@@ -29,7 +29,7 @@ class ObserveKeyguardQuickAffordanceUseCase
constructor(
private val repository: KeyguardQuickAffordanceRepository,
private val isDozingUseCase: ObserveIsDozingUseCase,
private val dozeAmountUseCase: ObserveDozeAmountUseCase,
private val isKeyguardShowingUseCase: ObserveIsKeyguardShowingUseCase,
) {
operator fun invoke(
position: KeyguardQuickAffordancePosition
@@ -37,9 +37,9 @@ constructor(
return combine(
repository.affordance(position),
isDozingUseCase(),
dozeAmountUseCase(),
) { affordance, isDozing, dozeAmount ->
if (!isDozing && dozeAmount == 0f) {
isKeyguardShowingUseCase(),
) { affordance, isDozing, isKeyguardShowing ->
if (!isDozing && isKeyguardShowing) {
affordance
} else {
KeyguardQuickAffordanceModel.Hidden

View File

@@ -1,46 +0,0 @@
/*
* 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.policy
import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging
import com.android.systemui.common.coroutine.ConflatedCallbackFlow
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
object KeyguardStateControllerExt {
/**
* Returns an observable for whether the keyguard is currently shown or not.
*/
fun KeyguardStateController.isKeyguardShowing(loggingTag: String): Flow<Boolean> {
return ConflatedCallbackFlow.conflatedCallbackFlow {
val callback =
object : KeyguardStateController.Callback {
override fun onKeyguardShowingChanged() {
trySendWithFailureLogging(
isShowing, loggingTag, "updated isKeyguardShowing")
}
}
addCallback(callback)
// Adding the callback does not send an initial update.
trySendWithFailureLogging(isShowing, loggingTag, "initial isKeyguardShowing")
awaitClose { removeCallback(callback) }
}
}
}

View File

@@ -27,7 +27,7 @@ class FakeKeyguardQuickAffordanceRepository : KeyguardQuickAffordanceRepository
private val modelByPosition =
mutableMapOf<
KeyguardQuickAffordancePosition, MutableStateFlow<KeyguardQuickAffordanceModel>>()
KeyguardQuickAffordancePosition, MutableStateFlow<KeyguardQuickAffordanceModel>>()
init {
KeyguardQuickAffordancePosition.values().forEach { value ->

View File

@@ -17,9 +17,7 @@
package com.android.systemui.keyguard.data.repository
import com.android.systemui.common.data.model.Position
import kotlinx.coroutines.channels.BufferOverflow
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
@@ -36,18 +34,13 @@ class FakeKeyguardRepository : KeyguardRepository {
private val _clockPosition = MutableStateFlow(Position(0, 0))
override val clockPosition: StateFlow<Position> = _clockPosition
private val _isDozing =
MutableSharedFlow<Boolean>(
replay = 1,
onBufferOverflow = BufferOverflow.DROP_OLDEST,
)
private val _isKeyguardShowing = MutableStateFlow(false)
override val isKeyguardShowing: Flow<Boolean> = _isKeyguardShowing
private val _isDozing = MutableStateFlow(false)
override val isDozing: Flow<Boolean> = _isDozing
private val _dozeAmount =
MutableSharedFlow<Float>(
replay = 1,
onBufferOverflow = BufferOverflow.DROP_OLDEST,
)
private val _dozeAmount = MutableStateFlow(0f)
override val dozeAmount: Flow<Float> = _dozeAmount
init {
@@ -67,11 +60,15 @@ class FakeKeyguardRepository : KeyguardRepository {
_clockPosition.value = Position(x, y)
}
fun setKeyguardShowing(isShowing: Boolean) {
_isKeyguardShowing.value = isShowing
}
fun setDozing(isDozing: Boolean) {
_isDozing.tryEmit(isDozing)
_isDozing.value = isDozing
}
fun setDozeAmount(dozeAmount: Float) {
_dozeAmount.tryEmit(dozeAmount)
_dozeAmount.value = dozeAmount
}
}

View File

@@ -20,6 +20,7 @@ import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.common.data.model.Position
import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.statusbar.policy.KeyguardStateController
import com.android.systemui.util.mockito.argumentCaptor
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.flow.launchIn
@@ -31,6 +32,7 @@ import org.junit.runner.RunWith
import org.junit.runners.JUnit4
import org.mockito.Mock
import org.mockito.Mockito.verify
import org.mockito.Mockito.`when` as whenever
import org.mockito.MockitoAnnotations
@SmallTest
@@ -38,6 +40,7 @@ import org.mockito.MockitoAnnotations
class KeyguardRepositoryImplTest : SysuiTestCase() {
@Mock private lateinit var statusBarStateController: StatusBarStateController
@Mock private lateinit var keyguardStateController: KeyguardStateController
private lateinit var underTest: KeyguardRepositoryImpl
@@ -45,7 +48,7 @@ class KeyguardRepositoryImplTest : SysuiTestCase() {
fun setUp() {
MockitoAnnotations.initMocks(this)
underTest = KeyguardRepositoryImpl(statusBarStateController)
underTest = KeyguardRepositoryImpl(statusBarStateController, keyguardStateController)
}
@Test
@@ -99,6 +102,28 @@ class KeyguardRepositoryImplTest : SysuiTestCase() {
assertThat(underTest.clockPosition.value).isEqualTo(Position(3, 1))
}
@Test
fun isKeyguardShowing() = runBlockingTest {
whenever(keyguardStateController.isShowing).thenReturn(false)
var latest: Boolean? = null
val job = underTest.isKeyguardShowing.onEach { latest = it }.launchIn(this)
assertThat(latest).isFalse()
val captor = argumentCaptor<KeyguardStateController.Callback>()
verify(keyguardStateController).addCallback(captor.capture())
whenever(keyguardStateController.isShowing).thenReturn(true)
captor.value.onKeyguardShowingChanged()
assertThat(latest).isTrue()
whenever(keyguardStateController.isShowing).thenReturn(false)
captor.value.onKeyguardShowingChanged()
assertThat(latest).isFalse()
job.cancel()
}
@Test
fun isDozing() = runBlockingTest {
var latest: Boolean? = null

View File

@@ -51,7 +51,7 @@ class QrCodeScannerKeyguardQuickAffordanceConfigTest : SysuiTestCase() {
MockitoAnnotations.initMocks(this)
whenever(controller.intent).thenReturn(INTENT_1)
underTest = QrCodeScannerKeyguardQuickAffordanceConfig(context, controller)
underTest = QrCodeScannerKeyguardQuickAffordanceConfig(controller)
}
@Test

View File

@@ -26,7 +26,6 @@ import com.android.systemui.containeddrawable.ContainedDrawable
import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceConfig
import com.android.systemui.keyguard.data.quickaffordance.QuickAccessWalletKeyguardQuickAffordanceConfig
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.statusbar.policy.KeyguardStateController
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.mock
import com.android.systemui.wallet.controller.QuickAccessWalletController
@@ -48,7 +47,6 @@ import org.mockito.MockitoAnnotations
class QuickAccessWalletKeyguardQuickAffordanceConfigTest : SysuiTestCase() {
@Mock private lateinit var walletController: QuickAccessWalletController
@Mock private lateinit var keyguardStateController: KeyguardStateController
@Mock private lateinit var activityStarter: ActivityStarter
private lateinit var underTest: QuickAccessWalletKeyguardQuickAffordanceConfig
@@ -59,7 +57,6 @@ class QuickAccessWalletKeyguardQuickAffordanceConfigTest : SysuiTestCase() {
underTest =
QuickAccessWalletKeyguardQuickAffordanceConfig(
keyguardStateController,
walletController,
activityStarter,
)
@@ -67,7 +64,7 @@ class QuickAccessWalletKeyguardQuickAffordanceConfigTest : SysuiTestCase() {
@Test
fun `affordance - keyguard showing - has wallet card - visible model`() = runBlockingTest {
val callback = setUpState()
setUpState()
var latest: KeyguardQuickAffordanceConfig.State? = null
val job = underTest.state.onEach { latest = it }.launchIn(this)
@@ -76,25 +73,11 @@ class QuickAccessWalletKeyguardQuickAffordanceConfigTest : SysuiTestCase() {
assertThat(visibleModel.icon).isEqualTo(ContainedDrawable.WithDrawable(ICON))
assertThat(visibleModel.contentDescriptionResourceId).isNotNull()
job.cancel()
callback?.let { verify(keyguardStateController).removeCallback(it) }
}
@Test
fun `affordance - keyguard not showing - model is none`() = runBlockingTest {
val callback = setUpState(isKeyguardShowing = false)
var latest: KeyguardQuickAffordanceConfig.State? = null
val job = underTest.state.onEach { latest = it }.launchIn(this)
assertThat(latest).isEqualTo(KeyguardQuickAffordanceConfig.State.Hidden)
job.cancel()
callback?.let { verify(keyguardStateController).removeCallback(it) }
}
@Test
fun `affordance - wallet not enabled - model is none`() = runBlockingTest {
val callback = setUpState(isWalletEnabled = false)
setUpState(isWalletEnabled = false)
var latest: KeyguardQuickAffordanceConfig.State? = null
val job = underTest.state.onEach { latest = it }.launchIn(this)
@@ -102,12 +85,11 @@ class QuickAccessWalletKeyguardQuickAffordanceConfigTest : SysuiTestCase() {
assertThat(latest).isEqualTo(KeyguardQuickAffordanceConfig.State.Hidden)
job.cancel()
callback?.let { verify(keyguardStateController).removeCallback(it) }
}
@Test
fun `affordance - query not successful - model is none`() = runBlockingTest {
val callback = setUpState(isWalletQuerySuccessful = false)
setUpState(isWalletQuerySuccessful = false)
var latest: KeyguardQuickAffordanceConfig.State? = null
val job = underTest.state.onEach { latest = it }.launchIn(this)
@@ -115,12 +97,11 @@ class QuickAccessWalletKeyguardQuickAffordanceConfigTest : SysuiTestCase() {
assertThat(latest).isEqualTo(KeyguardQuickAffordanceConfig.State.Hidden)
job.cancel()
callback?.let { verify(keyguardStateController).removeCallback(it) }
}
@Test
fun `affordance - missing icon - model is none`() = runBlockingTest {
val callback = setUpState(hasWalletIcon = false)
setUpState(hasWalletIcon = false)
var latest: KeyguardQuickAffordanceConfig.State? = null
val job = underTest.state.onEach { latest = it }.launchIn(this)
@@ -128,12 +109,11 @@ class QuickAccessWalletKeyguardQuickAffordanceConfigTest : SysuiTestCase() {
assertThat(latest).isEqualTo(KeyguardQuickAffordanceConfig.State.Hidden)
job.cancel()
callback?.let { verify(keyguardStateController).removeCallback(it) }
}
@Test
fun `affordance - no selected card - model is none`() = runBlockingTest {
val callback = setUpState(hasWalletIcon = false)
setUpState(hasWalletIcon = false)
var latest: KeyguardQuickAffordanceConfig.State? = null
val job = underTest.state.onEach { latest = it }.launchIn(this)
@@ -141,7 +121,6 @@ class QuickAccessWalletKeyguardQuickAffordanceConfigTest : SysuiTestCase() {
assertThat(latest).isEqualTo(KeyguardQuickAffordanceConfig.State.Hidden)
job.cancel()
callback?.let { verify(keyguardStateController).removeCallback(it) }
}
@Test
@@ -159,21 +138,11 @@ class QuickAccessWalletKeyguardQuickAffordanceConfigTest : SysuiTestCase() {
}
private fun setUpState(
isKeyguardShowing: Boolean = true,
isWalletEnabled: Boolean = true,
isWalletQuerySuccessful: Boolean = true,
hasWalletIcon: Boolean = true,
hasSelectedCard: Boolean = true,
): KeyguardStateController.Callback? {
var returnedCallback: KeyguardStateController.Callback? = null
whenever(keyguardStateController.isShowing).thenReturn(isKeyguardShowing)
whenever(keyguardStateController.addCallback(any())).thenAnswer { invocation ->
with(invocation.arguments[0] as KeyguardStateController.Callback) {
returnedCallback = this
onKeyguardShowingChanged()
}
}
) {
whenever(walletController.isWalletEnabled).thenReturn(isWalletEnabled)
val walletClient: QuickAccessWalletClient = mock()
@@ -203,8 +172,6 @@ class QuickAccessWalletKeyguardQuickAffordanceConfigTest : SysuiTestCase() {
}
}
}
return returnedCallback
}
companion object {

View File

@@ -43,20 +43,21 @@ class ObserveKeyguardQuickAffordanceUseCaseTest : SysuiTestCase() {
private lateinit var repository: FakeKeyguardRepository
private lateinit var quickAffordanceRepository: FakeKeyguardQuickAffordanceRepository
private lateinit var isDozingUseCase: ObserveIsDozingUseCase
private lateinit var dozeAmountUseCase: ObserveDozeAmountUseCase
private lateinit var isKeyguardShowingUseCase: ObserveIsKeyguardShowingUseCase
@Before
fun setUp() {
repository = FakeKeyguardRepository()
repository.setKeyguardShowing(true)
isDozingUseCase = ObserveIsDozingUseCase(repository)
dozeAmountUseCase = ObserveDozeAmountUseCase(repository)
isKeyguardShowingUseCase = ObserveIsKeyguardShowingUseCase(repository)
quickAffordanceRepository = FakeKeyguardQuickAffordanceRepository()
underTest =
ObserveKeyguardQuickAffordanceUseCase(
repository = quickAffordanceRepository,
isDozingUseCase = isDozingUseCase,
dozeAmountUseCase = dozeAmountUseCase,
isKeyguardShowingUseCase = isKeyguardShowingUseCase,
)
}
@@ -75,9 +76,10 @@ class ObserveKeyguardQuickAffordanceUseCaseTest : SysuiTestCase() {
)
var latest: KeyguardQuickAffordanceModel? = null
val job = underTest(KeyguardQuickAffordancePosition.BOTTOM_END)
.onEach { latest = it }
.launchIn(this)
val job =
underTest(KeyguardQuickAffordancePosition.BOTTOM_END)
.onEach { latest = it }
.launchIn(this)
assertThat(latest).isInstanceOf(KeyguardQuickAffordanceModel.Visible::class.java)
val visibleModel = latest as KeyguardQuickAffordanceModel.Visible
@@ -104,16 +106,17 @@ class ObserveKeyguardQuickAffordanceUseCaseTest : SysuiTestCase() {
)
var latest: KeyguardQuickAffordanceModel? = null
val job = underTest(KeyguardQuickAffordancePosition.BOTTOM_END)
.onEach { latest = it }
.launchIn(this)
val job =
underTest(KeyguardQuickAffordancePosition.BOTTOM_END)
.onEach { latest = it }
.launchIn(this)
assertThat(latest).isEqualTo(KeyguardQuickAffordanceModel.Hidden)
job.cancel()
}
@Test
fun `invoke - affordance not visible doze amount is not 0`() = runBlockingTest {
repository.setDozeAmount(0.3f)
fun `invoke - affordance not visible when lockscreen is not showing`() = runBlockingTest {
repository.setKeyguardShowing(false)
val configKey = HomeControlsKeyguardQuickAffordanceConfig::class
val model =
KeyguardQuickAffordanceModel.Visible(
@@ -127,9 +130,10 @@ class ObserveKeyguardQuickAffordanceUseCaseTest : SysuiTestCase() {
)
var latest: KeyguardQuickAffordanceModel? = null
val job = underTest(KeyguardQuickAffordancePosition.BOTTOM_END)
.onEach { latest = it }
.launchIn(this)
val job =
underTest(KeyguardQuickAffordancePosition.BOTTOM_END)
.onEach { latest = it }
.launchIn(this)
assertThat(latest).isEqualTo(KeyguardQuickAffordanceModel.Hidden)
job.cancel()
}
@@ -142,9 +146,10 @@ class ObserveKeyguardQuickAffordanceUseCaseTest : SysuiTestCase() {
)
var latest: KeyguardQuickAffordanceModel? = null
val job = underTest(KeyguardQuickAffordancePosition.BOTTOM_START)
.onEach { latest = it }
.launchIn(this)
val job =
underTest(KeyguardQuickAffordancePosition.BOTTOM_START)
.onEach { latest = it }
.launchIn(this)
assertThat(latest).isEqualTo(KeyguardQuickAffordanceModel.Hidden)
job.cancel()
}

View File

@@ -33,6 +33,7 @@ import com.android.systemui.keyguard.domain.usecase.ObserveBottomAreaAlphaUseCas
import com.android.systemui.keyguard.domain.usecase.ObserveClockPositionUseCase
import com.android.systemui.keyguard.domain.usecase.ObserveDozeAmountUseCase
import com.android.systemui.keyguard.domain.usecase.ObserveIsDozingUseCase
import com.android.systemui.keyguard.domain.usecase.ObserveIsKeyguardShowingUseCase
import com.android.systemui.keyguard.domain.usecase.ObserveKeyguardQuickAffordanceUseCase
import com.android.systemui.keyguard.domain.usecase.OnKeyguardQuickAffordanceClickedUseCase
import com.android.systemui.keyguard.shared.model.KeyguardQuickAffordanceModel
@@ -65,7 +66,7 @@ class KeyguardBottomAreaViewModelTest : SysuiTestCase() {
private lateinit var affordanceRepository: FakeKeyguardQuickAffordanceRepository
private lateinit var repository: FakeKeyguardRepository
private lateinit var isDozingUseCase: ObserveIsDozingUseCase
private lateinit var dozeAmountUseCase: ObserveDozeAmountUseCase
private lateinit var isKeyguardShowingUseCase: ObserveIsKeyguardShowingUseCase
private lateinit var launchQuickAffordanceUseCase: FakeLaunchKeyguardQuickAffordanceUseCase
private lateinit var homeControlsQuickAffordanceConfig: FakeKeyguardQuickAffordanceConfig
private lateinit var quickAccessWalletAffordanceConfig: FakeKeyguardQuickAffordanceConfig
@@ -83,8 +84,8 @@ class KeyguardBottomAreaViewModelTest : SysuiTestCase() {
ObserveIsDozingUseCase(
repository = repository,
)
dozeAmountUseCase =
ObserveDozeAmountUseCase(
isKeyguardShowingUseCase =
ObserveIsKeyguardShowingUseCase(
repository = repository,
)
launchQuickAffordanceUseCase = FakeLaunchKeyguardQuickAffordanceUseCase()
@@ -98,7 +99,7 @@ class KeyguardBottomAreaViewModelTest : SysuiTestCase() {
ObserveKeyguardQuickAffordanceUseCase(
repository = affordanceRepository,
isDozingUseCase = isDozingUseCase,
dozeAmountUseCase = dozeAmountUseCase,
isKeyguardShowingUseCase = isKeyguardShowingUseCase,
),
onQuickAffordanceClickedUseCase =
OnKeyguardQuickAffordanceClickedUseCase(
@@ -140,12 +141,13 @@ class KeyguardBottomAreaViewModelTest : SysuiTestCase() {
}
@Test
fun `startButton - present and not dozing - visible model - starts activity on click`() =
fun `startButton - present - not dozing - lockscreen showing - visible model - starts activity on click`() = // ktlint-disable max-line-length
runBlockingTest {
var latest: KeyguardQuickAffordanceViewModel? = null
val job = underTest.startButton.onEach { latest = it }.launchIn(this)
repository.setDozing(false)
repository.setKeyguardShowing(true)
val testConfig =
TestConfig(
isVisible = true,
@@ -168,12 +170,13 @@ class KeyguardBottomAreaViewModelTest : SysuiTestCase() {
}
@Test
fun `endButton - present and not dozing - visible model - do nothing on click`() =
fun `endButton - present - not dozing - lockscreen showing - visible model - do nothing on click`() = // ktlint-disable max-line-length
runBlockingTest {
var latest: KeyguardQuickAffordanceViewModel? = null
val job = underTest.endButton.onEach { latest = it }.launchIn(this)
repository.setDozing(false)
repository.setKeyguardShowing(true)
val config =
TestConfig(
isVisible = true,
@@ -197,35 +200,38 @@ class KeyguardBottomAreaViewModelTest : SysuiTestCase() {
}
@Test
fun `startButton - not present and not dozing - model is none`() = runBlockingTest {
var latest: KeyguardQuickAffordanceViewModel? = null
val job = underTest.startButton.onEach { latest = it }.launchIn(this)
fun `startButton - not present - not dozing - lockscreen showing - model is none`() =
runBlockingTest {
var latest: KeyguardQuickAffordanceViewModel? = null
val job = underTest.startButton.onEach { latest = it }.launchIn(this)
repository.setDozing(false)
val config =
TestConfig(
isVisible = false,
)
val configKey =
setUpQuickAffordanceModel(
position = KeyguardQuickAffordancePosition.BOTTOM_START,
repository.setDozing(false)
repository.setKeyguardShowing(true)
val config =
TestConfig(
isVisible = false,
)
val configKey =
setUpQuickAffordanceModel(
position = KeyguardQuickAffordancePosition.BOTTOM_START,
testConfig = config,
)
assertQuickAffordanceViewModel(
viewModel = latest,
testConfig = config,
configKey = configKey,
)
assertQuickAffordanceViewModel(
viewModel = latest,
testConfig = config,
configKey = configKey,
)
job.cancel()
}
job.cancel()
}
@Test
fun `startButton - present but dozing - model is none`() = runBlockingTest {
fun `startButton - present - dozing - lockscreen showing - model is none`() = runBlockingTest {
var latest: KeyguardQuickAffordanceViewModel? = null
val job = underTest.startButton.onEach { latest = it }.launchIn(this)
repository.setDozing(true)
repository.setKeyguardShowing(true)
val config =
TestConfig(
isVisible = true,
@@ -247,6 +253,35 @@ class KeyguardBottomAreaViewModelTest : SysuiTestCase() {
job.cancel()
}
@Test
fun `startButton - present - not dozing - lockscreen not showing - model is none`() =
runBlockingTest {
var latest: KeyguardQuickAffordanceViewModel? = null
val job = underTest.startButton.onEach { latest = it }.launchIn(this)
repository.setDozing(false)
repository.setKeyguardShowing(false)
val config =
TestConfig(
isVisible = true,
icon = mock(),
canShowWhileLocked = false,
intent = Intent("action"),
)
val configKey =
setUpQuickAffordanceModel(
position = KeyguardQuickAffordancePosition.BOTTOM_START,
testConfig = config,
)
assertQuickAffordanceViewModel(
viewModel = latest,
testConfig = TestConfig(isVisible = false),
configKey = configKey,
)
job.cancel()
}
@Test
fun animateButtonReveal() = runBlockingTest {
val values = mutableListOf<Boolean>()
@@ -287,6 +322,7 @@ class KeyguardBottomAreaViewModelTest : SysuiTestCase() {
@Test
fun isIndicationAreaPadded() = runBlockingTest {
repository.setKeyguardShowing(true)
val values = mutableListOf<Boolean>()
val job = underTest.isIndicationAreaPadded.onEach(values::add).launchIn(this)