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.statusbar.phone
18 
19 import android.graphics.Rect
20 import android.testing.TestableLooper.RunWithLooper
21 import android.view.View
22 import android.widget.FrameLayout
23 import androidx.test.ext.junit.runners.AndroidJUnit4
24 import androidx.test.filters.SmallTest
25 import com.android.systemui.SysuiTestCase
26 import com.android.systemui.statusbar.phone.StatusBarBoundsProvider.BoundsChangeListener
27 import com.android.systemui.util.mockito.any
28 import com.google.common.truth.Truth.assertThat
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.doAnswer
34 import org.mockito.Mockito.never
35 import org.mockito.Mockito.reset
36 import org.mockito.Mockito.spy
37 import org.mockito.Mockito.verify
38 import org.mockito.MockitoAnnotations
39 
40 @RunWith(AndroidJUnit4::class)
41 @RunWithLooper(setAsMainLooper = true)
42 @SmallTest
43 class StatusBarBoundsProviderTest : SysuiTestCase() {
44 
45     companion object {
46         private val START_SIDE_BOUNDS = Rect(50, 100, 150, 200)
47         private val END_SIDE_BOUNDS = Rect(250, 300, 350, 400)
48     }
49 
50     @Mock private lateinit var boundsChangeListener: BoundsChangeListener
51 
52     private lateinit var boundsProvider: StatusBarBoundsProvider
53 
54     private lateinit var startSideContent: View
55     private lateinit var endSideContent: View
56 
57     @Before
58     fun setUp() {
59         MockitoAnnotations.initMocks(this)
60 
61         startSideContent = spy(FrameLayout(context)).apply { setBoundsOnScreen(START_SIDE_BOUNDS) }
62         endSideContent = spy(FrameLayout(context)).apply { setBoundsOnScreen(END_SIDE_BOUNDS) }
63 
64         boundsProvider = StatusBarBoundsProvider(startSideContent, endSideContent)
65         boundsProvider.addChangeListener(boundsChangeListener)
66         reset(boundsChangeListener)
67     }
68 
69     @Test
70     fun visibleStartSideBounds_returnsBoundsFromStartSideContentView() {
71         assertThat(boundsProvider.visibleStartSideBounds).isEqualTo(START_SIDE_BOUNDS)
72     }
73 
74     @Test
75     fun visibleEndSideBounds_returnsBoundsFromEndSideContentView() {
76         assertThat(boundsProvider.visibleEndSideBounds).isEqualTo(END_SIDE_BOUNDS)
77     }
78 
79     @Test
80     fun startBoundsChange_afterStart_notifiesListener() {
81         boundsProvider.start()
82         val newBounds = Rect(START_SIDE_BOUNDS).apply { left += 1 }
83 
84         startSideContent.setBoundsOnScreen(newBounds)
85 
86         verify(boundsChangeListener).onStatusBarBoundsChanged(any())
87     }
88 
89     @Test
90     fun startBoundsChange_beforeStart_doesNotNotifyListener() {
91         val newBounds = Rect(START_SIDE_BOUNDS).apply { left += 1 }
92 
93         startSideContent.setBoundsOnScreen(newBounds)
94 
95         verify(boundsChangeListener, never()).onStatusBarBoundsChanged(any())
96     }
97 
98     @Test
99     fun startBoundsChange_afterStop_doesNotNotifyListener() {
100         boundsProvider.start()
101         boundsProvider.stop()
102         val newBounds = Rect(START_SIDE_BOUNDS).apply { left += 1 }
103 
104         startSideContent.setBoundsOnScreen(newBounds)
105 
106         verify(boundsChangeListener, never()).onStatusBarBoundsChanged(any())
107     }
108 
109     @Test
110     fun startLayoutChange_afterStart_boundsOnScreenSame_doesNotNotifyListener() {
111         boundsProvider.start()
112         val newBounds = Rect(START_SIDE_BOUNDS).apply { left += 1 }
113 
114         startSideContent.layout(newBounds)
115 
116         verify(boundsChangeListener, never()).onStatusBarBoundsChanged(any())
117     }
118 
119     @Test
120     fun endBoundsChange_afterStart_notifiesListener() {
121         boundsProvider.start()
122         val newBounds = Rect(START_SIDE_BOUNDS).apply { right += 1 }
123 
124         endSideContent.setBoundsOnScreen(newBounds)
125 
126         verify(boundsChangeListener).onStatusBarBoundsChanged(any())
127     }
128 
129     @Test
130     fun endBoundsChange_beforeStart_doesNotNotifyListener() {
131         val newBounds = Rect(START_SIDE_BOUNDS).apply { right += 1 }
132 
133         endSideContent.setBoundsOnScreen(newBounds)
134 
135         verify(boundsChangeListener, never()).onStatusBarBoundsChanged(any())
136     }
137 
138     @Test
139     fun endBoundsChange_afterStop_doesNotNotifyListener() {
140         boundsProvider.start()
141         boundsProvider.stop()
142         val newBounds = Rect(START_SIDE_BOUNDS).apply { right += 1 }
143 
144         endSideContent.setBoundsOnScreen(newBounds)
145 
146         verify(boundsChangeListener, never()).onStatusBarBoundsChanged(any())
147     }
148 
149     @Test
150     fun endLayoutChange_afterStart_boundsOnScreenSame_doesNotNotifyListener() {
151         boundsProvider.start()
152         val newBounds = Rect(START_SIDE_BOUNDS).apply { right += 1 }
153 
154         endSideContent.layout(newBounds)
155 
156         verify(boundsChangeListener, never()).onStatusBarBoundsChanged(any())
157     }
158 }
159 
Viewnull160 private fun View.setBoundsOnScreen(bounds: Rect) {
161     doAnswer { invocation ->
162             val boundsOutput = invocation.arguments[0] as Rect
163             boundsOutput.set(bounds)
164             return@doAnswer Unit
165         }
166         .`when`(this)
167         .getBoundsOnScreen(any())
168     layout(bounds.left, bounds.top, bounds.right, bounds.bottom)
169 }
170 
layoutnull171 private fun View.layout(rect: Rect) {
172     layout(rect.left, rect.top, rect.right, rect.bottom)
173 }
174