Last active
August 13, 2018 06:31
-
-
Save felHR85/afe18397dc2441862337 to your computer and use it in GitHub Desktop.
An easy to use android solution to get a readable representation of Usb vid (vendor name) and pid (product name). Data is collected and stored in a local SQLite database from http://www.linux-usb.org/usb-ids.html
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class UsbData | |
{ | |
private String vendorId; | |
private String vendorName; | |
private String productId; | |
private String productName; | |
public UsbData(String vendorId, String vendorName, String productId, String productName) | |
{ | |
this.vendorId = vendorId; | |
this.vendorName = vendorName; | |
this.productId = productId; | |
this.productName = productName; | |
} | |
public String getVendorId() | |
{ | |
return vendorId; | |
} | |
public void setVendorId(String vendorId) | |
{ | |
this.vendorId = vendorId; | |
} | |
public String getVendorName() | |
{ | |
return vendorName; | |
} | |
public void setVendorName(String vendorName) | |
{ | |
this.vendorName = vendorName; | |
} | |
public String getProductId() | |
{ | |
return productId; | |
} | |
public void setProductId(String productId) | |
{ | |
this.productId = productId; | |
} | |
public String getProductName() | |
{ | |
return productName; | |
} | |
public void setProductName(String productName) | |
{ | |
this.productName = productName; | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.io.BufferedReader; | |
import java.io.IOException; | |
import java.io.InputStream; | |
import java.io.InputStreamReader; | |
import java.net.HttpURLConnection; | |
import java.net.MalformedURLException; | |
import java.net.URL; | |
import java.net.URLConnection; | |
import java.util.ArrayList; | |
import java.util.Iterator; | |
import java.util.List; | |
public class UsbDataHelper | |
{ | |
private final static String USB_URL = "http://www.linux-usb.org/usb.ids"; | |
private UsbDataHelper() | |
{ | |
} | |
// Parse a given number of lines from url. Returns null if an error occur. | |
public static List<String> parseDataFromUrl(int numberLines) | |
{ | |
return UrlDownloaderHelper.fetchDataFromUrl(numberLines); | |
} | |
// Parse data from url to a local database. | |
public static void parseStringToDb(List<String> data, UsbDbAdapter dbAdapter) | |
{ | |
UsbIdRepositoryHelper.populateDb(data, dbAdapter); | |
} | |
// Get current repository version from url. Returns null if an error occur | |
public static String getRepositoryVersion() | |
{ | |
return UsbIdRepositoryHelper.getVersion(); | |
} | |
private static class UrlDownloaderHelper | |
{ | |
public static List<String> fetchDataFromUrl(int linesNumber) | |
{ | |
int counter = 0; | |
List<String> lines = new ArrayList<String>(19000); | |
URL url = null; | |
try | |
{ | |
url = new URL(USB_URL); | |
}catch(MalformedURLException e) | |
{ | |
e.printStackTrace(); | |
url = null; | |
} | |
if(url != null) | |
{ | |
try | |
{ | |
URLConnection newConnection = url.openConnection(); | |
HttpURLConnection httpConexion = (HttpURLConnection) newConnection; | |
int responseCode = httpConexion.getResponseCode(); | |
if(responseCode == HttpURLConnection.HTTP_OK) | |
{ | |
InputStream is = httpConexion.getInputStream(); | |
BufferedReader br = new BufferedReader(new InputStreamReader(is,"UTF-8")); | |
String line; | |
while((line = br.readLine()) != null) | |
{ | |
lines.add(line); | |
if(linesNumber != 0) | |
{ | |
counter++; | |
if(linesNumber == counter) | |
return lines; | |
} | |
} | |
}else | |
{ | |
return null; | |
} | |
} catch (IOException e) | |
{ | |
e.printStackTrace(); | |
return null; | |
} | |
}else | |
{ | |
return null; | |
} | |
return lines; | |
} | |
} | |
private static class UsbIdRepositoryHelper | |
{ | |
// Flags | |
private static boolean VID_PID_PARSING; // Parser is already parsing Vids and Pids | |
// Next Section of file, there are no more vid an pids beyond this line | |
private static final String NEXT_SECTION = "# List of known device classes, subclasses and protocols"; | |
//Tokens | |
private static final char NUMBER_SIGN = '#'; | |
private static final String VERSION = "Version:"; | |
private static final String DATE = "Date:"; | |
private UsbIdRepositoryHelper() | |
{ | |
VID_PID_PARSING = false; | |
} | |
public static void populateDb(List<String> data, UsbDbAdapter dbAdapter) | |
{ | |
boolean keep = true; | |
String tempVidKey = null; | |
String tempVidName = null; | |
String tempVersion = null; | |
String tempDate = null; | |
List<UsbData> productList = new ArrayList<UsbData>(); | |
Iterator<String> e = data.iterator(); | |
dbAdapter.beginTransaction(); | |
while(keep && e.hasNext()) | |
{ | |
String line = e.next(); | |
if(line.length() > 0) | |
{ | |
if(!VID_PID_PARSING && line.charAt(0) == NUMBER_SIGN && line.contains(VERSION)) // Get Version | |
{ | |
line = line.trim(); | |
tempVersion = line.substring(11, line.length()); | |
}else if(!VID_PID_PARSING && line.charAt(0) == NUMBER_SIGN && line.contains(DATE)) // Get Date | |
{ | |
line = line.trim(); | |
tempDate = line.substring(11,line.length()); | |
dbAdapter.insertEntryVersion(tempVersion, tempDate); | |
}else if(line.charAt(0) >= 0x30) // Get VID and Vendor name | |
{ | |
if(!productList.isEmpty()) // List of Pids associated to a Vid has been completely read. | |
{ | |
dbAdapter.insertEntryVendor(tempVidKey, tempVidName); | |
Iterator<UsbData> t = productList.iterator(); | |
while(t.hasNext()) | |
{ | |
UsbData usbData = t.next(); | |
dbAdapter.insertEntryProduct(usbData); | |
} | |
productList.clear(); | |
}else if((VID_PID_PARSING && productList.isEmpty())) // There is a VID without PIDS | |
{ | |
dbAdapter.insertEntryVendor(tempVidKey, tempVidName); | |
} | |
line = line.trim(); | |
tempVidKey = line.substring(0, 4); | |
tempVidName = line.substring(5, line.length()); | |
if(!VID_PID_PARSING) | |
VID_PID_PARSING = true; | |
}else if(VID_PID_PARSING && line.charAt(0) != NUMBER_SIGN && line.length() > 1) // Get PID and product name | |
{ | |
line = line.trim(); | |
String pid = line.substring(0, 4); | |
String namePid = line.substring(6,line.length()); | |
UsbData productData = new UsbData(tempVidKey, tempVidName, pid, namePid); | |
productList.add(productData); | |
}else if(VID_PID_PARSING && line.equals(NEXT_SECTION)) // No more devices, add the last Vid and Pids associated | |
{ | |
dbAdapter.insertEntryVendor(tempVidKey, tempVidName); | |
Iterator<UsbData> t = productList.iterator(); | |
while(t.hasNext()) | |
{ | |
UsbData usbData = t.next(); | |
dbAdapter.insertEntryProduct(usbData); | |
} | |
productList.clear(); | |
keep = false; | |
} | |
} | |
} | |
dbAdapter.setTransactionSuccesful(); | |
dbAdapter.endTransaction(); | |
} | |
public static String getVersion() | |
{ | |
List<String> data = UrlDownloaderHelper.fetchDataFromUrl(12); | |
if(data != null) | |
{ | |
Iterator<String> e = data.iterator(); | |
while(e.hasNext()) | |
{ | |
String line = e.next(); | |
if(line.charAt(0) == NUMBER_SIGN && line.contains(VERSION)) // Get Version | |
{ | |
return line.substring(11, line.length()); | |
} | |
} | |
} | |
return null; | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.io.File; | |
import java.util.List; | |
import android.content.Context; | |
import android.util.Log; | |
public class UsbDataProvider | |
{ | |
private static final String CLASS_ID = UsbDataProvider.class.getSimpleName(); | |
private Context context; | |
private HeavyTasksThread heavyTasksThread; | |
private UsbDbCallback mCallback; | |
private UsbDbAdapter dbAdapter; | |
public UsbDataProvider(Context context) | |
{ | |
this.context = context; | |
heavyTasksThread = new HeavyTasksThread(); | |
heavyTasksThread.start(); | |
} | |
public UsbDataProvider(Context context, UsbDbCallback mCallback) | |
{ | |
this.context = context; | |
heavyTasksThread = new HeavyTasksThread(); | |
this.mCallback = mCallback; | |
heavyTasksThread.start(); | |
} | |
public UsbData lookup(String vid, String pid) | |
{ | |
if(dbAdapter != null) | |
return dbAdapter.query(vid, pid); | |
else | |
return null; | |
} | |
private class HeavyTasksThread extends Thread | |
{ | |
private boolean isDbCreated; | |
public HeavyTasksThread() | |
{ | |
isDbCreated = false; | |
} | |
@Override | |
public void run() | |
{ | |
File dbPath = context.getDatabasePath(UsbDbAdapter.DB_NAME); | |
if(dbPath.exists()) | |
isDbCreated = true; | |
if(!isDbCreated) | |
{ | |
// First time, populate DB | |
List<String> data = UsbDataHelper.parseDataFromUrl(0); | |
if(data != null) // | |
{ | |
// Open Database | |
dbAdapter = new UsbDbAdapter(context, UsbDbAdapter.DB_VERSION_1); | |
dbAdapter.open(); | |
// Data correctly parsed from url | |
UsbDataHelper.parseStringToDb(data, dbAdapter); | |
if(mCallback != null) | |
mCallback.onDbOpenedFirstTime(true); | |
}else | |
{ | |
// Some error occurred when parsing data from url | |
if(mCallback != null) | |
mCallback.onDbOpenedFirstTime(false); | |
} | |
}else | |
{ | |
// Database has been created before. Check version and update if necessary | |
dbAdapter = new UsbDbAdapter(context, UsbDbAdapter.DB_VERSION_1); | |
dbAdapter.open(); | |
String currentVersion = UsbDataHelper.getRepositoryVersion(); | |
if(currentVersion != null) | |
{ | |
// Current remote version could be read. Check version and if not equal, update | |
String localVersion = dbAdapter.queryLocalVersion(); | |
int idLocalVersion = dbAdapter.queryLocalVersionId(); | |
Log.i(CLASS_ID, "Local version: " + localVersion + " Local version Id: " + | |
String.valueOf(idLocalVersion)+ " Remote version: " + currentVersion); | |
if(!currentVersion.equals(localVersion)) // Remote version != local version. Try to update | |
{ | |
List<String> data = UsbDataHelper.parseDataFromUrl(0); | |
if(data != null) | |
{ | |
dbAdapter.close(); | |
idLocalVersion++; | |
dbAdapter = new UsbDbAdapter(context, idLocalVersion); | |
dbAdapter.open(); | |
UsbDataHelper.parseStringToDb(data, dbAdapter); | |
if(mCallback != null) | |
mCallback.onDbUpdated(currentVersion); | |
}else | |
{ | |
dbAdapter = new UsbDbAdapter(context, idLocalVersion); | |
dbAdapter.open(); | |
Log.i(CLASS_ID, "Db could not be updated"); | |
} | |
}else // Remote version == Local version Open Database normally | |
{ | |
if(mCallback != null) | |
mCallback.onDbOpened(); | |
} | |
}else | |
{ | |
Log.i(CLASS_ID, "Remote version could not be read from url, Last db version opened"); | |
if(mCallback != null) | |
mCallback.onDbOpened(); | |
} | |
} | |
} | |
} | |
public interface UsbDbCallback | |
{ | |
public void onDbOpenedFirstTime(boolean status); | |
public void onDbOpened(); | |
public void onDbUpdated(String newVersion); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import android.content.ContentValues; | |
import android.content.Context; | |
import android.database.Cursor; | |
import android.database.SQLException; | |
import android.database.sqlite.SQLiteDatabase; | |
import android.database.sqlite.SQLiteDatabase.CursorFactory; | |
import android.database.sqlite.SQLiteOpenHelper; | |
import android.database.sqlite.SQLiteStatement; | |
public class UsbDbAdapter | |
{ | |
public static final String DB_NAME = "usbIds.db"; | |
public static final int DB_VERSION_1 = 1; | |
private static final String VERSION_TABLE = "versionTable"; | |
private static final String VENDOR_TABLE = "vendorTable"; | |
private static final String PRODUCT_TABLE = "productTable"; | |
//Version Table Columns | |
private static final String VERSION_COLUMN = "version"; | |
private static final String DATE_COLUMN = "date"; | |
private static final String ID_VERSION = "id_version"; | |
// Vendor Table Columns | |
private static final String KEY_ID = "_id"; | |
private static final String VID_COLUMN = "vid"; | |
private static final String VID_NAME_COLUMN = "vid_name"; | |
// Product Table Columns | |
private static final String KEY_ID_PRODUCT = "_id"; | |
private static final String VID_PRODUCT_COLUMN = "vid"; | |
private static final String PID_PRODUCT_COLUMN = "pid"; | |
private static final String PID_NAME_PRODUCT_COLUMN = "pid_name"; | |
// SQL Statements | |
private static final String CREATE_VERSION_TABLE = "create table " + VERSION_TABLE + "(" | |
+ KEY_ID + " integer primary key autoincrement, " + VERSION_COLUMN + " text not null, " | |
+ DATE_COLUMN + " text not null, " + ID_VERSION + " integer);"; | |
private static final String CREATE_VENDOR_TABLE = "create table " + VENDOR_TABLE + "(" | |
+KEY_ID + " integer primary key autoincrement, " + VID_COLUMN + " text not null, " + VID_NAME_COLUMN + " text not null);"; | |
private static final String CREATE_PRODUCT_TABLE = "create table " + PRODUCT_TABLE + "(" | |
+ KEY_ID_PRODUCT + " integer primary key autoincrement, " + VID_PRODUCT_COLUMN + " text not null, " | |
+ PID_PRODUCT_COLUMN + " text not null, " + PID_NAME_PRODUCT_COLUMN + " text not null);" ; | |
private static final String SELECT_VENDOR_PRODUCT = "select vid_name, pid_name from " | |
+ VENDOR_TABLE + ", " + PRODUCT_TABLE + " where " + VENDOR_TABLE +".vid = ?" + " and " + PRODUCT_TABLE + ".vid = ? " + "and pid = ?"; | |
private static final String SELECT_VENDOR = "select vid, vid_name from " + VENDOR_TABLE + " where vid = ?"; | |
private static final String SELECT_VERSION = "select " + VERSION_COLUMN + " from " + VERSION_TABLE; | |
private static final String SELECT_VERSION_ID = "select " + ID_VERSION + " from " + VERSION_TABLE; | |
private static final String INSERT_VENDOR = "insert into " + VENDOR_TABLE + " (" + VID_COLUMN + ", " + VID_NAME_COLUMN | |
+ ") values(?,?)"; | |
private static final String INSERT_PRODUCT = "insert into " + PRODUCT_TABLE + " (" + VID_PRODUCT_COLUMN | |
+ ", " + PID_PRODUCT_COLUMN + ", " + PID_NAME_PRODUCT_COLUMN + ") values(?,?,?)"; | |
// Compiled SQL Statements | |
private static SQLiteStatement insertVendor; | |
private static SQLiteStatement insertProduct; | |
private SQLiteDatabase db; | |
private DbHelper dbHelper; | |
private int currentVersion; | |
public UsbDbAdapter(Context context, int version) | |
{ | |
this.currentVersion = version; | |
dbHelper = new DbHelper(context, DB_NAME, null, version); | |
} | |
public UsbDbAdapter open() throws SQLException | |
{ | |
db = dbHelper.getWritableDatabase(); | |
return this; | |
} | |
public void close() | |
{ | |
db.close(); | |
} | |
public void beginTransaction() | |
{ | |
db.beginTransaction(); | |
} | |
public void endTransaction() | |
{ | |
db.endTransaction(); | |
} | |
public void setTransactionSuccesful() | |
{ | |
db.setTransactionSuccessful(); | |
} | |
public long insertEntryVersion(String version, String date) | |
{ | |
ContentValues values = new ContentValues(); | |
values.put(VERSION_COLUMN, version); | |
values.put(DATE_COLUMN, date); | |
values.put(ID_VERSION, currentVersion); | |
return db.insert(VERSION_TABLE, null, values); | |
} | |
public void insertEntryVendor(String vid, String vidName) | |
{ | |
insertVendor.bindString(1, vid); | |
insertVendor.bindString(2, vidName); | |
insertVendor.execute(); | |
insertVendor.clearBindings(); | |
} | |
public void insertEntryProduct(UsbData data) | |
{ | |
insertProduct.bindString(1, data.getVendorId()); | |
insertProduct.bindString(2, data.getProductId()); | |
insertProduct.bindString(3, data.getProductName()); | |
insertProduct.execute(); | |
insertProduct.clearBindings(); | |
} | |
public String queryLocalVersion() | |
{ | |
Cursor cursor = db.rawQuery(SELECT_VERSION, null); | |
cursor.moveToFirst(); | |
return cursor.getString(0); | |
} | |
public int queryLocalVersionId() | |
{ | |
Cursor cursor = db.rawQuery(SELECT_VERSION_ID, null); | |
cursor.moveToFirst(); | |
return cursor.getInt(0); | |
} | |
public UsbData query(String vid, String pid) | |
{ | |
if(validateInput(vid, pid)) | |
{ | |
Cursor cursor = db.rawQuery(SELECT_VENDOR_PRODUCT, new String[]{vid, vid, pid}); | |
cursor.moveToFirst(); | |
if(cursor.getCount() > 0) | |
{ | |
String vidName = cursor.getString(0); | |
String pidName = cursor.getString(1); | |
return new UsbData(vid, vidName, pid, pidName); | |
}else | |
{ | |
cursor = db.rawQuery(SELECT_VENDOR, new String[]{vid}); | |
cursor.moveToFirst(); | |
if(cursor.getCount() > 0) | |
{ | |
String stringName = cursor.getString(1); | |
return new UsbData(vid, stringName, pid, "None"); | |
}else | |
{ | |
return new UsbData("None", "None", "None", "None"); | |
} | |
} | |
}else | |
{ | |
return null; | |
} | |
} | |
private boolean validateInput(String vid, String pid) | |
{ | |
if((vid.length() > 4 || pid.length() > 4)) | |
return false; | |
if(checkHexValue(vid) && checkHexValue(pid)) | |
return true; | |
else | |
return false; | |
} | |
private boolean checkHexValue(String value) | |
{ | |
for(int i=0;i<=value.length()-1;i++) | |
{ | |
if(value.charAt(i) < 0x30 || value.charAt(i) > 0x66) | |
{ | |
return false; | |
}else | |
{ | |
if(value.charAt(i) > 0x39 && value.charAt(i) < 0x41) | |
{ | |
return false; | |
}else | |
{ | |
if(value.charAt(i) > 0x46 && value.charAt(i) < 0x61) | |
{ | |
return false; | |
} | |
} | |
} | |
} | |
return true; | |
} | |
private static class DbHelper extends SQLiteOpenHelper | |
{ | |
public DbHelper(Context context, String name, CursorFactory factory, | |
int version) | |
{ | |
super(context, name, factory, version); | |
} | |
@Override | |
public void onCreate(SQLiteDatabase db) | |
{ | |
db.execSQL(CREATE_VERSION_TABLE); | |
db.execSQL(CREATE_VENDOR_TABLE); | |
db.execSQL(CREATE_PRODUCT_TABLE); | |
insertVendor = db.compileStatement(INSERT_VENDOR); | |
insertProduct = db.compileStatement(INSERT_PRODUCT); | |
} | |
@Override | |
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) | |
{ | |
if(newVersion > oldVersion) | |
{ | |
db.execSQL("DROP TABLE IF EXISTS " + VERSION_TABLE); | |
db.execSQL("DROP TABLE IF EXISTS " + VENDOR_TABLE); | |
db.execSQL("DROP TABLE IF EXISTS " + PRODUCT_TABLE); | |
db.execSQL("VACUUM"); | |
onCreate(db); | |
}else | |
{ | |
db.setVersion(oldVersion); | |
} | |
} | |
@Override | |
public void onDowngrade (SQLiteDatabase db, int oldVersion, int newVersion) | |
{ | |
onUpgrade(db, oldVersion, newVersion); | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Example of use | |
* @author: felhr ([email protected]) | |
*/ | |
// Permissions needed: <uses-permission android:name="android.permission.INTERNET" /> | |
// There are some callbacks related with created, opened and updated database events. It is not necessary to use them. | |
private UsbDataProvider.UsbDbCallback mCallback = new UsbDataProvider.UsbDbCallback() | |
{ | |
@Override | |
public void onDbOpenedFirstTime(boolean status) | |
{ | |
// status == false means database could not be created due to an error fetching data from source | |
// status == true means database was successfully created | |
// Code here | |
} | |
@Override | |
public void onDbOpened() | |
{ | |
// Database opened | |
// Code here | |
} | |
@Override | |
public void onDbUpdated(String newVersion) | |
{ | |
// Database updated with newVersion | |
// Code here | |
} | |
}; | |
UsbDataProvider dataProvider; | |
dataProvider = new UsbDataProvider(context, mCallback); // Create and open, open or update and open database if necessary. Notifications on callback | |
//dataProvider = new UsbDataProvider(context) | |
String vid = "03f0"; // Must be an hex representation of 16 bit number (0000-FFFF). Don't worry about uppercase or lowercase | |
String pid= "010C"; // Must be an hex representation of 16 bit number (0000-FFFF). Don't worry about uppercase or lowercase | |
UsbData data = dataProvider.lookup(vid, pid); // Returns null if vid or pid are not valid inputs or database could not be created | |
if(data != null) | |
{ | |
String vendorName = data.getVendorName(); // Vendor name | |
String productName = data.getProductName(); // Product name | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment