1 /*
2  * 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.dream.lowlight
17 
18 import android.animation.Animator
19 import android.app.DreamManager
20 import android.content.ComponentName
21 import android.testing.AndroidTestingRunner
22 import androidx.test.filters.SmallTest
23 import kotlinx.coroutines.ExperimentalCoroutinesApi
24 import kotlinx.coroutines.test.StandardTestDispatcher
25 import kotlinx.coroutines.test.TestScope
26 import kotlinx.coroutines.test.advanceTimeBy
27 import kotlinx.coroutines.test.runCurrent
28 import kotlinx.coroutines.test.runTest
29 import org.junit.Before
30 import org.junit.Test
31 import org.junit.runner.RunWith
32 import org.mockito.Mock
33 import org.mockito.Mockito.clearInvocations
34 import org.mockito.Mockito.never
35 import org.mockito.Mockito.times
36 import org.mockito.Mockito.verify
37 import org.mockito.MockitoAnnotations
38 import src.com.android.dream.lowlight.utils.any
39 import src.com.android.dream.lowlight.utils.withArgCaptor
40 
41 @OptIn(ExperimentalCoroutinesApi::class)
42 @SmallTest
43 @RunWith(AndroidTestingRunner::class)
44 class LowLightDreamManagerTest {
45     @Mock
46     private lateinit var mDreamManager: DreamManager
47     @Mock
48     private lateinit var mEnterAnimator: Animator
49     @Mock
50     private lateinit var mExitAnimator: Animator
51 
52     private lateinit var mTransitionCoordinator: LowLightTransitionCoordinator
53     private lateinit var mLowLightDreamManager: LowLightDreamManager
54     private lateinit var testScope: TestScope
55 
56     @Before
setUpnull57     fun setUp() {
58         MockitoAnnotations.initMocks(this)
59         testScope = TestScope(StandardTestDispatcher())
60 
61         mTransitionCoordinator = LowLightTransitionCoordinator()
62         mTransitionCoordinator.setLowLightEnterListener(
63             object : LowLightTransitionCoordinator.LowLightEnterListener {
64                 override fun onBeforeEnterLowLight() = mEnterAnimator
65             })
66         mTransitionCoordinator.setLowLightExitListener(
67             object : LowLightTransitionCoordinator.LowLightExitListener {
68                 override fun onBeforeExitLowLight() = mExitAnimator
69             })
70 
71         mLowLightDreamManager = LowLightDreamManager(
72             coroutineScope = testScope,
73             dreamManager = mDreamManager,
74             lowLightTransitionCoordinator = mTransitionCoordinator,
75             lowLightDreamComponent = DREAM_COMPONENT,
76             lowLightTransitionTimeoutMs = LOW_LIGHT_TIMEOUT_MS
77         )
78     }
79 
80     @Test
setAmbientLightMode_lowLight_setSystemDreamnull81     fun setAmbientLightMode_lowLight_setSystemDream() = testScope.runTest {
82         mLowLightDreamManager.setAmbientLightMode(LowLightDreamManager.AMBIENT_LIGHT_MODE_LOW_LIGHT)
83         runCurrent()
84         verify(mDreamManager, never()).setSystemDreamComponent(DREAM_COMPONENT)
85         completeEnterAnimations()
86         runCurrent()
87         verify(mDreamManager).setSystemDreamComponent(DREAM_COMPONENT)
88     }
89 
90     @Test
<lambda>null91     fun setAmbientLightMode_regularLight_clearSystemDream() = testScope.runTest {
92         mLowLightDreamManager.setAmbientLightMode(LowLightDreamManager.AMBIENT_LIGHT_MODE_REGULAR)
93         runCurrent()
94         verify(mDreamManager, never()).setSystemDreamComponent(null)
95         completeExitAnimations()
96         runCurrent()
97         verify(mDreamManager).setSystemDreamComponent(null)
98     }
99 
100     @Test
<lambda>null101     fun setAmbientLightMode_defaultUnknownMode_clearSystemDream() = testScope.runTest {
102         // Set to low light first.
103         mLowLightDreamManager.setAmbientLightMode(LowLightDreamManager.AMBIENT_LIGHT_MODE_LOW_LIGHT)
104         runCurrent()
105         completeEnterAnimations()
106         runCurrent()
107         verify(mDreamManager).setSystemDreamComponent(DREAM_COMPONENT)
108         clearInvocations(mDreamManager)
109 
110         // Return to default unknown mode.
111         mLowLightDreamManager.setAmbientLightMode(LowLightDreamManager.AMBIENT_LIGHT_MODE_UNKNOWN)
112         runCurrent()
113         completeExitAnimations()
114         runCurrent()
115         verify(mDreamManager).setSystemDreamComponent(null)
116     }
117 
118     @Test
<lambda>null119     fun setAmbientLightMode_dreamComponentNotSet_doNothing() = testScope.runTest {
120         val lowLightDreamManager = LowLightDreamManager(
121             coroutineScope = testScope,
122             dreamManager = mDreamManager,
123             lowLightTransitionCoordinator = mTransitionCoordinator,
124             lowLightDreamComponent = null,
125             lowLightTransitionTimeoutMs = LOW_LIGHT_TIMEOUT_MS
126         )
127         lowLightDreamManager.setAmbientLightMode(LowLightDreamManager.AMBIENT_LIGHT_MODE_LOW_LIGHT)
128         runCurrent()
129         verify(mEnterAnimator, never()).addListener(any())
130         verify(mDreamManager, never()).setSystemDreamComponent(any())
131     }
132 
133     @Test
<lambda>null134     fun setAmbientLightMode_multipleTimesBeforeAnimationEnds_cancelsPrevious() = testScope.runTest {
135         mLowLightDreamManager.setAmbientLightMode(LowLightDreamManager.AMBIENT_LIGHT_MODE_LOW_LIGHT)
136         runCurrent()
137         // If we reset the light mode back to regular before the previous animation finishes, it
138         // should be ignored.
139         mLowLightDreamManager.setAmbientLightMode(LowLightDreamManager.AMBIENT_LIGHT_MODE_REGULAR)
140         runCurrent()
141         completeEnterAnimations()
142         completeExitAnimations()
143         runCurrent()
144         verify(mDreamManager, times(1)).setSystemDreamComponent(null)
145     }
146 
147     @Test
<lambda>null148     fun setAmbientLightMode_animatorNeverFinishes_timesOut() = testScope.runTest {
149         mLowLightDreamManager.setAmbientLightMode(LowLightDreamManager.AMBIENT_LIGHT_MODE_LOW_LIGHT)
150         advanceTimeBy(delayTimeMillis = LOW_LIGHT_TIMEOUT_MS + 1)
151         // Animation never finishes, but we should still set the system dream
152         verify(mDreamManager).setSystemDreamComponent(DREAM_COMPONENT)
153     }
154 
155     @Test
<lambda>null156     fun setAmbientLightMode_animationCancelled_SetsSystemDream() = testScope.runTest {
157         mLowLightDreamManager.setAmbientLightMode(LowLightDreamManager.AMBIENT_LIGHT_MODE_LOW_LIGHT)
158         runCurrent()
159         cancelEnterAnimations()
160         runCurrent()
161         // Animation never finishes, but we should still set the system dream
162         verify(mDreamManager).setSystemDreamComponent(DREAM_COMPONENT)
163     }
164 
cancelEnterAnimationsnull165     private fun cancelEnterAnimations() {
166         val listener = withArgCaptor { verify(mEnterAnimator).addListener(capture()) }
167         listener.onAnimationCancel(mEnterAnimator)
168     }
169 
completeEnterAnimationsnull170     private fun completeEnterAnimations() {
171         val listener = withArgCaptor { verify(mEnterAnimator).addListener(capture()) }
172         listener.onAnimationEnd(mEnterAnimator)
173     }
174 
completeExitAnimationsnull175     private fun completeExitAnimations() {
176         val listener = withArgCaptor { verify(mExitAnimator).addListener(capture()) }
177         listener.onAnimationEnd(mExitAnimator)
178     }
179 
180     companion object {
181         private val DREAM_COMPONENT = ComponentName("test_package", "test_dream")
182         private const val LOW_LIGHT_TIMEOUT_MS: Long = 1000
183     }
184 }