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 }