blob: c698290df630a14d83d1ad6f29568ef5d851d697 [file] [log] [blame]
Pavel Maltsev6b49b9b2019-03-14 10:14:24 -07001/*
2 * Copyright (C) 2019 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
17package android.car.usb.handler;
18
19import android.hardware.usb.UsbDevice;
20import android.hardware.usb.UsbInterface;
21import android.util.Log;
22
23import org.xmlpull.v1.XmlPullParser;
24
25/**
26 * This class is used to describe a USB device. When used in HashMaps all values must be specified,
27 * but wildcards can be used for any of the fields in the package meta-data.
28 */
29class UsbDeviceFilter {
30 private static final String TAG = UsbDeviceFilter.class.getSimpleName();
31
32 // USB Vendor ID (or -1 for unspecified)
33 public final int mVendorId;
34 // USB Product ID (or -1 for unspecified)
35 public final int mProductId;
36 // USB device or interface class (or -1 for unspecified)
37 public final int mClass;
38 // USB device subclass (or -1 for unspecified)
39 public final int mSubclass;
40 // USB device protocol (or -1 for unspecified)
41 public final int mProtocol;
42 // USB device manufacturer name string (or null for unspecified)
43 public final String mManufacturerName;
44 // USB device product name string (or null for unspecified)
45 public final String mProductName;
46 // USB device serial number string (or null for unspecified)
47 public final String mSerialNumber;
48
49 // USB device in AOAP mode manufacturer
50 public final String mAoapManufacturer;
51 // USB device in AOAP mode model
52 public final String mAoapModel;
53 // USB device in AOAP mode description string
54 public final String mAoapDescription;
55 // USB device in AOAP mode version
56 public final String mAoapVersion;
57 // USB device in AOAP mode URI
58 public final String mAoapUri;
59 // USB device in AOAP mode serial
60 public final String mAoapSerial;
61 // USB device in AOAP mode verification service
62 public final String mAoapService;
63
64 UsbDeviceFilter(int vid, int pid, int clasz, int subclass, int protocol,
65 String manufacturer, String product, String serialnum,
66 String aoapManufacturer, String aoapModel, String aoapDescription,
67 String aoapVersion, String aoapUri, String aoapSerial,
68 String aoapService) {
69 mVendorId = vid;
70 mProductId = pid;
71 mClass = clasz;
72 mSubclass = subclass;
73 mProtocol = protocol;
74 mManufacturerName = manufacturer;
75 mProductName = product;
76 mSerialNumber = serialnum;
77
78 mAoapManufacturer = aoapManufacturer;
79 mAoapModel = aoapModel;
80 mAoapDescription = aoapDescription;
81 mAoapVersion = aoapVersion;
82 mAoapUri = aoapUri;
83 mAoapSerial = aoapSerial;
84 mAoapService = aoapService;
85 }
86
87 public static UsbDeviceFilter read(XmlPullParser parser, boolean aoapData) {
88 int vendorId = -1;
89 int productId = -1;
90 int deviceClass = -1;
91 int deviceSubclass = -1;
92 int deviceProtocol = -1;
93 String manufacturerName = null;
94 String productName = null;
95 String serialNumber = null;
96
97 String aoapManufacturer = null;
98 String aoapModel = null;
99 String aoapDescription = null;
100 String aoapVersion = null;
101 String aoapUri = null;
102 String aoapSerial = null;
103 String aoapService = null;
104
105 int count = parser.getAttributeCount();
106 for (int i = 0; i < count; i++) {
107 String name = parser.getAttributeName(i);
108 String value = parser.getAttributeValue(i);
109 // Attribute values are ints or strings
110 if (!aoapData && "manufacturer-name".equals(name)) {
111 manufacturerName = value;
112 } else if (!aoapData && "product-name".equals(name)) {
113 productName = value;
114 } else if (!aoapData && "serial-number".equals(name)) {
115 serialNumber = value;
116 } else if (aoapData && "manufacturer".equals(name)) {
117 aoapManufacturer = value;
118 } else if (aoapData && "model".equals(name)) {
119 aoapModel = value;
120 } else if (aoapData && "description".equals(name)) {
121 aoapDescription = value;
122 } else if (aoapData && "version".equals(name)) {
123 aoapVersion = value;
124 } else if (aoapData && "uri".equals(name)) {
125 aoapUri = value;
126 } else if (aoapData && "serial".equals(name)) {
127 aoapSerial = value;
128 } else if (aoapData && "service".equals(name)) {
129 aoapService = value;
130 } else if (!aoapData) {
131 int intValue = -1;
132 int radix = 10;
133 if (value != null && value.length() > 2 && value.charAt(0) == '0'
134 && (value.charAt(1) == 'x' || value.charAt(1) == 'X')) {
135 // allow hex values starting with 0x or 0X
136 radix = 16;
137 value = value.substring(2);
138 }
139 try {
140 intValue = Integer.parseInt(value, radix);
141 } catch (NumberFormatException e) {
142 Log.e(TAG, "invalid number for field " + name, e);
143 continue;
144 }
145 if ("vendor-id".equals(name)) {
146 vendorId = intValue;
147 } else if ("product-id".equals(name)) {
148 productId = intValue;
149 } else if ("class".equals(name)) {
150 deviceClass = intValue;
151 } else if ("subclass".equals(name)) {
152 deviceSubclass = intValue;
153 } else if ("protocol".equals(name)) {
154 deviceProtocol = intValue;
155 }
156 }
157 }
158 return new UsbDeviceFilter(vendorId, productId,
159 deviceClass, deviceSubclass, deviceProtocol,
160 manufacturerName, productName, serialNumber, aoapManufacturer,
161 aoapModel, aoapDescription, aoapVersion, aoapUri, aoapSerial,
162 aoapService);
163 }
164
165 private boolean matches(int clasz, int subclass, int protocol) {
166 return ((mClass == -1 || clasz == mClass)
167 && (mSubclass == -1 || subclass == mSubclass)
168 && (mProtocol == -1 || protocol == mProtocol));
169 }
170
171 public boolean matches(UsbDevice device) {
172 if (mVendorId != -1 && device.getVendorId() != mVendorId) {
173 return false;
174 }
175 if (mProductId != -1 && device.getProductId() != mProductId) {
176 return false;
177 }
178 if (mManufacturerName != null && device.getManufacturerName() == null) {
179 return false;
180 }
181 if (mProductName != null && device.getProductName() == null) {
182 return false;
183 }
184 if (mSerialNumber != null && device.getSerialNumber() == null) {
185 return false;
186 }
187 if (mManufacturerName != null && device.getManufacturerName() != null
188 && !mManufacturerName.equals(device.getManufacturerName())) {
189 return false;
190 }
191 if (mProductName != null && device.getProductName() != null
192 && !mProductName.equals(device.getProductName())) {
193 return false;
194 }
195 if (mSerialNumber != null && device.getSerialNumber() != null
196 && !mSerialNumber.equals(device.getSerialNumber())) {
197 return false;
198 }
199
200 // check device class/subclass/protocol
201 if (matches(device.getDeviceClass(), device.getDeviceSubclass(),
202 device.getDeviceProtocol())) {
203 return true;
204 }
205
206 // if device doesn't match, check the interfaces
207 int count = device.getInterfaceCount();
208 for (int i = 0; i < count; i++) {
209 UsbInterface intf = device.getInterface(i);
210 if (matches(intf.getInterfaceClass(), intf.getInterfaceSubclass(),
211 intf.getInterfaceProtocol())) {
212 return true;
213 }
214 }
215
216 return false;
217 }
218
219 @Override
220 public boolean equals(Object obj) {
221 // can't compare if we have wildcard strings
222 if (mVendorId == -1 || mProductId == -1
223 || mClass == -1 || mSubclass == -1 || mProtocol == -1) {
224 return false;
225 }
226 if (obj instanceof UsbDeviceFilter) {
227 UsbDeviceFilter filter = (UsbDeviceFilter) obj;
228
229 if (filter.mVendorId != mVendorId
230 || filter.mProductId != mProductId
231 || filter.mClass != mClass
232 || filter.mSubclass != mSubclass
233 || filter.mProtocol != mProtocol) {
234 return false;
235 }
236 if ((filter.mManufacturerName != null && mManufacturerName == null)
237 || (filter.mManufacturerName == null && mManufacturerName != null)
238 || (filter.mProductName != null && mProductName == null)
239 || (filter.mProductName == null && mProductName != null)
240 || (filter.mSerialNumber != null && mSerialNumber == null)
241 || (filter.mSerialNumber == null && mSerialNumber != null)) {
242 return false;
243 }
244 if ((filter.mManufacturerName != null && mManufacturerName != null
245 && !mManufacturerName.equals(filter.mManufacturerName))
246 || (filter.mProductName != null && mProductName != null
247 && !mProductName.equals(filter.mProductName))
248 || (filter.mSerialNumber != null && mSerialNumber != null
249 && !mSerialNumber.equals(filter.mSerialNumber))) {
250 return false;
251 }
252 return true;
253 }
254 if (obj instanceof UsbDevice) {
255 UsbDevice device = (UsbDevice) obj;
256 if (device.getVendorId() != mVendorId
257 || device.getProductId() != mProductId
258 || device.getDeviceClass() != mClass
259 || device.getDeviceSubclass() != mSubclass
260 || device.getDeviceProtocol() != mProtocol) {
261 return false;
262 }
263 if ((mManufacturerName != null && device.getManufacturerName() == null)
264 || (mManufacturerName == null && device.getManufacturerName() != null)
265 || (mProductName != null && device.getProductName() == null)
266 || (mProductName == null && device.getProductName() != null)
267 || (mSerialNumber != null && device.getSerialNumber() == null)
268 || (mSerialNumber == null && device.getSerialNumber() != null)) {
269 return false;
270 }
271 if ((device.getManufacturerName() != null
272 && !mManufacturerName.equals(device.getManufacturerName()))
273 || (device.getProductName() != null
274 && !mProductName.equals(device.getProductName()))
275 || (device.getSerialNumber() != null
276 && !mSerialNumber.equals(device.getSerialNumber()))) {
277 return false;
278 }
279 return true;
280 }
281 return false;
282 }
283
284 @Override
285 public int hashCode() {
286 return (((mVendorId << 16) | mProductId)
287 ^ ((mClass << 16) | (mSubclass << 8) | mProtocol));
288 }
289
290 @Override
291 public String toString() {
292 return "DeviceFilter[mVendorId=" + mVendorId + ",mProductId=" + mProductId
293 + ",mClass=" + mClass + ",mSubclass=" + mSubclass
294 + ",mProtocol=" + mProtocol + ",mManufacturerName=" + mManufacturerName
295 + ",mProductName=" + mProductName + ",mSerialNumber=" + mSerialNumber + "]";
296 }
297}