1 /* 2 * Copyright (C) 2016 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 package com.google.android.car.kitchensink.setting.usb; 17 18 import android.car.IUsbAoapSupportCheckService; 19 import android.content.ComponentName; 20 import android.content.Context; 21 import android.content.Intent; 22 import android.content.ServiceConnection; 23 import android.content.pm.ActivityInfo; 24 import android.content.pm.PackageManager; 25 import android.content.pm.PackageManager.NameNotFoundException; 26 import android.content.pm.ResolveInfo; 27 import android.content.res.XmlResourceParser; 28 import android.hardware.usb.UsbDevice; 29 import android.hardware.usb.UsbInterface; 30 import android.hardware.usb.UsbManager; 31 import android.os.Handler; 32 import android.os.HandlerThread; 33 import android.os.IBinder; 34 import android.os.Looper; 35 import android.os.Message; 36 import android.os.RemoteException; 37 import android.util.Log; 38 import android.util.Pair; 39 40 import com.android.internal.util.XmlUtils; 41 42 import org.xmlpull.v1.XmlPullParser; 43 import org.xmlpull.v1.XmlPullParserException; 44 45 import java.io.IOException; 46 import java.util.ArrayList; 47 import java.util.LinkedList; 48 import java.util.List; 49 import java.util.Queue; 50 51 /** 52 * Resolves supported handlers for USB device. 53 */ 54 public final class UsbDeviceHandlerResolver 55 implements UsbDeviceStateController.UsbDeviceStateListener { 56 private static final String TAG = UsbDeviceHandlerResolver.class.getSimpleName(); 57 private static final boolean LOCAL_LOGD = true; 58 59 private static final int MODE_OFF = 0; 60 private static final int MODE_PROBE = 1; 61 private static final int MODE_PROBE_AOAP = 2; 62 private static final int MODE_DISPATCH = 3; 63 64 /** 65 * Callbacks for device reolver. 66 */ 67 public interface UsbDeviceHandlerResolverCallback { 68 /** Handlers are reolved */ 69 void onHandlersResolveCompleted( 70 UsbDevice device, List<UsbDeviceSettings> availableSettings); 71 /** Device was dispatched */ 72 void onDeviceDispatched(); 73 } 74 75 private final UsbManager mUsbManager; 76 private final PackageManager mPackageManager; 77 private final UsbDeviceHandlerResolverCallback mDeviceCallback; 78 private final Context mContext; 79 private final HandlerThread mHandlerThread; 80 private final UsbDeviceResolverHandler mHandler; 81 private final UsbDeviceStateController mStateController; 82 private final Queue<Pair<ResolveInfo, DeviceFilter>> mActiveDeviceOptions = new LinkedList<>(); 83 private final List<UsbDeviceSettings> mActiveDeviceSettings = new ArrayList<>(); 84 85 private String mActiveDeviceSerial; 86 private UsbDevice mActiveUsbDevice; 87 private UsbDeviceSettings mBaseSettings; 88 private int mDeviceMode = MODE_OFF; 89 private Intent mDispatchIntent; 90 private int mDispatchUid; 91 private IUsbAoapSupportCheckService mIUsbAoapSupportCheckService; 92 private boolean mBound; 93 94 // This class is used to describe a USB device. 95 // When used in HashMaps all values must be specified, 96 // but wildcards can be used for any of the fields in 97 // the package meta-data. 98 private static class DeviceFilter { 99 // USB Vendor ID (or -1 for unspecified) 100 public final int mVendorId; 101 // USB Product ID (or -1 for unspecified) 102 public final int mProductId; 103 // USB device or interface class (or -1 for unspecified) 104 public final int mClass; 105 // USB device subclass (or -1 for unspecified) 106 public final int mSubclass; 107 // USB device protocol (or -1 for unspecified) 108 public final int mProtocol; 109 // USB device manufacturer name string (or null for unspecified) 110 public final String mManufacturerName; 111 // USB device product name string (or null for unspecified) 112 public final String mProductName; 113 // USB device serial number string (or null for unspecified) 114 public final String mSerialNumber; 115 116 // USB device in AOAP mode manufacturer 117 public final String mAoapManufacturer; 118 // USB device in AOAP mode modeal 119 public final String mAoapModel; 120 // USB device in AOAP mode description string 121 public final String mAoapDescription; 122 // USB device in AOAP mode version 123 public final String mAoapVersion; 124 // USB device in AOAP mode URI 125 public final String mAoapUri; 126 // USB device in AOAP mode serial 127 public final String mAoapSerial; 128 // USB device in AOAP mode verification service 129 public final String mAoapService; 130 131 DeviceFilter(int vid, int pid, int clasz, int subclass, int protocol, 132 String manufacturer, String product, String serialnum, 133 String aoapManufacturer, String aoapModel, String aoapDescription, 134 String aoapVersion, String aoapUri, String aoapSerial, 135 String aoapService) { 136 mVendorId = vid; 137 mProductId = pid; 138 mClass = clasz; 139 mSubclass = subclass; 140 mProtocol = protocol; 141 mManufacturerName = manufacturer; 142 mProductName = product; 143 mSerialNumber = serialnum; 144 145 mAoapManufacturer = aoapManufacturer; 146 mAoapModel = aoapModel; 147 mAoapDescription = aoapDescription; 148 mAoapVersion = aoapVersion; 149 mAoapUri = aoapUri; 150 mAoapSerial = aoapSerial; 151 mAoapService = aoapService; 152 } 153 154 DeviceFilter(UsbDevice device) { 155 mVendorId = device.getVendorId(); 156 mProductId = device.getProductId(); 157 mClass = device.getDeviceClass(); 158 mSubclass = device.getDeviceSubclass(); 159 mProtocol = device.getDeviceProtocol(); 160 mManufacturerName = device.getManufacturerName(); 161 mProductName = device.getProductName(); 162 mSerialNumber = device.getSerialNumber(); 163 mAoapManufacturer = null; 164 mAoapModel = null; 165 mAoapDescription = null; 166 mAoapVersion = null; 167 mAoapUri = null; 168 mAoapSerial = null; 169 mAoapService = null; 170 } 171 172 public static DeviceFilter read(XmlPullParser parser, boolean aoapData) 173 throws XmlPullParserException, IOException { 174 int vendorId = -1; 175 int productId = -1; 176 int deviceClass = -1; 177 int deviceSubclass = -1; 178 int deviceProtocol = -1; 179 String manufacturerName = null; 180 String productName = null; 181 String serialNumber = null; 182 183 String aoapManufacturer = null; 184 String aoapModel = null; 185 String aoapDescription = null; 186 String aoapVersion = null; 187 String aoapUri = null; 188 String aoapSerial = null; 189 String aoapService = null; 190 191 int count = parser.getAttributeCount(); 192 for (int i = 0; i < count; i++) { 193 String name = parser.getAttributeName(i); 194 String value = parser.getAttributeValue(i); 195 // Attribute values are ints or strings 196 if (!aoapData && "manufacturer-name".equals(name)) { 197 manufacturerName = value; 198 } else if (!aoapData && "product-name".equals(name)) { 199 productName = value; 200 } else if (!aoapData && "serial-number".equals(name)) { 201 serialNumber = value; 202 } else if (aoapData && "manufacturer".equals(name)) { 203 aoapManufacturer = value; 204 } else if (aoapData && "model".equals(name)) { 205 aoapModel = value; 206 } else if (aoapData && "description".equals(name)) { 207 aoapDescription = value; 208 } else if (aoapData && "version".equals(name)) { 209 aoapVersion = value; 210 } else if (aoapData && "uri".equals(name)) { 211 aoapUri = value; 212 } else if (aoapData && "serial".equals(name)) { 213 aoapSerial = value; 214 } else if (aoapData && "service".equals(name)) { 215 aoapService = value; 216 } else if (!aoapData) { 217 int intValue = -1; 218 int radix = 10; 219 if (value != null && value.length() > 2 && value.charAt(0) == '0' 220 && (value.charAt(1) == 'x' || value.charAt(1) == 'X')) { 221 // allow hex values starting with 0x or 0X 222 radix = 16; 223 value = value.substring(2); 224 } 225 try { 226 intValue = Integer.parseInt(value, radix); 227 } catch (NumberFormatException e) { 228 Log.e(TAG, "invalid number for field " + name, e); 229 continue; 230 } 231 if ("vendor-id".equals(name)) { 232 vendorId = intValue; 233 } else if ("product-id".equals(name)) { 234 productId = intValue; 235 } else if ("class".equals(name)) { 236 deviceClass = intValue; 237 } else if ("subclass".equals(name)) { 238 deviceSubclass = intValue; 239 } else if ("protocol".equals(name)) { 240 deviceProtocol = intValue; 241 } 242 } 243 } 244 return new DeviceFilter(vendorId, productId, 245 deviceClass, deviceSubclass, deviceProtocol, 246 manufacturerName, productName, serialNumber, aoapManufacturer, 247 aoapModel, aoapDescription, aoapVersion, aoapUri, aoapSerial, 248 aoapService); 249 } 250 251 private boolean matches(int clasz, int subclass, int protocol) { 252 return ((mClass == -1 || clasz == mClass) 253 && (mSubclass == -1 || subclass == mSubclass) 254 && (mProtocol == -1 || protocol == mProtocol)); 255 } 256 257 public boolean isAoap() { 258 return (mVendorId == AoapInterface.USB_ACCESSORY_VENDOR_ID 259 && mProductId == AoapInterface.USB_ACCESSORY_PRODUCT_ID); 260 } 261 262 public boolean matches(UsbDevice device) { 263 if (mVendorId != -1 && device.getVendorId() != mVendorId) { 264 return false; 265 } 266 if (mProductId != -1 && device.getProductId() != mProductId) { 267 return false; 268 } 269 if (mManufacturerName != null && device.getManufacturerName() == null) { 270 return false; 271 } 272 if (mProductName != null && device.getProductName() == null) { 273 return false; 274 } 275 if (mSerialNumber != null && device.getSerialNumber() == null) { 276 return false; 277 } 278 if (mManufacturerName != null && device.getManufacturerName() != null 279 && !mManufacturerName.equals(device.getManufacturerName())) { 280 return false; 281 } 282 if (mProductName != null && device.getProductName() != null 283 && !mProductName.equals(device.getProductName())) { 284 return false; 285 } 286 if (mSerialNumber != null && device.getSerialNumber() != null 287 && !mSerialNumber.equals(device.getSerialNumber())) { 288 return false; 289 } 290 291 // check device class/subclass/protocol 292 if (matches(device.getDeviceClass(), device.getDeviceSubclass(), 293 device.getDeviceProtocol())) { 294 return true; 295 } 296 297 // if device doesn't match, check the interfaces 298 int count = device.getInterfaceCount(); 299 for (int i = 0; i < count; i++) { 300 UsbInterface intf = device.getInterface(i); 301 if (matches(intf.getInterfaceClass(), intf.getInterfaceSubclass(), 302 intf.getInterfaceProtocol())) { 303 return true; 304 } 305 } 306 307 return false; 308 } 309 310 @Override 311 public boolean equals(Object obj) { 312 // can't compare if we have wildcard strings 313 if (mVendorId == -1 || mProductId == -1 314 || mClass == -1 || mSubclass == -1 || mProtocol == -1) { 315 return false; 316 } 317 if (obj instanceof DeviceFilter) { 318 DeviceFilter filter = (DeviceFilter) obj; 319 320 if (filter.mVendorId != mVendorId 321 || filter.mProductId != mProductId 322 || filter.mClass != mClass 323 || filter.mSubclass != mSubclass 324 || filter.mProtocol != mProtocol) { 325 return false; 326 } 327 if ((filter.mManufacturerName != null && mManufacturerName == null) 328 || (filter.mManufacturerName == null && mManufacturerName != null) 329 || (filter.mProductName != null && mProductName == null) 330 || (filter.mProductName == null && mProductName != null) 331 || (filter.mSerialNumber != null && mSerialNumber == null) 332 || (filter.mSerialNumber == null && mSerialNumber != null)) { 333 return false; 334 } 335 if ((filter.mManufacturerName != null && mManufacturerName != null 336 && !mManufacturerName.equals(filter.mManufacturerName)) 337 || (filter.mProductName != null && mProductName != null 338 && !mProductName.equals(filter.mProductName)) 339 || (filter.mSerialNumber != null && mSerialNumber != null 340 && !mSerialNumber.equals(filter.mSerialNumber))) { 341 return false; 342 } 343 return true; 344 } 345 if (obj instanceof UsbDevice) { 346 UsbDevice device = (UsbDevice) obj; 347 if (device.getVendorId() != mVendorId 348 || device.getProductId() != mProductId 349 || device.getDeviceClass() != mClass 350 || device.getDeviceSubclass() != mSubclass 351 || device.getDeviceProtocol() != mProtocol) { 352 return false; 353 } 354 if ((mManufacturerName != null && device.getManufacturerName() == null) 355 || (mManufacturerName == null && device.getManufacturerName() != null) 356 || (mProductName != null && device.getProductName() == null) 357 || (mProductName == null && device.getProductName() != null) 358 || (mSerialNumber != null && device.getSerialNumber() == null) 359 || (mSerialNumber == null && device.getSerialNumber() != null)) { 360 return false; 361 } 362 if ((device.getManufacturerName() != null 363 && !mManufacturerName.equals(device.getManufacturerName())) 364 || (device.getProductName() != null 365 && !mProductName.equals(device.getProductName())) 366 || (device.getSerialNumber() != null 367 && !mSerialNumber.equals(device.getSerialNumber()))) { 368 return false; 369 } 370 return true; 371 } 372 return false; 373 } 374 375 @Override 376 public int hashCode() { 377 return (((mVendorId << 16) | mProductId) 378 ^ ((mClass << 16) | (mSubclass << 8) | mProtocol)); 379 } 380 381 @Override 382 public String toString() { 383 return "DeviceFilter[mVendorId=" + mVendorId + ",mProductId=" + mProductId 384 + ",mClass=" + mClass + ",mSubclass=" + mSubclass 385 + ",mProtocol=" + mProtocol + ",mManufacturerName=" + mManufacturerName 386 + ",mProductName=" + mProductName + ",mSerialNumber=" + mSerialNumber + "]"; 387 } 388 } 389 390 private final ServiceConnection mConnection = new ServiceConnection() { 391 @Override 392 public void onServiceConnected(ComponentName className, IBinder service) { 393 Log.i(TAG, "onServiceConnected: " + className); 394 mHandler.requestOnServiceConnectionStateChanged( 395 IUsbAoapSupportCheckService.Stub.asInterface(service)); 396 } 397 398 @Override 399 public void onServiceDisconnected(ComponentName className) { 400 Log.i(TAG, "onServiceDisconnected: " + className); 401 mHandler.requestOnServiceConnectionStateChanged(null); 402 } 403 }; 404 405 public UsbDeviceHandlerResolver(UsbManager manager, Context context, 406 UsbDeviceHandlerResolverCallback deviceListener) { 407 mUsbManager = manager; 408 mContext = context; 409 mDeviceCallback = deviceListener; 410 mHandlerThread = new HandlerThread(TAG); 411 mHandlerThread.start(); 412 mHandler = new UsbDeviceResolverHandler(mHandlerThread.getLooper()); 413 mPackageManager = context.getPackageManager(); 414 mStateController = new UsbDeviceStateController(context, this, manager); 415 mStateController.init(); 416 } 417 418 /** 419 * Releases current object. 420 */ 421 public void release() { 422 if (mHandlerThread != null) { 423 mHandlerThread.quitSafely(); 424 } 425 if (mStateController != null) { 426 mStateController.release(); 427 } 428 } 429 430 /** 431 * Resolves handlers for USB device. 432 */ 433 public void resolve(UsbDevice device) { 434 mHandler.requestResolveHandlers(device); 435 } 436 437 /** 438 * Dispatches device to component. 439 */ 440 public boolean dispatch(UsbDevice device, ComponentName component, boolean inAoap) { 441 if (LOCAL_LOGD) { 442 Log.d(TAG, "dispatch: " + device + " component: " + component + " inAoap:" + inAoap); 443 } 444 445 mActiveUsbDevice = device; 446 mDeviceMode = MODE_DISPATCH; 447 ActivityInfo activityInfo; 448 try { 449 activityInfo = mPackageManager.getActivityInfo(component, PackageManager.GET_META_DATA); 450 } catch (NameNotFoundException e) { 451 Log.e(TAG, "Activity not found: " + component); 452 return false; 453 } 454 455 Intent intent = createDeviceAttachedIntent(device); 456 if (inAoap) { 457 DeviceFilter filter = packageMatches(activityInfo, intent.getAction(), device, true); 458 intent.setComponent(component); 459 mDispatchIntent = intent; 460 mDispatchUid = activityInfo.applicationInfo.uid; 461 if (filter != null) { 462 requestAoapSwitch(filter); 463 return true; 464 } 465 } 466 467 intent.setComponent(component); 468 mUsbManager.grantPermission(device, activityInfo.applicationInfo.uid); 469 470 mContext.startActivity(intent); 471 mHandler.requestCompleteDeviceDispatch(); 472 return true; 473 } 474 475 private static Intent createDeviceAttachedIntent(UsbDevice device) { 476 Intent intent = new Intent(UsbManager.ACTION_USB_DEVICE_ATTACHED); 477 intent.putExtra(UsbManager.EXTRA_DEVICE, device); 478 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 479 return intent; 480 } 481 482 private void doHandleResolveHandlers( 483 UsbDevice device) { 484 mActiveDeviceSettings.clear(); 485 mActiveDeviceOptions.clear(); 486 mActiveUsbDevice = device; 487 mDeviceMode = MODE_PROBE; 488 489 if (LOCAL_LOGD) { 490 Log.d(TAG, "doHandleResolveHandlers: " + device); 491 } 492 boolean maySupportAoap = UsbUtil.possiblyAndroid(device); 493 boolean isInAoap = AoapInterface.isDeviceInAoapMode(device); 494 495 Intent intent = createDeviceAttachedIntent(device); 496 List<Pair<ResolveInfo, DeviceFilter>> matches = getDeviceMatches(device, intent, false); 497 if (LOCAL_LOGD) { 498 Log.d(TAG, "matches size: " + matches.size()); 499 } 500 for (Pair<ResolveInfo, DeviceFilter> info : matches) { 501 UsbDeviceSettings setting = UsbDeviceSettings.constructSettings(mActiveUsbDevice); 502 setting.setHandler( 503 new ComponentName( 504 info.first.activityInfo.packageName, info.first.activityInfo.name)); 505 mActiveDeviceSettings.add(setting); 506 } 507 mBaseSettings = UsbDeviceSettings.constructSettings(mActiveUsbDevice); 508 if (!AoapInterface.isDeviceInAoapMode(device) && maySupportAoap) { 509 mActiveDeviceOptions.addAll(getDeviceMatches(device, intent, true)); 510 handleTryNextAoapMode(); 511 } else { 512 doHandleCompleteDeviceProbing(); 513 } 514 } 515 516 private void handleTryNextAoapMode() { 517 if (LOCAL_LOGD) { 518 Log.d(TAG, "handleTryNextAoapMode"); 519 } 520 Pair<ResolveInfo, DeviceFilter> option = mActiveDeviceOptions.peek(); 521 if (option == null) { 522 mHandler.requestCompleteDeviceProbing(); 523 return; 524 } 525 requestAoapSwitch(option.second); 526 } 527 528 private void requestAoapSwitch(DeviceFilter filter) { 529 UsbDeviceStateController.AoapSwitchRequest request = 530 new UsbDeviceStateController.AoapSwitchRequest( 531 mActiveUsbDevice, 532 filter.mAoapManufacturer, 533 filter.mAoapModel, 534 filter.mAoapDescription, 535 filter.mAoapVersion, 536 filter.mAoapUri, 537 filter.mAoapSerial); 538 mStateController.startAoap(request); 539 } 540 541 private void doHandleCompleteDeviceProbing() { 542 if (LOCAL_LOGD) { 543 Log.d(TAG, "doHandleCompleteDeviceProbing"); 544 } 545 mDeviceCallback.onHandlersResolveCompleted(mActiveUsbDevice, mActiveDeviceSettings); 546 stopDeviceProcessing(mActiveUsbDevice); 547 mActiveUsbDevice = null; 548 mBaseSettings = null; 549 mDeviceMode = MODE_OFF; 550 } 551 552 private void doHandleAoapStartComplete(UsbDevice device) { 553 if (LOCAL_LOGD) { 554 Log.d(TAG, "doHandleAoapStartComplete:" + device + " mode: " + MODE_DISPATCH); 555 } 556 if (mDeviceMode == MODE_DISPATCH && mDispatchIntent != null) { 557 mDispatchIntent.putExtra(UsbManager.EXTRA_DEVICE, device); 558 mUsbManager.grantPermission(device, mDispatchUid); 559 mContext.startActivity(mDispatchIntent); 560 mDispatchIntent = null; 561 mDispatchUid = 0; 562 mDeviceMode = MODE_OFF; 563 mDeviceCallback.onDeviceDispatched(); 564 return; 565 } 566 mActiveUsbDevice = device; 567 mDeviceMode = MODE_PROBE_AOAP; 568 if (device == null) { 569 mActiveDeviceOptions.poll(); 570 handleTryNextAoapMode(); 571 } 572 573 Pair<ResolveInfo, DeviceFilter> option = mActiveDeviceOptions.peek(); 574 if (option == null) { 575 Log.w(TAG, "No more options left."); 576 mStateController.startDeviceReset(mActiveUsbDevice); 577 return; 578 } 579 DeviceFilter filter = option.second; 580 Intent serviceIntent = new Intent(); 581 serviceIntent.setComponent(ComponentName.unflattenFromString(option.second.mAoapService)); 582 boolean bound = mContext.bindService(serviceIntent, mConnection, Context.BIND_AUTO_CREATE); 583 if (bound) { 584 mHandler.requestServiceConnectionTimeout(); 585 } else { 586 if (LOCAL_LOGD) { 587 Log.d(TAG, "Failed to bind to the service"); 588 } 589 mStateController.startDeviceReset(mActiveUsbDevice); 590 } 591 } 592 593 private void doHandleDeviceResetComplete(UsbDevice device) { 594 if (LOCAL_LOGD) { 595 Log.d(TAG, "doHandleDeviceResetComplete:" + device); 596 } 597 mActiveDeviceOptions.poll(); 598 mActiveUsbDevice = device; 599 mDeviceMode = MODE_PROBE; 600 handleTryNextAoapMode(); 601 } 602 603 private void doHandleServiceConnectionStateChanged(IUsbAoapSupportCheckService service) { 604 if (LOCAL_LOGD) { 605 Log.d(TAG, "doHandleServiceConnectionStateChanged: " + service); 606 } 607 mBound = service != null; 608 mIUsbAoapSupportCheckService = service; 609 if (mBound && mActiveUsbDevice != null && mDeviceMode == MODE_PROBE_AOAP) { 610 boolean deviceSupported = false; 611 try { 612 deviceSupported = 613 mIUsbAoapSupportCheckService.isDeviceSupported(mActiveUsbDevice); 614 } catch (RemoteException e) { 615 Log.e(TAG, "Call to remote service failed", e); 616 } 617 if (deviceSupported) { 618 Pair<ResolveInfo, DeviceFilter> option = mActiveDeviceOptions.peek(); 619 620 UsbDeviceSettings setting = UsbDeviceSettings.constructSettings(mBaseSettings); 621 setting.setHandler( 622 new ComponentName( 623 option.first.activityInfo.packageName, option.first.activityInfo.name)); 624 setting.setAoap(true); 625 mActiveDeviceSettings.add(setting); 626 } 627 mContext.unbindService(mConnection); 628 mBound = false; 629 mIUsbAoapSupportCheckService = null; 630 mStateController.startDeviceReset(mActiveUsbDevice); 631 } else if (mActiveUsbDevice != null && mDeviceMode == MODE_PROBE_AOAP) { 632 mStateController.startDeviceReset(mActiveUsbDevice); 633 } else { 634 handleTryNextAoapMode(); 635 } 636 } 637 638 private List<Pair<ResolveInfo, DeviceFilter>> getDeviceMatches( 639 UsbDevice device, Intent intent, boolean forAoap) { 640 List<Pair<ResolveInfo, DeviceFilter>> matches = new ArrayList<>(); 641 List<ResolveInfo> resolveInfos = 642 mPackageManager.queryIntentActivities(intent, PackageManager.GET_META_DATA); 643 for (ResolveInfo resolveInfo : resolveInfos) { 644 DeviceFilter filter = packageMatches(resolveInfo.activityInfo, 645 intent.getAction(), device, forAoap); 646 if (filter != null) { 647 matches.add(Pair.create(resolveInfo, filter)); 648 } 649 } 650 return matches; 651 } 652 653 private DeviceFilter packageMatches(ActivityInfo ai, String metaDataName, UsbDevice device, 654 boolean forAoap) { 655 if (LOCAL_LOGD) { 656 Log.d(TAG, "packageMatches ai: " + ai + "metaDataName: " + metaDataName + " forAoap: " 657 + forAoap); 658 } 659 String filterTagName = forAoap ? "usb-aoap-accessory" : "usb-device"; 660 XmlResourceParser parser = null; 661 try { 662 parser = ai.loadXmlMetaData(mPackageManager, metaDataName); 663 if (parser == null) { 664 Log.w(TAG, "no meta-data for " + ai); 665 return null; 666 } 667 668 XmlUtils.nextElement(parser); 669 while (parser.getEventType() != XmlPullParser.END_DOCUMENT) { 670 String tagName = parser.getName(); 671 if (device != null && filterTagName.equals(tagName)) { 672 DeviceFilter filter = DeviceFilter.read(parser, forAoap); 673 if (forAoap || filter.matches(device)) { 674 return filter; 675 } 676 } 677 XmlUtils.nextElement(parser); 678 } 679 } catch (Exception e) { 680 Log.w(TAG, "Unable to load component info " + ai.toString(), e); 681 } finally { 682 if (parser != null) parser.close(); 683 } 684 return null; 685 } 686 687 @Override 688 public void onDeviceResetComplete(UsbDevice device) { 689 if (LOCAL_LOGD) { 690 Log.d(TAG, "onDeviceResetComplete: " + device); 691 } 692 mHandler.requestOnDeviceResetComplete(device); 693 } 694 695 @Override 696 public void onAoapStartComplete(UsbDevice device) { 697 if (LOCAL_LOGD) { 698 Log.d(TAG, "onAoapStartComplete: " + device); 699 } 700 mHandler.requestOnAoapStartComplete(device); 701 } 702 703 @Override 704 public void onAoapStartFailed(UsbDevice device) { 705 if (LOCAL_LOGD) { 706 Log.d(TAG, "onAoapStartFailed: " + device); 707 } 708 mActiveDeviceOptions.poll(); 709 handleTryNextAoapMode(); 710 } 711 712 private boolean isDeviceProcessing(UsbDevice device) { 713 return mActiveDeviceSerial != null 714 && mActiveDeviceSerial.equals(device.getSerialNumber()); 715 } 716 717 private boolean stopDeviceProcessing(UsbDevice device) { 718 if (device == null || device.getSerialNumber().equals(mActiveDeviceSerial)) { 719 mActiveDeviceSerial = null; 720 return true; 721 } 722 return false; 723 } 724 725 private boolean startDeviceProcessing(UsbDevice device) { 726 if (mActiveDeviceSerial != null) { 727 return false; 728 } else { 729 mActiveDeviceSerial = device.getSerialNumber(); 730 return true; 731 } 732 } 733 734 private class UsbDeviceResolverHandler extends Handler { 735 private static final int MSG_RESOLVE_HANDLERS = 0; 736 private static final int MSG_DEVICE_RESET_COMPLETE = 1; 737 private static final int MSG_AOAP_START_COMPLETE = 2; 738 private static final int MSG_SERVICE_CONNECTION_STATE_CHANGE = 3; 739 private static final int MSG_SERVICE_CONNECTION_TIMEOUT = 4; 740 private static final int MSG_COMPLETE_PROBING = 5; 741 private static final int MSG_COMPLETE_DISPATCH = 6; 742 743 private static final long RESCHEDULE_TIMEOUT_MS = 100; 744 private static final long CONNECT_TIMEOUT_MS = 5000; 745 private static final long FINISH_PROBING_TIMEOUT_MS = 200; 746 747 private UsbDeviceResolverHandler(Looper looper) { 748 super(looper); 749 } 750 751 public void requestResolveHandlers(UsbDevice device) { 752 Message msg = obtainMessage(MSG_RESOLVE_HANDLERS, device); 753 sendMessage(msg); 754 } 755 756 public void requestOnAoapStartComplete(UsbDevice device) { 757 sendMessage(obtainMessage(MSG_AOAP_START_COMPLETE, device)); 758 } 759 760 public void requestOnDeviceResetComplete(UsbDevice device) { 761 sendMessage(obtainMessage(MSG_DEVICE_RESET_COMPLETE, device)); 762 } 763 764 public void requestOnServiceConnectionStateChanged(IUsbAoapSupportCheckService service) { 765 sendMessage(obtainMessage(MSG_SERVICE_CONNECTION_STATE_CHANGE, service)); 766 } 767 768 public void requestServiceConnectionTimeout() { 769 sendEmptyMessageDelayed(MSG_SERVICE_CONNECTION_TIMEOUT, CONNECT_TIMEOUT_MS); 770 } 771 772 public void requestCompleteDeviceProbing() { 773 sendEmptyMessageDelayed(MSG_COMPLETE_PROBING, FINISH_PROBING_TIMEOUT_MS); 774 } 775 776 public void requestCompleteDeviceDispatch() { 777 sendEmptyMessage(MSG_COMPLETE_DISPATCH); 778 } 779 780 @Override 781 public void handleMessage(Message msg) { 782 switch (msg.what) { 783 case MSG_RESOLVE_HANDLERS: 784 UsbDevice device = (UsbDevice) msg.obj; 785 // if this device is already being processed - drop the request. 786 if (!isDeviceProcessing(device)) { 787 if (startDeviceProcessing(device)) { 788 doHandleResolveHandlers(device); 789 } else { 790 // Reschedule this device for processing at later time. 791 sendMessageDelayed(msg, RESCHEDULE_TIMEOUT_MS); 792 } 793 } else { 794 Log.i(TAG, "Device is already being processed: " + device); 795 } 796 break; 797 case MSG_AOAP_START_COMPLETE: 798 doHandleAoapStartComplete((UsbDevice) msg.obj); 799 break; 800 case MSG_DEVICE_RESET_COMPLETE: 801 doHandleDeviceResetComplete((UsbDevice) msg.obj); 802 break; 803 case MSG_SERVICE_CONNECTION_STATE_CHANGE: 804 removeMessages(MSG_SERVICE_CONNECTION_TIMEOUT); 805 doHandleServiceConnectionStateChanged((IUsbAoapSupportCheckService) msg.obj); 806 break; 807 case MSG_SERVICE_CONNECTION_TIMEOUT: 808 Log.i(TAG, "Service connection timeout"); 809 doHandleServiceConnectionStateChanged(null); 810 break; 811 case MSG_COMPLETE_PROBING: 812 doHandleCompleteDeviceProbing(); 813 break; 814 case MSG_COMPLETE_DISPATCH: 815 mDeviceCallback.onDeviceDispatched(); 816 break; 817 default: 818 Log.w(TAG, "Unsupported message: " + msg); 819 } 820 } 821 } 822 } 823