1 /*
2  * Copyright (C) 2021 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.server.companion.virtual;
18 
19 import static android.companion.virtual.VirtualDeviceParams.DEVICE_POLICY_CUSTOM;
20 import static android.companion.virtual.VirtualDeviceParams.DEVICE_POLICY_DEFAULT;
21 import static android.companion.virtual.VirtualDeviceParams.POLICY_TYPE_RECENTS;
22 import static android.companion.virtual.VirtualDeviceParams.POLICY_TYPE_SENSORS;
23 import static android.content.Context.DEVICE_ID_DEFAULT;
24 import static android.content.Context.DEVICE_ID_INVALID;
25 import static android.content.Intent.ACTION_VIEW;
26 import static android.content.pm.ActivityInfo.FLAG_CAN_DISPLAY_ON_REMOTE_DEVICES;
27 import static android.content.pm.PackageManager.ACTION_REQUEST_PERMISSIONS;
28 
29 import static com.google.common.truth.Truth.assertThat;
30 import static com.google.common.truth.Truth.assertWithMessage;
31 
32 import static org.mockito.ArgumentMatchers.any;
33 import static org.mockito.ArgumentMatchers.anyBoolean;
34 import static org.mockito.ArgumentMatchers.anyFloat;
35 import static org.mockito.ArgumentMatchers.anyInt;
36 import static org.mockito.ArgumentMatchers.anyLong;
37 import static org.mockito.ArgumentMatchers.anyString;
38 import static org.mockito.ArgumentMatchers.eq;
39 import static org.mockito.ArgumentMatchers.nullable;
40 import static org.mockito.Mockito.argThat;
41 import static org.mockito.Mockito.clearInvocations;
42 import static org.mockito.Mockito.doAnswer;
43 import static org.mockito.Mockito.doNothing;
44 import static org.mockito.Mockito.doReturn;
45 import static org.mockito.Mockito.mock;
46 import static org.mockito.Mockito.never;
47 import static org.mockito.Mockito.times;
48 import static org.mockito.Mockito.verify;
49 import static org.mockito.Mockito.verifyNoMoreInteractions;
50 import static org.mockito.Mockito.when;
51 import static org.testng.Assert.assertThrows;
52 
53 import android.Manifest;
54 import android.app.WindowConfiguration;
55 import android.app.admin.DevicePolicyManager;
56 import android.companion.AssociationInfo;
57 import android.companion.AssociationRequest;
58 import android.companion.virtual.IVirtualDeviceActivityListener;
59 import android.companion.virtual.IVirtualDeviceIntentInterceptor;
60 import android.companion.virtual.IVirtualDeviceSoundEffectListener;
61 import android.companion.virtual.VirtualDeviceManager;
62 import android.companion.virtual.VirtualDeviceParams;
63 import android.companion.virtual.audio.IAudioConfigChangedCallback;
64 import android.companion.virtual.audio.IAudioRoutingCallback;
65 import android.companion.virtual.flags.Flags;
66 import android.companion.virtual.sensor.VirtualSensor;
67 import android.companion.virtual.sensor.VirtualSensorCallback;
68 import android.companion.virtual.sensor.VirtualSensorConfig;
69 import android.content.AttributionSource;
70 import android.content.ComponentName;
71 import android.content.Context;
72 import android.content.ContextWrapper;
73 import android.content.Intent;
74 import android.content.IntentFilter;
75 import android.content.pm.ActivityInfo;
76 import android.content.pm.ApplicationInfo;
77 import android.content.pm.PackageManager;
78 import android.hardware.Sensor;
79 import android.hardware.display.DisplayManagerGlobal;
80 import android.hardware.display.DisplayManagerInternal;
81 import android.hardware.display.IDisplayManager;
82 import android.hardware.display.IVirtualDisplayCallback;
83 import android.hardware.display.VirtualDisplayConfig;
84 import android.hardware.input.IInputManager;
85 import android.hardware.input.VirtualDpadConfig;
86 import android.hardware.input.VirtualKeyEvent;
87 import android.hardware.input.VirtualKeyboardConfig;
88 import android.hardware.input.VirtualMouseButtonEvent;
89 import android.hardware.input.VirtualMouseConfig;
90 import android.hardware.input.VirtualMouseRelativeEvent;
91 import android.hardware.input.VirtualMouseScrollEvent;
92 import android.hardware.input.VirtualNavigationTouchpadConfig;
93 import android.hardware.input.VirtualTouchEvent;
94 import android.hardware.input.VirtualTouchscreenConfig;
95 import android.media.AudioManager;
96 import android.net.MacAddress;
97 import android.net.Uri;
98 import android.os.Binder;
99 import android.os.Handler;
100 import android.os.IBinder;
101 import android.os.IPowerManager;
102 import android.os.IThermalService;
103 import android.os.LocaleList;
104 import android.os.PowerManager;
105 import android.os.Process;
106 import android.os.RemoteException;
107 import android.os.WorkSource;
108 import android.platform.test.annotations.Presubmit;
109 import android.platform.test.flag.junit.SetFlagsRule;
110 import android.testing.AndroidTestingRunner;
111 import android.testing.TestableLooper;
112 import android.util.ArraySet;
113 import android.view.Display;
114 import android.view.DisplayInfo;
115 import android.view.KeyEvent;
116 import android.view.WindowManager;
117 
118 import androidx.test.platform.app.InstrumentationRegistry;
119 
120 import com.android.compatibility.common.util.AdoptShellPermissionsRule;
121 import com.android.internal.app.BlockedAppStreamingActivity;
122 import com.android.internal.os.BackgroundThread;
123 import com.android.server.LocalServices;
124 import com.android.server.companion.virtual.camera.VirtualCameraController;
125 import com.android.server.input.InputManagerInternal;
126 import com.android.server.sensors.SensorManagerInternal;
127 
128 import com.google.android.collect.Sets;
129 
130 import org.junit.After;
131 import org.junit.Before;
132 import org.junit.Rule;
133 import org.junit.Test;
134 import org.junit.runner.RunWith;
135 import org.mockito.ArgumentCaptor;
136 import org.mockito.Mock;
137 import org.mockito.Mockito;
138 import org.mockito.MockitoAnnotations;
139 
140 import java.util.Arrays;
141 import java.util.Collections;
142 import java.util.List;
143 import java.util.Set;
144 import java.util.function.Consumer;
145 
146 @Presubmit
147 @RunWith(AndroidTestingRunner.class)
148 @TestableLooper.RunWithLooper(setAsMainLooper = true)
149 public class VirtualDeviceManagerServiceTest {
150 
151     private static final String NONBLOCKED_APP_PACKAGE_NAME = "com.someapp";
152     private static final String PERMISSION_CONTROLLER_PACKAGE_NAME =
153             "com.android.permissioncontroller";
154     private static final String SETTINGS_PACKAGE_NAME = "com.android.settings";
155     private static final String VENDING_PACKAGE_NAME = "com.android.vending";
156     private static final String GOOGLE_DIALER_PACKAGE_NAME = "com.google.android.dialer";
157     private static final String GOOGLE_MAPS_PACKAGE_NAME = "com.google.android.apps.maps";
158     private static final String DEVICE_NAME_1 = "device name 1";
159     private static final String DEVICE_NAME_2 = "device name 2";
160     private static final String DEVICE_NAME_3 = "device name 3";
161     private static final int DISPLAY_ID_1 = 2;
162     private static final int DISPLAY_ID_2 = 3;
163     private static final int NON_EXISTENT_DISPLAY_ID = 42;
164     private static final int DEVICE_OWNER_UID_1 = 50;
165     private static final int DEVICE_OWNER_UID_2 = 51;
166     private static final int UID_1 = 0;
167     private static final int UID_2 = 10;
168     private static final int UID_3 = 10000;
169     private static final int UID_4 = 10001;
170     private static final int PRODUCT_ID = 10;
171     private static final int VENDOR_ID = 5;
172     private static final String UNIQUE_ID = "uniqueid";
173     private static final String PHYS = "phys";
174     private static final int INPUT_DEVICE_ID = 53;
175     private static final int HEIGHT = 1800;
176     private static final int WIDTH = 900;
177     private static final int SENSOR_HANDLE = 64;
178     private static final Binder BINDER = new Binder("binder");
179     private static final int FLAG_CANNOT_DISPLAY_ON_REMOTE_DEVICES = 0x00000;
180     private static final int VIRTUAL_DEVICE_ID_1 = 42;
181     private static final int VIRTUAL_DEVICE_ID_2 = 43;
182     private static final VirtualDisplayConfig VIRTUAL_DISPLAY_CONFIG =
183             new VirtualDisplayConfig.Builder("virtual_display", 640, 480, 400).build();
184     private static final VirtualDpadConfig DPAD_CONFIG =
185             new VirtualDpadConfig.Builder()
186                     .setVendorId(VENDOR_ID)
187                     .setProductId(PRODUCT_ID)
188                     .setInputDeviceName(DEVICE_NAME_1)
189                     .setAssociatedDisplayId(DISPLAY_ID_1)
190                     .build();
191     private static final VirtualKeyboardConfig KEYBOARD_CONFIG =
192             new VirtualKeyboardConfig.Builder()
193                     .setVendorId(VENDOR_ID)
194                     .setProductId(PRODUCT_ID)
195                     .setInputDeviceName(DEVICE_NAME_1)
196                     .setAssociatedDisplayId(DISPLAY_ID_1)
197                     .setLanguageTag(VirtualKeyboardConfig.DEFAULT_LANGUAGE_TAG)
198                     .setLayoutType(VirtualKeyboardConfig.DEFAULT_LAYOUT_TYPE)
199                     .build();
200     private static final VirtualMouseConfig MOUSE_CONFIG =
201             new VirtualMouseConfig.Builder()
202                     .setVendorId(VENDOR_ID)
203                     .setProductId(PRODUCT_ID)
204                     .setInputDeviceName(DEVICE_NAME_1)
205                     .setAssociatedDisplayId(DISPLAY_ID_1)
206                     .build();
207     private static final VirtualTouchscreenConfig TOUCHSCREEN_CONFIG =
208             new VirtualTouchscreenConfig.Builder(WIDTH, HEIGHT)
209                     .setVendorId(VENDOR_ID)
210                     .setProductId(PRODUCT_ID)
211                     .setInputDeviceName(DEVICE_NAME_1)
212                     .setAssociatedDisplayId(DISPLAY_ID_1)
213                     .build();
214     private static final VirtualNavigationTouchpadConfig NAVIGATION_TOUCHPAD_CONFIG =
215             new VirtualNavigationTouchpadConfig.Builder(WIDTH, HEIGHT)
216                     .setVendorId(VENDOR_ID)
217                     .setProductId(PRODUCT_ID)
218                     .setInputDeviceName(DEVICE_NAME_1)
219                     .setAssociatedDisplayId(DISPLAY_ID_1)
220                     .build();
221     private static final String TEST_SITE = "http://test";
222 
223     @Rule
224     public SetFlagsRule mSetFlagsRule = new SetFlagsRule();
225 
226     @Rule
227     public AdoptShellPermissionsRule mAdoptShellPermissionsRule = new AdoptShellPermissionsRule(
228             InstrumentationRegistry.getInstrumentation().getUiAutomation(),
229             Manifest.permission.CREATE_VIRTUAL_DEVICE);
230 
231     private Context mContext;
232     private InputManagerMockHelper mInputManagerMockHelper;
233     private VirtualDeviceImpl mDeviceImpl;
234     private InputController mInputController;
235     private SensorController mSensorController;
236     private CameraAccessController mCameraAccessController;
237     private AssociationInfo mAssociationInfo;
238     private VirtualDeviceManagerService mVdms;
239     private VirtualDeviceManagerInternal mLocalService;
240     private VirtualDeviceManagerService.VirtualDeviceManagerImpl mVdm;
241     private VirtualDeviceManagerService.VirtualDeviceManagerNativeImpl mVdmNative;
242     private VirtualDeviceLog mVirtualDeviceLog;
243     @Mock
244     private InputController.NativeWrapper mNativeWrapperMock;
245     @Mock
246     private DisplayManagerInternal mDisplayManagerInternalMock;
247     @Mock
248     private IDisplayManager mIDisplayManager;
249     @Mock
250     private VirtualDeviceImpl.PendingTrampolineCallback mPendingTrampolineCallback;
251     @Mock
252     private DevicePolicyManager mDevicePolicyManagerMock;
253     @Mock
254     private InputManagerInternal mInputManagerInternalMock;
255     @Mock
256     private SensorManagerInternal mSensorManagerInternalMock;
257     @Mock
258     private VirtualSensorCallback mSensorCallback;
259     @Mock
260     private IVirtualDeviceActivityListener mActivityListener;
261     @Mock
262     private IVirtualDeviceSoundEffectListener mSoundEffectListener;
263     @Mock
264     private IVirtualDisplayCallback mVirtualDisplayCallback;
265     @Mock
266     private Consumer<ArraySet<Integer>> mRunningAppsChangedCallback;
267     @Mock
268     private VirtualDeviceManagerInternal.AppsOnVirtualDeviceListener mAppsOnVirtualDeviceListener;
269     @Mock
270     private Consumer<String> mPersistentDeviceIdRemovedListener;
271     @Mock
272     IPowerManager mIPowerManagerMock;
273     @Mock
274     IThermalService mIThermalServiceMock;
275     @Mock
276     private IAudioRoutingCallback mRoutingCallback;
277     @Mock
278     private IAudioConfigChangedCallback mConfigChangedCallback;
279     @Mock
280     private CameraAccessController.CameraAccessBlockedCallback mCameraAccessBlockedCallback;
281     @Mock
282     private ApplicationInfo mApplicationInfoMock;
283     @Mock
284     IInputManager mIInputManagerMock;
285 
getBlockedActivities()286     private ArraySet<ComponentName> getBlockedActivities() {
287         ArraySet<ComponentName> blockedActivities = new ArraySet<>();
288         blockedActivities.add(new ComponentName(SETTINGS_PACKAGE_NAME, SETTINGS_PACKAGE_NAME));
289         blockedActivities.add(new ComponentName(VENDING_PACKAGE_NAME, VENDING_PACKAGE_NAME));
290         blockedActivities.add(
291                 new ComponentName(GOOGLE_DIALER_PACKAGE_NAME, GOOGLE_DIALER_PACKAGE_NAME));
292         blockedActivities.add(
293                 new ComponentName(GOOGLE_MAPS_PACKAGE_NAME, GOOGLE_MAPS_PACKAGE_NAME));
294         return blockedActivities;
295     }
296 
createRestrictedActivityBlockedIntent(Set<String> displayCategories, String targetDisplayCategory)297     private Intent createRestrictedActivityBlockedIntent(Set<String> displayCategories,
298             String targetDisplayCategory) {
299         when(mDisplayManagerInternalMock.createVirtualDisplay(any(), any(), any(), any(),
300                 eq(NONBLOCKED_APP_PACKAGE_NAME))).thenReturn(DISPLAY_ID_1);
301         VirtualDisplayConfig config = new VirtualDisplayConfig.Builder("display", 640, 480,
302                 420).setDisplayCategories(displayCategories).build();
303         mDeviceImpl.createVirtualDisplay(config, mVirtualDisplayCallback,
304                 NONBLOCKED_APP_PACKAGE_NAME);
305         GenericWindowPolicyController gwpc = mDeviceImpl.getDisplayWindowPolicyControllerForTest(
306                 DISPLAY_ID_1);
307         doNothing().when(mContext).startActivityAsUser(any(), any(), any());
308 
309         ActivityInfo activityInfo = getActivityInfo(
310                 NONBLOCKED_APP_PACKAGE_NAME,
311                 NONBLOCKED_APP_PACKAGE_NAME,
312                 /* displayOnRemoteDevices= */ true,
313                 targetDisplayCategory);
314         Intent blockedAppIntent = BlockedAppStreamingActivity.createIntent(
315                 activityInfo, mAssociationInfo.getDisplayName());
316         gwpc.canActivityBeLaunched(activityInfo, blockedAppIntent,
317                 WindowConfiguration.WINDOWING_MODE_FULLSCREEN, DISPLAY_ID_1, /*isNewTask=*/false);
318         return blockedAppIntent;
319     }
320 
321 
getActivityInfo( String packageName, String name, boolean displayOnRemoteDevices, String requiredDisplayCategory)322     private ActivityInfo getActivityInfo(
323             String packageName, String name, boolean displayOnRemoteDevices,
324             String requiredDisplayCategory) {
325         ActivityInfo activityInfo = new ActivityInfo();
326         activityInfo.packageName = packageName;
327         activityInfo.name = name;
328         activityInfo.flags = displayOnRemoteDevices
329                 ? FLAG_CAN_DISPLAY_ON_REMOTE_DEVICES : FLAG_CANNOT_DISPLAY_ON_REMOTE_DEVICES;
330         activityInfo.applicationInfo = mApplicationInfoMock;
331         activityInfo.requiredDisplayCategory = requiredDisplayCategory;
332         return activityInfo;
333     }
334 
335     @Before
setUp()336     public void setUp() throws Exception {
337         MockitoAnnotations.initMocks(this);
338 
339         LocalServices.removeServiceForTest(DisplayManagerInternal.class);
340         LocalServices.addService(DisplayManagerInternal.class, mDisplayManagerInternalMock);
341 
342         doNothing().when(mInputManagerInternalMock)
343                 .setMousePointerAccelerationEnabled(anyBoolean(), anyInt());
344         doNothing().when(mInputManagerInternalMock).setPointerIconVisible(anyBoolean(), anyInt());
345         LocalServices.removeServiceForTest(InputManagerInternal.class);
346         LocalServices.addService(InputManagerInternal.class, mInputManagerInternalMock);
347 
348         LocalServices.removeServiceForTest(SensorManagerInternal.class);
349         LocalServices.addService(SensorManagerInternal.class, mSensorManagerInternalMock);
350 
351         final DisplayInfo displayInfo = new DisplayInfo();
352         displayInfo.uniqueId = UNIQUE_ID;
353         doReturn(displayInfo).when(mDisplayManagerInternalMock).getDisplayInfo(anyInt());
354         doReturn(Display.INVALID_DISPLAY).when(mDisplayManagerInternalMock)
355                 .getDisplayIdToMirror(anyInt());
356         LocalServices.removeServiceForTest(DisplayManagerInternal.class);
357         LocalServices.addService(DisplayManagerInternal.class, mDisplayManagerInternalMock);
358 
359         mContext = Mockito.spy(new ContextWrapper(
360                 InstrumentationRegistry.getInstrumentation().getTargetContext()));
361         doReturn(mContext).when(mContext).createContextAsUser(eq(Process.myUserHandle()), anyInt());
362         doNothing().when(mContext).sendBroadcastAsUser(any(), any());
363         when(mContext.getSystemService(Context.DEVICE_POLICY_SERVICE)).thenReturn(
364                 mDevicePolicyManagerMock);
365 
366         PowerManager powerManager = new PowerManager(mContext, mIPowerManagerMock,
367                 mIThermalServiceMock,
368                 new Handler(TestableLooper.get(this).getLooper()));
369         when(mContext.getSystemService(Context.POWER_SERVICE)).thenReturn(powerManager);
370 
371         when(mNativeWrapperMock.writeButtonEvent(anyLong(), anyInt(), anyInt(), anyLong()))
372                 .thenReturn(true);
373         when(mNativeWrapperMock.writeRelativeEvent(anyLong(), anyFloat(), anyFloat(), anyLong()))
374                 .thenReturn(true);
375         when(mNativeWrapperMock.writeScrollEvent(anyLong(), anyFloat(), anyFloat(), anyLong()))
376                 .thenReturn(true);
377         when(mNativeWrapperMock.writeKeyEvent(anyLong(), anyInt(), anyInt(), anyLong()))
378                 .thenReturn(true);
379         when(mNativeWrapperMock.writeTouchEvent(anyLong(), anyInt(), anyInt(), anyInt(),
380                 anyFloat(), anyFloat(), anyFloat(), anyFloat(), anyLong()))
381                 .thenReturn(true);
382 
383         mInputManagerMockHelper = new InputManagerMockHelper(
384                 TestableLooper.get(this), mNativeWrapperMock, mIInputManagerMock);
385         // Allow virtual devices to be created on the looper thread for testing.
386         final InputController.DeviceCreationThreadVerifier threadVerifier = () -> true;
387         mInputController = new InputController(mNativeWrapperMock,
388                 new Handler(TestableLooper.get(this).getLooper()),
389                 mContext.getSystemService(WindowManager.class),
390                 AttributionSource.myAttributionSource(), threadVerifier);
391         mCameraAccessController =
392                 new CameraAccessController(mContext, mLocalService, mCameraAccessBlockedCallback);
393 
394         mAssociationInfo = createAssociationInfo(
395                 /* associationId= */ 1, AssociationRequest.DEVICE_PROFILE_APP_STREAMING);
396 
397         mVdms = new VirtualDeviceManagerService(mContext);
398         mLocalService = mVdms.getLocalServiceInstance();
399         mVdm = mVdms.new VirtualDeviceManagerImpl();
400         mVdmNative = mVdms.new VirtualDeviceManagerNativeImpl();
401         mVirtualDeviceLog = new VirtualDeviceLog(mContext);
402         mDeviceImpl = createVirtualDevice(VIRTUAL_DEVICE_ID_1, DEVICE_OWNER_UID_1);
403         mSensorController = mDeviceImpl.getSensorControllerForTest();
404     }
405 
406     @After
tearDown()407     public void tearDown() {
408         mDeviceImpl.close();
409         mInputManagerMockHelper.tearDown();
410     }
411 
412     @Test
getDeviceIdForDisplayId_invalidDisplayId_returnsDefault()413     public void getDeviceIdForDisplayId_invalidDisplayId_returnsDefault() {
414         assertThat(mVdm.getDeviceIdForDisplayId(Display.INVALID_DISPLAY))
415                 .isEqualTo(DEVICE_ID_DEFAULT);
416         assertThat(mLocalService.getDeviceIdForDisplayId(Display.INVALID_DISPLAY))
417                 .isEqualTo(DEVICE_ID_DEFAULT);
418     }
419 
420     @Test
getDeviceIdForDisplayId_defaultDisplayId_returnsDefault()421     public void getDeviceIdForDisplayId_defaultDisplayId_returnsDefault() {
422         assertThat(mVdm.getDeviceIdForDisplayId(Display.DEFAULT_DISPLAY))
423                 .isEqualTo(DEVICE_ID_DEFAULT);
424         assertThat(mLocalService.getDeviceIdForDisplayId(Display.DEFAULT_DISPLAY))
425                 .isEqualTo(DEVICE_ID_DEFAULT);
426     }
427 
428     @Test
getDeviceIdForDisplayId_nonExistentDisplayId_returnsDefault()429     public void getDeviceIdForDisplayId_nonExistentDisplayId_returnsDefault() {
430         assertThat(mVdm.getDeviceIdForDisplayId(NON_EXISTENT_DISPLAY_ID))
431                 .isEqualTo(DEVICE_ID_DEFAULT);
432         assertThat(mLocalService.getDeviceIdForDisplayId(NON_EXISTENT_DISPLAY_ID))
433                 .isEqualTo(DEVICE_ID_DEFAULT);
434     }
435 
436     @Test
getDeviceIdForDisplayId_withValidVirtualDisplayId_returnsDeviceId()437     public void getDeviceIdForDisplayId_withValidVirtualDisplayId_returnsDeviceId() {
438         addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1);
439 
440         assertThat(mVdm.getDeviceIdForDisplayId(DISPLAY_ID_1))
441                 .isEqualTo(mDeviceImpl.getDeviceId());
442         assertThat(mLocalService.getDeviceIdForDisplayId(DISPLAY_ID_1))
443                 .isEqualTo(mDeviceImpl.getDeviceId());
444     }
445 
446     @Test
isDeviceIdValid_invalidDeviceId_returnsFalse()447     public void isDeviceIdValid_invalidDeviceId_returnsFalse() {
448         assertThat(mVdm.isValidVirtualDeviceId(DEVICE_ID_INVALID)).isFalse();
449         assertThat(mLocalService.isValidVirtualDeviceId(DEVICE_ID_INVALID)).isFalse();
450     }
451 
452     @Test
isDeviceIdValid_defaultDeviceId_returnsFalse()453     public void isDeviceIdValid_defaultDeviceId_returnsFalse() {
454         assertThat(mVdm.isValidVirtualDeviceId(DEVICE_ID_DEFAULT)).isFalse();
455         assertThat(mLocalService.isValidVirtualDeviceId(DEVICE_ID_DEFAULT)).isFalse();
456     }
457 
458     @Test
isDeviceIdValid_validVirtualDeviceId_returnsTrue()459     public void isDeviceIdValid_validVirtualDeviceId_returnsTrue() {
460         assertThat(mVdm.isValidVirtualDeviceId(mDeviceImpl.getDeviceId())).isTrue();
461         assertThat(mLocalService.isValidVirtualDeviceId(mDeviceImpl.getDeviceId())).isTrue();
462     }
463 
464     @Test
isDeviceIdValid_nonExistentDeviceId_returnsFalse()465     public void isDeviceIdValid_nonExistentDeviceId_returnsFalse() {
466         assertThat(mVdm.isValidVirtualDeviceId(mDeviceImpl.getDeviceId() + 1)).isFalse();
467         assertThat(mLocalService.isValidVirtualDeviceId(mDeviceImpl.getDeviceId() + 1)).isFalse();
468     }
469 
470     @Test
getDevicePolicy_invalidDeviceId_returnsDefault()471     public void getDevicePolicy_invalidDeviceId_returnsDefault() {
472         assertThat(mVdm.getDevicePolicy(DEVICE_ID_INVALID, POLICY_TYPE_SENSORS))
473                 .isEqualTo(DEVICE_POLICY_DEFAULT);
474         assertThat(mVdmNative.getDevicePolicy(DEVICE_ID_INVALID, POLICY_TYPE_SENSORS))
475                 .isEqualTo(DEVICE_POLICY_DEFAULT);
476     }
477 
478     @Test
getDevicePolicy_defaultDeviceId_returnsDefault()479     public void getDevicePolicy_defaultDeviceId_returnsDefault() {
480         assertThat(mVdm.getDevicePolicy(DEVICE_ID_DEFAULT, POLICY_TYPE_SENSORS))
481                 .isEqualTo(DEVICE_POLICY_DEFAULT);
482         assertThat(mVdmNative.getDevicePolicy(DEVICE_ID_DEFAULT, POLICY_TYPE_SENSORS))
483                 .isEqualTo(DEVICE_POLICY_DEFAULT);
484     }
485 
486     @Test
getDevicePolicy_nonExistentDeviceId_returnsDefault()487     public void getDevicePolicy_nonExistentDeviceId_returnsDefault() {
488         assertThat(mVdm.getDevicePolicy(mDeviceImpl.getDeviceId() + 1, POLICY_TYPE_SENSORS))
489                 .isEqualTo(DEVICE_POLICY_DEFAULT);
490         assertThat(mVdmNative.getDevicePolicy(mDeviceImpl.getDeviceId() + 1, POLICY_TYPE_SENSORS))
491                 .isEqualTo(DEVICE_POLICY_DEFAULT);
492     }
493 
494     @Test
getDevicePolicy_unspecifiedPolicy_returnsDefault()495     public void getDevicePolicy_unspecifiedPolicy_returnsDefault() {
496         assertThat(mVdm.getDevicePolicy(mDeviceImpl.getDeviceId(), POLICY_TYPE_SENSORS))
497                 .isEqualTo(DEVICE_POLICY_DEFAULT);
498         assertThat(mVdmNative.getDevicePolicy(mDeviceImpl.getDeviceId(), POLICY_TYPE_SENSORS))
499                 .isEqualTo(DEVICE_POLICY_DEFAULT);
500     }
501 
502     @Test
getDevicePolicy_returnsCustom()503     public void getDevicePolicy_returnsCustom() {
504         VirtualDeviceParams params = new VirtualDeviceParams
505                 .Builder()
506                 .setBlockedActivities(getBlockedActivities())
507                 .setDevicePolicy(POLICY_TYPE_SENSORS, DEVICE_POLICY_CUSTOM)
508                 .build();
509         mDeviceImpl.close();
510         mDeviceImpl = createVirtualDevice(VIRTUAL_DEVICE_ID_1, DEVICE_OWNER_UID_1, params);
511 
512         assertThat(mVdm.getDevicePolicy(mDeviceImpl.getDeviceId(), POLICY_TYPE_SENSORS))
513                 .isEqualTo(DEVICE_POLICY_CUSTOM);
514         assertThat(mVdmNative.getDevicePolicy(mDeviceImpl.getDeviceId(), POLICY_TYPE_SENSORS))
515                 .isEqualTo(DEVICE_POLICY_CUSTOM);
516     }
517 
518     @Test
getDevicePolicy_defaultRecentsPolicy_gwpcCanShowRecentsOnHostDevice()519     public void getDevicePolicy_defaultRecentsPolicy_gwpcCanShowRecentsOnHostDevice() {
520         VirtualDeviceParams params = new VirtualDeviceParams
521                 .Builder()
522                 .build();
523         mDeviceImpl.close();
524         mDeviceImpl = createVirtualDevice(VIRTUAL_DEVICE_ID_1, DEVICE_OWNER_UID_1, params);
525         addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1);
526 
527         GenericWindowPolicyController gwpc =
528                 mDeviceImpl.getDisplayWindowPolicyControllerForTest(DISPLAY_ID_1);
529         assertThat(gwpc.canShowTasksInHostDeviceRecents()).isTrue();
530     }
531 
532     @Test
getDevicePolicy_customRecentsPolicy_gwpcCannotShowRecentsOnHostDevice()533     public void getDevicePolicy_customRecentsPolicy_gwpcCannotShowRecentsOnHostDevice() {
534         VirtualDeviceParams params = new VirtualDeviceParams
535                 .Builder()
536                 .setDevicePolicy(POLICY_TYPE_RECENTS, DEVICE_POLICY_CUSTOM)
537                 .build();
538         mDeviceImpl.close();
539         mDeviceImpl = createVirtualDevice(VIRTUAL_DEVICE_ID_1, DEVICE_OWNER_UID_1, params);
540         addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1);
541 
542         GenericWindowPolicyController gwpc =
543                 mDeviceImpl.getDisplayWindowPolicyControllerForTest(DISPLAY_ID_1);
544         assertThat(gwpc.canShowTasksInHostDeviceRecents()).isFalse();
545     }
546 
547     @Test
getDeviceOwnerUid_oneDevice_returnsCorrectId()548     public void getDeviceOwnerUid_oneDevice_returnsCorrectId() {
549         int ownerUid = mLocalService.getDeviceOwnerUid(mDeviceImpl.getDeviceId());
550         assertThat(ownerUid).isEqualTo(mDeviceImpl.getOwnerUid());
551     }
552 
553     @Test
getDeviceOwnerUid_twoDevices_returnsCorrectId()554     public void getDeviceOwnerUid_twoDevices_returnsCorrectId() {
555         createVirtualDevice(VIRTUAL_DEVICE_ID_2, DEVICE_OWNER_UID_2);
556 
557         int secondDeviceOwner = mLocalService.getDeviceOwnerUid(VIRTUAL_DEVICE_ID_2);
558         assertThat(secondDeviceOwner).isEqualTo(DEVICE_OWNER_UID_2);
559 
560         int firstDeviceOwner = mLocalService.getDeviceOwnerUid(VIRTUAL_DEVICE_ID_1);
561         assertThat(firstDeviceOwner).isEqualTo(DEVICE_OWNER_UID_1);
562     }
563 
564     @Test
getDeviceOwnerUid_nonExistentDevice_returnsInvalidUid()565     public void getDeviceOwnerUid_nonExistentDevice_returnsInvalidUid() {
566         int nonExistentDeviceId = DEVICE_ID_DEFAULT;
567         int ownerUid = mLocalService.getDeviceOwnerUid(nonExistentDeviceId);
568         assertThat(ownerUid).isEqualTo(Process.INVALID_UID);
569     }
570 
571     @Test
getVirtualSensor_defaultDeviceId_returnsNull()572     public void getVirtualSensor_defaultDeviceId_returnsNull() {
573         assertThat(mLocalService.getVirtualSensor(DEVICE_ID_DEFAULT, SENSOR_HANDLE)).isNull();
574     }
575 
576     @Test
getVirtualSensor_invalidDeviceId_returnsNull()577     public void getVirtualSensor_invalidDeviceId_returnsNull() {
578         assertThat(mLocalService.getVirtualSensor(DEVICE_ID_INVALID, SENSOR_HANDLE)).isNull();
579     }
580 
581     @Test
getVirtualSensor_noSensors_returnsNull()582     public void getVirtualSensor_noSensors_returnsNull() {
583         assertThat(mLocalService.getVirtualSensor(VIRTUAL_DEVICE_ID_1, SENSOR_HANDLE)).isNull();
584     }
585 
586     @Test
getVirtualSensor_returnsCorrectSensor()587     public void getVirtualSensor_returnsCorrectSensor() {
588         VirtualDeviceParams params = new VirtualDeviceParams.Builder()
589                 .setDevicePolicy(POLICY_TYPE_SENSORS, DEVICE_POLICY_CUSTOM)
590                 .addVirtualSensorConfig(
591                         new VirtualSensorConfig.Builder(Sensor.TYPE_ACCELEROMETER, DEVICE_NAME_1)
592                                 .build())
593                 .setVirtualSensorCallback(BackgroundThread.getExecutor(), mSensorCallback)
594                 .build();
595 
596         doReturn(SENSOR_HANDLE).when(mSensorManagerInternalMock).createRuntimeSensor(
597                 anyInt(), anyInt(), anyString(), anyString(), anyFloat(), anyFloat(), anyFloat(),
598                 anyInt(), anyInt(), anyInt(), any());
599         mDeviceImpl.close();
600         mDeviceImpl = createVirtualDevice(VIRTUAL_DEVICE_ID_1, DEVICE_OWNER_UID_1, params);
601 
602         VirtualSensor sensor = mLocalService.getVirtualSensor(VIRTUAL_DEVICE_ID_1, SENSOR_HANDLE);
603         assertThat(sensor).isNotNull();
604         assertThat(sensor.getDeviceId()).isEqualTo(VIRTUAL_DEVICE_ID_1);
605         assertThat(sensor.getHandle()).isEqualTo(SENSOR_HANDLE);
606         assertThat(sensor.getType()).isEqualTo(Sensor.TYPE_ACCELEROMETER);
607     }
608 
609     @Test
testIsInputDeviceOwnedByVirtualDevice()610     public void testIsInputDeviceOwnedByVirtualDevice() {
611         assertThat(mLocalService.isInputDeviceOwnedByVirtualDevice(INPUT_DEVICE_ID)).isFalse();
612 
613         final int fd = 1;
614         mInputController.addDeviceForTesting(BINDER, fd,
615                 InputController.InputDeviceDescriptor.TYPE_KEYBOARD, DISPLAY_ID_1, PHYS,
616                 DEVICE_NAME_1, INPUT_DEVICE_ID);
617         assertThat(mLocalService.isInputDeviceOwnedByVirtualDevice(INPUT_DEVICE_ID)).isTrue();
618 
619         mInputController.unregisterInputDevice(BINDER);
620         assertThat(mLocalService.isInputDeviceOwnedByVirtualDevice(INPUT_DEVICE_ID)).isFalse();
621     }
622 
623     @Test
getDeviceIdsForUid_noRunningApps_returnsNull()624     public void getDeviceIdsForUid_noRunningApps_returnsNull() {
625         assertThat(mLocalService.getDeviceIdsForUid(UID_1)).isEmpty();
626         assertThat(mVdmNative.getDeviceIdsForUid(UID_1)).isEmpty();
627     }
628 
629     @Test
getDeviceIdsForUid_differentUidOnDevice_returnsNull()630     public void getDeviceIdsForUid_differentUidOnDevice_returnsNull() {
631         addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1);
632         mDeviceImpl.getDisplayWindowPolicyControllerForTest(DISPLAY_ID_1).onRunningAppsChanged(
633                 Sets.newArraySet(UID_2));
634 
635         assertThat(mLocalService.getDeviceIdsForUid(UID_1)).isEmpty();
636         assertThat(mVdmNative.getDeviceIdsForUid(UID_1)).isEmpty();
637     }
638 
639     @Test
getDeviceIdsForUid_oneUidOnDevice_returnsCorrectId()640     public void getDeviceIdsForUid_oneUidOnDevice_returnsCorrectId() {
641         addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1);
642         mDeviceImpl.getDisplayWindowPolicyControllerForTest(DISPLAY_ID_1).onRunningAppsChanged(
643                 Sets.newArraySet(UID_1));
644 
645         int deviceId = mDeviceImpl.getDeviceId();
646         assertThat(mLocalService.getDeviceIdsForUid(UID_1)).containsExactly(deviceId);
647         assertThat(mVdmNative.getDeviceIdsForUid(UID_1)).asList().containsExactly(deviceId);
648     }
649 
650     @Test
getDeviceIdsForUid_twoUidsOnDevice_returnsCorrectId()651     public void getDeviceIdsForUid_twoUidsOnDevice_returnsCorrectId() {
652         addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1);
653 
654         mDeviceImpl.getDisplayWindowPolicyControllerForTest(DISPLAY_ID_1).onRunningAppsChanged(
655                 Sets.newArraySet(UID_1, UID_2));
656 
657         int deviceId = mDeviceImpl.getDeviceId();
658         assertThat(mLocalService.getDeviceIdsForUid(UID_1)).containsExactly(deviceId);
659         assertThat(mVdmNative.getDeviceIdsForUid(UID_1)).asList().containsExactly(deviceId);
660     }
661 
662     @Test
getDeviceIdsForUid_twoDevicesUidOnOne_returnsCorrectId()663     public void getDeviceIdsForUid_twoDevicesUidOnOne_returnsCorrectId() {
664         VirtualDeviceImpl secondDevice = createVirtualDevice(VIRTUAL_DEVICE_ID_2,
665                 DEVICE_OWNER_UID_2);
666         addVirtualDisplay(secondDevice, DISPLAY_ID_2);
667 
668         secondDevice.getDisplayWindowPolicyControllerForTest(DISPLAY_ID_2).onRunningAppsChanged(
669                 Sets.newArraySet(UID_1));
670 
671         int deviceId = secondDevice.getDeviceId();
672         assertThat(mLocalService.getDeviceIdsForUid(UID_1)).containsExactly(deviceId);
673         assertThat(mVdmNative.getDeviceIdsForUid(UID_1)).asList().containsExactly(deviceId);
674     }
675 
676     @Test
getDeviceIdsForUid_twoDevicesUidOnBoth_returnsCorrectId()677     public void getDeviceIdsForUid_twoDevicesUidOnBoth_returnsCorrectId() {
678         addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1);
679         VirtualDeviceImpl secondDevice = createVirtualDevice(VIRTUAL_DEVICE_ID_2,
680                 DEVICE_OWNER_UID_2);
681         addVirtualDisplay(secondDevice, DISPLAY_ID_2);
682 
683 
684         mDeviceImpl.getDisplayWindowPolicyControllerForTest(DISPLAY_ID_1).onRunningAppsChanged(
685                 Sets.newArraySet(UID_1));
686         secondDevice.getDisplayWindowPolicyControllerForTest(DISPLAY_ID_2).onRunningAppsChanged(
687                 Sets.newArraySet(UID_1, UID_2));
688 
689         assertThat(mLocalService.getDeviceIdsForUid(UID_1)).containsExactly(
690                 mDeviceImpl.getDeviceId(), secondDevice.getDeviceId());
691         assertThat(mVdmNative.getDeviceIdsForUid(UID_1)).asList().containsExactly(
692                 mDeviceImpl.getDeviceId(), secondDevice.getDeviceId());
693     }
694 
695     @Test
getPreferredLocaleListForApp_keyboardAttached_returnLocaleHints()696     public void getPreferredLocaleListForApp_keyboardAttached_returnLocaleHints() {
697         addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1);
698         mDeviceImpl.createVirtualKeyboard(KEYBOARD_CONFIG, BINDER);
699 
700         mVdms.notifyRunningAppsChanged(mDeviceImpl.getDeviceId(), Sets.newArraySet(UID_1));
701 
702         LocaleList localeList = mLocalService.getPreferredLocaleListForUid(UID_1);
703         assertThat(localeList).isEqualTo(
704                 LocaleList.forLanguageTags(KEYBOARD_CONFIG.getLanguageTag()));
705     }
706 
707     @Test
getPreferredLocaleListForApp_noKeyboardAttached_nullLocaleHints()708     public void getPreferredLocaleListForApp_noKeyboardAttached_nullLocaleHints() {
709         mVdms.notifyRunningAppsChanged(mDeviceImpl.getDeviceId(), Sets.newArraySet(UID_1));
710 
711         // no preceding call to createVirtualKeyboard()
712         assertThat(mLocalService.getPreferredLocaleListForUid(UID_1)).isNull();
713     }
714 
715     @Test
getPreferredLocaleListForApp_appOnMultipleVD_localeOnFirstVDReturned()716     public void getPreferredLocaleListForApp_appOnMultipleVD_localeOnFirstVDReturned() {
717         VirtualDeviceImpl secondDevice = createVirtualDevice(VIRTUAL_DEVICE_ID_2,
718                 DEVICE_OWNER_UID_2);
719         Binder secondBinder = new Binder("secondBinder");
720         VirtualKeyboardConfig firstKeyboardConfig =
721                 new VirtualKeyboardConfig.Builder()
722                         .setVendorId(VENDOR_ID)
723                         .setProductId(PRODUCT_ID)
724                         .setInputDeviceName(DEVICE_NAME_1)
725                         .setAssociatedDisplayId(DISPLAY_ID_1)
726                         .setLanguageTag("zh-CN")
727                         .build();
728         VirtualKeyboardConfig secondKeyboardConfig =
729                 new VirtualKeyboardConfig.Builder()
730                         .setVendorId(VENDOR_ID)
731                         .setProductId(PRODUCT_ID)
732                         .setInputDeviceName(DEVICE_NAME_2)
733                         .setAssociatedDisplayId(DISPLAY_ID_2)
734                         .setLanguageTag("fr-FR")
735                         .build();
736 
737         addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1);
738         addVirtualDisplay(secondDevice, DISPLAY_ID_2);
739 
740         mDeviceImpl.createVirtualKeyboard(firstKeyboardConfig, BINDER);
741         secondDevice.createVirtualKeyboard(secondKeyboardConfig, secondBinder);
742 
743         mVdms.notifyRunningAppsChanged(mDeviceImpl.getDeviceId(), Sets.newArraySet(UID_1));
744         mVdms.notifyRunningAppsChanged(secondDevice.getDeviceId(), Sets.newArraySet(UID_1));
745 
746         LocaleList localeList = mLocalService.getPreferredLocaleListForUid(UID_1);
747         assertThat(localeList).isEqualTo(
748                 LocaleList.forLanguageTags(firstKeyboardConfig.getLanguageTag()));
749     }
750 
751     @Test
cameraAccessController_observerCountUpdated()752     public void cameraAccessController_observerCountUpdated() {
753         assertThat(mCameraAccessController.getObserverCount()).isEqualTo(1);
754 
755         VirtualDeviceImpl secondDevice =
756                 createVirtualDevice(VIRTUAL_DEVICE_ID_2, DEVICE_OWNER_UID_2);
757         assertThat(mCameraAccessController.getObserverCount()).isEqualTo(2);
758 
759         mDeviceImpl.close();
760         assertThat(mCameraAccessController.getObserverCount()).isEqualTo(1);
761 
762         secondDevice.close();
763         assertThat(mCameraAccessController.getObserverCount()).isEqualTo(0);
764     }
765 
766     @Test
onVirtualDisplayRemovedLocked_doesNotThrowException()767     public void onVirtualDisplayRemovedLocked_doesNotThrowException() {
768         addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1);
769         // This call should not throw any exceptions.
770         mDeviceImpl.onVirtualDisplayRemoved(DISPLAY_ID_1);
771     }
772 
773     @Test
onPersistentDeviceIdsRemoved_listenersNotified()774     public void onPersistentDeviceIdsRemoved_listenersNotified() {
775         mLocalService.registerPersistentDeviceIdRemovedListener(mPersistentDeviceIdRemovedListener);
776         mLocalService.onPersistentDeviceIdsRemoved(Set.of(mDeviceImpl.getPersistentDeviceId()));
777         TestableLooper.get(this).processAllMessages();
778 
779         verify(mPersistentDeviceIdRemovedListener).accept(mDeviceImpl.getPersistentDeviceId());
780     }
781 
782     @Test
onCdmAssociationsChanged_persistentDeviceIdRemovedListenersNotified()783     public void onCdmAssociationsChanged_persistentDeviceIdRemovedListenersNotified() {
784         mLocalService.registerPersistentDeviceIdRemovedListener(mPersistentDeviceIdRemovedListener);
785         mVdms.onCdmAssociationsChanged(List.of(mAssociationInfo));
786         TestableLooper.get(this).processAllMessages();
787 
788         mVdms.onCdmAssociationsChanged(List.of(
789                 createAssociationInfo(2, AssociationRequest.DEVICE_PROFILE_APP_STREAMING),
790                 createAssociationInfo(3, AssociationRequest.DEVICE_PROFILE_AUTOMOTIVE_PROJECTION),
791                 createAssociationInfo(4, AssociationRequest.DEVICE_PROFILE_WATCH)));
792         TestableLooper.get(this).processAllMessages();
793 
794         verify(mPersistentDeviceIdRemovedListener).accept(mDeviceImpl.getPersistentDeviceId());
795 
796         mVdms.onCdmAssociationsChanged(Collections.emptyList());
797         TestableLooper.get(this).processAllMessages();
798 
799         verify(mPersistentDeviceIdRemovedListener)
800                 .accept(VirtualDeviceImpl.createPersistentDeviceId(2));
801         verify(mPersistentDeviceIdRemovedListener)
802                 .accept(VirtualDeviceImpl.createPersistentDeviceId(3));
803         verifyNoMoreInteractions(mPersistentDeviceIdRemovedListener);
804     }
805 
806     @Test
getAllPersistentDeviceIds_respectsCurrentAssociations()807     public void getAllPersistentDeviceIds_respectsCurrentAssociations() {
808         mVdms.onCdmAssociationsChanged(List.of(mAssociationInfo));
809         TestableLooper.get(this).processAllMessages();
810 
811         assertThat(mLocalService.getAllPersistentDeviceIds())
812                 .containsExactly(mDeviceImpl.getPersistentDeviceId());
813 
814         mVdms.onCdmAssociationsChanged(List.of(
815                 createAssociationInfo(2, AssociationRequest.DEVICE_PROFILE_APP_STREAMING),
816                 createAssociationInfo(3, AssociationRequest.DEVICE_PROFILE_AUTOMOTIVE_PROJECTION),
817                 createAssociationInfo(4, AssociationRequest.DEVICE_PROFILE_WATCH)));
818         TestableLooper.get(this).processAllMessages();
819 
820         assertThat(mLocalService.getAllPersistentDeviceIds()).containsExactly(
821                 VirtualDeviceImpl.createPersistentDeviceId(2),
822                 VirtualDeviceImpl.createPersistentDeviceId(3));
823 
824         mVdms.onCdmAssociationsChanged(Collections.emptyList());
825         TestableLooper.get(this).processAllMessages();
826 
827         assertThat(mLocalService.getAllPersistentDeviceIds()).isEmpty();
828     }
829 
830     @Test
getDisplayNameForPersistentDeviceId_nonExistentPeristentId_returnsNull()831     public void getDisplayNameForPersistentDeviceId_nonExistentPeristentId_returnsNull() {
832         assertThat(mVdm.getDisplayNameForPersistentDeviceId("nonExistentPersistentId")).isNull();
833     }
834 
835     @Test
getDisplayNameForPersistentDeviceId_defaultDevicePeristentId_returnsNull()836     public void getDisplayNameForPersistentDeviceId_defaultDevicePeristentId_returnsNull() {
837         assertThat(mVdm.getDisplayNameForPersistentDeviceId(
838                 VirtualDeviceManager.PERSISTENT_DEVICE_ID_DEFAULT))
839                 .isNull();
840     }
841 
842     @Test
getDisplayNameForPersistentDeviceId_validVirtualDevice_returnsCorrectId()843     public void getDisplayNameForPersistentDeviceId_validVirtualDevice_returnsCorrectId() {
844         mVdms.onCdmAssociationsChanged(List.of(mAssociationInfo));
845         CharSequence persistentIdDisplayName =
846                 mVdm.getDisplayNameForPersistentDeviceId(mDeviceImpl.getPersistentDeviceId());
847         assertThat(persistentIdDisplayName.toString())
848                 .isEqualTo(mAssociationInfo.getDisplayName().toString());
849     }
850 
851     @Test
getDisplayNameForPersistentDeviceId_noVirtualDevice_returnsCorrectId()852     public void getDisplayNameForPersistentDeviceId_noVirtualDevice_returnsCorrectId() {
853         CharSequence displayName = "New display name for the new association";
854         mVdms.onCdmAssociationsChanged(List.of(
855                 createAssociationInfo(2, AssociationRequest.DEVICE_PROFILE_APP_STREAMING,
856                         displayName)));
857 
858         CharSequence persistentIdDisplayName =
859                 mVdm.getDisplayNameForPersistentDeviceId(
860                         VirtualDeviceImpl.createPersistentDeviceId(2));
861         assertThat(persistentIdDisplayName.toString()).isEqualTo(displayName.toString());
862     }
863 
864     @Test
onAppsOnVirtualDeviceChanged_singleVirtualDevice_listenersNotified()865     public void onAppsOnVirtualDeviceChanged_singleVirtualDevice_listenersNotified() {
866         ArraySet<Integer> uids = new ArraySet<>(Arrays.asList(UID_1, UID_2));
867         mLocalService.registerAppsOnVirtualDeviceListener(mAppsOnVirtualDeviceListener);
868 
869         mVdms.notifyRunningAppsChanged(mDeviceImpl.getDeviceId(), uids);
870         TestableLooper.get(this).processAllMessages();
871 
872         verify(mAppsOnVirtualDeviceListener).onAppsOnAnyVirtualDeviceChanged(uids);
873     }
874 
875     @Test
onAppsOnVirtualDeviceChanged_multipleVirtualDevices_listenersNotified()876     public void onAppsOnVirtualDeviceChanged_multipleVirtualDevices_listenersNotified() {
877         createVirtualDevice(VIRTUAL_DEVICE_ID_2, DEVICE_OWNER_UID_2);
878 
879         ArraySet<Integer> uidsOnDevice1 = new ArraySet<>(Arrays.asList(UID_1, UID_2));
880         ArraySet<Integer> uidsOnDevice2 = new ArraySet<>(Arrays.asList(UID_3, UID_4));
881         mLocalService.registerAppsOnVirtualDeviceListener(mAppsOnVirtualDeviceListener);
882 
883         // Notifies that the running apps on the first virtual device has changed.
884         mVdms.notifyRunningAppsChanged(mDeviceImpl.getDeviceId(), uidsOnDevice1);
885         TestableLooper.get(this).processAllMessages();
886         verify(mAppsOnVirtualDeviceListener).onAppsOnAnyVirtualDeviceChanged(
887                 new ArraySet<>(Arrays.asList(UID_1, UID_2)));
888 
889         // Notifies that the running apps on the second virtual device has changed.
890         mVdms.notifyRunningAppsChanged(VIRTUAL_DEVICE_ID_2, uidsOnDevice2);
891         TestableLooper.get(this).processAllMessages();
892         // The union of the apps running on both virtual devices are sent to the listeners.
893         verify(mAppsOnVirtualDeviceListener).onAppsOnAnyVirtualDeviceChanged(
894                 new ArraySet<>(Arrays.asList(UID_1, UID_2, UID_3, UID_4)));
895 
896         // Notifies that the running apps on the first virtual device has changed again.
897         uidsOnDevice1.remove(UID_2);
898         mVdms.notifyRunningAppsChanged(mDeviceImpl.getDeviceId(), uidsOnDevice1);
899         mLocalService.onAppsOnVirtualDeviceChanged();
900         TestableLooper.get(this).processAllMessages();
901         // The union of the apps running on both virtual devices are sent to the listeners.
902         verify(mAppsOnVirtualDeviceListener).onAppsOnAnyVirtualDeviceChanged(
903                 new ArraySet<>(Arrays.asList(UID_1, UID_3, UID_4)));
904 
905         // Notifies that the running apps on the first virtual device has changed but with the same
906         // set of UIDs.
907         mVdms.notifyRunningAppsChanged(mDeviceImpl.getDeviceId(), uidsOnDevice1);
908         mLocalService.onAppsOnVirtualDeviceChanged();
909         TestableLooper.get(this).processAllMessages();
910         // Listeners should not be notified.
911         verifyNoMoreInteractions(mAppsOnVirtualDeviceListener);
912     }
913 
914     @Test
onVirtualDisplayCreatedLocked_wakeLockIsAcquired()915     public void onVirtualDisplayCreatedLocked_wakeLockIsAcquired() throws RemoteException {
916         verify(mIPowerManagerMock, never()).acquireWakeLock(any(Binder.class), anyInt(),
917                 nullable(String.class), nullable(String.class), nullable(WorkSource.class),
918                 nullable(String.class), anyInt(), eq(null));
919         addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1);
920         verify(mIPowerManagerMock).acquireWakeLock(any(Binder.class), anyInt(),
921                 nullable(String.class), nullable(String.class), nullable(WorkSource.class),
922                 nullable(String.class), eq(DISPLAY_ID_1), eq(null));
923     }
924 
925     @Test
onVirtualDisplayCreatedLocked_duplicateCalls_onlyOneWakeLockIsAcquired()926     public void onVirtualDisplayCreatedLocked_duplicateCalls_onlyOneWakeLockIsAcquired()
927             throws RemoteException {
928         addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1);
929         assertThrows(IllegalStateException.class,
930                 () -> addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1));
931         TestableLooper.get(this).processAllMessages();
932         verify(mIPowerManagerMock).acquireWakeLock(any(Binder.class), anyInt(),
933                 nullable(String.class), nullable(String.class), nullable(WorkSource.class),
934                 nullable(String.class), eq(DISPLAY_ID_1), eq(null));
935     }
936 
937     @Test
onVirtualDisplayRemovedLocked_wakeLockIsReleased()938     public void onVirtualDisplayRemovedLocked_wakeLockIsReleased() throws RemoteException {
939         addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1);
940         ArgumentCaptor<IBinder> wakeLockCaptor = ArgumentCaptor.forClass(IBinder.class);
941         TestableLooper.get(this).processAllMessages();
942         verify(mIPowerManagerMock).acquireWakeLock(wakeLockCaptor.capture(),
943                 anyInt(),
944                 nullable(String.class), nullable(String.class), nullable(WorkSource.class),
945                 nullable(String.class), eq(DISPLAY_ID_1), eq(null));
946 
947         IBinder wakeLock = wakeLockCaptor.getValue();
948         mDeviceImpl.onVirtualDisplayRemoved(DISPLAY_ID_1);
949         verify(mIPowerManagerMock).releaseWakeLock(eq(wakeLock), anyInt());
950     }
951 
952     @Test
addVirtualDisplay_displayNotReleased_wakeLockIsReleased()953     public void addVirtualDisplay_displayNotReleased_wakeLockIsReleased() throws RemoteException {
954         addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1);
955         ArgumentCaptor<IBinder> wakeLockCaptor = ArgumentCaptor.forClass(IBinder.class);
956         TestableLooper.get(this).processAllMessages();
957         verify(mIPowerManagerMock).acquireWakeLock(wakeLockCaptor.capture(),
958                 anyInt(),
959                 nullable(String.class), nullable(String.class), nullable(WorkSource.class),
960                 nullable(String.class), eq(DISPLAY_ID_1), eq(null));
961         IBinder wakeLock = wakeLockCaptor.getValue();
962 
963         // Close the VirtualDevice without first notifying it of the VirtualDisplay removal.
964         mDeviceImpl.close();
965         verify(mIPowerManagerMock).releaseWakeLock(eq(wakeLock), anyInt());
966     }
967 
968     @Test
createVirtualDpad_noDisplay_failsSecurityException()969     public void createVirtualDpad_noDisplay_failsSecurityException() {
970         assertThrows(SecurityException.class,
971                 () -> mDeviceImpl.createVirtualDpad(DPAD_CONFIG, BINDER));
972     }
973 
974     @Test
createVirtualKeyboard_noDisplay_failsSecurityException()975     public void createVirtualKeyboard_noDisplay_failsSecurityException() {
976         assertThrows(SecurityException.class,
977                 () -> mDeviceImpl.createVirtualKeyboard(KEYBOARD_CONFIG, BINDER));
978     }
979 
980     @Test
createVirtualMouse_noDisplay_failsSecurityException()981     public void createVirtualMouse_noDisplay_failsSecurityException() {
982         assertThrows(SecurityException.class,
983                 () -> mDeviceImpl.createVirtualMouse(MOUSE_CONFIG, BINDER));
984     }
985 
986     @Test
createVirtualTouchscreen_noDisplay_failsSecurityException()987     public void createVirtualTouchscreen_noDisplay_failsSecurityException() {
988         assertThrows(SecurityException.class,
989                 () -> mDeviceImpl.createVirtualTouchscreen(TOUCHSCREEN_CONFIG, BINDER));
990     }
991 
992     @Test
createVirtualTouchscreen_zeroDisplayDimension_failsIllegalArgumentException()993     public void createVirtualTouchscreen_zeroDisplayDimension_failsIllegalArgumentException() {
994         assertThrows(IllegalArgumentException.class,
995                 () -> new VirtualTouchscreenConfig.Builder(
996                         /* touchscrenWidth= */ 0, /* touchscreenHeight= */ 0));
997     }
998 
999     @Test
createVirtualTouchscreen_negativeDisplayDimension_failsIllegalArgumentException()1000     public void createVirtualTouchscreen_negativeDisplayDimension_failsIllegalArgumentException() {
1001         assertThrows(IllegalArgumentException.class,
1002                 () -> new VirtualTouchscreenConfig.Builder(
1003                         /* touchscrenWidth= */ -100, /* touchscreenHeight= */ -100));
1004     }
1005 
1006     @Test
createVirtualTouchscreen_positiveDisplayDimension_successful()1007     public void createVirtualTouchscreen_positiveDisplayDimension_successful() {
1008         addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1);
1009         VirtualTouchscreenConfig positiveConfig =
1010                 new VirtualTouchscreenConfig.Builder(
1011                         /* touchscrenWidth= */ 600, /* touchscreenHeight= */ 800)
1012                         .setVendorId(VENDOR_ID)
1013                         .setProductId(PRODUCT_ID)
1014                         .setInputDeviceName(DEVICE_NAME_1)
1015                         .setAssociatedDisplayId(DISPLAY_ID_1)
1016                         .build();
1017         mDeviceImpl.createVirtualTouchscreen(positiveConfig, BINDER);
1018         assertWithMessage(
1019                 "Virtual touchscreen should create input device descriptor on successful creation"
1020                         + ".").that(mInputController.getInputDeviceDescriptors()).isNotEmpty();
1021     }
1022 
1023     @Test
createVirtualNavigationTouchpad_noDisplay_failsSecurityException()1024     public void createVirtualNavigationTouchpad_noDisplay_failsSecurityException() {
1025         assertThrows(SecurityException.class,
1026                 () -> mDeviceImpl.createVirtualNavigationTouchpad(NAVIGATION_TOUCHPAD_CONFIG,
1027                         BINDER));
1028     }
1029 
1030     @Test
createVirtualNavigationTouchpad_zeroDisplayDimension_failsWithException()1031     public void createVirtualNavigationTouchpad_zeroDisplayDimension_failsWithException() {
1032         assertThrows(IllegalArgumentException.class,
1033                 () -> new VirtualNavigationTouchpadConfig.Builder(
1034                         /* touchpadHeight= */ 0, /* touchpadWidth= */ 0));
1035     }
1036 
1037     @Test
createVirtualNavigationTouchpad_negativeDisplayDimension_failsWithException()1038     public void createVirtualNavigationTouchpad_negativeDisplayDimension_failsWithException() {
1039         assertThrows(IllegalArgumentException.class,
1040                 () -> new VirtualNavigationTouchpadConfig.Builder(
1041                         /* touchpadHeight= */ -50, /* touchpadWidth= */ 50));
1042     }
1043 
1044     @Test
createVirtualNavigationTouchpad_positiveDisplayDimension_successful()1045     public void createVirtualNavigationTouchpad_positiveDisplayDimension_successful() {
1046         addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1);
1047         VirtualNavigationTouchpadConfig positiveConfig =
1048                 new VirtualNavigationTouchpadConfig.Builder(
1049                         /* touchpadHeight= */ 50, /* touchpadWidth= */ 50)
1050                         .setVendorId(VENDOR_ID)
1051                         .setProductId(PRODUCT_ID)
1052                         .setInputDeviceName(DEVICE_NAME_1)
1053                         .setAssociatedDisplayId(DISPLAY_ID_1)
1054                         .build();
1055         mDeviceImpl.createVirtualNavigationTouchpad(positiveConfig, BINDER);
1056         assertWithMessage(
1057                 "Virtual navigation touchpad should create input device descriptor on successful "
1058                         + "creation"
1059                         + ".").that(mInputController.getInputDeviceDescriptors()).isNotEmpty();
1060     }
1061 
1062     @Test
onAudioSessionStarting_noDisplay_failsSecurityException()1063     public void onAudioSessionStarting_noDisplay_failsSecurityException() {
1064         assertThrows(SecurityException.class,
1065                 () -> mDeviceImpl.onAudioSessionStarting(
1066                         DISPLAY_ID_1, mRoutingCallback, mConfigChangedCallback));
1067     }
1068 
1069     @Test
createVirtualDpad_noPermission_failsSecurityException()1070     public void createVirtualDpad_noPermission_failsSecurityException() {
1071         addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1);
1072         try (DropShellPermissionsTemporarily drop = new DropShellPermissionsTemporarily()) {
1073             assertThrows(SecurityException.class,
1074                     () -> mDeviceImpl.createVirtualDpad(DPAD_CONFIG, BINDER));
1075         }
1076     }
1077 
1078     @Test
createVirtualKeyboard_noPermission_failsSecurityException()1079     public void createVirtualKeyboard_noPermission_failsSecurityException() {
1080         addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1);
1081         try (DropShellPermissionsTemporarily drop = new DropShellPermissionsTemporarily()) {
1082             assertThrows(SecurityException.class,
1083                     () -> mDeviceImpl.createVirtualKeyboard(KEYBOARD_CONFIG, BINDER));
1084         }
1085     }
1086 
1087     @Test
createVirtualMouse_noPermission_failsSecurityException()1088     public void createVirtualMouse_noPermission_failsSecurityException() {
1089         addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1);
1090         try (DropShellPermissionsTemporarily drop = new DropShellPermissionsTemporarily()) {
1091             assertThrows(SecurityException.class,
1092                     () -> mDeviceImpl.createVirtualMouse(MOUSE_CONFIG, BINDER));
1093         }
1094     }
1095 
1096     @Test
createVirtualTouchscreen_noPermission_failsSecurityException()1097     public void createVirtualTouchscreen_noPermission_failsSecurityException() {
1098         addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1);
1099         try (DropShellPermissionsTemporarily drop = new DropShellPermissionsTemporarily()) {
1100             assertThrows(SecurityException.class,
1101                     () -> mDeviceImpl.createVirtualTouchscreen(TOUCHSCREEN_CONFIG, BINDER));
1102         }
1103     }
1104 
1105     @Test
createVirtualNavigationTouchpad_noPermission_failsSecurityException()1106     public void createVirtualNavigationTouchpad_noPermission_failsSecurityException() {
1107         addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1);
1108         try (DropShellPermissionsTemporarily drop = new DropShellPermissionsTemporarily()) {
1109             assertThrows(SecurityException.class,
1110                     () -> mDeviceImpl.createVirtualNavigationTouchpad(NAVIGATION_TOUCHPAD_CONFIG,
1111                             BINDER));
1112         }
1113     }
1114 
1115     @Test
onAudioSessionStarting_noPermission_failsSecurityException()1116     public void onAudioSessionStarting_noPermission_failsSecurityException() {
1117         addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1);
1118         try (DropShellPermissionsTemporarily drop = new DropShellPermissionsTemporarily()) {
1119             assertThrows(SecurityException.class,
1120                     () -> mDeviceImpl.onAudioSessionStarting(
1121                             DISPLAY_ID_1, mRoutingCallback, mConfigChangedCallback));
1122         }
1123     }
1124 
1125     @Test
onAudioSessionEnded_noPermission_failsSecurityException()1126     public void onAudioSessionEnded_noPermission_failsSecurityException() {
1127         try (DropShellPermissionsTemporarily drop = new DropShellPermissionsTemporarily()) {
1128             assertThrows(SecurityException.class, () -> mDeviceImpl.onAudioSessionEnded());
1129         }
1130     }
1131 
1132     @Test
createVirtualDpad_hasDisplay_obtainFileDescriptor()1133     public void createVirtualDpad_hasDisplay_obtainFileDescriptor() {
1134         addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1);
1135         mDeviceImpl.createVirtualDpad(DPAD_CONFIG, BINDER);
1136         assertWithMessage("Virtual dpad should register fd when the display matches").that(
1137                 mInputController.getInputDeviceDescriptors()).isNotEmpty();
1138         verify(mNativeWrapperMock).openUinputDpad(eq(DEVICE_NAME_1), eq(VENDOR_ID), eq(PRODUCT_ID),
1139                 anyString());
1140     }
1141 
1142     @Test
createVirtualKeyboard_hasDisplay_obtainFileDescriptor()1143     public void createVirtualKeyboard_hasDisplay_obtainFileDescriptor() {
1144         addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1);
1145         mDeviceImpl.createVirtualKeyboard(KEYBOARD_CONFIG, BINDER);
1146         assertWithMessage("Virtual keyboard should register fd when the display matches").that(
1147                 mInputController.getInputDeviceDescriptors()).isNotEmpty();
1148         verify(mNativeWrapperMock).openUinputKeyboard(eq(DEVICE_NAME_1), eq(VENDOR_ID),
1149                 eq(PRODUCT_ID), anyString());
1150     }
1151 
1152     @Test
createVirtualKeyboard_keyboardCreated_localeUpdated()1153     public void createVirtualKeyboard_keyboardCreated_localeUpdated() {
1154         addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1);
1155         mDeviceImpl.createVirtualKeyboard(KEYBOARD_CONFIG, BINDER);
1156         assertWithMessage("Virtual keyboard should register fd when the display matches")
1157                 .that(mInputController.getInputDeviceDescriptors())
1158                 .isNotEmpty();
1159         verify(mNativeWrapperMock).openUinputKeyboard(eq(DEVICE_NAME_1), eq(VENDOR_ID),
1160                 eq(PRODUCT_ID), anyString());
1161         assertThat(mDeviceImpl.getDeviceLocaleList()).isEqualTo(
1162                 LocaleList.forLanguageTags(KEYBOARD_CONFIG.getLanguageTag()));
1163     }
1164 
1165     @Test
createVirtualKeyboard_keyboardWithoutExplicitLayoutInfo_localeUpdatedWithDefault()1166     public void createVirtualKeyboard_keyboardWithoutExplicitLayoutInfo_localeUpdatedWithDefault() {
1167         VirtualKeyboardConfig configWithoutExplicitLayoutInfo =
1168                 new VirtualKeyboardConfig.Builder()
1169                         .setVendorId(VENDOR_ID)
1170                         .setProductId(PRODUCT_ID)
1171                         .setInputDeviceName(DEVICE_NAME_1)
1172                         .setAssociatedDisplayId(DISPLAY_ID_1)
1173                         .build();
1174 
1175         addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1);
1176         mDeviceImpl.createVirtualKeyboard(configWithoutExplicitLayoutInfo, BINDER);
1177         assertWithMessage("Virtual keyboard should register fd when the display matches")
1178                 .that(mInputController.getInputDeviceDescriptors())
1179                 .isNotEmpty();
1180         verify(mNativeWrapperMock).openUinputKeyboard(eq(DEVICE_NAME_1), eq(VENDOR_ID),
1181                 eq(PRODUCT_ID), anyString());
1182         assertThat(mDeviceImpl.getDeviceLocaleList()).isEqualTo(
1183                 LocaleList.forLanguageTags(VirtualKeyboardConfig.DEFAULT_LANGUAGE_TAG));
1184     }
1185 
1186     @Test
virtualDeviceWithoutKeyboard_noLocaleUpdate()1187     public void virtualDeviceWithoutKeyboard_noLocaleUpdate() {
1188         addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1);
1189 
1190         // no preceding call to createVirtualKeyboard()
1191         assertThat(mDeviceImpl.getDeviceLocaleList()).isNull();
1192     }
1193 
1194     @Test
createVirtualMouse_hasDisplay_obtainFileDescriptor()1195     public void createVirtualMouse_hasDisplay_obtainFileDescriptor() {
1196         addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1);
1197         mDeviceImpl.createVirtualMouse(MOUSE_CONFIG, BINDER);
1198         assertWithMessage("Virtual mouse should register fd when the display matches").that(
1199                 mInputController.getInputDeviceDescriptors()).isNotEmpty();
1200         verify(mNativeWrapperMock).openUinputMouse(eq(DEVICE_NAME_1), eq(VENDOR_ID), eq(PRODUCT_ID),
1201                 anyString());
1202     }
1203 
1204     @Test
createVirtualTouchscreen_hasDisplay_obtainFileDescriptor()1205     public void createVirtualTouchscreen_hasDisplay_obtainFileDescriptor() {
1206         addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1);
1207         mDeviceImpl.createVirtualTouchscreen(TOUCHSCREEN_CONFIG, BINDER);
1208         assertWithMessage("Virtual touchscreen should register fd when the display matches").that(
1209                 mInputController.getInputDeviceDescriptors()).isNotEmpty();
1210         verify(mNativeWrapperMock).openUinputTouchscreen(eq(DEVICE_NAME_1), eq(VENDOR_ID),
1211                 eq(PRODUCT_ID), anyString(), eq(HEIGHT), eq(WIDTH));
1212     }
1213 
1214     @Test
createVirtualNavigationTouchpad_hasDisplay_obtainFileDescriptor()1215     public void createVirtualNavigationTouchpad_hasDisplay_obtainFileDescriptor() {
1216         addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1);
1217         mDeviceImpl.createVirtualNavigationTouchpad(NAVIGATION_TOUCHPAD_CONFIG, BINDER);
1218         assertWithMessage("Virtual navigation touchpad should register fd when the display matches")
1219                 .that(
1220                         mInputController.getInputDeviceDescriptors()).isNotEmpty();
1221         verify(mNativeWrapperMock).openUinputTouchscreen(eq(DEVICE_NAME_1), eq(VENDOR_ID),
1222                 eq(PRODUCT_ID), anyString(), eq(HEIGHT), eq(WIDTH));
1223     }
1224 
1225     @Test
createVirtualKeyboard_inputDeviceId_obtainFromInputController()1226     public void createVirtualKeyboard_inputDeviceId_obtainFromInputController() {
1227         final int fd = 1;
1228         mInputController.addDeviceForTesting(BINDER, fd,
1229                 InputController.InputDeviceDescriptor.TYPE_KEYBOARD, DISPLAY_ID_1, PHYS,
1230                 DEVICE_NAME_1, INPUT_DEVICE_ID);
1231         assertWithMessage(
1232                 "InputController should return device id from InputDeviceDescriptor").that(
1233                 mInputController.getInputDeviceId(BINDER)).isEqualTo(INPUT_DEVICE_ID);
1234     }
1235 
1236     @Test
onAudioSessionStarting_hasVirtualAudioController()1237     public void onAudioSessionStarting_hasVirtualAudioController() {
1238         addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1);
1239 
1240         mDeviceImpl.onAudioSessionStarting(DISPLAY_ID_1, mRoutingCallback, mConfigChangedCallback);
1241 
1242         assertThat(mDeviceImpl.getVirtualAudioControllerForTesting()).isNotNull();
1243     }
1244 
1245     @Test
onAudioSessionEnded_noVirtualAudioController()1246     public void onAudioSessionEnded_noVirtualAudioController() {
1247         addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1);
1248         mDeviceImpl.onAudioSessionStarting(DISPLAY_ID_1, mRoutingCallback, mConfigChangedCallback);
1249 
1250         mDeviceImpl.onAudioSessionEnded();
1251 
1252         assertThat(mDeviceImpl.getVirtualAudioControllerForTesting()).isNull();
1253     }
1254 
1255     @Test
close_cleanVirtualAudioController()1256     public void close_cleanVirtualAudioController() {
1257         addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1);
1258         mDeviceImpl.onAudioSessionStarting(DISPLAY_ID_1, mRoutingCallback, mConfigChangedCallback);
1259 
1260         mDeviceImpl.close();
1261 
1262         assertThat(mDeviceImpl.getVirtualAudioControllerForTesting()).isNull();
1263     }
1264 
1265     @Test
close_cleanSensorController()1266     public void close_cleanSensorController() {
1267         mSensorController.addSensorForTesting(
1268                 BINDER, SENSOR_HANDLE, Sensor.TYPE_ACCELEROMETER, DEVICE_NAME_1);
1269 
1270         mDeviceImpl.close();
1271 
1272         assertThat(mSensorController.getSensorDescriptors()).isEmpty();
1273         verify(mSensorManagerInternalMock).removeRuntimeSensor(SENSOR_HANDLE);
1274     }
1275 
1276     @Test
closedDevice_lateCallToRunningAppsChanged_isIgnored()1277     public void closedDevice_lateCallToRunningAppsChanged_isIgnored() {
1278         mLocalService.registerAppsOnVirtualDeviceListener(mAppsOnVirtualDeviceListener);
1279         int deviceId = mDeviceImpl.getDeviceId();
1280         mDeviceImpl.close();
1281         mVdms.notifyRunningAppsChanged(deviceId, Sets.newArraySet(UID_1));
1282         TestableLooper.get(this).processAllMessages();
1283         verify(mAppsOnVirtualDeviceListener, never()).onAppsOnAnyVirtualDeviceChanged(any());
1284     }
1285 
1286     @Test
sendKeyEvent_noFd()1287     public void sendKeyEvent_noFd() {
1288         assertThat(mDeviceImpl.sendKeyEvent(BINDER,
1289                 new VirtualKeyEvent.Builder()
1290                         .setKeyCode(KeyEvent.KEYCODE_A)
1291                         .setAction(VirtualKeyEvent.ACTION_DOWN)
1292                         .build()))
1293                 .isFalse();
1294     }
1295 
1296     @Test
sendKeyEvent_hasFd_writesEvent()1297     public void sendKeyEvent_hasFd_writesEvent() {
1298         final int fd = 1;
1299         final int keyCode = KeyEvent.KEYCODE_A;
1300         final int action = VirtualKeyEvent.ACTION_UP;
1301         final long eventTimeNanos = 5000L;
1302         mInputController.addDeviceForTesting(BINDER, fd,
1303                 InputController.InputDeviceDescriptor.TYPE_KEYBOARD, DISPLAY_ID_1, PHYS,
1304                 DEVICE_NAME_1, INPUT_DEVICE_ID);
1305 
1306         assertThat(mDeviceImpl.sendKeyEvent(BINDER,
1307                 new VirtualKeyEvent.Builder()
1308                         .setKeyCode(keyCode)
1309                         .setAction(action)
1310                         .setEventTimeNanos(eventTimeNanos)
1311                         .build()))
1312                 .isTrue();
1313         verify(mNativeWrapperMock).writeKeyEvent(fd, keyCode, action, eventTimeNanos);
1314     }
1315 
1316     @Test
sendButtonEvent_noFd()1317     public void sendButtonEvent_noFd() {
1318         assertThat(mDeviceImpl.sendButtonEvent(BINDER,
1319                 new VirtualMouseButtonEvent.Builder()
1320                         .setButtonCode(VirtualMouseButtonEvent.BUTTON_BACK)
1321                         .setAction(VirtualMouseButtonEvent.ACTION_BUTTON_PRESS)
1322                         .build()))
1323                 .isFalse();
1324     }
1325 
1326     @Test
sendButtonEvent_hasFd_writesEvent()1327     public void sendButtonEvent_hasFd_writesEvent() {
1328         final int fd = 1;
1329         final int buttonCode = VirtualMouseButtonEvent.BUTTON_BACK;
1330         final int action = VirtualMouseButtonEvent.ACTION_BUTTON_PRESS;
1331         final long eventTimeNanos = 5000L;
1332         mInputController.addDeviceForTesting(BINDER, fd,
1333                 InputController.InputDeviceDescriptor.TYPE_MOUSE, DISPLAY_ID_1, PHYS,
1334                 DEVICE_NAME_1, INPUT_DEVICE_ID);
1335         assertThat(mDeviceImpl.sendButtonEvent(BINDER,
1336                 new VirtualMouseButtonEvent.Builder()
1337                         .setButtonCode(buttonCode)
1338                         .setAction(action)
1339                         .setEventTimeNanos(eventTimeNanos)
1340                         .build()))
1341                 .isTrue();
1342         verify(mNativeWrapperMock).writeButtonEvent(fd, buttonCode, action, eventTimeNanos);
1343     }
1344 
1345     @Test
sendRelativeEvent_noFd()1346     public void sendRelativeEvent_noFd() {
1347         assertThat(mDeviceImpl.sendRelativeEvent(BINDER,
1348                 new VirtualMouseRelativeEvent.Builder()
1349                         .setRelativeX(0.0f)
1350                         .setRelativeY(0.0f)
1351                         .build()))
1352                 .isFalse();
1353     }
1354 
1355     @Test
sendRelativeEvent_hasFd_writesEvent()1356     public void sendRelativeEvent_hasFd_writesEvent() {
1357         final int fd = 1;
1358         final float x = -0.2f;
1359         final float y = 0.7f;
1360         final long eventTimeNanos = 5000L;
1361         mInputController.addDeviceForTesting(BINDER, fd,
1362                 InputController.InputDeviceDescriptor.TYPE_MOUSE, DISPLAY_ID_1, PHYS, DEVICE_NAME_1,
1363                 INPUT_DEVICE_ID);
1364         assertThat(mDeviceImpl.sendRelativeEvent(BINDER,
1365                 new VirtualMouseRelativeEvent.Builder()
1366                         .setRelativeX(x)
1367                         .setRelativeY(y)
1368                         .setEventTimeNanos(eventTimeNanos)
1369                         .build()))
1370                 .isTrue();
1371         verify(mNativeWrapperMock).writeRelativeEvent(fd, x, y, eventTimeNanos);
1372     }
1373 
1374 
1375     @Test
sendScrollEvent_noFd()1376     public void sendScrollEvent_noFd() {
1377         assertThat(mDeviceImpl.sendScrollEvent(BINDER,
1378                 new VirtualMouseScrollEvent.Builder()
1379                         .setXAxisMovement(-1f)
1380                         .setYAxisMovement(1f)
1381                         .build()))
1382                 .isFalse();
1383     }
1384 
1385     @Test
sendScrollEvent_hasFd_writesEvent()1386     public void sendScrollEvent_hasFd_writesEvent() {
1387         final int fd = 1;
1388         final float x = 0.5f;
1389         final float y = 1f;
1390         final long eventTimeNanos = 5000L;
1391         mInputController.addDeviceForTesting(BINDER, fd,
1392                 InputController.InputDeviceDescriptor.TYPE_MOUSE, DISPLAY_ID_1, PHYS, DEVICE_NAME_1,
1393                 INPUT_DEVICE_ID);
1394         assertThat(mDeviceImpl.sendScrollEvent(BINDER,
1395                 new VirtualMouseScrollEvent.Builder()
1396                         .setXAxisMovement(x)
1397                         .setYAxisMovement(y)
1398                         .setEventTimeNanos(eventTimeNanos)
1399                         .build()))
1400                 .isTrue();
1401         verify(mNativeWrapperMock).writeScrollEvent(fd, x, y, eventTimeNanos);
1402     }
1403 
1404 
1405     @Test
sendTouchEvent_noFd()1406     public void sendTouchEvent_noFd() {
1407         assertThat(mDeviceImpl.sendTouchEvent(BINDER,
1408                 new VirtualTouchEvent.Builder()
1409                         .setX(0.0f)
1410                         .setY(0.0f)
1411                         .setAction(VirtualTouchEvent.ACTION_UP)
1412                         .setPointerId(1)
1413                         .setToolType(VirtualTouchEvent.TOOL_TYPE_FINGER)
1414                         .build()))
1415                 .isFalse();
1416     }
1417 
1418     @Test
sendTouchEvent_hasFd_writesEvent_withoutPressureOrMajorAxisSize()1419     public void sendTouchEvent_hasFd_writesEvent_withoutPressureOrMajorAxisSize() {
1420         final int fd = 1;
1421         final int pointerId = 5;
1422         final int toolType = VirtualTouchEvent.TOOL_TYPE_FINGER;
1423         final float x = 100.5f;
1424         final float y = 200.5f;
1425         final int action = VirtualTouchEvent.ACTION_UP;
1426         final long eventTimeNanos = 5000L;
1427         mInputController.addDeviceForTesting(BINDER, fd,
1428                 InputController.InputDeviceDescriptor.TYPE_TOUCHSCREEN, DISPLAY_ID_1, PHYS,
1429                 DEVICE_NAME_1, INPUT_DEVICE_ID);
1430         assertThat(mDeviceImpl.sendTouchEvent(BINDER,
1431                 new VirtualTouchEvent.Builder()
1432                         .setX(x)
1433                         .setY(y)
1434                         .setAction(action)
1435                         .setPointerId(pointerId)
1436                         .setToolType(toolType)
1437                         .setEventTimeNanos(eventTimeNanos)
1438                         .build()))
1439                 .isTrue();
1440         verify(mNativeWrapperMock).writeTouchEvent(fd, pointerId, toolType, action, x, y, Float.NaN,
1441                 Float.NaN, eventTimeNanos);
1442     }
1443 
1444     @Test
sendTouchEvent_hasFd_writesEvent()1445     public void sendTouchEvent_hasFd_writesEvent() {
1446         final int fd = 1;
1447         final int pointerId = 5;
1448         final int toolType = VirtualTouchEvent.TOOL_TYPE_FINGER;
1449         final float x = 100.5f;
1450         final float y = 200.5f;
1451         final int action = VirtualTouchEvent.ACTION_UP;
1452         final float pressure = 1.0f;
1453         final float majorAxisSize = 10.0f;
1454         final long eventTimeNanos = 5000L;
1455         mInputController.addDeviceForTesting(BINDER, fd,
1456                 InputController.InputDeviceDescriptor.TYPE_TOUCHSCREEN, DISPLAY_ID_1, PHYS,
1457                 DEVICE_NAME_1, INPUT_DEVICE_ID);
1458         assertThat(mDeviceImpl.sendTouchEvent(BINDER,
1459                 new VirtualTouchEvent.Builder()
1460                         .setX(x)
1461                         .setY(y)
1462                         .setAction(action)
1463                         .setPointerId(pointerId)
1464                         .setToolType(toolType)
1465                         .setPressure(pressure)
1466                         .setMajorAxisSize(majorAxisSize)
1467                         .setEventTimeNanos(eventTimeNanos)
1468                         .build()))
1469                 .isTrue();
1470         verify(mNativeWrapperMock).writeTouchEvent(fd, pointerId, toolType, action, x, y, pressure,
1471                 majorAxisSize, eventTimeNanos);
1472     }
1473 
1474     @Test
setShowPointerIcon_setsValueForAllDisplays()1475     public void setShowPointerIcon_setsValueForAllDisplays() {
1476         addVirtualDisplay(mDeviceImpl, 1);
1477         addVirtualDisplay(mDeviceImpl, 2);
1478         addVirtualDisplay(mDeviceImpl, 3);
1479         VirtualMouseConfig config1 = new VirtualMouseConfig.Builder()
1480                 .setAssociatedDisplayId(1)
1481                 .setInputDeviceName(DEVICE_NAME_1)
1482                 .setVendorId(VENDOR_ID)
1483                 .setProductId(PRODUCT_ID)
1484                 .build();
1485         VirtualMouseConfig config2 = new VirtualMouseConfig.Builder()
1486                 .setAssociatedDisplayId(2)
1487                 .setInputDeviceName(DEVICE_NAME_2)
1488                 .setVendorId(VENDOR_ID)
1489                 .setProductId(PRODUCT_ID)
1490                 .build();
1491         VirtualMouseConfig config3 = new VirtualMouseConfig.Builder()
1492                 .setAssociatedDisplayId(3)
1493                 .setInputDeviceName(DEVICE_NAME_3)
1494                 .setVendorId(VENDOR_ID)
1495                 .setProductId(PRODUCT_ID)
1496                 .build();
1497 
1498         mDeviceImpl.createVirtualMouse(config1, BINDER);
1499         mDeviceImpl.createVirtualMouse(config2, BINDER);
1500         mDeviceImpl.createVirtualMouse(config3, BINDER);
1501         clearInvocations(mInputManagerInternalMock);
1502         mDeviceImpl.setShowPointerIcon(false);
1503 
1504         verify(mInputManagerInternalMock, times(3)).setPointerIconVisible(eq(false), anyInt());
1505         verify(mInputManagerInternalMock, never()).setPointerIconVisible(eq(true), anyInt());
1506         mDeviceImpl.setShowPointerIcon(true);
1507         verify(mInputManagerInternalMock, times(3)).setPointerIconVisible(eq(true), anyInt());
1508     }
1509 
1510     @Test
openNonBlockedAppOnVirtualDisplay_doesNotStartBlockedAlertActivity()1511     public void openNonBlockedAppOnVirtualDisplay_doesNotStartBlockedAlertActivity() {
1512         addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1);
1513         GenericWindowPolicyController gwpc = mDeviceImpl.getDisplayWindowPolicyControllerForTest(
1514                 DISPLAY_ID_1);
1515         doNothing().when(mContext).startActivityAsUser(any(), any(), any());
1516 
1517         ActivityInfo activityInfo = getActivityInfo(
1518                 NONBLOCKED_APP_PACKAGE_NAME,
1519                 NONBLOCKED_APP_PACKAGE_NAME,
1520                 /* displayOnRemoteDevices */ true,
1521                 /* targetDisplayCategory */ null);
1522         Intent blockedAppIntent = BlockedAppStreamingActivity.createIntent(
1523                 activityInfo, mAssociationInfo.getDisplayName());
1524         gwpc.canActivityBeLaunched(activityInfo, blockedAppIntent,
1525                 WindowConfiguration.WINDOWING_MODE_FULLSCREEN, DISPLAY_ID_1, /*isNewTask=*/false);
1526 
1527         verify(mContext, never()).startActivityAsUser(argThat(intent ->
1528                 intent.filterEquals(blockedAppIntent)), any(), any());
1529     }
1530 
1531     @Test
openPermissionControllerOnVirtualDisplay_startBlockedAlertActivity()1532     public void openPermissionControllerOnVirtualDisplay_startBlockedAlertActivity() {
1533         addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1);
1534         GenericWindowPolicyController gwpc = mDeviceImpl.getDisplayWindowPolicyControllerForTest(
1535                 DISPLAY_ID_1);
1536         doNothing().when(mContext).startActivityAsUser(any(), any(), any());
1537 
1538         ActivityInfo activityInfo = getActivityInfo(
1539                 PERMISSION_CONTROLLER_PACKAGE_NAME,
1540                 PERMISSION_CONTROLLER_PACKAGE_NAME,
1541                 /* displayOnRemoteDevices */  false,
1542                 /* targetDisplayCategory */ null);
1543         Intent blockedAppIntent = BlockedAppStreamingActivity.createIntent(
1544                 activityInfo, mAssociationInfo.getDisplayName());
1545         gwpc.canActivityBeLaunched(activityInfo, blockedAppIntent,
1546                 WindowConfiguration.WINDOWING_MODE_FULLSCREEN, DISPLAY_ID_1, /*isNewTask=*/false);
1547 
1548         verify(mContext).startActivityAsUser(argThat(intent ->
1549                 intent.filterEquals(blockedAppIntent)), any(), any());
1550     }
1551 
1552     @Test
openPermissionControllerOnVirtualDisplay_displayOnRemoteDevices_startsWhenFlagIsEnabled()1553     public void openPermissionControllerOnVirtualDisplay_displayOnRemoteDevices_startsWhenFlagIsEnabled() {
1554         mSetFlagsRule.enableFlags(Flags.FLAG_STREAM_PERMISSIONS);
1555         addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1);
1556         GenericWindowPolicyController gwpc = mDeviceImpl.getDisplayWindowPolicyControllerForTest(
1557                 DISPLAY_ID_1);
1558         doNothing().when(mContext).startActivityAsUser(any(), any(), any());
1559 
1560         ActivityInfo activityInfo = getActivityInfo(
1561                 PERMISSION_CONTROLLER_PACKAGE_NAME,
1562                 PERMISSION_CONTROLLER_PACKAGE_NAME,
1563                 /* displayOnRemoveDevices */ true,
1564                 /* targetDisplayCategory */ null);
1565         Intent blockedAppIntent = BlockedAppStreamingActivity.createIntent(
1566                 activityInfo, mAssociationInfo.getDisplayName());
1567         gwpc.canActivityBeLaunched(activityInfo, blockedAppIntent,
1568                 WindowConfiguration.WINDOWING_MODE_FULLSCREEN, DISPLAY_ID_1, /*isNewTask=*/false);
1569 
1570         verify(mContext, never()).startActivityAsUser(argThat(intent ->
1571                 intent.filterEquals(blockedAppIntent)), any(), any());
1572     }
1573 
1574     @Test
openPermissionControllerOnVirtualDisplay_dontDisplayOnRemoteDevices_startsWhenFlagIsEnabled()1575     public void openPermissionControllerOnVirtualDisplay_dontDisplayOnRemoteDevices_startsWhenFlagIsEnabled() {
1576         mSetFlagsRule.enableFlags(Flags.FLAG_STREAM_PERMISSIONS);
1577         addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1);
1578         GenericWindowPolicyController gwpc = mDeviceImpl.getDisplayWindowPolicyControllerForTest(
1579                 DISPLAY_ID_1);
1580         doNothing().when(mContext).startActivityAsUser(any(), any(), any());
1581 
1582         ActivityInfo activityInfo = getActivityInfo(
1583                 PERMISSION_CONTROLLER_PACKAGE_NAME,
1584                 PERMISSION_CONTROLLER_PACKAGE_NAME,
1585                 /* displayOnRemoveDevices */ false,
1586                 /* targetDisplayCategory */ null);
1587         Intent blockedAppIntent = BlockedAppStreamingActivity.createIntent(
1588                 activityInfo, mAssociationInfo.getDisplayName());
1589         gwpc.canActivityBeLaunched(activityInfo, blockedAppIntent,
1590                 WindowConfiguration.WINDOWING_MODE_FULLSCREEN, DISPLAY_ID_1, /*isNewTask=*/false);
1591 
1592         verify(mContext).startActivityAsUser(argThat(intent ->
1593                 intent.filterEquals(blockedAppIntent)), any(), any());
1594     }
1595 
1596     @Test
openSettingsOnVirtualDisplay_startBlockedAlertActivity()1597     public void openSettingsOnVirtualDisplay_startBlockedAlertActivity() {
1598         addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1);
1599         GenericWindowPolicyController gwpc = mDeviceImpl.getDisplayWindowPolicyControllerForTest(
1600                 DISPLAY_ID_1);
1601         doNothing().when(mContext).startActivityAsUser(any(), any(), any());
1602 
1603         ActivityInfo activityInfo = getActivityInfo(
1604                 SETTINGS_PACKAGE_NAME,
1605                 SETTINGS_PACKAGE_NAME,
1606                 /* displayOnRemoteDevices */ true,
1607                 /* targetDisplayCategory */ null);
1608         Intent blockedAppIntent = BlockedAppStreamingActivity.createIntent(
1609                 activityInfo, mAssociationInfo.getDisplayName());
1610         gwpc.canActivityBeLaunched(activityInfo, blockedAppIntent,
1611                 WindowConfiguration.WINDOWING_MODE_FULLSCREEN, DISPLAY_ID_1, /*isNewTask=*/false);
1612 
1613         verify(mContext).startActivityAsUser(argThat(intent ->
1614                 intent.filterEquals(blockedAppIntent)), any(), any());
1615     }
1616 
1617     @Test
openVendingOnVirtualDisplay_startBlockedAlertActivity()1618     public void openVendingOnVirtualDisplay_startBlockedAlertActivity() {
1619         addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1);
1620         GenericWindowPolicyController gwpc = mDeviceImpl.getDisplayWindowPolicyControllerForTest(
1621                 DISPLAY_ID_1);
1622         doNothing().when(mContext).startActivityAsUser(any(), any(), any());
1623 
1624         ActivityInfo activityInfo = getActivityInfo(
1625                 VENDING_PACKAGE_NAME,
1626                 VENDING_PACKAGE_NAME,
1627                 /* displayOnRemoteDevices */ true,
1628                 /* targetDisplayCategory */ null);
1629         Intent blockedAppIntent = BlockedAppStreamingActivity.createIntent(
1630                 activityInfo, mAssociationInfo.getDisplayName());
1631         gwpc.canActivityBeLaunched(activityInfo, blockedAppIntent,
1632                 WindowConfiguration.WINDOWING_MODE_FULLSCREEN, DISPLAY_ID_1, /*isNewTask=*/false);
1633 
1634         verify(mContext).startActivityAsUser(argThat(intent ->
1635                 intent.filterEquals(blockedAppIntent)), any(), any());
1636     }
1637 
1638     @Test
openGoogleDialerOnVirtualDisplay_startBlockedAlertActivity()1639     public void openGoogleDialerOnVirtualDisplay_startBlockedAlertActivity() {
1640         addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1);
1641         GenericWindowPolicyController gwpc = mDeviceImpl.getDisplayWindowPolicyControllerForTest(
1642                 DISPLAY_ID_1);
1643         doNothing().when(mContext).startActivityAsUser(any(), any(), any());
1644 
1645         ActivityInfo activityInfo = getActivityInfo(
1646                 GOOGLE_DIALER_PACKAGE_NAME,
1647                 GOOGLE_DIALER_PACKAGE_NAME,
1648                 /* displayOnRemoteDevices */ true,
1649                 /* targetDisplayCategory */ null);
1650         Intent blockedAppIntent = BlockedAppStreamingActivity.createIntent(
1651                 activityInfo, mAssociationInfo.getDisplayName());
1652         gwpc.canActivityBeLaunched(activityInfo, blockedAppIntent,
1653                 WindowConfiguration.WINDOWING_MODE_FULLSCREEN, DISPLAY_ID_1, /*isNewTask=*/false);
1654 
1655         verify(mContext).startActivityAsUser(argThat(intent ->
1656                 intent.filterEquals(blockedAppIntent)), any(), any());
1657     }
1658 
1659     @Test
openGoogleMapsOnVirtualDisplay_startBlockedAlertActivity()1660     public void openGoogleMapsOnVirtualDisplay_startBlockedAlertActivity() {
1661         addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1);
1662         GenericWindowPolicyController gwpc = mDeviceImpl.getDisplayWindowPolicyControllerForTest(
1663                 DISPLAY_ID_1);
1664         doNothing().when(mContext).startActivityAsUser(any(), any(), any());
1665 
1666         ActivityInfo activityInfo = getActivityInfo(
1667                 GOOGLE_MAPS_PACKAGE_NAME,
1668                 GOOGLE_MAPS_PACKAGE_NAME,
1669                 /* displayOnRemoteDevices */ true,
1670                 /* targetDisplayCategory */ null);
1671         Intent blockedAppIntent = BlockedAppStreamingActivity.createIntent(
1672                 activityInfo, mAssociationInfo.getDisplayName());
1673         gwpc.canActivityBeLaunched(activityInfo, blockedAppIntent,
1674                 WindowConfiguration.WINDOWING_MODE_FULLSCREEN, DISPLAY_ID_1, /*isNewTask=*/false);
1675 
1676         verify(mContext).startActivityAsUser(argThat(intent ->
1677                 intent.filterEquals(blockedAppIntent)), any(), any());
1678     }
1679 
1680     @Test
openNonBlockedAppOnMirrorDisplay_flagEnabled_cannotBeLaunched()1681     public void openNonBlockedAppOnMirrorDisplay_flagEnabled_cannotBeLaunched() {
1682         mSetFlagsRule.enableFlags(Flags.FLAG_INTERACTIVE_SCREEN_MIRROR);
1683         when(mDisplayManagerInternalMock.getDisplayIdToMirror(anyInt()))
1684                 .thenReturn(Display.DEFAULT_DISPLAY);
1685         addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1);
1686         GenericWindowPolicyController gwpc = mDeviceImpl.getDisplayWindowPolicyControllerForTest(
1687                 DISPLAY_ID_1);
1688         doNothing().when(mContext).startActivityAsUser(any(), any(), any());
1689 
1690         ActivityInfo activityInfo = getActivityInfo(
1691                 NONBLOCKED_APP_PACKAGE_NAME,
1692                 NONBLOCKED_APP_PACKAGE_NAME,
1693                 /* displayOnRemoteDevices */ true,
1694                 /* targetDisplayCategory */ null);
1695         assertThat(gwpc.canActivityBeLaunched(activityInfo, null,
1696                 WindowConfiguration.WINDOWING_MODE_FULLSCREEN, DISPLAY_ID_1, /*isNewTask=*/ false))
1697                 .isFalse();
1698         // Verify that BlockedAppStreamingActivity also doesn't launch for mirror displays.
1699         Intent blockedAppIntent = BlockedAppStreamingActivity.createIntent(
1700                 activityInfo, mAssociationInfo.getDisplayName());
1701         verify(mContext, never()).startActivityAsUser(argThat(intent ->
1702                 intent.filterEquals(blockedAppIntent)), any(), any());
1703     }
1704 
1705     @Test
openNonBlockedAppOnMirrorDisplay_flagDisabled_launchesActivity()1706     public void openNonBlockedAppOnMirrorDisplay_flagDisabled_launchesActivity() {
1707         mSetFlagsRule.disableFlags(Flags.FLAG_INTERACTIVE_SCREEN_MIRROR);
1708         when(mDisplayManagerInternalMock.getDisplayIdToMirror(anyInt()))
1709                 .thenReturn(Display.DEFAULT_DISPLAY);
1710         addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1);
1711         GenericWindowPolicyController gwpc = mDeviceImpl.getDisplayWindowPolicyControllerForTest(
1712                 DISPLAY_ID_1);
1713         doNothing().when(mContext).startActivityAsUser(any(), any(), any());
1714 
1715         ActivityInfo activityInfo = getActivityInfo(
1716                 NONBLOCKED_APP_PACKAGE_NAME,
1717                 NONBLOCKED_APP_PACKAGE_NAME,
1718                 /* displayOnRemoteDevices */ true,
1719                 /* targetDisplayCategory */ null);
1720         assertThat(gwpc.canActivityBeLaunched(activityInfo, null,
1721                 WindowConfiguration.WINDOWING_MODE_FULLSCREEN, DISPLAY_ID_1, /*isNewTask=*/ false))
1722                 .isTrue();
1723         Intent blockedAppIntent = BlockedAppStreamingActivity.createIntent(
1724                 activityInfo, mAssociationInfo.getDisplayName());
1725         verify(mContext, never()).startActivityAsUser(argThat(intent ->
1726                 intent.filterEquals(blockedAppIntent)), any(), any());
1727     }
1728 
1729     @Test
registerRunningAppsChangedListener_onRunningAppsChanged_listenersNotified()1730     public void registerRunningAppsChangedListener_onRunningAppsChanged_listenersNotified() {
1731         ArraySet<Integer> uids = new ArraySet<>(Arrays.asList(UID_1, UID_2));
1732         addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1);
1733         GenericWindowPolicyController gwpc = mDeviceImpl.getDisplayWindowPolicyControllerForTest(
1734                 DISPLAY_ID_1);
1735 
1736         gwpc.onRunningAppsChanged(uids);
1737         mDeviceImpl.onRunningAppsChanged(uids);
1738 
1739         assertThat(gwpc.getRunningAppsChangedListenersSizeForTesting()).isEqualTo(1);
1740         verify(mRunningAppsChangedCallback).accept(new ArraySet<>(Arrays.asList(UID_1, UID_2)));
1741     }
1742 
1743     @Test
noRunningAppsChangedListener_onRunningAppsChanged_doesNotThrowException()1744     public void noRunningAppsChangedListener_onRunningAppsChanged_doesNotThrowException() {
1745         ArraySet<Integer> uids = new ArraySet<>(Arrays.asList(UID_1, UID_2));
1746         addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1);
1747         GenericWindowPolicyController gwpc = mDeviceImpl.getDisplayWindowPolicyControllerForTest(
1748                 DISPLAY_ID_1);
1749         gwpc.unregisterRunningAppsChangedListener(mDeviceImpl);
1750 
1751         // This call should not throw any exceptions.
1752         gwpc.onRunningAppsChanged(uids);
1753 
1754         assertThat(gwpc.getRunningAppsChangedListenersSizeForTesting()).isEqualTo(0);
1755     }
1756 
1757     @Test
canActivityBeLaunched_permissionDialog_flagDisabled_isBlocked()1758     public void canActivityBeLaunched_permissionDialog_flagDisabled_isBlocked() {
1759         mSetFlagsRule.disableFlags(Flags.FLAG_STREAM_PERMISSIONS);
1760         VirtualDeviceParams params = new VirtualDeviceParams.Builder().build();
1761         mDeviceImpl.close();
1762         mDeviceImpl = createVirtualDevice(VIRTUAL_DEVICE_ID_1, DEVICE_OWNER_UID_1, params);
1763         doNothing().when(mContext).startActivityAsUser(any(), any(), any());
1764 
1765         addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1);
1766         GenericWindowPolicyController gwpc = mDeviceImpl.getDisplayWindowPolicyControllerForTest(
1767                 DISPLAY_ID_1);
1768         ComponentName permissionComponent = getPermissionDialogComponent();
1769         ActivityInfo activityInfo = getActivityInfo(
1770                 permissionComponent.getPackageName(),
1771                 permissionComponent.getClassName(),
1772                 /* displayOnRemoteDevices */ true,
1773                 /* targetDisplayCategory */ null);
1774         assertThat(gwpc.canActivityBeLaunched(activityInfo, null,
1775                 WindowConfiguration.WINDOWING_MODE_FULLSCREEN, DISPLAY_ID_1, /*isNewTask=*/false))
1776                 .isFalse();
1777 
1778         Intent blockedAppIntent = BlockedAppStreamingActivity.createIntent(
1779                 activityInfo, mAssociationInfo.getDisplayName());
1780         verify(mContext).startActivityAsUser(argThat(intent ->
1781                 intent.filterEquals(blockedAppIntent)), any(), any());
1782     }
1783 
1784     @Test
canActivityBeLaunched_permissionDialog_flagEnabled_isStreamed()1785     public void canActivityBeLaunched_permissionDialog_flagEnabled_isStreamed() {
1786         mSetFlagsRule.enableFlags(Flags.FLAG_STREAM_PERMISSIONS);
1787         VirtualDeviceParams params = new VirtualDeviceParams.Builder().build();
1788         mDeviceImpl.close();
1789         mDeviceImpl = createVirtualDevice(VIRTUAL_DEVICE_ID_1, DEVICE_OWNER_UID_1, params);
1790 
1791         addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1);
1792         GenericWindowPolicyController gwpc = mDeviceImpl.getDisplayWindowPolicyControllerForTest(
1793                 DISPLAY_ID_1);
1794         ComponentName permissionComponent = getPermissionDialogComponent();
1795         ActivityInfo activityInfo = getActivityInfo(
1796                 permissionComponent.getPackageName(),
1797                 permissionComponent.getClassName(),
1798                 /* displayOnRemoteDevices */ true,
1799                 /* targetDisplayCategory */ null);
1800         assertThat(gwpc.canActivityBeLaunched(activityInfo, null,
1801                 WindowConfiguration.WINDOWING_MODE_FULLSCREEN, DISPLAY_ID_1, /*isNewTask=*/false))
1802                 .isTrue();
1803     }
1804 
1805     @Test
canActivityBeLaunched_activityCanLaunch()1806     public void canActivityBeLaunched_activityCanLaunch() {
1807         Intent intent = new Intent(ACTION_VIEW, Uri.parse(TEST_SITE));
1808         addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1);
1809         GenericWindowPolicyController gwpc = mDeviceImpl.getDisplayWindowPolicyControllerForTest(
1810                 DISPLAY_ID_1);
1811         ActivityInfo activityInfo = getActivityInfo(
1812                 NONBLOCKED_APP_PACKAGE_NAME,
1813                 NONBLOCKED_APP_PACKAGE_NAME,
1814                 /* displayOnRemoteDevices */ true,
1815                 /* targetDisplayCategory */ null);
1816         assertThat(gwpc.canActivityBeLaunched(activityInfo, intent,
1817                 WindowConfiguration.WINDOWING_MODE_FULLSCREEN, DISPLAY_ID_1, /*isNewTask=*/false))
1818                 .isTrue();
1819     }
1820 
1821     @Test
canActivityBeLaunched_intentInterceptedWhenRegistered_activityNoLaunch()1822     public void canActivityBeLaunched_intentInterceptedWhenRegistered_activityNoLaunch()
1823             throws RemoteException {
1824         Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(TEST_SITE));
1825 
1826         IVirtualDeviceIntentInterceptor.Stub interceptor =
1827                 mock(IVirtualDeviceIntentInterceptor.Stub.class);
1828         doNothing().when(interceptor).onIntentIntercepted(any());
1829         doReturn(interceptor).when(interceptor).asBinder();
1830         doReturn(interceptor).when(interceptor).queryLocalInterface(anyString());
1831 
1832         addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1);
1833         GenericWindowPolicyController gwpc = mDeviceImpl.getDisplayWindowPolicyControllerForTest(
1834                 DISPLAY_ID_1);
1835         ActivityInfo activityInfo = getActivityInfo(
1836                 NONBLOCKED_APP_PACKAGE_NAME,
1837                 NONBLOCKED_APP_PACKAGE_NAME,
1838                 /* displayOnRemoteDevices */ true,
1839                 /* targetDisplayCategory */ null);
1840 
1841         IntentFilter intentFilter = new IntentFilter(Intent.ACTION_VIEW);
1842         intentFilter.addDataScheme(IntentFilter.SCHEME_HTTP);
1843         intentFilter.addDataScheme(IntentFilter.SCHEME_HTTPS);
1844 
1845         // register interceptor and intercept intent
1846         mDeviceImpl.registerIntentInterceptor(interceptor, intentFilter);
1847         assertThat(gwpc.canActivityBeLaunched(activityInfo, intent,
1848                 WindowConfiguration.WINDOWING_MODE_FULLSCREEN, DISPLAY_ID_1, /*isNewTask=*/false))
1849                 .isFalse();
1850         ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
1851         verify(interceptor).onIntentIntercepted(intentCaptor.capture());
1852         Intent cIntent = intentCaptor.getValue();
1853         assertThat(cIntent).isNotNull();
1854         assertThat(cIntent.getAction()).isEqualTo(Intent.ACTION_VIEW);
1855         assertThat(cIntent.getData().toString()).isEqualTo(TEST_SITE);
1856 
1857         // unregister interceptor and launch activity
1858         mDeviceImpl.unregisterIntentInterceptor(interceptor);
1859         assertThat(gwpc.canActivityBeLaunched(activityInfo, intent,
1860                 WindowConfiguration.WINDOWING_MODE_FULLSCREEN, DISPLAY_ID_1, /*isNewTask=*/false))
1861                 .isTrue();
1862     }
1863 
1864     @Test
canActivityBeLaunched_noMatchIntentFilter_activityLaunches()1865     public void canActivityBeLaunched_noMatchIntentFilter_activityLaunches()
1866             throws RemoteException {
1867         Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("testing"));
1868 
1869         IVirtualDeviceIntentInterceptor.Stub interceptor =
1870                 mock(IVirtualDeviceIntentInterceptor.Stub.class);
1871         doNothing().when(interceptor).onIntentIntercepted(any());
1872         doReturn(interceptor).when(interceptor).asBinder();
1873         doReturn(interceptor).when(interceptor).queryLocalInterface(anyString());
1874 
1875         addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1);
1876         GenericWindowPolicyController gwpc = mDeviceImpl.getDisplayWindowPolicyControllerForTest(
1877                 DISPLAY_ID_1);
1878         ActivityInfo activityInfo = getActivityInfo(
1879                 NONBLOCKED_APP_PACKAGE_NAME,
1880                 NONBLOCKED_APP_PACKAGE_NAME,
1881                 /* displayOnRemoteDevices */ true,
1882                 /* targetDisplayCategory */ null);
1883 
1884         IntentFilter intentFilter = new IntentFilter(Intent.ACTION_VIEW);
1885         intentFilter.addDataScheme("mailto");
1886 
1887         // register interceptor with different filter
1888         mDeviceImpl.registerIntentInterceptor(interceptor, intentFilter);
1889 
1890         assertThat(gwpc.canActivityBeLaunched(activityInfo, intent,
1891                 WindowConfiguration.WINDOWING_MODE_FULLSCREEN, DISPLAY_ID_1, /*isNewTask=*/false))
1892                 .isTrue();
1893     }
1894 
1895     @Test
nonRestrictedActivityOnRestrictedVirtualDisplay_startBlockedAlertActivity()1896     public void nonRestrictedActivityOnRestrictedVirtualDisplay_startBlockedAlertActivity() {
1897         Intent blockedAppIntent = createRestrictedActivityBlockedIntent(Set.of("abc"),
1898                 /* targetDisplayCategory= */ null);
1899         verify(mContext).startActivityAsUser(argThat(intent ->
1900                 intent.filterEquals(blockedAppIntent)), any(), any());
1901     }
1902 
1903     @Test
restrictedActivityOnRestrictedVirtualDisplay_doesNotStartBlockedAlertActivity()1904     public void restrictedActivityOnRestrictedVirtualDisplay_doesNotStartBlockedAlertActivity() {
1905         Intent blockedAppIntent = createRestrictedActivityBlockedIntent(Set.of("abc"), "abc");
1906         verify(mContext, never()).startActivityAsUser(argThat(intent ->
1907                 intent.filterEquals(blockedAppIntent)), any(), any());
1908     }
1909 
1910     @Test
restrictedActivityOnNonRestrictedVirtualDisplay_startBlockedAlertActivity()1911     public void restrictedActivityOnNonRestrictedVirtualDisplay_startBlockedAlertActivity() {
1912         Intent blockedAppIntent = createRestrictedActivityBlockedIntent(
1913                 /* displayCategories= */ Set.of(), "abc");
1914         verify(mContext).startActivityAsUser(argThat(intent ->
1915                 intent.filterEquals(blockedAppIntent)), any(), any());
1916     }
1917 
1918     @Test
restrictedActivityNonMatchingRestrictedVirtualDisplay_startBlockedAlertActivity()1919     public void restrictedActivityNonMatchingRestrictedVirtualDisplay_startBlockedAlertActivity() {
1920         Intent blockedAppIntent = createRestrictedActivityBlockedIntent(Set.of("abc"), "def");
1921         verify(mContext).startActivityAsUser(argThat(intent ->
1922                 intent.filterEquals(blockedAppIntent)), any(), any());
1923     }
1924 
1925     @Test
playSoundEffect_callsSoundEffectListener()1926     public void playSoundEffect_callsSoundEffectListener() throws Exception {
1927         mVdm.playSoundEffect(mDeviceImpl.getDeviceId(), AudioManager.FX_KEY_CLICK);
1928 
1929         verify(mSoundEffectListener).onPlaySoundEffect(AudioManager.FX_KEY_CLICK);
1930     }
1931 
1932     @Test
getDisplayIdsForDevice_invalidDeviceId_emptyResult()1933     public void getDisplayIdsForDevice_invalidDeviceId_emptyResult() {
1934         ArraySet<Integer> displayIds = mLocalService.getDisplayIdsForDevice(VIRTUAL_DEVICE_ID_2);
1935         assertThat(displayIds).isEmpty();
1936     }
1937 
1938     @Test
getDisplayIdsForDevice_noDisplays_emptyResult()1939     public void getDisplayIdsForDevice_noDisplays_emptyResult() {
1940         ArraySet<Integer> displayIds = mLocalService.getDisplayIdsForDevice(VIRTUAL_DEVICE_ID_1);
1941         assertThat(displayIds).isEmpty();
1942     }
1943 
1944     @Test
getDisplayIdsForDevice_oneDisplay_resultContainsCorrectDisplayId()1945     public void getDisplayIdsForDevice_oneDisplay_resultContainsCorrectDisplayId() {
1946         addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1);
1947         ArraySet<Integer> displayIds = mLocalService.getDisplayIdsForDevice(VIRTUAL_DEVICE_ID_1);
1948         assertThat(displayIds).containsExactly(DISPLAY_ID_1);
1949     }
1950 
1951     @Test
getDisplayIdsForDevice_twoDisplays_resultContainsCorrectDisplayIds()1952     public void getDisplayIdsForDevice_twoDisplays_resultContainsCorrectDisplayIds() {
1953         addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1);
1954         addVirtualDisplay(mDeviceImpl, DISPLAY_ID_2);
1955         ArraySet<Integer> displayIds = mLocalService.getDisplayIdsForDevice(VIRTUAL_DEVICE_ID_1);
1956         assertThat(displayIds).containsExactly(DISPLAY_ID_1, DISPLAY_ID_2);
1957     }
1958 
1959     @Test
getPersistentIdForDevice_invalidDeviceId_returnsNull()1960     public void getPersistentIdForDevice_invalidDeviceId_returnsNull() {
1961         assertThat(mLocalService.getPersistentIdForDevice(DEVICE_ID_INVALID)).isNull();
1962         assertThat(mLocalService.getPersistentIdForDevice(VIRTUAL_DEVICE_ID_2)).isNull();
1963     }
1964 
1965     @Test
getPersistentIdForDevice_defaultDeviceId()1966     public void getPersistentIdForDevice_defaultDeviceId() {
1967         assertThat(mLocalService.getPersistentIdForDevice(DEVICE_ID_DEFAULT)).isEqualTo(
1968                 VirtualDeviceManager.PERSISTENT_DEVICE_ID_DEFAULT);
1969     }
1970 
1971     @Test
getPersistentIdForDevice_returnsCorrectId()1972     public void getPersistentIdForDevice_returnsCorrectId() {
1973         assertThat(mLocalService.getPersistentIdForDevice(VIRTUAL_DEVICE_ID_1))
1974                 .isEqualTo(mDeviceImpl.getPersistentDeviceId());
1975     }
1976 
createVirtualDevice(int virtualDeviceId, int ownerUid)1977     private VirtualDeviceImpl createVirtualDevice(int virtualDeviceId, int ownerUid) {
1978         VirtualDeviceParams params = new VirtualDeviceParams.Builder()
1979                 .setBlockedActivities(getBlockedActivities())
1980                 .build();
1981         return createVirtualDevice(virtualDeviceId, ownerUid, params);
1982     }
1983 
createVirtualDevice(int virtualDeviceId, int ownerUid, VirtualDeviceParams params)1984     private VirtualDeviceImpl createVirtualDevice(int virtualDeviceId, int ownerUid,
1985             VirtualDeviceParams params) {
1986         VirtualDeviceImpl virtualDeviceImpl =
1987                 new VirtualDeviceImpl(
1988                         mContext,
1989                         mAssociationInfo,
1990                         mVdms,
1991                         mVirtualDeviceLog,
1992                         new Binder(),
1993                         new AttributionSource(
1994                                 ownerUid, "com.android.virtualdevice.test", "virtualdevice"),
1995                         virtualDeviceId,
1996                         mInputController,
1997                         mCameraAccessController,
1998                         mPendingTrampolineCallback,
1999                         mActivityListener,
2000                         mSoundEffectListener,
2001                         mRunningAppsChangedCallback,
2002                         params,
2003                         new DisplayManagerGlobal(mIDisplayManager),
2004                         new VirtualCameraController(DEVICE_POLICY_DEFAULT, virtualDeviceId));
2005         mVdms.addVirtualDevice(virtualDeviceImpl);
2006         assertThat(virtualDeviceImpl.getAssociationId()).isEqualTo(mAssociationInfo.getId());
2007         assertThat(virtualDeviceImpl.getPersistentDeviceId())
2008                 .isEqualTo("companion:" + mAssociationInfo.getId());
2009         return virtualDeviceImpl;
2010     }
2011 
addVirtualDisplay(VirtualDeviceImpl virtualDevice, int displayId)2012     private void addVirtualDisplay(VirtualDeviceImpl virtualDevice, int displayId) {
2013         when(mDisplayManagerInternalMock.createVirtualDisplay(any(), eq(mVirtualDisplayCallback),
2014                 eq(virtualDevice), any(), any())).thenReturn(displayId);
2015         virtualDevice.createVirtualDisplay(VIRTUAL_DISPLAY_CONFIG, mVirtualDisplayCallback,
2016                 NONBLOCKED_APP_PACKAGE_NAME);
2017         final String uniqueId = UNIQUE_ID + displayId;
2018         doAnswer(inv -> {
2019             final DisplayInfo displayInfo = new DisplayInfo();
2020             displayInfo.uniqueId = uniqueId;
2021             return displayInfo;
2022         }).when(mDisplayManagerInternalMock).getDisplayInfo(eq(displayId));
2023         mInputManagerMockHelper.addDisplayIdMapping(uniqueId, displayId);
2024     }
2025 
getPermissionDialogComponent()2026     private ComponentName getPermissionDialogComponent() {
2027         Intent intent = new Intent(ACTION_REQUEST_PERMISSIONS);
2028         PackageManager packageManager = mContext.getPackageManager();
2029         intent.setPackage(packageManager.getPermissionControllerPackageName());
2030         return intent.resolveActivity(packageManager);
2031     }
2032 
createAssociationInfo(int associationId, String deviceProfile)2033     private AssociationInfo createAssociationInfo(int associationId, String deviceProfile) {
2034         return createAssociationInfo(
2035                 associationId, deviceProfile, /* displayName= */ deviceProfile);
2036     }
2037 
createAssociationInfo(int associationId, String deviceProfile, CharSequence displayName)2038     private AssociationInfo createAssociationInfo(int associationId, String deviceProfile,
2039             CharSequence displayName) {
2040         return new AssociationInfo(associationId, /* userId= */ 0, /* packageName=*/ null,
2041                 /* tag= */ null, MacAddress.BROADCAST_ADDRESS, displayName, deviceProfile,
2042                 /* associatedDevice= */ null, /* selfManaged= */ true,
2043                 /* notifyOnDeviceNearby= */ false, /* revoked= */ false, /* pending= */ false,
2044                 /* timeApprovedMs= */0, /* lastTimeConnectedMs= */0, /* systemDataSyncFlags= */ -1);
2045     }
2046 
2047     /** Helper class to drop permissions temporarily and restore them at the end of a test. */
2048     static final class DropShellPermissionsTemporarily implements AutoCloseable {
DropShellPermissionsTemporarily()2049         DropShellPermissionsTemporarily() {
2050             InstrumentationRegistry.getInstrumentation().getUiAutomation()
2051                     .dropShellPermissionIdentity();
2052         }
2053 
2054         @Override
close()2055         public void close() {
2056             InstrumentationRegistry.getInstrumentation().getUiAutomation()
2057                     .adoptShellPermissionIdentity();
2058         }
2059     }
2060 }
2061