天天看點

Android USB攝像頭插拔監聽共勉:人生沒有一條路是白走的。每個不滿意的現在,都有個不努力的曾經。一個人至少擁有一個夢想,有一個理由去堅強。

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++底層對節點進行分析判斷(這部分内容有寫文章專門分析)
           

共勉:人生沒有一條路是白走的。每個不滿意的現在,都有個不努力的曾經。一個人至少擁有一個夢想,有一個理由去堅強。