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