Android USB攝像頭插拔監聽
-
- 一、簡要介紹
- 二、使用廣播監聽USB攝像頭插拔情況
-
- 1、注冊監聽USB裝置插拔廣播
- 2、判斷UsbDevice是否是Camera裝置 (重點)
- 二、通過UsbManager來擷取目前裝置的Usb攝像頭資訊
- Camera裝置節點
-
- 使用裝置節點要注意:
- 共勉:人生沒有一條路是白走的。每個不滿意的現在,都有個不努力的曾經。一個人至少擁有一個夢想,有一個理由去堅強。
部分Android開發裝置可以插入USB攝像頭使用,剛好工作用到了,本文将對USBCamera拔插監聽進行總結記錄。
一、簡要介紹
USB攝像頭,可以通過廣播監聽,監聽到USB攝像頭的插拔情況;
還可以使用UsbManager來擷取目前裝置存在的外設,從中擷取USB攝像頭資訊。
還可以在底層監聽Camera變化,不過這個比較麻煩,本文不做介紹。
使用廣播可以動态擷取UsbCamera,并作出相應的操作;
使用UsbManager,主要是用在即時性的操作,
比如某個頁面準備要用UsbCamera可以提前判斷是否已存在UsbCamera裝置。
二、使用廣播監聽USB攝像頭插拔情況
1、注冊監聽USB裝置插拔廣播
private BroadcastReceiver mBroadcastReceiver;
//注冊監聽Usb裝置插拔廣播
private void registerBroadcastReceiver() {
Log.i(TAG, "registerBroadcastReceiver");
if (mBroadcastReceiver == null) {
mBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (intent == null) {
return;
}
// 這裡可以拿到插入的USB裝置對象
UsbDevice usbDevice = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
switch (intent.getAction()) {
case UsbManager.ACTION_USB_DEVICE_ATTACHED: // 插入USB裝置
if (isUsbCameraDevice(usbDevice)) {
Toast.makeText(UsbCameraActivity.this, "Usb攝像頭已插入", Toast.LENGTH_LONG).show();
//do some thing
}
break;
case UsbManager.ACTION_USB_DEVICE_DETACHED: // 拔出USB裝置
if (isUsbCameraDevice(usbDevice)) {
Toast.makeText(UsbCameraActivity.this, "Usb攝像頭已拔出", Toast.LENGTH_LONG).show();
//do some thing
}
break;
default:
break;
}
}
};
}
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED); //外設插入廣播
intentFilter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED); //外設拔出廣播
registerReceiver(mBroadcastReceiver, intentFilter);
}
//反注冊監聽Usb裝置插拔廣播
private void unregisterBroadcastReceiver() {
Log.i(TAG, "unregisterBroadcastReceiver");
if (mBroadcastReceiver != null) {
unregisterReceiver(mBroadcastReceiver);
}
}
2、判斷UsbDevice是否是Camera裝置 (重點)
private static final int USB_CAMERA_TYPE = 14; //可能跟不同系統裝置相關,一般是某個固定值,可以打Log驗證。
/**
* 判斷目前Usb裝置是否是Camera裝置
*/
private boolean isUsbCameraDevice(UsbDevice usbDevice) {
Log.i(TAG, "isUsbCameraDevice usbDevice " + usbDevice.getProductName() + usbDevice.getDeviceClass() + ", subclass = " + usbDevice.getDeviceSubclass());
if (usbDevice == null) {
return false;
}
boolean isCamera = false;
int interfaceCount = usbDevice.getInterfaceCount();
for (int interIndex = 0; interIndex < interfaceCount; interIndex++) {
UsbInterface usbInterface = usbDevice.getInterface(interIndex);
//usbInterface.getName()遇到過為null的情況
if ((usbInterface.getName() == null || usbDevice.getProductName().equals(usbInterface.getName())) && usbInterface.getInterfaceClass() == USB_CAMERA_TYPE) {
isCamera = true;
break;
}
}
Log.i(TAG, "onReceive usbDevice = " + usbDevice.getProductName() + "isCamera = " + isCamera);
return isCamera;
}
網上是有很多判斷UsbDevice是否是Camera裝置的邏輯代碼,但是好像沒有完全正确的。
比如下面這個:
//不準确的判斷
public boolean isUsbCamera(UsbDevice usbDevice) {
return usbDevice != null && 239 == usbDevice.getDeviceClass() && 2 == usbDevice.getDeviceSubclass();
}
很多裝置都會符合這個條件,比分mic裝置,無線WiFi裝置等等。是以使用這個邏輯會有機率的誤判斷。
通過我的多次研究判斷,usbInterface.getInterfaceClass()也是不同裝置的類型值,但是這個值在api中未定義。
這個值在MTK848,9950,USB攝像頭裝置擷取到的都是等于14。
二、通過UsbManager來擷取目前裝置的Usb攝像頭資訊
/**
* 通過 UsbManager擷取目前外設攝像頭資訊
*/
private List<UsbDevice> getCameraList() {
Log.i(TAG, "getCameraList");
List<UsbDevice> cameraList = new ArrayList<>();
UsbManager mUsbManager = (UsbManager) getSystemService(Context.USB_SERVICE); //這個隻适用于Usb裝置
HashMap<String, UsbDevice> mDeviceMap = mUsbManager.getDeviceList();
if (mDeviceMap != null) {
for (UsbDevice usbDevice : mDeviceMap.values()) {
if (isUsbCameraDevice(usbDevice)) {
cameraList.add(usbDevice);
}
}
}
return cameraList;
}
/**
* 通過 UsbManager擷取目前外設攝像頭名稱資訊
*/
private List<String> getCameraStringList() {
List<String> cameraList = new ArrayList<>();
UsbManager mUsbManager = (UsbManager) getSystemService(Context.USB_SERVICE);
HashMap<String, UsbDevice> mDeviceMap = mUsbManager.getDeviceList();
if (mDeviceMap != null) {
for (UsbDevice usbDevice : mDeviceMap.values()) {
if (isUsbCameraDevice(usbDevice)) {
cameraList.add(usbDevice.getProductName());
}
}
}
return cameraList;
}
同樣是通過周遊所有UsbDevice對象來判斷是否是Usb攝像頭裝置。
Camera裝置節點
外部裝置節點都是在dev下的,相機節點的關鍵字是video,
比如:/dev/video0 表示第一個插入的攝像頭,video1表示插入的第二個攝像頭,以此類推。
有系統權限的應用,可以直接讀取這個節點的名稱,
private void updateDevVideoList() {
File file = new File("/dev");
if (file.isDirectory()) {
File[] list = file.listFiles();
if (list != null) {
for (File it : list) {
if (it.getName().contains("video")){
//videoX
}
}
}
}
}
使用裝置節點要注意:
1、節點資料裡面,沒有裝置名稱
2、并不是所有外接攝像頭都是隻有一個裝置節點,
部分裝置存在兩個節點,需要在C++底層對節點進行分析判斷(這部分内容有寫文章專門分析)