blob: af4c425c24e7b6d48da3a982d96e19ef33f16da6 [file] [log] [blame]
Mike Lockwood24236072010-06-23 17:36:36 -04001/*
2 * Copyright (C) 2010 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 com.android.server;
18
19import android.content.ContentResolver;
20import android.content.Context;
21import android.content.Intent;
Mike Lockwoode7d511e2010-12-30 13:39:37 -050022import android.hardware.IUsbManager;
Mike Lockwood9182d3c2011-02-15 09:50:22 -050023import android.hardware.UsbAccessory;
Mike Lockwoode7d511e2010-12-30 13:39:37 -050024import android.hardware.UsbConstants;
25import android.hardware.UsbDevice;
26import android.hardware.UsbEndpoint;
27import android.hardware.UsbInterface;
Mike Lockwood770126a2010-12-09 22:30:37 -080028import android.hardware.UsbManager;
Mike Lockwood24236072010-06-23 17:36:36 -040029import android.net.Uri;
Mike Lockwoode7d511e2010-12-30 13:39:37 -050030import android.os.Bundle;
Mike Lockwood24236072010-06-23 17:36:36 -040031import android.os.Handler;
32import android.os.Message;
Mike Lockwoode7d511e2010-12-30 13:39:37 -050033import android.os.Parcelable;
34import android.os.ParcelFileDescriptor;
Mike Lockwood24236072010-06-23 17:36:36 -040035import android.os.UEventObserver;
36import android.provider.Settings;
37import android.util.Log;
38import android.util.Slog;
39
40import java.io.File;
41import java.io.FileNotFoundException;
42import java.io.FileReader;
43import java.util.ArrayList;
Mike Lockwoode7d511e2010-12-30 13:39:37 -050044import java.util.HashMap;
Mike Lockwood24236072010-06-23 17:36:36 -040045
46/**
Mike Lockwood770126a2010-12-09 22:30:37 -080047 * <p>UsbService monitors for changes to USB state.
Mike Lockwood24236072010-06-23 17:36:36 -040048 */
Mike Lockwoode7d511e2010-12-30 13:39:37 -050049class UsbService extends IUsbManager.Stub {
Mike Lockwood770126a2010-12-09 22:30:37 -080050 private static final String TAG = UsbService.class.getSimpleName();
Mike Lockwood24236072010-06-23 17:36:36 -040051 private static final boolean LOG = false;
52
Mike Lockwoodb92df0f2010-12-10 16:19:32 -080053 private static final String USB_CONNECTED_MATCH =
54 "DEVPATH=/devices/virtual/switch/usb_connected";
55 private static final String USB_CONFIGURATION_MATCH =
56 "DEVPATH=/devices/virtual/switch/usb_configuration";
57 private static final String USB_FUNCTIONS_MATCH =
58 "DEVPATH=/devices/virtual/usb_composite/";
59 private static final String USB_CONNECTED_PATH =
60 "/sys/class/switch/usb_connected/state";
61 private static final String USB_CONFIGURATION_PATH =
62 "/sys/class/switch/usb_configuration/state";
63 private static final String USB_COMPOSITE_CLASS_PATH =
64 "/sys/class/usb_composite";
Mike Lockwood24236072010-06-23 17:36:36 -040065
66 private static final int MSG_UPDATE = 0;
67
Mike Lockwoodb92df0f2010-12-10 16:19:32 -080068 // Delay for debouncing USB disconnects.
69 // We often get rapid connect/disconnect events when enabling USB functions,
70 // which need debouncing.
71 private static final int UPDATE_DELAY = 1000;
72
73 // current connected and configuration state
74 private int mConnected;
75 private int mConfiguration;
76
77 // last broadcasted connected and configuration state
78 private int mLastConnected = -1;
79 private int mLastConfiguration = -1;
Mike Lockwood24236072010-06-23 17:36:36 -040080
Mike Lockwoode7d511e2010-12-30 13:39:37 -050081 // lists of enabled and disabled USB functions (for USB device mode)
Mike Lockwood9182d3c2011-02-15 09:50:22 -050082 // synchronize on mEnabledFunctions when using either of these lists
Mike Lockwood24236072010-06-23 17:36:36 -040083 private final ArrayList<String> mEnabledFunctions = new ArrayList<String>();
84 private final ArrayList<String> mDisabledFunctions = new ArrayList<String>();
85
Mike Lockwood9182d3c2011-02-15 09:50:22 -050086 // contains all connected USB devices (for USB host mode)
Mike Lockwoode7d511e2010-12-30 13:39:37 -050087 private final HashMap<String,UsbDevice> mDevices = new HashMap<String,UsbDevice>();
88
Mike Lockwooda8e3a892011-02-01 13:46:50 -050089 // USB busses to exclude from USB host support
90 private final String[] mHostBlacklist;
91
Mike Lockwood24236072010-06-23 17:36:36 -040092 private boolean mSystemReady;
Mike Lockwood9182d3c2011-02-15 09:50:22 -050093 private UsbAccessory mCurrentAccessory;
Mike Lockwood24236072010-06-23 17:36:36 -040094
95 private final Context mContext;
96
Mike Lockwood9182d3c2011-02-15 09:50:22 -050097 private final void functionEnabled(String function, boolean enabled) {
98 synchronized (mEnabledFunctions) {
99 if (enabled) {
100 if (!mEnabledFunctions.contains(function)) {
101 mEnabledFunctions.add(function);
102 }
103 mDisabledFunctions.remove(function);
104 } else {
105 if (!mDisabledFunctions.contains(function)) {
106 mDisabledFunctions.add(function);
107 }
108 mEnabledFunctions.remove(function);
109 }
110 }
111
112 if (enabled && UsbManager.USB_FUNCTION_ACCESSORY.equals(function)) {
113 String[] strings = nativeGetAccessoryStrings();
114 if (strings != null) {
115 Log.d(TAG, "entering USB accessory mode");
116 mCurrentAccessory = new UsbAccessory(strings);
117 Intent intent = new Intent(UsbManager.ACTION_USB_ACCESSORY_ATTACHED);
118 intent.putExtra(UsbManager.EXTRA_ACCESSORY, mCurrentAccessory);
119 // add strings as separate extras to allow filtering
120 if (strings[0] != null) {
121 intent.putExtra(UsbManager.EXTRA_ACCESSORY_MANUFACTURER, strings[0]);
122 }
123 if (strings[1] != null) {
124 intent.putExtra(UsbManager.EXTRA_ACCESSORY_PRODUCT, strings[1]);
125 }
126 if (strings[2] != null) {
127 intent.putExtra(UsbManager.EXTRA_ACCESSORY_TYPE, strings[2]);
128 }
129 if (strings[3] != null) {
130 intent.putExtra(UsbManager.EXTRA_ACCESSORY_VERSION, strings[3]);
131 }
132 mContext.sendBroadcast(intent);
133 } else {
134 Log.e(TAG, "nativeGetAccessoryStrings failed");
135 }
136 }
137 }
138
Mike Lockwood770126a2010-12-09 22:30:37 -0800139 private final UEventObserver mUEventObserver = new UEventObserver() {
140 @Override
141 public void onUEvent(UEventObserver.UEvent event) {
142 if (Log.isLoggable(TAG, Log.VERBOSE)) {
143 Slog.v(TAG, "USB UEVENT: " + event.toString());
144 }
Mike Lockwood24236072010-06-23 17:36:36 -0400145
Mike Lockwood770126a2010-12-09 22:30:37 -0800146 synchronized (this) {
Mike Lockwoodb92df0f2010-12-10 16:19:32 -0800147 String name = event.get("SWITCH_NAME");
148 String state = event.get("SWITCH_STATE");
149 if (name != null && state != null) {
Mike Lockwood770126a2010-12-09 22:30:37 -0800150 try {
Mike Lockwoodb92df0f2010-12-10 16:19:32 -0800151 int intState = Integer.parseInt(state);
152 if ("usb_connected".equals(name)) {
153 mConnected = intState;
Mike Lockwood770126a2010-12-09 22:30:37 -0800154 // trigger an Intent broadcast
155 if (mSystemReady) {
Mike Lockwoodb92df0f2010-12-10 16:19:32 -0800156 // debounce disconnects
157 update(mConnected == 0);
158 }
159 } else if ("usb_configuration".equals(name)) {
160 mConfiguration = intState;
161 // trigger an Intent broadcast
162 if (mSystemReady) {
163 update(mConnected == 0);
Mike Lockwood770126a2010-12-09 22:30:37 -0800164 }
Mike Lockwood24236072010-06-23 17:36:36 -0400165 }
Mike Lockwood770126a2010-12-09 22:30:37 -0800166 } catch (NumberFormatException e) {
167 Slog.e(TAG, "Could not parse switch state from event " + event);
Mike Lockwood24236072010-06-23 17:36:36 -0400168 }
Mike Lockwood770126a2010-12-09 22:30:37 -0800169 } else {
170 String function = event.get("FUNCTION");
171 String enabledStr = event.get("ENABLED");
172 if (function != null && enabledStr != null) {
173 // Note: we do not broadcast a change when a function is enabled or disabled.
174 // We just record the state change for the next broadcast.
175 boolean enabled = "1".equals(enabledStr);
Mike Lockwood9182d3c2011-02-15 09:50:22 -0500176 functionEnabled(function, enabled);
Mike Lockwood24236072010-06-23 17:36:36 -0400177 }
178 }
179 }
180 }
Mike Lockwood770126a2010-12-09 22:30:37 -0800181 };
182
183 public UsbService(Context context) {
184 mContext = context;
Mike Lockwooda8e3a892011-02-01 13:46:50 -0500185 mHostBlacklist = context.getResources().getStringArray(
186 com.android.internal.R.array.config_usbHostBlacklist);
187
Mike Lockwood770126a2010-12-09 22:30:37 -0800188 init(); // set initial status
189
David 'Digit' Turner49db8532011-01-17 00:19:37 +0100190 if (mConfiguration >= 0) {
191 mUEventObserver.startObserving(USB_CONNECTED_MATCH);
192 mUEventObserver.startObserving(USB_CONFIGURATION_MATCH);
193 mUEventObserver.startObserving(USB_FUNCTIONS_MATCH);
194 }
Mike Lockwood24236072010-06-23 17:36:36 -0400195 }
Mike Lockwood770126a2010-12-09 22:30:37 -0800196
Mike Lockwood24236072010-06-23 17:36:36 -0400197 private final void init() {
198 char[] buffer = new char[1024];
199
David 'Digit' Turner49db8532011-01-17 00:19:37 +0100200 mConfiguration = -1;
Mike Lockwood24236072010-06-23 17:36:36 -0400201 try {
Mike Lockwoodb92df0f2010-12-10 16:19:32 -0800202 FileReader file = new FileReader(USB_CONNECTED_PATH);
Mike Lockwood24236072010-06-23 17:36:36 -0400203 int len = file.read(buffer, 0, 1024);
Brian Carlstromfd9ddd12010-11-04 11:24:58 -0700204 file.close();
Mike Lockwoodb92df0f2010-12-10 16:19:32 -0800205 mConnected = Integer.valueOf((new String(buffer, 0, len)).trim());
206
207 file = new FileReader(USB_CONFIGURATION_PATH);
208 len = file.read(buffer, 0, 1024);
209 file.close();
210 mConfiguration = Integer.valueOf((new String(buffer, 0, len)).trim());
Mike Lockwood24236072010-06-23 17:36:36 -0400211
212 } catch (FileNotFoundException e) {
David 'Digit' Turner49db8532011-01-17 00:19:37 +0100213 Slog.i(TAG, "This kernel does not have USB configuration switch support");
Mike Lockwood24236072010-06-23 17:36:36 -0400214 } catch (Exception e) {
215 Slog.e(TAG, "" , e);
216 }
David 'Digit' Turner49db8532011-01-17 00:19:37 +0100217 if (mConfiguration < 0)
218 return;
Mike Lockwood24236072010-06-23 17:36:36 -0400219
220 try {
Mike Lockwood9182d3c2011-02-15 09:50:22 -0500221 synchronized (mEnabledFunctions) {
222 File[] files = new File(USB_COMPOSITE_CLASS_PATH).listFiles();
223 for (int i = 0; i < files.length; i++) {
224 File file = new File(files[i], "enable");
225 FileReader reader = new FileReader(file);
226 int len = reader.read(buffer, 0, 1024);
227 reader.close();
228 int value = Integer.valueOf((new String(buffer, 0, len)).trim());
229 String functionName = files[i].getName();
230 if (value == 1) {
231 mEnabledFunctions.add(functionName);
232 } else {
233 mDisabledFunctions.add(functionName);
234 }
Mike Lockwood24236072010-06-23 17:36:36 -0400235 }
236 }
237 } catch (FileNotFoundException e) {
238 Slog.w(TAG, "This kernel does not have USB composite class support");
239 } catch (Exception e) {
240 Slog.e(TAG, "" , e);
241 }
242 }
243
Mike Lockwooda8e3a892011-02-01 13:46:50 -0500244 private boolean isBlackListed(String deviceName) {
245 int count = mHostBlacklist.length;
246 for (int i = 0; i < count; i++) {
247 if (deviceName.startsWith(mHostBlacklist[i])) {
248 return true;
249 }
250 }
251 return false;
252 }
253
Mike Lockwood8b682ad2011-02-01 15:53:11 -0500254 private boolean isBlackListed(int clazz, int subClass, int protocol) {
255 // blacklist hubs
256 if (clazz == UsbConstants.USB_CLASS_HUB) return true;
257
258 // blacklist HID boot devices (mouse and keyboard)
259 if (clazz == UsbConstants.USB_CLASS_HID &&
260 subClass == UsbConstants.USB_INTERFACE_SUBCLASS_BOOT) {
261 return true;
262 }
263
264 return false;
265 }
266
Mike Lockwoode7d511e2010-12-30 13:39:37 -0500267 // called from JNI in monitorUsbHostBus()
268 private void usbDeviceAdded(String deviceName, int vendorID, int productID,
269 int deviceClass, int deviceSubclass, int deviceProtocol,
270 /* array of quintuples containing id, class, subclass, protocol
271 and number of endpoints for each interface */
272 int[] interfaceValues,
273 /* array of quadruples containing address, attributes, max packet size
274 and interval for each endpoint */
275 int[] endpointValues) {
276
Mike Lockwood8b682ad2011-02-01 15:53:11 -0500277 if (isBlackListed(deviceName) ||
278 isBlackListed(deviceClass, deviceSubclass, deviceProtocol)) {
Mike Lockwooda8e3a892011-02-01 13:46:50 -0500279 return;
280 }
281
Mike Lockwoode7d511e2010-12-30 13:39:37 -0500282 synchronized (mDevices) {
283 if (mDevices.get(deviceName) != null) {
284 Log.w(TAG, "device already on mDevices list: " + deviceName);
285 return;
286 }
287
288 int numInterfaces = interfaceValues.length / 5;
289 Parcelable[] interfaces = new UsbInterface[numInterfaces];
290 try {
291 // repackage interfaceValues as an array of UsbInterface
292 int intf, endp, ival = 0, eval = 0;
Mike Lockwoode7d511e2010-12-30 13:39:37 -0500293 for (intf = 0; intf < numInterfaces; intf++) {
294 int interfaceId = interfaceValues[ival++];
295 int interfaceClass = interfaceValues[ival++];
296 int interfaceSubclass = interfaceValues[ival++];
297 int interfaceProtocol = interfaceValues[ival++];
298 int numEndpoints = interfaceValues[ival++];
299
300 Parcelable[] endpoints = new UsbEndpoint[numEndpoints];
301 for (endp = 0; endp < numEndpoints; endp++) {
302 int address = endpointValues[eval++];
303 int attributes = endpointValues[eval++];
304 int maxPacketSize = endpointValues[eval++];
305 int interval = endpointValues[eval++];
306 endpoints[endp] = new UsbEndpoint(address, attributes,
307 maxPacketSize, interval);
308 }
309
Mike Lockwood8b682ad2011-02-01 15:53:11 -0500310 // don't allow if any interfaces are blacklisted
311 if (isBlackListed(interfaceClass, interfaceSubclass, interfaceProtocol)) {
312 return;
Mike Lockwoode7d511e2010-12-30 13:39:37 -0500313 }
314 interfaces[intf] = new UsbInterface(interfaceId, interfaceClass,
315 interfaceSubclass, interfaceProtocol, endpoints);
316 }
Mike Lockwoode7d511e2010-12-30 13:39:37 -0500317 } catch (Exception e) {
318 // beware of index out of bound exceptions, which might happen if
319 // a device does not set bNumEndpoints correctly
320 Log.e(TAG, "error parsing USB descriptors", e);
321 return;
322 }
323
324 UsbDevice device = new UsbDevice(deviceName, vendorID, productID,
325 deviceClass, deviceSubclass, deviceProtocol, interfaces);
326 mDevices.put(deviceName, device);
327
328 Intent intent = new Intent(UsbManager.ACTION_USB_DEVICE_ATTACHED);
329 intent.putExtra(UsbManager.EXTRA_DEVICE_NAME, deviceName);
330 intent.putExtra(UsbManager.EXTRA_VENDOR_ID, vendorID);
331 intent.putExtra(UsbManager.EXTRA_PRODUCT_ID, productID);
332 intent.putExtra(UsbManager.EXTRA_DEVICE_CLASS, deviceClass);
333 intent.putExtra(UsbManager.EXTRA_DEVICE_SUBCLASS, deviceSubclass);
334 intent.putExtra(UsbManager.EXTRA_DEVICE_PROTOCOL, deviceProtocol);
335 intent.putExtra(UsbManager.EXTRA_DEVICE, device);
336 Log.d(TAG, "usbDeviceAdded, sending " + intent);
337 mContext.sendBroadcast(intent);
338 }
339 }
340
341 // called from JNI in monitorUsbHostBus()
342 private void usbDeviceRemoved(String deviceName) {
343 synchronized (mDevices) {
344 UsbDevice device = mDevices.remove(deviceName);
345 if (device != null) {
346 Intent intent = new Intent(UsbManager.ACTION_USB_DEVICE_DETACHED);
347 intent.putExtra(UsbManager.EXTRA_DEVICE_NAME, deviceName);
348 Log.d(TAG, "usbDeviceRemoved, sending " + intent);
349 mContext.sendBroadcast(intent);
350 }
351 }
352 }
353
Mike Lockwoodda39f0e2010-07-27 18:44:30 -0400354 private void initHostSupport() {
Mike Lockwoode7d511e2010-12-30 13:39:37 -0500355 // Create a thread to call into native code to wait for USB host events.
356 // This thread will call us back on usbDeviceAdded and usbDeviceRemoved.
357 Runnable runnable = new Runnable() {
358 public void run() {
359 monitorUsbHostBus();
360 }
361 };
362 new Thread(null, runnable, "UsbService host thread").start();
Mike Lockwoodda39f0e2010-07-27 18:44:30 -0400363 }
364
Mike Lockwood24236072010-06-23 17:36:36 -0400365 void systemReady() {
366 synchronized (this) {
Mike Lockwoodda39f0e2010-07-27 18:44:30 -0400367 if (mContext.getResources().getBoolean(
368 com.android.internal.R.bool.config_hasUsbHostSupport)) {
369 // start monitoring for connected USB devices
370 initHostSupport();
371 }
372
Mike Lockwoodb92df0f2010-12-10 16:19:32 -0800373 update(false);
Mike Lockwood24236072010-06-23 17:36:36 -0400374 mSystemReady = true;
375 }
376 }
377
Mike Lockwoodb92df0f2010-12-10 16:19:32 -0800378 private final void update(boolean delayed) {
379 mHandler.removeMessages(MSG_UPDATE);
380 mHandler.sendEmptyMessageDelayed(MSG_UPDATE, delayed ? UPDATE_DELAY : 0);
Mike Lockwood24236072010-06-23 17:36:36 -0400381 }
382
Mike Lockwoode7d511e2010-12-30 13:39:37 -0500383 /* Returns a list of all currently attached USB devices */
384 public void getDeviceList(Bundle devices) {
385 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.ACCESS_USB, null);
386 synchronized (mDevices) {
387 for (String name : mDevices.keySet()) {
388 devices.putParcelable(name, mDevices.get(name));
389 }
390 }
391 }
392
393 public ParcelFileDescriptor openDevice(String deviceName) {
Mike Lockwooda8e3a892011-02-01 13:46:50 -0500394 if (isBlackListed(deviceName)) {
395 throw new SecurityException("USB device is on a restricted bus");
396 }
Mike Lockwoode7d511e2010-12-30 13:39:37 -0500397 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.ACCESS_USB, null);
Mike Lockwood8b682ad2011-02-01 15:53:11 -0500398 if (mDevices.get(deviceName) == null) {
399 // if it is not in mDevices, it either does not exist or is blacklisted
Mike Lockwood9182d3c2011-02-15 09:50:22 -0500400 throw new IllegalArgumentException(
401 "device " + deviceName + " does not exist or is restricted");
Mike Lockwood8b682ad2011-02-01 15:53:11 -0500402 }
Mike Lockwoode7d511e2010-12-30 13:39:37 -0500403 return nativeOpenDevice(deviceName);
404 }
405
Mike Lockwood9182d3c2011-02-15 09:50:22 -0500406 public UsbAccessory getCurrentAccessory() {
407 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.ACCESS_USB, null);
408 return mCurrentAccessory;
409 }
410
411 public ParcelFileDescriptor openAccessory() {
412 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.ACCESS_USB, null);
413 return nativeOpenAccessory();
414 }
415
Mike Lockwood24236072010-06-23 17:36:36 -0400416 private final Handler mHandler = new Handler() {
Mike Lockwood709981e2010-06-28 09:58:58 -0400417 private void addEnabledFunctions(Intent intent) {
Mike Lockwood9182d3c2011-02-15 09:50:22 -0500418 synchronized (mEnabledFunctions) {
Mike Lockwood709981e2010-06-28 09:58:58 -0400419 // include state of all USB functions in our extras
Mike Lockwood9182d3c2011-02-15 09:50:22 -0500420 for (int i = 0; i < mEnabledFunctions.size(); i++) {
421 intent.putExtra(mEnabledFunctions.get(i), UsbManager.USB_FUNCTION_ENABLED);
422 }
423 for (int i = 0; i < mDisabledFunctions.size(); i++) {
424 intent.putExtra(mDisabledFunctions.get(i), UsbManager.USB_FUNCTION_DISABLED);
425 }
Mike Lockwood709981e2010-06-28 09:58:58 -0400426 }
427 }
428
Mike Lockwood24236072010-06-23 17:36:36 -0400429 @Override
430 public void handleMessage(Message msg) {
431 switch (msg.what) {
432 case MSG_UPDATE:
433 synchronized (this) {
Mike Lockwoodb92df0f2010-12-10 16:19:32 -0800434 if (mConnected != mLastConnected || mConfiguration != mLastConfiguration) {
Mike Lockwood9182d3c2011-02-15 09:50:22 -0500435 if (mConnected == 0 && mCurrentAccessory != null) {
436 // turn off accessory mode when we are disconnected
437 if (UsbManager.setFunctionEnabled(
438 UsbManager.USB_FUNCTION_ACCESSORY, false)) {
439 Log.d(TAG, "exited USB accessory mode");
440
441 Intent intent = new Intent(
442 UsbManager.ACTION_USB_ACCESSORY_DETACHED);
443 intent.putExtra(UsbManager.EXTRA_ACCESSORY, mCurrentAccessory);
444 mContext.sendBroadcast(intent);
445 mCurrentAccessory = null;
446
447 // this will cause an immediate reset of the USB bus,
448 // so there is no point in sending the
449 // function disabled broadcast.
450 return;
451 } else {
452 Log.e(TAG, "could not disable USB_FUNCTION_ACCESSORY");
453 }
454 }
Mike Lockwood24236072010-06-23 17:36:36 -0400455
Mike Lockwoodb92df0f2010-12-10 16:19:32 -0800456 final ContentResolver cr = mContext.getContentResolver();
457 if (Settings.Secure.getInt(cr,
458 Settings.Secure.DEVICE_PROVISIONED, 0) == 0) {
459 Slog.i(TAG, "Device not provisioned, skipping USB broadcast");
460 return;
461 }
462
463 mLastConnected = mConnected;
464 mLastConfiguration = mConfiguration;
465
466 // send a sticky broadcast containing current USB state
467 Intent intent = new Intent(UsbManager.ACTION_USB_STATE);
468 intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
469 intent.putExtra(UsbManager.USB_CONNECTED, mConnected != 0);
470 intent.putExtra(UsbManager.USB_CONFIGURATION, mConfiguration);
Mike Lockwood709981e2010-06-28 09:58:58 -0400471 addEnabledFunctions(intent);
Mike Lockwoodb92df0f2010-12-10 16:19:32 -0800472 mContext.sendStickyBroadcast(intent);
Mike Lockwood24236072010-06-23 17:36:36 -0400473 }
Mike Lockwood24236072010-06-23 17:36:36 -0400474 }
475 break;
476 }
477 }
478 };
Mike Lockwoode7d511e2010-12-30 13:39:37 -0500479
480 private native void monitorUsbHostBus();
481 private native ParcelFileDescriptor nativeOpenDevice(String deviceName);
Mike Lockwood9182d3c2011-02-15 09:50:22 -0500482 private native String[] nativeGetAccessoryStrings();
483 private native ParcelFileDescriptor nativeOpenAccessory();
Mike Lockwood24236072010-06-23 17:36:36 -0400484}