]> sigrok.org Git - sigrok-androidutils.git/blame - src/org/sigrok/androidutils/UsbSupplicant.java
Parse vendor-id and product-id as hexadecimal values
[sigrok-androidutils.git] / src / org / sigrok / androidutils / UsbSupplicant.java
CommitLineData
ea3ce762 1/*
5de7ce63 2 * This file is part of the sigrok-androidutils project.
ea3ce762
MC
3 *
4 * Copyright (C) 2014 Marcus Comstedt <marcus@mc.pp.se>
5 *
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
da4934ab
UH
19/*
20 * Copyright (C) 2011 The Android Open Source Project
21 *
22 * Licensed under the Apache License, Version 2.0 (the "License");
23 * you may not use this file except in compliance with the License.
24 * You may obtain a copy of the License at
25 *
26 * http://www.apache.org/licenses/LICENSE-2.0
27 *
28 * Unless required by applicable law or agreed to in writing, software
29 * distributed under the License is distributed on an "AS IS" BASIS,
30 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
31 * See the License for the specific language governing permissions and
32 * limitations under the License.
33 */
ea3ce762
MC
34
35package org.sigrok.androidutils;
36
37import android.app.PendingIntent;
38import android.content.BroadcastReceiver;
39import android.content.Context;
40import android.content.Intent;
41import android.content.IntentFilter;
42import android.content.res.Resources;
43import android.content.res.XmlResourceParser;
44import android.hardware.usb.UsbDevice;
45import android.hardware.usb.UsbInterface;
46import android.hardware.usb.UsbManager;
47import android.util.Log;
48import java.io.IOException;
49import java.util.HashMap;
50import java.util.Vector;
51import org.xmlpull.v1.XmlPullParser;
52import org.xmlpull.v1.XmlPullParserException;
53
54public class UsbSupplicant
55{
054991d3 56 static final String ACTION_USB_PERMISSION =
ea3ce762
MC
57 "org.sigrok.androidutils.USB_PERMISSION";
58
6f1c3a93
UH
59 protected final Context context;
60 protected final UsbManager manager;
61 private final BroadcastReceiver permReceiver;
62 private final BroadcastReceiver hotplugReceiver;
63 private final IntentFilter permFilter;
64 private final IntentFilter hotplugFilter;
65 private final Vector<DeviceFilter> deviceFilters;
66
67 // The code in the following inner class is taken from AOSP,
68 // which is licensed under the Apache License, Version 2.0.
69 private static class DeviceFilter {
70 // USB Vendor ID (or -1 for unspecified)
71 public final int mVendorId;
72 // USB Product ID (or -1 for unspecified)
73 public final int mProductId;
74 // USB device or interface class (or -1 for unspecified)
75 public final int mClass;
76 // USB device subclass (or -1 for unspecified)
77 public final int mSubclass;
78 // USB device protocol (or -1 for unspecified)
79 public final int mProtocol;
80
81 public DeviceFilter(int vid, int pid, int clasz, int subclass, int protocol) {
82 mVendorId = vid;
83 mProductId = pid;
84 mClass = clasz;
85 mSubclass = subclass;
86 mProtocol = protocol;
87 }
88
89 public DeviceFilter(UsbDevice device) {
90 mVendorId = device.getVendorId();
91 mProductId = device.getProductId();
92 mClass = device.getDeviceClass();
93 mSubclass = device.getDeviceSubclass();
94 mProtocol = device.getDeviceProtocol();
95 }
96
97 public static DeviceFilter read(XmlPullParser parser)
98 throws XmlPullParserException, IOException {
99 int vendorId = -1;
100 int productId = -1;
101 int deviceClass = -1;
102 int deviceSubclass = -1;
103 int deviceProtocol = -1;
104
105 int count = parser.getAttributeCount();
106 for (int i = 0; i < count; i++) {
107 String name = parser.getAttributeName(i);
108 // All attribute values are ints
2606541d 109 int value = parseAttribute(name, parser.getAttributeValue(i));
6f1c3a93
UH
110
111 if ("vendor-id".equals(name)) {
112 vendorId = value;
113 } else if ("product-id".equals(name)) {
114 productId = value;
115 } else if ("class".equals(name)) {
116 deviceClass = value;
117 } else if ("subclass".equals(name)) {
118 deviceSubclass = value;
119 } else if ("protocol".equals(name)) {
120 deviceProtocol = value;
121 }
122 }
123 return new DeviceFilter(vendorId, productId,
124 deviceClass, deviceSubclass, deviceProtocol);
ea3ce762 125 }
6f1c3a93 126
2606541d
DS
127 private static int parseAttribute(String name, String value) {
128 // vendor-id and product-id are in hexadecimal format.
129 if ("vendor-id".equals(name) || "product-id".equals(name))
130 return Integer.parseInt(value, 16);
131 else
132 return Integer.parseInt(value);
133 }
134
6f1c3a93
UH
135 private boolean matches(int clasz, int subclass, int protocol) {
136 return ((mClass == -1 || clasz == mClass) &&
137 (mSubclass == -1 || subclass == mSubclass) &&
138 (mProtocol == -1 || protocol == mProtocol));
139 }
140
141 public boolean matches(UsbDevice device) {
142 if (mVendorId != -1 && device.getVendorId() != mVendorId)
143 return false;
144 if (mProductId != -1 && device.getProductId() != mProductId)
145 return false;
146
147 // Check device class/subclass/protocol.
148 if (matches(device.getDeviceClass(), device.getDeviceSubclass(),
149 device.getDeviceProtocol()))
150 return true;
151
152 // If device doesn't match, check the interfaces.
153 int count = device.getInterfaceCount();
154 for (int i = 0; i < count; i++) {
155 UsbInterface intf = device.getInterface(i);
156 if (matches(intf.getInterfaceClass(), intf.getInterfaceSubclass(),
157 intf.getInterfaceProtocol()))
158 return true;
159 }
160
161 return false;
162 }
163
ea3ce762 164 @Override
6f1c3a93
UH
165 public String toString() {
166 return "DeviceFilter[mVendorId=" + mVendorId + ",mProductId=" + mProductId +
167 ",mClass=" + mClass + ",mSubclass=" + mSubclass +
168 ",mProtocol=" + mProtocol + "]";
ea3ce762 169 }
ea3ce762 170 }
6f1c3a93
UH
171
172 public UsbSupplicant(Context ctx, int device_filter_resource)
173 {
174 context = ctx;
175 manager = (UsbManager) ctx.getSystemService(Context.USB_SERVICE);
176 permReceiver = new BroadcastReceiver() {
177 @Override
178 public void onReceive(Context context, Intent intent) {
179 String action = intent.getAction();
180 if (ACTION_USB_PERMISSION.equals(action)) {
181 permissionCallback((UsbDevice)intent.getParcelableExtra(
182 UsbManager.EXTRA_DEVICE), intent.getBooleanExtra(
183 UsbManager.EXTRA_PERMISSION_GRANTED, false));
184 }
185 }
186 };
187 hotplugReceiver = new BroadcastReceiver() {
188 @Override
189 public void onReceive(Context context, Intent intent) {
190 if (intent != null && UsbManager.ACTION_USB_DEVICE_ATTACHED.equals(intent.getAction())) {
191 attachCallback((UsbDevice)intent.getParcelableExtra(UsbManager.EXTRA_DEVICE));
192 } else if (intent != null && UsbManager.ACTION_USB_DEVICE_DETACHED.equals(intent.getAction())) {
193 detachCallback((UsbDevice)intent.getParcelableExtra(UsbManager.EXTRA_DEVICE));
194 }
195 }
196 };
197 permFilter = new IntentFilter(ACTION_USB_PERMISSION);
198 hotplugFilter = new IntentFilter(UsbManager.ACTION_USB_DEVICE_ATTACHED);
199 hotplugFilter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED);
200 deviceFilters = new Vector<DeviceFilter>();
201 addDeviceFilters(ctx.getResources(), device_filter_resource);
202 }
203
204 private void addDeviceFilters(Resources res, int res_id)
205 {
206 XmlResourceParser parser = res.getXml(res_id);
207 if (parser == null) {
208 Log.w("UsbSupplicant", "Unable to get device filter resource");
209 return;
210 }
211 deviceFilters.clear();
212 try {
213 while (parser.next() != XmlPullParser.END_DOCUMENT) {
214 if (parser.getEventType() == XmlPullParser.START_TAG) {
215 if ("usb-device".equals(parser.getName()))
216 deviceFilters.add(DeviceFilter.read(parser));
217 }
218 }
219 } catch (IOException e) {
220 Log.wtf("UsbSupplicant",
221 "Failed to parse device filter resource", e);
222 } catch (XmlPullParserException e) {
223 Log.wtf("UsbSupplicant",
224 "Failed to parse device filter resource", e);
ea3ce762 225 }
ea3ce762 226 }
6f1c3a93 227
ed3a4c3c 228 protected boolean interesting(UsbDevice dev)
6f1c3a93
UH
229 {
230 if (dev == null)
231 return false;
232
233 for (DeviceFilter f : deviceFilters)
234 if (f.matches(dev))
235 return true;
236
237 return false;
ea3ce762 238 }
6f1c3a93
UH
239
240 protected void askFor(UsbDevice dev)
241 {
242 manager.requestPermission(dev, PendingIntent.getBroadcast(context, 0,
243 new Intent(ACTION_USB_PERMISSION), 0));
ea3ce762 244 }
ea3ce762 245
6f1c3a93
UH
246 public void start()
247 {
248 context.registerReceiver(permReceiver, permFilter);
249 context.registerReceiver(hotplugReceiver, hotplugFilter);
250 HashMap<String,UsbDevice> devlist = manager.getDeviceList();
251 for (UsbDevice dev : devlist.values()) {
ed3a4c3c
UH
252 if (interesting(dev) && !manager.hasPermission(dev)) {
253 Log.d("UsbSupplicant", "found interesting device " + dev);
6f1c3a93
UH
254 askFor(dev);
255 }
256 }
257 }
258
259 public void stop()
260 {
261 context.unregisterReceiver(hotplugReceiver);
262 context.unregisterReceiver(permReceiver);
263 }
264
265 protected void permissionCallback(UsbDevice dev, boolean granted)
266 {
267 Log.d("UsbSupplicant", "permission " +
268 (granted ? "granted" : "denied") + " for device " + dev);
269 }
270
271 protected void attachCallback(UsbDevice dev)
272 {
ed3a4c3c 273 if (interesting(dev) && !manager.hasPermission(dev))
6f1c3a93
UH
274 askFor(dev);
275 }
276
277 protected void detachCallback(UsbDevice dev)
278 {
279 }
ea3ce762 280}