1 /*
<lambda>null2  * Copyright (C) 2022 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 
17 package com.android.systemui.media.controls.ui.animation
18 
19 import android.animation.ValueAnimator
20 import android.graphics.Color
21 import android.testing.TestableLooper
22 import androidx.test.ext.junit.runners.AndroidJUnit4
23 import androidx.test.filters.SmallTest
24 import com.android.systemui.SysuiTestCase
25 import com.android.systemui.media.controls.ui.view.GutsViewHolder
26 import com.android.systemui.media.controls.ui.view.MediaViewHolder
27 import com.android.systemui.monet.ColorScheme
28 import com.android.systemui.surfaceeffects.ripple.MultiRippleController
29 import com.android.systemui.surfaceeffects.turbulencenoise.TurbulenceNoiseController
30 import junit.framework.Assert.assertEquals
31 import org.junit.After
32 import org.junit.Before
33 import org.junit.Rule
34 import org.junit.Test
35 import org.junit.runner.RunWith
36 import org.mockito.Mock
37 import org.mockito.Mockito.never
38 import org.mockito.Mockito.times
39 import org.mockito.Mockito.verify
40 import org.mockito.Mockito.`when` as whenever
41 import org.mockito.junit.MockitoJUnit
42 
43 private const val DEFAULT_COLOR = Color.RED
44 private const val TARGET_COLOR = Color.BLUE
45 
46 @SmallTest
47 @RunWith(AndroidJUnit4::class)
48 @TestableLooper.RunWithLooper(setAsMainLooper = true)
49 class ColorSchemeTransitionTest : SysuiTestCase() {
50 
51     private interface ExtractCB : (ColorScheme) -> Int
52     private interface ApplyCB : (Int) -> Unit
53     private lateinit var colorTransition: AnimatingColorTransition
54     private lateinit var colorSchemeTransition: ColorSchemeTransition
55 
56     @Mock private lateinit var mockAnimatingTransition: AnimatingColorTransition
57     @Mock private lateinit var valueAnimator: ValueAnimator
58     @Mock private lateinit var colorScheme: ColorScheme
59     @Mock private lateinit var extractColor: ExtractCB
60     @Mock private lateinit var applyColor: ApplyCB
61 
62     private lateinit var animatingColorTransitionFactory: AnimatingColorTransitionFactory
63     @Mock private lateinit var mediaViewHolder: MediaViewHolder
64     @Mock private lateinit var gutsViewHolder: GutsViewHolder
65     @Mock private lateinit var multiRippleController: MultiRippleController
66     @Mock private lateinit var turbulenceNoiseController: TurbulenceNoiseController
67 
68     @JvmField @Rule val mockitoRule = MockitoJUnit.rule()
69 
70     @Before
71     fun setUp() {
72         whenever(mediaViewHolder.gutsViewHolder).thenReturn(gutsViewHolder)
73         animatingColorTransitionFactory = { _, _, _ -> mockAnimatingTransition }
74         whenever(extractColor.invoke(colorScheme)).thenReturn(TARGET_COLOR)
75 
76         colorSchemeTransition =
77             ColorSchemeTransition(
78                 context,
79                 mediaViewHolder,
80                 multiRippleController,
81                 turbulenceNoiseController,
82                 animatingColorTransitionFactory
83             )
84 
85         colorTransition =
86             object : AnimatingColorTransition(DEFAULT_COLOR, extractColor, applyColor) {
87                 override fun buildAnimator(): ValueAnimator {
88                     return valueAnimator
89                 }
90             }
91     }
92 
93     @After fun tearDown() {}
94 
95     @Test
96     fun testColorTransition_nullColorScheme_keepsDefault() {
97         colorTransition.updateColorScheme(null)
98         verify(applyColor, times(1)).invoke(DEFAULT_COLOR)
99         verify(valueAnimator, never()).start()
100         assertEquals(DEFAULT_COLOR, colorTransition.sourceColor)
101         assertEquals(DEFAULT_COLOR, colorTransition.targetColor)
102     }
103 
104     @Test
105     fun testColorTransition_newColor_startsAnimation() {
106         colorTransition.updateColorScheme(colorScheme)
107         verify(applyColor, times(1)).invoke(DEFAULT_COLOR)
108         verify(valueAnimator, times(1)).start()
109         assertEquals(DEFAULT_COLOR, colorTransition.sourceColor)
110         assertEquals(TARGET_COLOR, colorTransition.targetColor)
111     }
112 
113     @Test
114     fun testColorTransition_sameColor_noAnimation() {
115         whenever(extractColor.invoke(colorScheme)).thenReturn(DEFAULT_COLOR)
116         colorTransition.updateColorScheme(colorScheme)
117         verify(valueAnimator, never()).start()
118         assertEquals(DEFAULT_COLOR, colorTransition.sourceColor)
119         assertEquals(DEFAULT_COLOR, colorTransition.targetColor)
120     }
121 
122     @Test
123     fun testColorTransition_colorAnimation_startValues() {
124         val expectedColor = DEFAULT_COLOR
125         whenever(valueAnimator.animatedFraction).thenReturn(0f)
126         colorTransition.updateColorScheme(colorScheme)
127         colorTransition.onAnimationUpdate(valueAnimator)
128 
129         assertEquals(expectedColor, colorTransition.currentColor)
130         assertEquals(expectedColor, colorTransition.sourceColor)
131         verify(applyColor, times(2)).invoke(expectedColor) // applied once in constructor
132     }
133 
134     @Test
135     fun testColorTransition_colorAnimation_endValues() {
136         val expectedColor = TARGET_COLOR
137         whenever(valueAnimator.animatedFraction).thenReturn(1f)
138         colorTransition.updateColorScheme(colorScheme)
139         colorTransition.onAnimationUpdate(valueAnimator)
140 
141         assertEquals(expectedColor, colorTransition.currentColor)
142         assertEquals(expectedColor, colorTransition.targetColor)
143         verify(applyColor).invoke(expectedColor)
144     }
145 
146     @Test
147     fun testColorTransition_colorAnimation_interpolatedMidpoint() {
148         val expectedColor = Color.rgb(186, 0, 186)
149         whenever(valueAnimator.animatedFraction).thenReturn(0.5f)
150         colorTransition.updateColorScheme(colorScheme)
151         colorTransition.onAnimationUpdate(valueAnimator)
152 
153         assertEquals(expectedColor, colorTransition.currentColor)
154         verify(applyColor).invoke(expectedColor)
155     }
156 
157     @Test
158     fun testColorSchemeTransition_update() {
159         colorSchemeTransition.updateColorScheme(colorScheme)
160         verify(mockAnimatingTransition, times(8)).updateColorScheme(colorScheme)
161         verify(gutsViewHolder).colorScheme = colorScheme
162     }
163 }
164