1 /*
2  * Copyright (C) 2018 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.usb;
18 
19 import static org.junit.Assert.assertEquals;
20 import static org.junit.Assert.assertFalse;
21 import static org.junit.Assert.assertTrue;
22 import static org.junit.Assert.fail;
23 
24 import android.content.Context;
25 import android.content.res.Resources;
26 import android.content.res.Resources.NotFoundException;
27 
28 import androidx.test.InstrumentationRegistry;
29 import androidx.test.filters.SmallTest;
30 import androidx.test.runner.AndroidJUnit4;
31 
32 import com.android.server.usb.descriptors.UsbDescriptorParser;
33 
34 import com.google.common.io.ByteStreams;
35 
36 import org.junit.Test;
37 import org.junit.runner.RunWith;
38 
39 import java.io.IOException;
40 import java.io.InputStream;
41 
42 /**
43  * Tests for {@link com.android.server.usb.descriptors.UsbDescriptorParser}
44  */
45 @RunWith(AndroidJUnit4.class)
46 public class UsbDescriptorParserTests {
47 
loadParser(int resource)48     public UsbDescriptorParser loadParser(int resource) {
49         Context c = InstrumentationRegistry.getContext();
50         Resources res = c.getResources();
51         InputStream is = null;
52         try {
53             is = res.openRawResource(resource);
54         } catch (NotFoundException e) {
55             fail("Failed to load resource.");
56         }
57 
58         byte[] descriptors = null;
59         try {
60             descriptors = ByteStreams.toByteArray(is);
61         } catch (IOException e) {
62             fail("Failed to convert descriptor strema to bytearray.");
63         }
64 
65         // Testing same codepath as UsbHostManager.java:usbDeviceAdded
66         UsbDescriptorParser parser = new UsbDescriptorParser("test-usb-addr", descriptors);
67         return parser;
68     }
69 
70     /** A Headset has a microphone and a speaker and is a headset.
71      * Descriptors for this example show up on lsusb -v with:
72      *   bcdDevice           22.80
73      * and a UAC1 audio device with the following control interface:
74      *       bInterfaceClass         1 Audio
75      * ...
76      *       bDescriptorSubtype      2 (INPUT_TERMINAL)
77      *       bTerminalID             1
78      *       wTerminalType      0x0201 Microphone
79      * ...
80      *       bDescriptorSubtype      3 (OUTPUT_TERMINAL)
81      *       bTerminalID            15
82      *       wTerminalType      0x0302 Headphones
83      */
84     @Test
85     @SmallTest
testHeadsetDescriptorParser()86     public void testHeadsetDescriptorParser() {
87         UsbDescriptorParser parser = loadParser(R.raw.usbdescriptors_headset);
88         assertTrue(parser.hasInput());
89         assertTrue(parser.hasOutput());
90         assertTrue(parser.isInputHeadset());
91         assertTrue(parser.isOutputHeadset());
92 
93         assertTrue(parser.hasAudioInterface());
94         assertTrue(parser.hasHIDInterface());
95         assertFalse(parser.hasStorageInterface());
96 
97         assertEquals(parser.getDeviceDescriptor().getDeviceReleaseString(), "22.80");
98     }
99 
100     /** Headphones have no microphones but are considered a headset.
101      * Descriptors for this example show up on lsusb -v with:
102      *   bcdDevice           22.80
103      * and a UAC1 audio device with the following control interface:
104      *       bInterfaceClass         1 Audio
105      * ...
106      *       bDescriptorSubtype      3 (OUTPUT_TERMINAL)
107      *       bTerminalID            15
108      *       wTerminalType      0x0302 Headphones
109      */
110     @Test
111     @SmallTest
testHeadphoneDescriptorParser()112     public void testHeadphoneDescriptorParser() {
113         UsbDescriptorParser parser = loadParser(R.raw.usbdescriptors_headphones);
114         assertFalse(parser.hasInput());
115         assertTrue(parser.hasOutput());
116         assertFalse(parser.isInputHeadset());
117         assertTrue(parser.isOutputHeadset());
118 
119         assertTrue(parser.hasAudioInterface());
120         assertTrue(parser.hasHIDInterface());
121         assertFalse(parser.hasStorageInterface());
122 
123         assertEquals(parser.getDeviceDescriptor().getDeviceReleaseString(), "22.80");
124     }
125 
126     /** Line out with no microphones aren't considered a headset.
127      * Descriptors for this example show up on lsusb -v with:
128      *     bcdDevice           22.80
129      * and the following UAC1 audio control interface
130      *  bInterfaceClass         1 Audio
131      *  ...
132      *   bDescriptorSubtype      3 (OUTPUT_TERMINAL)
133      *   bTerminalID            15
134      *   wTerminalType      0x0603 Line Connector
135      */
136     @Test
137     @SmallTest
testLineoutDescriptorParser()138     public void testLineoutDescriptorParser() {
139         UsbDescriptorParser parser = loadParser(R.raw.usbdescriptors_lineout);
140         assertFalse(parser.hasInput());
141         assertTrue(parser.hasOutput());
142         assertFalse(parser.isInputHeadset());
143         assertFalse(parser.isOutputHeadset());
144 
145         assertTrue(parser.hasAudioInterface());
146         assertTrue(parser.hasHIDInterface());
147         assertFalse(parser.hasStorageInterface());
148 
149         assertEquals(parser.getDeviceDescriptor().getDeviceReleaseString(), "22.80");
150     }
151 
152     /** An HID-only device shouldn't be considered anything at all.
153     /* Descriptors show up on lsusb -v with:
154      *   bcdDevice           22.80
155      * and a single HID interface,
156      *   bInterfaceClass         3 Human Interface Device
157      */
158     @Test
159     @SmallTest
testNothingDescriptorParser()160     public void testNothingDescriptorParser() {
161         UsbDescriptorParser parser = loadParser(R.raw.usbdescriptors_nothing);
162         assertFalse(parser.hasInput());
163         assertFalse(parser.hasOutput());
164         assertFalse(parser.isInputHeadset());
165         assertFalse(parser.isOutputHeadset());
166 
167         assertFalse(parser.hasAudioInterface());
168         assertTrue(parser.hasHIDInterface());
169         assertFalse(parser.hasStorageInterface());
170 
171         assertEquals(parser.getDeviceDescriptor().getDeviceReleaseString(), "22.80");
172     }
173 
174     /** A USB mass-storage device.
175      * Shows up on lsusb -v with:
176      *    bcdDevice            2.08
177      * and a single interface descriptor,
178      *    bInterfaceClass         8 Mass Storage
179      */
180     @Test
181     @SmallTest
testMassStorageDescriptorParser()182     public void testMassStorageDescriptorParser() {
183         UsbDescriptorParser parser = loadParser(R.raw.usbdescriptors_massstorage);
184         assertFalse(parser.hasInput());
185         assertFalse(parser.hasOutput());
186         assertFalse(parser.isInputHeadset());
187         assertFalse(parser.isOutputHeadset());
188 
189         assertFalse(parser.hasAudioInterface());
190         assertFalse(parser.hasHIDInterface());
191         assertTrue(parser.hasStorageInterface());
192 
193         assertEquals(parser.getDeviceDescriptor().getDeviceReleaseString(), "2.08");
194     }
195 
196 }
197