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