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