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 17 package android.media.projection; 18 19 import static android.Manifest.permission.MANAGE_MEDIA_PROJECTION; 20 import static android.media.projection.MediaProjection.MEDIA_PROJECTION_REQUIRES_CALLBACK; 21 import static android.view.Display.DEFAULT_DISPLAY; 22 23 import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession; 24 25 import static com.google.common.truth.Truth.assertThat; 26 27 import static libcore.junit.util.compat.CoreCompatChangeRule.DisableCompatChanges; 28 import static libcore.junit.util.compat.CoreCompatChangeRule.EnableCompatChanges; 29 30 import static org.junit.Assert.assertThrows; 31 import static org.mockito.ArgumentMatchers.any; 32 import static org.mockito.ArgumentMatchers.nullable; 33 import static org.mockito.Mockito.doReturn; 34 35 import android.annotation.Nullable; 36 import android.app.ActivityOptions.LaunchCookie; 37 import android.compat.testing.PlatformCompatChangeRule; 38 import android.hardware.display.DisplayManager; 39 import android.hardware.display.VirtualDisplay; 40 import android.hardware.display.VirtualDisplayConfig; 41 import android.os.Handler; 42 import android.os.Looper; 43 import android.os.RemoteException; 44 import android.os.test.FakePermissionEnforcer; 45 import android.platform.test.annotations.Presubmit; 46 import android.testing.TestableContext; 47 import android.view.Display; 48 49 import androidx.test.ext.junit.runners.AndroidJUnit4; 50 import androidx.test.filters.SmallTest; 51 import androidx.test.platform.app.InstrumentationRegistry; 52 53 import org.junit.After; 54 import org.junit.Before; 55 import org.junit.Rule; 56 import org.junit.Test; 57 import org.junit.rules.TestRule; 58 import org.junit.runner.RunWith; 59 import org.mockito.Mock; 60 import org.mockito.MockitoSession; 61 import org.mockito.quality.Strictness; 62 63 64 /** 65 * Tests for the {@link MediaProjection} class. 66 * 67 * Build/Install/Run: 68 * atest MediaProjectionTests:MediaProjectionTest 69 */ 70 @SmallTest 71 @Presubmit 72 @RunWith(AndroidJUnit4.class) 73 public class MediaProjectionTest { 74 // Values for creating a VirtualDisplay. 75 private static final String VIRTUAL_DISPLAY_NAME = "MEDIA_PROJECTION_VIRTUAL_DISPLAY"; 76 private static final int VIRTUAL_DISPLAY_WIDTH = 500; 77 private static final int VIRTUAL_DISPLAY_HEIGHT = 600; 78 private static final int VIRTUAL_DISPLAY_DENSITY = 100; 79 private static final int VIRTUAL_DISPLAY_FLAGS = 0; 80 81 private final Handler mHandler = new Handler(Looper.getMainLooper()); 82 // Fake the connection to the system server. 83 private FakeIMediaProjection mFakeIMediaProjection; 84 // Callback registered by an app. 85 private MediaProjection mMediaProjection; 86 87 @Mock 88 private MediaProjection.Callback mMediaProjectionCallback; 89 @Mock 90 private Display mDisplay; 91 @Mock 92 private VirtualDisplay.Callback mVirtualDisplayCallback; 93 @Mock 94 private VirtualDisplay mVirtualDisplay; 95 @Mock 96 private DisplayManager mDisplayManager; 97 98 @Rule 99 public TestRule compatChangeRule = new PlatformCompatChangeRule(); 100 101 @Rule 102 public final TestableContext mTestableContext = new TestableContext( 103 InstrumentationRegistry.getInstrumentation().getTargetContext()); 104 105 private MockitoSession mMockingSession; 106 107 @Before setup()108 public void setup() throws Exception { 109 mMockingSession = 110 mockitoSession() 111 .initMocks(this) 112 .strictness(Strictness.LENIENT) 113 .startMocking(); 114 115 FakePermissionEnforcer permissionEnforcer = new FakePermissionEnforcer(); 116 permissionEnforcer.grant(MANAGE_MEDIA_PROJECTION); 117 // Support the MediaProjection instance. 118 mFakeIMediaProjection = new FakeIMediaProjection(permissionEnforcer); 119 mFakeIMediaProjection.setLaunchCookie(new LaunchCookie()); 120 mMediaProjection = new MediaProjection(mTestableContext, mFakeIMediaProjection, 121 mDisplayManager); 122 123 // Support creation of the VirtualDisplay. 124 mTestableContext.addMockSystemService(DisplayManager.class, mDisplayManager); 125 doReturn(mDisplay).when(mVirtualDisplay).getDisplay(); 126 doReturn(DEFAULT_DISPLAY + 7).when(mDisplay).getDisplayId(); 127 doReturn(mVirtualDisplay).when(mDisplayManager).createVirtualDisplay( 128 any(MediaProjection.class), any(VirtualDisplayConfig.class), 129 nullable(VirtualDisplay.Callback.class), nullable(Handler.class)); 130 } 131 132 @After tearDown()133 public void tearDown() { 134 mMockingSession.finishMocking(); 135 } 136 137 @Test testConstruction()138 public void testConstruction() throws RemoteException { 139 assertThat(mMediaProjection).isNotNull(); 140 assertThat(mFakeIMediaProjection.mIsStarted).isTrue(); 141 } 142 143 @Test testRegisterCallback_null()144 public void testRegisterCallback_null() { 145 assertThrows(NullPointerException.class, 146 () -> mMediaProjection.registerCallback(null, mHandler)); 147 } 148 149 @Test testUnregisterCallback_null()150 public void testUnregisterCallback_null() { 151 mMediaProjection.registerCallback(mMediaProjectionCallback, mHandler); 152 assertThrows(NullPointerException.class, 153 () -> mMediaProjection.unregisterCallback(null)); 154 } 155 156 @Test 157 @DisableCompatChanges({MEDIA_PROJECTION_REQUIRES_CALLBACK}) createVirtualDisplay_noCallbackRequired_missingMediaProjectionCallback()158 public void createVirtualDisplay_noCallbackRequired_missingMediaProjectionCallback() { 159 assertThat(createVirtualDisplay(null)).isNotNull(); 160 assertThat(createVirtualDisplay(mVirtualDisplayCallback)).isNotNull(); 161 } 162 163 @Test 164 @DisableCompatChanges({MEDIA_PROJECTION_REQUIRES_CALLBACK}) createVirtualDisplay_noCallbackRequired_givenMediaProjectionCallback()165 public void createVirtualDisplay_noCallbackRequired_givenMediaProjectionCallback() { 166 mMediaProjection.registerCallback(mMediaProjectionCallback, mHandler); 167 assertThat(createVirtualDisplay(null)).isNotNull(); 168 assertThat(createVirtualDisplay(mVirtualDisplayCallback)).isNotNull(); 169 } 170 171 @Test 172 @EnableCompatChanges({MEDIA_PROJECTION_REQUIRES_CALLBACK}) createVirtualDisplay_callbackRequired_missingMediaProjectionCallback()173 public void createVirtualDisplay_callbackRequired_missingMediaProjectionCallback() { 174 assertThrows(IllegalStateException.class, 175 () -> createVirtualDisplay(mVirtualDisplayCallback)); 176 } 177 178 @Test 179 @EnableCompatChanges({MEDIA_PROJECTION_REQUIRES_CALLBACK}) createVirtualDisplay_callbackRequired_givenMediaProjectionCallback()180 public void createVirtualDisplay_callbackRequired_givenMediaProjectionCallback() { 181 mMediaProjection.registerCallback(mMediaProjectionCallback, mHandler); 182 assertThat(createVirtualDisplay(null)).isNotNull(); 183 assertThat(createVirtualDisplay(mVirtualDisplayCallback)).isNotNull(); 184 } 185 createVirtualDisplay(@ullable VirtualDisplay.Callback callback)186 private VirtualDisplay createVirtualDisplay(@Nullable VirtualDisplay.Callback callback) { 187 // No recording will take place with a null surface. 188 return mMediaProjection.createVirtualDisplay( 189 VIRTUAL_DISPLAY_NAME, VIRTUAL_DISPLAY_WIDTH, 190 VIRTUAL_DISPLAY_HEIGHT, VIRTUAL_DISPLAY_DENSITY, 191 VIRTUAL_DISPLAY_FLAGS, /* surface = */ null, 192 callback, /* handler= */ mHandler); 193 } 194 } 195