aboutsummaryrefslogtreecommitdiff
path: root/car-usb-handler
diff options
context:
space:
mode:
authorKevin Crossan <kcrossan@google.com>2017-03-27 16:06:21 -0700
committerKevin Crossan <kcrossan@google.com>2017-04-03 16:04:21 -0700
commit4f208d8be0fd9cbf1d9defb0587507f11a092b98 (patch)
tree867002002ce4ec93b974b7dacd8eee3d7850dacb /car-usb-handler
parent045c3284c2fdb4cf7c61121af35027d4771664fc (diff)
downloadCar-4f208d8be0fd9cbf1d9defb0587507f11a092b98.tar.gz
Support handling USB devices without serials.
If the serial number is null, then match based on the product ID and vendor ID. The serial number is optional depending on the USB device class. Note: if the device supports AOAP, it is required to have a unique serial number. This is because when a device is in AOAP mode it is signaled by advertising a specific vendor and product ID; the serial is the only data that can re-identify the USB device. Test: manual - plugged in Lilliput touchscreen and verified logging with no crash. Test: manual - plugged in MD before new database schema and launched projection. After updating code+schema, plugging in MD still launched projection. Test: manual - plugged in new MD and was able to start projection. Change-Id: If2010feea075f88b2bb6f3cda7e9b2e1c5c4a15c Fixes: 36599687
Diffstat (limited to 'car-usb-handler')
-rw-r--r--car-usb-handler/res/values/strings.xml1
-rw-r--r--car-usb-handler/src/android/car/usb/handler/UsbDeviceSettings.java13
-rw-r--r--car-usb-handler/src/android/car/usb/handler/UsbHostController.java43
-rw-r--r--car-usb-handler/src/android/car/usb/handler/UsbSettingsStorage.java75
4 files changed, 96 insertions, 36 deletions
diff --git a/car-usb-handler/res/values/strings.xml b/car-usb-handler/res/values/strings.xml
index 2242648941..be1e7a2332 100644
--- a/car-usb-handler/res/values/strings.xml
+++ b/car-usb-handler/res/values/strings.xml
@@ -26,4 +26,5 @@
<string name="usb_pref_delete_yes">Yes</string>
<string name="usb_pref_delete_cancel">Cancel</string>
<string name="usb_resolving_handlers">Getting supported handlers</string>
+ <string name="usb_unknown_device">Unknown USB device</string>
</resources>
diff --git a/car-usb-handler/src/android/car/usb/handler/UsbDeviceSettings.java b/car-usb-handler/src/android/car/usb/handler/UsbDeviceSettings.java
index 5084414093..288f5982fe 100644
--- a/car-usb-handler/src/android/car/usb/handler/UsbDeviceSettings.java
+++ b/car-usb-handler/src/android/car/usb/handler/UsbDeviceSettings.java
@@ -17,7 +17,6 @@ package android.car.usb.handler;
import android.content.ComponentName;
import android.hardware.usb.UsbDevice;
-import com.android.internal.util.Preconditions;
/**
* Settings for USB device.
@@ -34,8 +33,6 @@ public final class UsbDeviceSettings {
private boolean mDefaultHandler;
UsbDeviceSettings(String serialNumber, int vid, int pid) {
- Preconditions.checkNotNull(serialNumber);
-
mSerialNumber = serialNumber;
mVid = vid;
mPid = pid;
@@ -96,7 +93,15 @@ public final class UsbDeviceSettings {
* Checks if setting matches {@code UsbDevice}.
*/
public boolean matchesDevice(UsbDevice device) {
- return getSerialNumber().equals(device.getSerialNumber());
+ String deviceSerial = device.getSerialNumber();
+ if (AoapInterface.isDeviceInAoapMode(device)) {
+ return mAoap && deviceSerial.equals(mSerialNumber);
+ } else if (deviceSerial == null) {
+ return mVid == device.getVendorId() && mPid == device.getProductId();
+ } else {
+ return mVid == device.getVendorId() && mPid == device.getProductId()
+ && deviceSerial.equals(mSerialNumber);
+ }
}
/**
diff --git a/car-usb-handler/src/android/car/usb/handler/UsbHostController.java b/car-usb-handler/src/android/car/usb/handler/UsbHostController.java
index b705928fec..5c61a98091 100644
--- a/car-usb-handler/src/android/car/usb/handler/UsbHostController.java
+++ b/car-usb-handler/src/android/car/usb/handler/UsbHostController.java
@@ -68,10 +68,10 @@ public final class UsbHostController
public void onReceive(Context context, Intent intent) {
if (UsbManager.ACTION_USB_DEVICE_DETACHED.equals(intent.getAction())) {
UsbDevice device = intent.<UsbDevice>getParcelableExtra(UsbManager.EXTRA_DEVICE);
- unsetActiveDeviceIfSerialMatch(device);
+ unsetActiveDeviceIfMatch(device);
} else if (UsbManager.ACTION_USB_DEVICE_ATTACHED.equals(intent.getAction())) {
UsbDevice device = intent.<UsbDevice>getParcelableExtra(UsbManager.EXTRA_DEVICE);
- setActiveDeviceIfSerialMatch(device);
+ setActiveDeviceIfMatch(device);
}
}
};
@@ -79,9 +79,6 @@ public final class UsbHostController
@GuardedBy("this")
private UsbDevice mActiveDevice;
- @GuardedBy("this")
- private String mProcessingDeviceSerial;
-
public UsbHostController(Context context, UsbHostControllerCallbacks callbacks) {
mContext = context;
mCallback = callbacks;
@@ -96,17 +93,17 @@ public final class UsbHostController
}
- private synchronized void setActiveDeviceIfSerialMatch(UsbDevice device) {
- if (device != null && device.getSerialNumber() != null
- && device.getSerialNumber().equals(mProcessingDeviceSerial)) {
+ private synchronized void setActiveDeviceIfMatch(UsbDevice device) {
+ if (mActiveDevice != null && device != null
+ && UsbUtil.isDevicesMatching(device, mActiveDevice)) {
mActiveDevice = device;
}
}
- private synchronized void unsetActiveDeviceIfSerialMatch(UsbDevice device) {
+ private synchronized void unsetActiveDeviceIfMatch(UsbDevice device) {
mHandler.requestDeviceRemoved();
- if (mActiveDevice != null && mActiveDevice.getSerialNumber() != null
- && mActiveDevice.getSerialNumber().equals(device.getSerialNumber())) {
+ if (mActiveDevice != null && device != null
+ && UsbUtil.isDevicesMatching(device, mActiveDevice)) {
mActiveDevice = null;
}
}
@@ -114,7 +111,6 @@ public final class UsbHostController
private synchronized boolean startDeviceProcessingIfNull(UsbDevice device) {
if (mActiveDevice == null) {
mActiveDevice = device;
- mProcessingDeviceSerial = device.getSerialNumber();
return true;
}
return false;
@@ -122,7 +118,6 @@ public final class UsbHostController
private synchronized void stopDeviceProcessing() {
mActiveDevice = null;
- mProcessingDeviceSerial = null;
}
private synchronized UsbDevice getActiveDevice() {
@@ -131,8 +126,22 @@ public final class UsbHostController
private boolean deviceMatchedActiveDevice(UsbDevice device) {
UsbDevice activeDevice = getActiveDevice();
- return activeDevice != null && activeDevice.getSerialNumber() != null
- && activeDevice.getSerialNumber().equals(device.getSerialNumber());
+ return activeDevice != null && UsbUtil.isDevicesMatching(activeDevice, device);
+ }
+
+ private String generateTitle() {
+ String manufacturer = mActiveDevice.getManufacturerName();
+ String product = mActiveDevice.getProductName();
+ if (manufacturer == null && product == null) {
+ return mContext.getString(R.string.usb_unknown_device);
+ }
+ if (manufacturer != null && product != null) {
+ return manufacturer + " " + product;
+ }
+ if (manufacturer != null) {
+ return manufacturer;
+ }
+ return product;
}
/**
@@ -147,7 +156,7 @@ public final class UsbHostController
mCallback.optionsUpdated(mEmptyList);
mCallback.processingStateChanged(true);
- UsbDeviceSettings settings = mUsbSettingsStorage.getSettings(device.getSerialNumber());
+ UsbDeviceSettings settings = mUsbSettingsStorage.getSettings(device);
if (settings != null && mUsbResolver.dispatch(
mActiveDevice, settings.getHandler(), settings.getAoap())) {
if (LOCAL_LOGV) {
@@ -156,7 +165,7 @@ public final class UsbHostController
}
return;
}
- mCallback.titleChanged(device.getManufacturerName() + " " + device.getProductName());
+ mCallback.titleChanged(generateTitle());
mUsbResolver.resolve(device);
}
diff --git a/car-usb-handler/src/android/car/usb/handler/UsbSettingsStorage.java b/car-usb-handler/src/android/car/usb/handler/UsbSettingsStorage.java
index 157c92f9d6..1b251f8eee 100644
--- a/car-usb-handler/src/android/car/usb/handler/UsbSettingsStorage.java
+++ b/car-usb-handler/src/android/car/usb/handler/UsbSettingsStorage.java
@@ -22,6 +22,7 @@ import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
+import android.hardware.usb.UsbDevice;
import android.util.Log;
import java.util.ArrayList;
import java.util.List;
@@ -47,26 +48,43 @@ public final class UsbSettingsStorage {
mDbHelper = new UsbSettingsDbHelper(context);
}
+ private Cursor queryFor(SQLiteDatabase db, UsbDevice device) {
+ String serial = device.getSerialNumber();
+ String selection;
+ String[] selectionArgs;
+ if (AoapInterface.isDeviceInAoapMode(device)) {
+ selection = COLUMN_SERIAL + " = ? AND " + COLUMN_AOAP + " = 1";
+ selectionArgs = new String[] {serial};
+ } else if (serial == null) {
+ selection = COLUMN_SERIAL + " IS NULL AND "
+ + COLUMN_VID + " = ? AND " + COLUMN_PID + " = ?";
+ selectionArgs = new String[] {
+ Integer.toString(device.getVendorId()),
+ Integer.toString(device.getProductId())};
+ } else {
+ selection =
+ COLUMN_SERIAL + " = ? AND " + COLUMN_VID + " = ? AND " + COLUMN_PID + " = ?";
+ selectionArgs = new String[] {
+ device.getSerialNumber(),
+ Integer.toString(device.getVendorId()),
+ Integer.toString(device.getProductId())};
+ }
+ return db.query(TABLE_USB_SETTINGS, null, selection, selectionArgs, null, null, null);
+ }
+
/**
* Returns settings for {@serialNumber} or null if it doesn't exist.
*/
@Nullable
- public UsbDeviceSettings getSettings(String serialNumber) {
+ public UsbDeviceSettings getSettings(UsbDevice device) {
try (SQLiteDatabase db = mDbHelper.getReadableDatabase();
- Cursor resultCursor = db.query(
- TABLE_USB_SETTINGS,
- null,
- COLUMN_SERIAL + " = ?",
- new String[]{serialNumber},
- null,
- null,
- null)) {
+ Cursor resultCursor = queryFor(db, device)) {
if (resultCursor.getCount() > 1) {
- throw new RuntimeException("Querying for serial number: " + serialNumber
+ throw new RuntimeException("Querying for device: " + device
+ " returned " + resultCursor.getCount() + " results");
}
if (resultCursor.getCount() == 0) {
- Log.w(TAG, "Usb setting missing for device serial: " + serialNumber);
+ Log.w(TAG, "Usb setting missing for device: " + device);
return null;
}
List<UsbDeviceSettings> settings = constructSettings(resultCursor);
@@ -168,7 +186,7 @@ public final class UsbSettingsStorage {
private static class UsbSettingsDbHelper extends SQLiteOpenHelper {
- private static final int DATABASE_VERSION = 1;
+ private static final int DATABASE_VERSION = 2;
private static final String DATABASE_NAME = "usb_devices.db";
UsbSettingsDbHelper(Context context) {
@@ -177,20 +195,47 @@ public final class UsbSettingsStorage {
@Override
public void onCreate(SQLiteDatabase db) {
- db.execSQL("CREATE TABLE " + TABLE_USB_SETTINGS + " ("
+ createTable(db, TABLE_USB_SETTINGS);
+ createSerialIndex(db);
+ }
+
+ private void createTable(SQLiteDatabase db, String tableName) {
+ db.execSQL("CREATE TABLE " + tableName + " ("
+ COLUMN_SERIAL + " TEXT,"
+ COLUMN_VID + " INTEGER,"
+ COLUMN_PID + " INTEGER,"
+ COLUMN_NAME + " TEXT, "
+ COLUMN_HANDLER + " TEXT,"
+ COLUMN_AOAP + " INTEGER,"
- + COLUMN_DEFAULT_HANDLER + " INTEGER," + "PRIMARY KEY (" + COLUMN_SERIAL
+ + COLUMN_DEFAULT_HANDLER + " INTEGER,"
+ + "PRIMARY KEY (" + COLUMN_SERIAL + ", " + COLUMN_VID + ", " + COLUMN_PID
+ "))");
}
+ private void createSerialIndex(SQLiteDatabase db) {
+ db.execSQL("CREATE INDEX " + TABLE_USB_SETTINGS + "_" + COLUMN_SERIAL + " ON "
+ + TABLE_USB_SETTINGS + "(" + COLUMN_SERIAL + ")");
+ }
+
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
- // Do nothing at this point. Not required for v1 database.
+ for (; oldVersion != newVersion; oldVersion++) {
+ switch (oldVersion) {
+ case 1:
+ String tempTableName = "temp_" + TABLE_USB_SETTINGS;
+ createTable(db, tempTableName);
+ db.execSQL("INSERT INTO " + tempTableName
+ + " SELECT * FROM " + TABLE_USB_SETTINGS);
+ db.execSQL("DROP TABLE " + TABLE_USB_SETTINGS);
+ db.execSQL("ALTER TABLE " + tempTableName + " RENAME TO "
+ + TABLE_USB_SETTINGS);
+ createSerialIndex(db);
+ break;
+ default:
+ throw new IllegalArgumentException(
+ "Unknown database version " + oldVersion);
+ }
+ }
}
}
}