1 /*
2  * 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.wm.shell.shared.handles
18 
19 
20 import android.graphics.Rect
21 import android.testing.TestableLooper.RunWithLooper
22 import android.view.SurfaceControl
23 import android.view.View
24 import android.view.ViewRootImpl
25 import androidx.concurrent.futures.DirectExecutor
26 import androidx.test.ext.junit.runners.AndroidJUnit4
27 import androidx.test.filters.SmallTest
28 import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation
29 import com.android.wm.shell.ShellTestCase
30 import com.android.wm.shell.TestShellExecutor
31 import com.google.common.truth.Truth.assertThat
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.ArgumentMatchers.any
37 import org.mockito.ArgumentMatchers.anyInt
38 import org.mockito.ArgumentMatchers.eq
39 import org.mockito.Mock
40 import org.mockito.Mockito.mock
41 import org.mockito.Mockito.never
42 import org.mockito.Mockito.verify
43 import org.mockito.Mockito.`when` as whenever
44 import org.mockito.junit.MockitoJUnit
45 import org.mockito.kotlin.argumentCaptor
46 
47 @RunWith(AndroidJUnit4::class)
48 @SmallTest
49 @RunWithLooper
50 class RegionSamplingHelperTest : ShellTestCase() {
51 
52     @Mock
53     lateinit var sampledView: View
54     @Mock
55     lateinit var samplingCallback: RegionSamplingHelper.SamplingCallback
56     @Mock
57     lateinit var compositionListener: RegionSamplingHelper.SysuiCompositionSamplingListener
58     @Mock
59     lateinit var viewRootImpl: ViewRootImpl
60     @Mock
61     lateinit var surfaceControl: SurfaceControl
62     @Mock
63     lateinit var wrappedSurfaceControl: SurfaceControl
64     @JvmField @Rule
65     var rule = MockitoJUnit.rule()
66     lateinit var regionSamplingHelper: RegionSamplingHelper
67 
68     @Before
setupnull69     fun setup() {
70         whenever(sampledView.isAttachedToWindow).thenReturn(true)
71         whenever(sampledView.viewRootImpl).thenReturn(viewRootImpl)
72         whenever(viewRootImpl.surfaceControl).thenReturn(surfaceControl)
73         whenever(surfaceControl.isValid).thenReturn(true)
74         whenever(wrappedSurfaceControl.isValid).thenReturn(true)
75         whenever(samplingCallback.isSamplingEnabled).thenReturn(true)
76         getInstrumentation().runOnMainSync(Runnable {
77             regionSamplingHelper = object : RegionSamplingHelper(
78                 sampledView, samplingCallback,
79                 DirectExecutor.INSTANCE, DirectExecutor.INSTANCE, compositionListener
80             ) {
81                 override fun wrap(stopLayerControl: SurfaceControl?): SurfaceControl {
82                     return wrappedSurfaceControl
83                 }
84             }
85         })
86         regionSamplingHelper.setWindowVisible(true)
87     }
88 
89     @Test
testStart_registernull90     fun testStart_register() {
91         regionSamplingHelper.start(Rect(0, 0, 100, 100))
92         verify(compositionListener).register(any(), anyInt(), eq(wrappedSurfaceControl), any())
93     }
94 
95     @Test
testStart_unregisternull96     fun testStart_unregister() {
97         regionSamplingHelper.start(Rect(0, 0, 100, 100))
98         regionSamplingHelper.setWindowVisible(false)
99         verify(compositionListener).unregister(any())
100     }
101 
102     @Test
testStart_hasBlur_neverRegistersnull103     fun testStart_hasBlur_neverRegisters() {
104         regionSamplingHelper.setWindowHasBlurs(true)
105         regionSamplingHelper.start(Rect(0, 0, 100, 100))
106         verify(compositionListener, never())
107             .register(any(), anyInt(), eq(wrappedSurfaceControl), any())
108     }
109 
110     @Test
testStart_stopAndDestroynull111     fun testStart_stopAndDestroy() {
112         regionSamplingHelper.start(Rect(0, 0, 100, 100))
113         regionSamplingHelper.stopAndDestroy()
114         verify(compositionListener).unregister(any())
115     }
116 
117     @Test
testCompositionSamplingListener_has_nonEmptyRectnull118     fun testCompositionSamplingListener_has_nonEmptyRect() {
119         // simulate race condition
120         val fakeExecutor = TestShellExecutor() // pass in as backgroundExecutor
121         val fakeSamplingCallback = mock(RegionSamplingHelper.SamplingCallback::class.java)
122 
123         whenever(fakeSamplingCallback.isSamplingEnabled).thenReturn(true)
124         whenever(wrappedSurfaceControl.isValid).thenReturn(true)
125         getInstrumentation().runOnMainSync(Runnable {
126             regionSamplingHelper = object : RegionSamplingHelper(
127                 sampledView, fakeSamplingCallback,
128                 DirectExecutor.INSTANCE, fakeExecutor, compositionListener
129             ) {
130                 override fun wrap(stopLayerControl: SurfaceControl?): SurfaceControl {
131                     return wrappedSurfaceControl
132                 }
133             }
134         })
135         regionSamplingHelper.setWindowVisible(true)
136         regionSamplingHelper.start(Rect(0, 0, 100, 100))
137 
138         // make sure background task is enqueued
139         assertThat(fakeExecutor.getCallbacks().size).isEqualTo(1)
140 
141         // make sure regionSamplingHelper will have empty Rect
142         whenever(fakeSamplingCallback.getSampledRegion(any())).thenReturn(Rect(0, 0, 0, 0))
143         regionSamplingHelper.onLayoutChange(sampledView, 0, 0, 0, 0, 0, 0, 0, 0)
144 
145         // resume running of background thread
146         fakeExecutor.flushAll()
147 
148         // grab Rect passed into compositionSamplingListener and make sure it's not empty
149         val argumentGrabber = argumentCaptor<Rect>()
150         verify(compositionListener).register(any(), anyInt(), eq(wrappedSurfaceControl),
151             argumentGrabber.capture())
152         assertThat(argumentGrabber.firstValue.isEmpty).isFalse()
153     }
154 }