1 /* <lambda>null2 * 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 package com.android.systemui.unfold.domain.interactor 17 18 import androidx.test.ext.junit.runners.AndroidJUnit4 19 import androidx.test.filters.SmallTest 20 import com.android.systemui.SysuiTestCase 21 import com.android.systemui.common.ui.data.repository.fakeConfigurationRepository 22 import com.android.systemui.coroutines.collectLastValue 23 import com.android.systemui.kosmos.testScope 24 import com.android.systemui.res.R 25 import com.android.systemui.testKosmos 26 import com.android.systemui.unfold.fakeUnfoldTransitionProgressProvider 27 import com.google.common.truth.Truth.assertThat 28 import java.util.Locale 29 import kotlinx.coroutines.ExperimentalCoroutinesApi 30 import kotlinx.coroutines.async 31 import kotlinx.coroutines.flow.combine 32 import kotlinx.coroutines.test.runCurrent 33 import kotlinx.coroutines.test.runTest 34 import org.junit.Test 35 import org.junit.runner.RunWith 36 37 @OptIn(ExperimentalCoroutinesApi::class) 38 @SmallTest 39 @RunWith(AndroidJUnit4::class) 40 class UnfoldTransitionInteractorTest : SysuiTestCase() { 41 42 private val kosmos = testKosmos() 43 private val testScope = kosmos.testScope 44 private val unfoldTransitionProgressProvider = kosmos.fakeUnfoldTransitionProgressProvider 45 46 private val underTest: UnfoldTransitionInteractor = kosmos.unfoldTransitionInteractor 47 48 @Test 49 fun waitForTransitionFinish_noEvents_doesNotComplete() = 50 testScope.runTest { 51 val deferred = async { underTest.waitForTransitionFinish() } 52 53 runCurrent() 54 55 assertThat(deferred.isCompleted).isFalse() 56 deferred.cancel() 57 } 58 59 @Test 60 fun waitForTransitionFinish_finishEvent_completes() = 61 testScope.runTest { 62 val deferred = async { underTest.waitForTransitionFinish() } 63 64 runCurrent() 65 unfoldTransitionProgressProvider.onTransitionFinished() 66 runCurrent() 67 68 assertThat(deferred.isCompleted).isTrue() 69 deferred.cancel() 70 } 71 72 @Test 73 fun waitForTransitionFinish_otherEvent_doesNotComplete() = 74 testScope.runTest { 75 val deferred = async { underTest.waitForTransitionFinish() } 76 77 runCurrent() 78 unfoldTransitionProgressProvider.onTransitionStarted() 79 runCurrent() 80 81 assertThat(deferred.isCompleted).isFalse() 82 deferred.cancel() 83 } 84 85 @Test 86 fun unfoldTranslationX_leftToRight() = 87 testScope.runTest { 88 val maxTranslation = prepareConfiguration(isLeftToRight = true) 89 val translations by 90 collectLastValue( 91 combine( 92 underTest.unfoldTranslationX(isOnStartSide = true), 93 underTest.unfoldTranslationX(isOnStartSide = false), 94 ) { start, end -> 95 Translations( 96 start = start, 97 end = end, 98 ) 99 } 100 ) 101 runCurrent() 102 103 unfoldTransitionProgressProvider.onTransitionStarted() 104 assertThat(translations?.start).isEqualTo(0f) 105 assertThat(translations?.end).isEqualTo(-0f) 106 107 repeat(10) { repetition -> 108 val transitionProgress = 1 - 0.1f * (repetition + 1) 109 unfoldTransitionProgressProvider.onTransitionProgress(transitionProgress) 110 assertThat(translations?.start).isEqualTo((1 - transitionProgress) * maxTranslation) 111 assertThat(translations?.end).isEqualTo(-(1 - transitionProgress) * maxTranslation) 112 } 113 114 unfoldTransitionProgressProvider.onTransitionFinishing() 115 assertThat(translations?.start).isEqualTo(maxTranslation) 116 assertThat(translations?.end).isEqualTo(-maxTranslation) 117 118 unfoldTransitionProgressProvider.onTransitionFinished() 119 assertThat(translations?.start).isEqualTo(0f) 120 assertThat(translations?.end).isEqualTo(-0f) 121 } 122 123 @Test 124 fun unfoldTranslationX_rightToLeft() = 125 testScope.runTest { 126 val maxTranslation = prepareConfiguration(isLeftToRight = false) 127 val translations by 128 collectLastValue( 129 combine( 130 underTest.unfoldTranslationX(isOnStartSide = true), 131 underTest.unfoldTranslationX(isOnStartSide = false), 132 ) { start, end -> 133 Translations( 134 start = start, 135 end = end, 136 ) 137 } 138 ) 139 runCurrent() 140 141 unfoldTransitionProgressProvider.onTransitionStarted() 142 assertThat(translations?.start).isEqualTo(-0f) 143 assertThat(translations?.end).isEqualTo(0f) 144 145 repeat(10) { repetition -> 146 val transitionProgress = 1 - 0.1f * (repetition + 1) 147 unfoldTransitionProgressProvider.onTransitionProgress(transitionProgress) 148 assertThat(translations?.start) 149 .isEqualTo(-(1 - transitionProgress) * maxTranslation) 150 assertThat(translations?.end).isEqualTo((1 - transitionProgress) * maxTranslation) 151 } 152 153 unfoldTransitionProgressProvider.onTransitionFinishing() 154 assertThat(translations?.start).isEqualTo(-maxTranslation) 155 assertThat(translations?.end).isEqualTo(maxTranslation) 156 157 unfoldTransitionProgressProvider.onTransitionFinished() 158 assertThat(translations?.start).isEqualTo(-0f) 159 assertThat(translations?.end).isEqualTo(0f) 160 } 161 162 private fun prepareConfiguration( 163 isLeftToRight: Boolean, 164 ): Int { 165 val configuration = context.resources.configuration 166 if (isLeftToRight) { 167 configuration.setLayoutDirection(Locale.US) 168 } else { 169 configuration.setLayoutDirection(Locale("he", "il")) 170 } 171 kosmos.fakeConfigurationRepository.onConfigurationChange(configuration) 172 val maxTranslation = 10 173 kosmos.fakeConfigurationRepository.setDimensionPixelSize( 174 R.dimen.notification_side_paddings, 175 maxTranslation 176 ) 177 return maxTranslation 178 } 179 180 private data class Translations( 181 val start: Float, 182 val end: Float, 183 ) 184 } 185