1 package org.robolectric.shadows;
2 
3 import static android.os.Build.VERSION_CODES.M;
4 import static android.os.Build.VERSION_CODES.N;
5 import static android.os.Build.VERSION_CODES.N_MR1;
6 import static android.os.Build.VERSION_CODES.O;
7 import static android.os.Build.VERSION_CODES.P;
8 import static android.os.Build.VERSION_CODES.Q;
9 import static com.google.common.truth.Truth.assertThat;
10 import static org.mockito.Mockito.when;
11 import static org.robolectric.Shadows.shadowOf;
12 import static org.robolectric.util.ReflectionHelpers.getStaticField;
13 import static org.robolectric.util.reflector.Reflector.reflector;
14 
15 import android.app.Activity;
16 import android.content.Context;
17 import android.hardware.usb.UsbAccessory;
18 import android.hardware.usb.UsbDevice;
19 import android.hardware.usb.UsbDeviceConnection;
20 import android.hardware.usb.UsbManager;
21 import android.hardware.usb.UsbPort;
22 import android.hardware.usb.UsbPortStatus;
23 import android.os.Build;
24 import android.os.ParcelFileDescriptor;
25 import androidx.test.core.app.ApplicationProvider;
26 import androidx.test.ext.junit.runners.AndroidJUnit4;
27 import java.util.Arrays;
28 import java.util.HashMap;
29 import java.util.List;
30 import java.util.stream.Collectors;
31 import org.junit.Before;
32 import org.junit.Test;
33 import org.junit.runner.RunWith;
34 import org.mockito.Mock;
35 import org.mockito.MockitoAnnotations;
36 import org.robolectric.Robolectric;
37 import org.robolectric.RuntimeEnvironment;
38 import org.robolectric.annotation.Config;
39 import org.robolectric.shadows.ShadowUsbManager._UsbManagerQ_;
40 import org.robolectric.shadows.ShadowUsbManager._UsbManager_;
41 
42 /** Unit tests for {@link ShadowUsbManager}. */
43 @RunWith(AndroidJUnit4.class)
44 public class ShadowUsbManagerTest {
45   private static final String DEVICE_NAME_1 = "usb1";
46   private static final String DEVICE_NAME_2 = "usb2";
47 
48   private UsbManager usbManager;
49 
50   @Mock UsbDevice usbDevice1;
51   @Mock UsbDevice usbDevice2;
52   @Mock UsbAccessory usbAccessory;
53 
54   @Before
setUp()55   public void setUp() {
56     MockitoAnnotations.initMocks(this);
57     usbManager =
58         (UsbManager)
59             ApplicationProvider.getApplicationContext().getSystemService(Context.USB_SERVICE);
60 
61     when(usbDevice1.getDeviceName()).thenReturn(DEVICE_NAME_1);
62     when(usbDevice2.getDeviceName()).thenReturn(DEVICE_NAME_2);
63   }
64 
65   @Test
getDeviceList()66   public void getDeviceList() {
67     assertThat(usbManager.getDeviceList()).isEmpty();
68     shadowOf(usbManager).addOrUpdateUsbDevice(usbDevice1, true);
69     shadowOf(usbManager).addOrUpdateUsbDevice(usbDevice2, true);
70     assertThat(usbManager.getDeviceList().values()).containsExactly(usbDevice1, usbDevice2);
71   }
72 
73   @Test
hasPermission_device()74   public void hasPermission_device() {
75     assertThat(usbManager.hasPermission(usbDevice1)).isFalse();
76 
77     shadowOf(usbManager).addOrUpdateUsbDevice(usbDevice1, false);
78     shadowOf(usbManager).addOrUpdateUsbDevice(usbDevice2, false);
79 
80     assertThat(usbManager.hasPermission(usbDevice1)).isFalse();
81     assertThat(usbManager.hasPermission(usbDevice2)).isFalse();
82 
83     shadowOf(usbManager).addOrUpdateUsbDevice(usbDevice1, true);
84 
85     assertThat(usbManager.hasPermission(usbDevice1)).isTrue();
86     assertThat(usbManager.hasPermission(usbDevice2)).isFalse();
87   }
88 
89   @Test
hasPermission_accessory()90   public void hasPermission_accessory() {
91     assertThat(usbManager.hasPermission(usbAccessory)).isFalse();
92     shadowOf(usbManager).setAttachedUsbAccessory(usbAccessory);
93     assertThat(usbManager.hasPermission(usbAccessory)).isFalse();
94     shadowOf(usbManager).grantPermission(usbAccessory);
95     assertThat(usbManager.hasPermission(usbAccessory)).isTrue();
96     shadowOf(usbManager)
97         .revokePermission(usbAccessory, RuntimeEnvironment.getApplication().getPackageName());
98     assertThat(usbManager.hasPermission(usbAccessory)).isFalse();
99   }
100 
101   @Test
102   @Config(minSdk = N)
grantPermission_selfPackage_shouldHavePermission()103   public void grantPermission_selfPackage_shouldHavePermission() {
104     usbManager.grantPermission(usbDevice1);
105 
106     assertThat(usbManager.hasPermission(usbDevice1)).isTrue();
107   }
108 
109   @Test
110   @Config(minSdk = N_MR1)
grantPermission_differentPackage_shouldHavePermission()111   public void grantPermission_differentPackage_shouldHavePermission() {
112     usbManager.grantPermission(usbDevice1, "foo.bar");
113 
114     assertThat(shadowOf(usbManager).hasPermissionForPackage(usbDevice1, "foo.bar")).isTrue();
115   }
116 
117   @Test
118   @Config(minSdk = N_MR1)
revokePermission_shouldNotHavePermission()119   public void revokePermission_shouldNotHavePermission() {
120     usbManager.grantPermission(usbDevice1, "foo.bar");
121     assertThat(shadowOf(usbManager).hasPermissionForPackage(usbDevice1, "foo.bar")).isTrue();
122 
123     shadowOf(usbManager).revokePermission(usbDevice1, "foo.bar");
124 
125     assertThat(shadowOf(usbManager).hasPermissionForPackage(usbDevice1, "foo.bar")).isFalse();
126   }
127 
128   @Test
129   @Config(minSdk = M, maxSdk = P)
getPorts_shouldReturnAddedPorts()130   public void getPorts_shouldReturnAddedPorts() {
131     shadowOf(usbManager).addPort("port1");
132     shadowOf(usbManager).addPort("port2");
133     shadowOf(usbManager).addPort("port3");
134 
135     List<UsbPort> usbPorts = getUsbPorts();
136     assertThat(usbPorts).hasSize(3);
137     assertThat(usbPorts.stream().map(UsbPort::getId).collect(Collectors.toList()))
138         .containsExactly("port1", "port2", "port3");
139   }
140 
141   @Test
142   @Config(minSdk = Q)
getPortStatus_shouldReturnStatusForCorrespondingPort()143   public void getPortStatus_shouldReturnStatusForCorrespondingPort() {
144     shadowOf(usbManager).addPort("port1");
145     shadowOf(usbManager).addPort("port2");
146     shadowOf(usbManager)
147         .addPort(
148             "port3",
149             UsbPortStatus.MODE_DUAL,
150             UsbPortStatus.POWER_ROLE_SINK,
151             UsbPortStatus.DATA_ROLE_DEVICE,
152             /* statusSupportedRoleCombinations= */ 0);
153 
154     UsbPortStatus portStatus = (UsbPortStatus) shadowOf(usbManager).getPortStatus("port3");
155     assertThat(portStatus.getCurrentMode()).isEqualTo(UsbPortStatus.MODE_DUAL);
156     assertThat(portStatus.getCurrentPowerRole()).isEqualTo(UsbPortStatus.POWER_ROLE_SINK);
157     assertThat(portStatus.getCurrentDataRole()).isEqualTo(UsbPortStatus.DATA_ROLE_DEVICE);
158     assertThat(portStatus.getSupportedRoleCombinations()).isEqualTo(0);
159   }
160 
161   @Test
162   @Config(minSdk = M)
clearPorts_shouldRemoveAllPorts()163   public void clearPorts_shouldRemoveAllPorts() {
164     shadowOf(usbManager).addPort("port1");
165     shadowOf(usbManager).clearPorts();
166 
167     List<UsbPort> usbPorts = getUsbPorts();
168     assertThat(usbPorts).isEmpty();
169   }
170 
171   @Test
172   @Config(minSdk = M, maxSdk = P)
setPortRoles_sinkHost_shouldSetPortStatus()173   public void setPortRoles_sinkHost_shouldSetPortStatus() {
174     final int powerRoleSink = getStaticField(UsbPort.class, "POWER_ROLE_SINK");
175     final int dataRoleHost = getStaticField(UsbPort.class, "DATA_ROLE_HOST");
176 
177     shadowOf(usbManager).addPort("port1");
178 
179     List<UsbPort> usbPorts = getUsbPorts();
180 
181     _usbManager_().setPortRoles(usbPorts.get(0), powerRoleSink, dataRoleHost);
182 
183     UsbPortStatus usbPortStatus = _usbManager_().getPortStatus(usbPorts.get(0));
184     assertThat(usbPortStatus.getCurrentPowerRole()).isEqualTo(powerRoleSink);
185     assertThat(usbPortStatus.getCurrentDataRole()).isEqualTo(dataRoleHost);
186   }
187 
188   @Test
189   @Config(minSdk = Q)
setPortRoles_sinkHost_shouldSetPortStatus_Q()190   public void setPortRoles_sinkHost_shouldSetPortStatus_Q() {
191     shadowOf(usbManager).addPort("port1");
192 
193     List<UsbPort> usbPorts = getUsbPorts();
194     _usbManager_()
195         .setPortRoles(usbPorts.get(0), UsbPortStatus.POWER_ROLE_SINK, UsbPortStatus.DATA_ROLE_HOST);
196 
197     UsbPortStatus usbPortStatus = _usbManager_().getPortStatus(usbPorts.get(0));
198     assertThat(usbPortStatus.getCurrentPowerRole()).isEqualTo(UsbPortStatus.POWER_ROLE_SINK);
199     assertThat(usbPortStatus.getCurrentDataRole()).isEqualTo(UsbPortStatus.DATA_ROLE_HOST);
200   }
201 
202   @Test
removeDevice()203   public void removeDevice() {
204     assertThat(usbManager.getDeviceList()).isEmpty();
205     shadowOf(usbManager).addOrUpdateUsbDevice(usbDevice1, false);
206     shadowOf(usbManager).addOrUpdateUsbDevice(usbDevice2, false);
207 
208     assertThat(usbManager.getDeviceList().values()).containsExactly(usbDevice1, usbDevice2);
209 
210     shadowOf(usbManager).removeUsbDevice(usbDevice1);
211     assertThat(usbManager.getDeviceList().values()).containsExactly(usbDevice2);
212   }
213 
214   @Test
openDevice()215   public void openDevice() throws Exception {
216     shadowOf(usbManager).addOrUpdateUsbDevice(usbDevice1, true);
217     UsbDeviceConnection connection = usbManager.openDevice(usbDevice1);
218     assertThat(connection).isNotNull();
219   }
220 
221   @Test
openAccessory()222   public void openAccessory() throws Exception {
223     try (ParcelFileDescriptor pfd = usbManager.openAccessory(usbAccessory)) {
224       assertThat(pfd).isNotNull();
225     }
226   }
227 
228   @Test
setAccessory()229   public void setAccessory() {
230     assertThat(usbManager.getAccessoryList()).isNull();
231     shadowOf(usbManager).setAttachedUsbAccessory(usbAccessory);
232     assertThat(usbManager.getAccessoryList()).hasLength(1);
233     assertThat(usbManager.getAccessoryList()[0]).isEqualTo(usbAccessory);
234   }
235 
236   /////////////////////////
237 
getUsbPorts()238   private List<UsbPort> getUsbPorts() {
239     // return type changed from UsbPort[] to List<UsbPort> in Q...
240     if (RuntimeEnvironment.getApiLevel() >= Build.VERSION_CODES.Q) {
241       return reflector(_UsbManagerQ_.class, usbManager).getPorts();
242     }
243     return Arrays.asList(_usbManager_().getPorts());
244   }
245 
_usbManager_()246   private _UsbManager_ _usbManager_() {
247     return reflector(_UsbManager_.class, usbManager);
248   }
249 
250   @Test
251   @Config(minSdk = O)
usbManager_activityContextEnabled_differentInstancesRetrieveSameUsbDevices()252   public void usbManager_activityContextEnabled_differentInstancesRetrieveSameUsbDevices() {
253     String originalProperty = System.getProperty("robolectric.createActivityContexts", "");
254     System.setProperty("robolectric.createActivityContexts", "true");
255     Activity activity = null;
256     try {
257       UsbManager applicationUsbManager =
258           ApplicationProvider.getApplicationContext().getSystemService(UsbManager.class);
259       activity = Robolectric.setupActivity(Activity.class);
260       UsbManager activityUsbManager = activity.getSystemService(UsbManager.class);
261 
262       assertThat(applicationUsbManager).isNotSameInstanceAs(activityUsbManager);
263 
264       HashMap<String, UsbDevice> applicationDevices = applicationUsbManager.getDeviceList();
265       HashMap<String, UsbDevice> activityDevices = activityUsbManager.getDeviceList();
266 
267       assertThat(activityDevices).isEqualTo(applicationDevices);
268     } finally {
269       if (activity != null) {
270         activity.finish();
271       }
272       System.setProperty("robolectric.createActivityContexts", originalProperty);
273     }
274   }
275 }
276