UVC驱动外接摄像头

博主免责声明:仅供研究讨论,严禁商用!!!

简单记录一下开发中遇到的手机驱动外接摄像头,目前只能针对个别机型,像小米,魅族MX2,ZTE测试过是可行的,Lenovo,VIVO,华为由于关闭了外接设备,并不支持外接摄像头。摄像头要支持UVC软驱。另外要注意,摄像头预览分辨率要是手机/平板分辨率和摄像头支持的分辨率交集,Demo中将查看分辨率的代码解开(代码改为true)可以查看两者支持的分辨率。还是有很多问题的,距离商用还有一段距离,仅供参考,还请感兴趣的大牛联系完善。

在平板测试过程中发现性能比较好的品牌平板表现良好,不过遇到一个棘手的问题就是HOME与BACk键交叉使用会导致图像不再显示,手机显示蛮好,平板表现比较次。

项目创建

本项目在EC下创建取名为UVCDemo,包名:com.serenegiant.uvccamera,我们先把底层库引入:

如果会NDK的话请研究jni文件:

资源文件:

权限如下:

 

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
<uses-permission android:name="android.permission.CAMERA"/>

上述权限并不是都要有,由于肯定牵扯到联网所以要有网络相关的权限,根据需求增删(本项目所用如下)

 

 

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.CAMERA"/>
<!-- 屏蔽HOME键需要的权限 -->
<uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<!-- 开机自启动需要的权限 -->
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" /> 

 

 

 

核心代码

原理是使用UVCCamera来控制、管理与外接设备的连接,UVCCameraTextureView控件进行图像的预览,USBMonitor进行驱动的连接和断开

先在需要的地方添加控件:

<com.serenegiant.usb.widget.UVCCameraTextureView
        android:id="@+id/camera_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_centerHorizontal="true"
        android:layout_centerVertical="true" />

我在CaptureActivity初始化:

final View view = findViewById(R.id.camera_view);
mUVCCameraView = (CameraViewInterface)view;
mUVCCameraView.setAspectRatio(PREVIEW_WIDTH / (float)PREVIEW_HEIGHT);//TODO
mUSBMonitor = new USBMonitor(this, mOnDeviceConnectListener);
mHandler = CameraHandler.createHandler(this, mUVCCameraView);

我通过CameraHandler将事件分发出去,里面包含了对外接摄像头的所有操作,拍照啊、录像啊、释放资源啊等等

在使用“.so”库的时候记得添加库才能使用本地语言

System.loadLibrary("usb100");
System.loadLibrary("uvc");
System.loadLibrary("UVCCamera");

预览的调用等都是通过调用native的方法c++实现的

    /**
     * start preview
     */
    public void startPreview() {
    	if (mCtrlBlock != null) {
    		nativeStartPreview(mNativePtr);
    	}
    }

    /**
     * stop preview
     */
    public void stopPreview() {
    	setFrameCallback(null, 0);
    	if (mCtrlBlock != null) {
    		nativeStopPreview(mNativePtr);
    	}
    }

驱动连接方面,我们自定义一个规则

<?xml version="1.0" encoding="utf-8"?>

<usb>
	<usb-device class="239" subclass="2" />	<!-- all device of UVC -->
</usb>

驱动列表是通过Android的USBManager获取得到的

    /**
     * Returns a HashMap containing all USB devices currently attached.
     * USB device name is the key for the returned HashMap.
     * The result will be empty if no devices are attached, or if
     * USB host mode is inactive or unsupported.
     *
     * @return HashMap containing all connected USB devices.
     */
    public HashMap<String,UsbDevice> getDeviceList() {
        Bundle bundle = new Bundle();
        try {
            mService.getDeviceList(bundle);
            HashMap<String,UsbDevice> result = new HashMap<String,UsbDevice>();
            for (String name : bundle.keySet()) {
                result.put(name, (UsbDevice)bundle.get(name));
            }
            return result;
        } catch (RemoteException e) {
            Log.e(TAG, "RemoteException in getDeviceList", e);
            return null;
        }
    }


项目源码

UVCCamera

package com.serenegiant.usb;
/*
 * UVCCamera
 * library and sample to access to UVC web camera on non-rooted Android device
 *
 * Copyright (c) 2014-2015 saki t_saki@serenegiant.com
 *
 * File name: UVCCamera.java
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 * All files in the folder are under this Apache License, Version 2.0.
 * Files in the jni/libjpeg, jni/libusb, jin/libuvc, jni/rapidjson folder may have a different license, see the respective files.
*/

import java.util.ArrayList;
import java.util.List;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import android.graphics.SurfaceTexture;
import android.hardware.usb.UsbDevice;
import android.text.TextUtils;
import android.util.Log;
import android.view.Surface;
import android.view.SurfaceHolder;

import com.serenegiant.usb.USBMonitor.UsbControlBlock;

public class UVCCamera {
	private static final boolean DEBUG = false;	// TODO set false when releasing
	private static final String TAG = UVCCamera.class.getSimpleName();
	private static final String DEFAULT_USBFS = "/dev/bus/usb";

	public static final int DEFAULT_PREVIEW_WIDTH = 1600;//640
	public static final int DEFAULT_PREVIEW_HEIGHT = 1200;//480
	public static final int DEFAULT_PREVIEW_MODE = 0;
	public static final float DEFAULT_BANDWIDTH = 1.0f;

	public static final int FRAME_FORMAT_YUYV = 0;
	public static final int FRAME_FORMAT_MJPEG = 1;

	public static final int PIXEL_FORMAT_RAW = 0;
	public static final int PIXEL_FORMAT_YUV = 1;
	public static final int PIXEL_FORMAT_RGB565 = 2;
	public static final int PIXEL_FORMAT_RGBX = 3;
	public static final int PIXEL_FORMAT_YUV420SP = 4;
	public static final int PIXEL_FORMAT_NV21 = 5;		// = YVU420SemiPlanar

	//--------------------------------------------------------------------------------
    public static final int	CTRL_SCANNING		= 0x00000001;	// D0:  Scanning Mode
    public static final int CTRL_AE				= 0x00000002;	// D1:  Auto-Exposure Mode
    public static final int CTRL_AE_PRIORITY	= 0x00000004;	// D2:  Auto-Exposure Priority
    public static final int CTRL_AE_ABS			= 0x00000008;	// D3:  Exposure Time (Absolute)
    public static final int CTRL_AR_REL			= 0x00000010;	// D4:  Exposure Time (Relative)
    public static final int CTRL_FOCUS_ABS		= 0x00000020;	// D5:  Focus (Absolute)
    public static final int CTRL_FOCUS_REL		= 0x00000040;	// D6:  Focus (Relative)
    public static final int CTRL_IRIS_ABS		= 0x00000080;	// D7:  Iris (Absolute)
    public static final int CTRL_IRIS_REL		= 0x00000100;	// D8:  Iris (Relative)
    public static final int CTRL_ZOOM_ABS		= 0x00000200;	// D9:  Zoom (Absolute)
    public static final int CTRL_ZOOM_REL		= 0x00000400;	// D10: Zoom (Relative)
    public static final int CTRL_PANTILT_ABS	= 0x00000800;	// D11: PanTilt (Absolute)
    public static final int CTRL_PANTILT_REL	= 0x00001000;	// D12: PanTilt (Relative)
    public static final int CTRL_ROLL_ABS		= 0x00002000;	// D13: Roll (Absolute)
    public static final int CTRL_ROLL_REL		= 0x00004000;	// D14: Roll (Relative)
    public static final int CTRL_FOCUS_AUTO		= 0x00020000;	// D17: Focus, Auto
    public static final int CTRL_PRIVACY		= 0x00040000;	// D18: Privacy
    public static final int CTRL_FOCUS_SIMPLE	= 0x00080000;	// D19: Focus, Simple
    public static final int CTRL_WINDOW			= 0x00100000;	// D20: Window

    public static final int PU_BRIGHTNESS		= 0x80000001;	// D0: Brightness
    public static final int PU_CONTRAST			= 0x80000002;	// D1: Contrast
    public static final int PU_HUE				= 0x80000004;	// D2: Hue
    public static final int PU_SATURATION		= 0x80000008;	// D3: Saturation
    public static final int PU_SHARPNESS		= 0x80000010;	// D4: Sharpness
    public static final int PU_GAMMA			= 0x80000020;	// D5: Gamma
    public static final int PU_WB_TEMP			= 0x80000040;	// D6: White Balance Temperature
    public static final int PU_WB_COMPO			= 0x80000080;	// D7: White Balance Component
    public static final int PU_BACKLIGHT		= 0x80000100;	// D8: Backlight Compensation
    public static final int PU_GAIN				= 0x80000200;	// D9: Gain
    public static final int PU_POWER_LF			= 0x80000400;	// D10: Power Line Frequency
    public static final int PU_HUE_AUTO			= 0x80000800;	// D11: Hue, Auto
    public static final int PU_WB_TEMP_AUTO		= 0x80001000;	// D12: White Balance Temperature, Auto
    public static final int PU_WB_COMPO_AUTO	= 0x80002000;	// D13: White Balance Component, Auto
    public static final int PU_DIGITAL_MULT		= 0x80004000;	// D14: Digital Multiplier
    public static final int PU_DIGITAL_LIMIT	= 0x80008000;	// D15: Digital Multiplier Limit
    public static final int PU_AVIDEO_STD		= 0x80010000;	// D16: Analog Video Standard
    public static final int PU_AVIDEO_LOCK		= 0x80020000;	// D17: Analog Video Lock Status
    public static final int PU_CONTRAST_AUTO	= 0x80040000;	// D18: Contrast, Auto

	// uvc_status_class from libuvc.h
	public static final int STATUS_CLASS_CONTROL = 0x10;
	public static final int STATUS_CLASS_CONTROL_CAMERA = 0x11;
	public static final int STATUS_CLASS_CONTROL_PROCESSING = 0x12;

	// uvc_status_attribute from libuvc.h
	public static final int STATUS_ATTRIBUTE_VALUE_CHANGE = 0x00;
	public static final int STATUS_ATTRIBUTE_INFO_CHANGE = 0x01;
	public static final int STATUS_ATTRIBUTE_FAILURE_CHANGE = 0x02;
	public static final int STATUS_ATTRIBUTE_UNKNOWN = 0xff;

	private static boolean isLoaded;
	static {
		if (!isLoaded) {
			System.loadLibrary("usb100");
			System.loadLibrary("uvc");
			System.loadLibrary("UVCCamera");
			isLoaded = true;
		}
	}

	private UsbControlBlock mCtrlBlock;
    protected long mControlSupports;			// カメラコントロールでサポートしている機能フラグ
    protected long mProcSupports;				// プロセッシングユニットでサポートしている機能フラグ
    protected int mCurrentPreviewMode = 0;
	protected int mCurrentPreviewWidth = DEFAULT_PREVIEW_WIDTH, mCurrentPreviewHeight = DEFAULT_PREVIEW_HEIGHT;
    protected String mSupportedSize;
	// these fields from here are accessed from native code and do not change name and remove
    protected long mNativePtr;
    protected int mScanningModeMin, mScanningModeMax, mScanningModeDef;
    protected int mExposureModeMin, mExposureModeMax, mExposureModeDef;
    protected int mExposurePriorityMin, mExposurePriorityMax, mExposurePriorityDef;
    protected int mExposureMin, mExposureMax, mExposureDef;
    protected int mAutoFocusMin, mAutoFocusMax, mAutoFocusDef;
    protected int mFocusMin, mFocusMax, mFocusDef;
    protected int mFocusRelMin, mFocusRelMax, mFocusRelDef;
    protected int mFocusSimpleMin, mFocusSimpleMax, mFocusSimpleDef;
    protected int mIrisMin, mIrisMax, mIrisDef;
    protected int mIrisRelMin, mIrisRelMax, mIrisRelDef;
    protected int mPanMin, mPanMax, mPanDef;
    protected int mTiltMin, mTiltMax, mTiltDef;
    protected int mRollMin, mRollMax, mRollDef;
    protected int mPanRelMin, mPanRelMax, mPanRelDef;
    protected int mTiltRelMin, mTiltRelMax, mTiltRelDef;
    protected int mRollRelMin, mRollRelMax, mRollRelDef;
    protected int mPrivacyMin, mPrivacyMax, mPrivacyDef;
    protected int mAutoWhiteBlanceMin, mAutoWhiteBlanceMax, mAutoWhiteBlanceDef;
    protected int mAutoWhiteBlanceCompoMin, mAutoWhiteBlanceCompoMax, mAutoWhiteBlanceCompoDef;
    protected int mWhiteBlanceMin, mWhiteBlanceMax, mWhiteBlanceDef;
    protected int mWhiteBlanceCompoMin, mWhiteBlanceCompoMax, mWhiteBlanceCompoDef;
    protected int mWhiteBlanceRelMin, mWhiteBlanceRelMax, mWhiteBlanceRelDef;
    protected int mBacklightCompMin, mBacklightCompMax, mBacklightCompDef;
    protected int mBrightnessMin, mBrightnessMax, mBrightnessDef;
    protected int mContrastMin, mContrastMax, mContrastDef;
    protected int mSharpnessMin, mSharpnessMax, mSharpnessDef;
    protected int mGainMin, mGainMax, mGainDef;
    protected int mGammaMin, mGammaMax, mGammaDef;
    protected int mSaturationMin, mSaturationMax, mSaturationDef;
    protected int mHueMin, mHueMax, mHueDef;
    protected int mZoomMin, mZoomMax, mZoomDef;
    protected int mZoomRelMin, mZoomRelMax, mZoomRelDef;
    protected int mPowerlineFrequencyMin, mPowerlineFrequencyMax, mPowerlineFrequencyDef;
    protected int mMultiplierMin, mMultiplierMax, mMultiplierDef;
    protected int mMultiplierLimitMin, mMultiplierLimitMax, mMultiplierLimitDef;
    protected int mAnalogVideoStandardMin, mAnalogVideoStandardMax, mAnalogVideoStandardDef;
    protected int mAnalogVideoLockStateMin, mAnalogVideoLockStateMax, mAnalogVideoLockStateDef;
    // until here
    /**
     * the sonctructor of this class should be call within the thread that has a looper
     * (UI thread or a thread that called Looper.prepare)
     */
    public UVCCamera() {
    	mNativePtr = nativeCreate();
    	mSupportedSize = null;
	}

    /**
     * connect to a UVC camera
     * USB permission is necessary before this method is called
     * @param ctrlBlock
     */
    public void open(final UsbControlBlock ctrlBlock) {
		mCtrlBlock = ctrlBlock;
		nativeConnect(mNativePtr,
			mCtrlBlock.getVenderId(), mCtrlBlock.getProductId(),
			mCtrlBlock.getFileDescriptor(),
			getUSBFSName(mCtrlBlock));
    	if (mNativePtr != 0 && TextUtils.isEmpty(mSupportedSize)) {
    		mSupportedSize = nativeGetSupportedSize(mNativePtr);
    	}
		nativeSetPreviewSize(mNativePtr, DEFAULT_PREVIEW_WIDTH, DEFAULT_PREVIEW_HEIGHT, DEFAULT_PREVIEW_MODE, DEFAULT_BANDWIDTH);
    }

	/**
	 * set status callback
	 * @param callback
	 */
	public void setStatusCallback(final IStatusCallback callback) {
		if (mNativePtr != 0) {
			nativeSetStatusCallback(mNativePtr, callback);
		}
	}

	/**
	 * set button callback
	 * @param callback
	 */
	public void setButtonCallback(final IButtonCallback callback) {
		if (mNativePtr != 0) {
			nativeSetButtonCallback(mNativePtr, callback);
		}
	}

    /**
     * close and release UVC camera
     */
    public void close() {
    	stopPreview();
    	if (mNativePtr != 0) {
    		nativeRelease(mNativePtr);
    	}
   		mCtrlBlock = null;
		mControlSupports = mProcSupports = 0;
		mCurrentPreviewMode = -1;
    }

	public UsbDevice getDevice() {
		return mCtrlBlock != null ? mCtrlBlock.getDevice() : null;
	}

	public String getDeviceName(){
		return mCtrlBlock != null ? mCtrlBlock.getDeviceName() : null;
	}

	public UsbControlBlock getUsbControlBlock() {
		return mCtrlBlock;
	}

	public synchronized String getSupportedSize() {
    	return !TextUtils.isEmpty(mSupportedSize) ? mSupportedSize : (mSupportedSize = nativeGetSupportedSize(mNativePtr));
    }

	public Size getPreviewSize() {
		Size result = null;
		final List<Size> list = getSupportedSizeList();
		for (final Size sz: list) {
			if ((sz.width == mCurrentPreviewWidth)
				|| (sz.height == mCurrentPreviewHeight)) {
				result =sz;
				break;
			}
		}
		return result;
	}
	
	/**
	 * Set preview size and preview mode
	 * @param width
	   @param height
	   @param mode 0:yuyv, other:MJPEG
	 */
	public void setPreviewSize(final int width, final int height) {
		setPreviewSize(width, height, mCurrentPreviewMode, 0);
	}

	/**
	 * Set preview size and preview mode
	 * @param width
	   @param height
	   @param mode 0:yuyv, other:MJPEG
	 */
	public void setPreviewSize(final int width, final int height, final int mode) {
		setPreviewSize(width, height, mode, 0);
	}
	
	/**
	 * Set preview size and preview mode
	 * @param width
	   @param height
	   @param mode 0:yuyv, other:MJPEG
	   @param bandwidth [0.0f,1.0f]
	 */
	public void setPreviewSize(final int width, final int height, final int mode, final float bandwidth) {
		if ((width == 0) || (height == 0))
			throw new IllegalArgumentException("invalid preview size");
		if (mNativePtr != 0) {
			final int result = nativeSetPreviewSize(mNativePtr, width, height, mode, bandwidth);
			if (result != 0)
				throw new IllegalArgumentException("Failed to set preview size");
			mCurrentPreviewMode = mode;
			mCurrentPreviewWidth = width;
			mCurrentPreviewHeight = height;
		}
	}

	public List<Size> getSupportedSizeList() {
		final int type = (mCurrentPreviewMode > 0) ? 6 : 4;
		return getSupportedSize(type, mSupportedSize);
	}

	public static List<Size> getSupportedSize(final int type, final String supportedSize) {
		final List<Size> result = new ArrayList<Size>();
		if (!TextUtils.isEmpty(supportedSize))
		try {
			final JSONObject json = new JSONObject(supportedSize);
			final JSONArray formats = json.getJSONArray("formats");
			final int format_nums = formats.length();
			for (int i = 0; i < format_nums; i++) {
				final JSONObject format = formats.getJSONObject(i);
				final int format_type = format.getInt("type");
				if ((format_type == type) || (type == -1)) {
					addSize(format, format_type, result);
				}
			}
		} catch (final JSONException e) {
		}
		return result;
	}

	private static final void addSize(final JSONObject format, final int type, final List<Size> size_list) throws JSONException {
		final JSONArray size = format.getJSONArray("size");
		final int size_nums = size.length();
		for (int j = 0; j < size_nums; j++) {
			final String[] sz = size.getString(j).split("x");
			try {
				size_list.add(new Size(type, j, Integer.parseInt(sz[0]), Integer.parseInt(sz[1])));
			} catch (final Exception e) {
				break;
			}
		}
	}

    /**
     * set preview surface with SurfaceHolder</br>
     * you can use SurfaceHolder came from SurfaceView/GLSurfaceView
     * @param holder
     */
    public void setPreviewDisplay(final SurfaceHolder holder) {
   		nativeSetPreviewDisplay(mNativePtr, holder.getSurface());
    }

    /**
     * set preview surface with SurfaceTexture.
     * this method require API >= 14
     * @param texture
     */
    public void setPreviewTexture(final SurfaceTexture texture) {	// API >= 11
    	final Surface surface = new Surface(texture);	// XXX API >= 14
    	nativeSetPreviewDisplay(mNativePtr, surface);
    }

    /**
     * set preview surface with Surface
     * @param Surface
     */
    public void setPreviewDisplay(final Surface surface) {
    	nativeSetPreviewDisplay(mNativePtr, surface);
    }

    /**
     * set frame callback
     * @param callback
     * @param pixelFormat
     */
    public void setFrameCallback(final IFrameCallback callback, final int pixelFormat) {
    	if (mNativePtr != 0) {
        	nativeSetFrameCallback(mNativePtr, callback, pixelFormat);
    	}
    }

    /**
     * start preview
     */
    public void startPreview() {
    	if (mCtrlBlock != null) {
    		nativeStartPreview(mNativePtr);
    	}
    }

    /**
     * stop preview
     */
    public void stopPreview() {
    	setFrameCallback(null, 0);
    	if (mCtrlBlock != null) {
    		nativeStopPreview(mNativePtr);
    	}
    }

    /**
     * destroy UVCCamera object
     */
    public void destroy() {
    	close();
    	if (mNativePtr != 0) {
    		nativeDestroy(mNativePtr);
    		mNativePtr = 0;
    	}
    }

    // wrong result may return when you call this just after camera open.
    // it is better to wait several hundreads millseconds.
	public boolean checkSupportFlag(final long flag) {
    	updateCameraParams();
    	if ((flag & 0x80000000) == 0x80000000)
    		return ((mProcSupports & flag) == (flag & 0x7ffffffF));
    	else
    		return (mControlSupports & flag) == flag;
    }

//================================================================================
	public synchronized void setAutoFocus(final boolean autoFocus) {
    	if (mNativePtr != 0) {
    		nativeSetAutoFocus(mNativePtr, autoFocus);
    	}
    }

	public synchronized boolean getAutoFocus() {
    	boolean result = true;
    	if (mNativePtr != 0) {
    		result = nativeGetAutoFocus(mNativePtr) > 0;
    	}
    	return result;
    }
//================================================================================
    /**
     * @param focus[%]
     */
	public synchronized void setFocus(final int focus) {
    	if (mNativePtr != 0) {
 		   final float range = Math.abs(mFocusMax - mFocusMin);
 		   if (range > 0)
 			   nativeSetFocus(mNativePtr, (int)(focus / 100.f * range) + mFocusMin);
    	}
    }

    /**
     * @param focus_abs
     * @return forcus[%]
     */
	public synchronized int getFocus(final int focus_abs) {
	   int result = 0;
	   if (mNativePtr != 0) {
		   nativeUpdateFocusLimit(mNativePtr);
		   final float range = Math.abs(mFocusMax - mFocusMin);
		   if (range > 0) {
			   result = (int)((focus_abs - mFocusMin) * 100.f / range);
		   }
	   }
	   return result;
	}

    /**
     * @return focus[%]
     */
	public synchronized int getFocus() {
    	return getFocus(nativeGetFocus(mNativePtr));
    }

	public synchronized void resetFocus() {
    	if (mNativePtr != 0) {
    		nativeSetFocus(mNativePtr, mFocusDef);
    	}
    }

//================================================================================
	public synchronized void setAutoWhiteBlance(final boolean autoWhiteBlance) {
    	if (mNativePtr != 0) {
    		nativeSetAutoWhiteBlance(mNativePtr, autoWhiteBlance);
    	}
    }

	public synchronized boolean getAutoWhiteBlance() {
    	boolean result = true;
    	if (mNativePtr != 0) {
    		result = nativeGetAutoWhiteBlance(mNativePtr) > 0;
    	}
    	return result;
    }

//================================================================================
    /**
     * @param whiteBlance[%]
     */
	public synchronized void setWhiteBlance(final int whiteBlance) {
    	if (mNativePtr != 0) {
 		   final float range = Math.abs(mWhiteBlanceMax - mWhiteBlanceMin);
 		   if (range > 0)
 			   nativeSetWhiteBlance(mNativePtr, (int)(whiteBlance / 100.f * range) + mWhiteBlanceMin);
    	}
    }

    /**
     * @param whiteBlance_abs
     * @return whiteBlance[%]
     */
	public synchronized int getWhiteBlance(final int whiteBlance_abs) {
	   int result = 0;
	   if (mNativePtr != 0) {
		   nativeUpdateWhiteBlanceLimit(mNativePtr);
		   final float range = Math.abs(mWhiteBlanceMax - mWhiteBlanceMin);
		   if (range > 0) {
			   result = (int)((whiteBlance_abs - mWhiteBlanceMin) * 100.f / range);
		   }
	   }
	   return result;
	}

    /**
     * @return white blance[%]
     */
	public synchronized int getWhiteBlance() {
    	return getFocus(nativeGetWhiteBlance(mNativePtr));
    }

	public synchronized void resetWhiteBlance() {
    	if (mNativePtr != 0) {
    		nativeSetWhiteBlance(mNativePtr, mWhiteBlanceDef);
    	}
    }
//================================================================================
    /**
     * @param brightness[%]
     */
	public synchronized void setBrightness(final int brightness) {
    	if (mNativePtr != 0) {
 		   final float range = Math.abs(mBrightnessMax - mBrightnessMin);
 		   if (range > 0)
 			   nativeSetBrightness(mNativePtr, (int)(brightness / 100.f * range) + mBrightnessMin);
    	}
    }

    /**
     * @param brightness_abs
     * @return brightness[%]
     */
	public synchronized int getBrightness(final int brightness_abs) {
	   int result = 0;
	   if (mNativePtr != 0) {
		   nativeUpdateBrightnessLimit(mNativePtr);
		   final float range = Math.abs(mBrightnessMax - mBrightnessMin);
		   if (range > 0) {
			   result = (int)((brightness_abs - mBrightnessMin) * 100.f / range);
		   }
	   }
	   return result;
	}

    /**
     * @return brightness[%]
     */
	public synchronized int getBrightness() {
    	return getBrightness(nativeGetBrightness(mNativePtr));
    }

	public synchronized void resetBrightness() {
    	if (mNativePtr != 0) {
    		nativeSetBrightness(mNativePtr, mBrightnessDef);
    	}
    }

//================================================================================
    /**
     * @param contrast[%]
     */
	public synchronized void setContrast(final int contrast) {
    	if (mNativePtr != 0) {
    		nativeUpdateContrastLimit(mNativePtr);
	    	final float range = Math.abs(mContrastMax - mContrastMin);
	    	if (range > 0)
	    		nativeSetContrast(mNativePtr, (int)(contrast / 100.f * range) + mContrastMin);
    	}
    }

    /**
     * @param contrast_abs
     * @return contrast[%]
     */
	public synchronized int getContrast(final int contrast_abs) {
	   int result = 0;
	   if (mNativePtr != 0) {
		   final float range = Math.abs(mContrastMax - mContrastMin);
		   if (range > 0) {
			   result = (int)((contrast_abs - mContrastMin) * 100.f / range);
		   }
	   }
	   return result;
	}

    /**
     * @return contrast[%]
     */
	public synchronized int getContrast() {
    	return getContrast(nativeGetContrast(mNativePtr));
    }

	public synchronized void resetContrast() {
    	if (mNativePtr != 0) {
    		nativeSetContrast(mNativePtr, mContrastDef);
    	}
    }

//================================================================================
    /**
     * @param sharpness[%]
     */
	public synchronized void setSharpness(final int sharpness) {
    	if (mNativePtr != 0) {
 		   final float range = Math.abs(mSharpnessMax - mSharpnessMin);
 		   if (range > 0)
 			   nativeSetSharpness(mNativePtr, (int)(sharpness / 100.f * range) + mSharpnessMin);
    	}
    }

    /**
     * @param sharpness_abs
     * @return sharpness[%]
     */
	public synchronized int getSharpness(final int sharpness_abs) {
	   int result = 0;
	   if (mNativePtr != 0) {
		   nativeUpdateSharpnessLimit(mNativePtr);
		   final float range = Math.abs(mSharpnessMax - mSharpnessMin);
		   if (range > 0) {
			   result = (int)((sharpness_abs - mSharpnessMin) * 100.f / range);
		   }
	   }
	   return result;
	}

    /**
     * @return sharpness[%]
     */
	public synchronized int getSharpness() {
    	return getSharpness(nativeGetSharpness(mNativePtr));
    }

	public synchronized void resetSharpness() {
    	if (mNativePtr != 0) {
    		nativeSetSharpness(mNativePtr, mSharpnessDef);
    	}
    }
//================================================================================
    /**
     * @param gain[%]
     */
	public synchronized void setGain(final int gain) {
    	if (mNativePtr != 0) {
 		   final float range = Math.abs(mGainMax - mGainMin);
 		   if (range > 0)
 			   nativeSetGain(mNativePtr, (int)(gain / 100.f * range) + mGainMin);
    	}
    }

    /**
     * @param gain_abs
     * @return gain[%]
     */
	public synchronized int getGain(final int gain_abs) {
	   int result = 0;
	   if (mNativePtr != 0) {
		   nativeUpdateGainLimit(mNativePtr);
		   final float range = Math.abs(mGainMax - mGainMin);
		   if (range > 0) {
			   result = (int)((gain_abs - mGainMin) * 100.f / range);
		   }
	   }
	   return result;
	}

    /**
     * @return gain[%]
     */
	public synchronized int getGain() {
    	return getGain(nativeGetGain(mNativePtr));
    }

	public synchronized void resetGain() {
    	if (mNativePtr != 0) {
    		nativeSetGain(mNativePtr, mGainDef);
    	}
    }

//================================================================================
    /**
     * @param gamma[%]
     */
	public synchronized void setGamma(final int gamma) {
    	if (mNativePtr != 0) {
 		   final float range = Math.abs(mGammaMax - mGammaMin);
 		   if (range > 0)
 			   nativeSetGamma(mNativePtr, (int)(gamma / 100.f * range) + mGammaMin);
    	}
    }

    /**
     * @param gamma_abs
     * @return gamma[%]
     */
	public synchronized int getGamma(final int gamma_abs) {
	   int result = 0;
	   if (mNativePtr != 0) {
		   nativeUpdateGammaLimit(mNativePtr);
		   final float range = Math.abs(mGammaMax - mGammaMin);
		   if (range > 0) {
			   result = (int)((gamma_abs - mGammaMin) * 100.f / range);
		   }
	   }
	   return result;
	}

    /**
     * @return gamma[%]
     */
	public synchronized int getGamma() {
    	return getGamma(nativeGetGamma(mNativePtr));
    }

	public synchronized void resetGamma() {
    	if (mNativePtr != 0) {
    		nativeSetGamma(mNativePtr, mGammaDef);
    	}
    }

//================================================================================
    /**
     * @param saturation[%]
     */
	public synchronized void setSaturation(final int saturation) {
    	if (mNativePtr != 0) {
 		   final float range = Math.abs(mSaturationMax - mSaturationMin);
 		   if (range > 0)
 			   nativeSetSaturation(mNativePtr, (int)(saturation / 100.f * range) + mSaturationMin);
    	}
    }

    /**
     * @param saturation_abs
     * @return saturation[%]
     */
	public synchronized int getSaturation(final int saturation_abs) {
	   int result = 0;
	   if (mNativePtr != 0) {
		   nativeUpdateSaturationLimit(mNativePtr);
		   final float range = Math.abs(mSaturationMax - mSaturationMin);
		   if (range > 0) {
			   result = (int)((saturation_abs - mSaturationMin) * 100.f / range);
		   }
	   }
	   return result;
	}

    /**
     * @return saturation[%]
     */
	public synchronized int getSaturation() {
    	return getSaturation(nativeGetSaturation(mNativePtr));
    }

	public synchronized void resetSaturation() {
    	if (mNativePtr != 0) {
    		nativeSetSaturation(mNativePtr, mSaturationDef);
    	}
    }
//================================================================================
    /**
     * @param hue[%]
     */
	public synchronized void setHue(final int hue) {
    	if (mNativePtr != 0) {
 		   final float range = Math.abs(mHueMax - mHueMin);
 		   if (range > 0)
 			   nativeSetHue(mNativePtr, (int)(hue / 100.f * range) + mHueMin);
    	}
    }

    /**
     * @param hue_abs
     * @return hue[%]
     */
	public synchronized int getHue(final int hue_abs) {
	   int result = 0;
	   if (mNativePtr != 0) {
		   nativeUpdateHueLimit(mNativePtr);
		   final float range = Math.abs(mHueMax - mHueMin);
		   if (range > 0) {
			   result = (int)((hue_abs - mHueMin) * 100.f / range);
		   }
	   }
	   return result;
	}

    /**
     * @return hue[%]
     */
	public synchronized int getHue() {
    	return getHue(nativeGetHue(mNativePtr));
    }

	public synchronized void resetHue() {
    	if (mNativePtr != 0) {
    		nativeSetHue(mNativePtr, mSaturationDef);
    	}
    }

//================================================================================
	public void setPowerlineFrequency(final int frequency) {
    	if (mNativePtr != 0)
    		nativeSetPowerlineFrequency(mNativePtr, frequency);
    }

	public int getPowerlineFrequency() {
    	return nativeGetPowerlineFrequency(mNativePtr);
    }

//================================================================================
    /**
     * this may not work well with some combination of camera and device
     * @param zoom[%]
     */
	public synchronized void setZoom(final int zoom) {
    	if (mNativePtr != 0) {
 		   final float range = Math.abs(mZoomMax - mZoomMin);
 		   if (range > 0) {
 			   final int z = (int)(zoom / 100.f * range) + mZoomMin;
// 			   Log.d(TAG, "setZoom:zoom=" + zoom + " ,value=" + z);
 			   nativeSetZoom(mNativePtr, z);
 		   }
    	}
    }

    /**
     * @param zoom_abs
     * @return zoom[%]
     */
	public synchronized int getZoom(final int zoom_abs) {
	   int result = 0;
	   if (mNativePtr != 0) {
		   nativeUpdateZoomLimit(mNativePtr);
		   final float range = Math.abs(mZoomMax - mZoomMin);
		   if (range > 0) {
			   result = (int)((zoom_abs - mZoomMin) * 100.f / range);
		   }
	   }
	   return result;
	}

    /**
     * @return zoom[%]
     */
	public synchronized int getZoom() {
    	return getZoom(nativeGetZoom(mNativePtr));
    }

	public synchronized void resetZoom() {
    	if (mNativePtr != 0) {
    		nativeSetZoom(mNativePtr, mZoomDef);
    	}
    }

//================================================================================
	public synchronized void updateCameraParams() {
    	if (mNativePtr != 0) {
    		if ((mControlSupports == 0) || (mProcSupports == 0)) {
        		// サポートしている機能フラグを取得
    			if (mControlSupports == 0)
    				mControlSupports = nativeGetCtrlSupports(mNativePtr);
    			if (mProcSupports == 0)
    				mProcSupports = nativeGetProcSupports(mNativePtr);
    	    	// 設定値を取得
    	    	if ((mControlSupports != 0) && (mProcSupports != 0)) {
	    	    	nativeUpdateBrightnessLimit(mNativePtr);
	    	    	nativeUpdateContrastLimit(mNativePtr);
	    	    	nativeUpdateSharpnessLimit(mNativePtr);
	    	    	nativeUpdateGainLimit(mNativePtr);
	    	    	nativeUpdateGammaLimit(mNativePtr);
	    	    	nativeUpdateSaturationLimit(mNativePtr);
	    	    	nativeUpdateHueLimit(mNativePtr);
	    	    	nativeUpdateZoomLimit(mNativePtr);
	    	    	nativeUpdateWhiteBlanceLimit(mNativePtr);
	    	    	nativeUpdateFocusLimit(mNativePtr);
    	    	}
    	    	if (DEBUG) {
					dumpControls(mControlSupports);
					dumpProc(mProcSupports);
					Log.v(TAG, String.format("Brightness:min=%d,max=%d,def=%d", mBrightnessMin, mBrightnessMax, mBrightnessDef));
					Log.v(TAG, String.format("Contrast:min=%d,max=%d,def=%d", mContrastMin, mContrastMax, mContrastDef));
					Log.v(TAG, String.format("Sharpness:min=%d,max=%d,def=%d", mSharpnessMin, mSharpnessMax, mSharpnessDef));
					Log.v(TAG, String.format("Gain:min=%d,max=%d,def=%d", mGainMin, mGainMax, mGainDef));
					Log.v(TAG, String.format("Gamma:min=%d,max=%d,def=%d", mGammaMin, mGammaMax, mGammaDef));
					Log.v(TAG, String.format("Saturation:min=%d,max=%d,def=%d", mSaturationMin, mSaturationMax, mSaturationDef));
					Log.v(TAG, String.format("Hue:min=%d,max=%d,def=%d", mHueMin, mHueMax, mHueDef));
					Log.v(TAG, String.format("Zoom:min=%d,max=%d,def=%d", mZoomMin, mZoomMax, mZoomDef));
					Log.v(TAG, String.format("WhiteBlance:min=%d,max=%d,def=%d", mWhiteBlanceMin, mWhiteBlanceMax, mWhiteBlanceDef));
					Log.v(TAG, String.format("Focus:min=%d,max=%d,def=%d", mFocusMin, mFocusMax, mFocusDef));
				}
			}
    	} else {
    		mControlSupports = mProcSupports = 0;
    	}
    }

    private static final String[] SUPPORTS_CTRL = {
    	"D0:  Scanning Mode",
    	"D1:  Auto-Exposure Mode",
    	"D2:  Auto-Exposure Priority",
    	"D3:  Exposure Time (Absolute)",
    	"D4:  Exposure Time (Relative)",
    	"D5:  Focus (Absolute)",
    	"D6:  Focus (Relative)",
    	"D7:  Iris (Absolute)",
    	"D8:  Iris (Relative)",
    	"D9:  Zoom (Absolute)",
    	"D10: Zoom (Relative)",
    	"D11: PanTilt (Absolute)",
    	"D12: PanTilt (Relative)",
    	"D13: Roll (Absolute)",
    	"D14: Roll (Relative)",
		"D15: Reserved",
		"D16: Reserved",
		"D17: Focus, Auto",
		"D18: Privacy",
		"D19: Focus, Simple",
		"D20: Window",
		"D21: Region of Interest",
		"D22: Reserved, set to zero",
		"D23: Reserved, set to zero",
    };

    private static final String[] SUPPORTS_PROC = {
		"D0: Brightness",
		"D1: Contrast",
		"D2: Hue",
		"D3: Saturation",
		"D4: Sharpness",
		"D5: Gamma",
		"D6: White Balance Temperature",
		"D7: White Balance Component",
		"D8: Backlight Compensation",
		"D9: Gain",
		"D10: Power Line Frequency",
		"D11: Hue, Auto",
		"D12: White Balance Temperature, Auto",
		"D13: White Balance Component, Auto",
		"D14: Digital Multiplier",
		"D15: Digital Multiplier Limit",
		"D16: Analog Video Standard",
		"D17: Analog Video Lock Status",
		"D18: Contrast, Auto",
		"D19: Reserved. Set to zero",
		"D20: Reserved. Set to zero",
		"D21: Reserved. Set to zero",
		"D22: Reserved. Set to zero",
		"D23: Reserved. Set to zero",
	};

    private static final void dumpControls(final long controlSupports) {
    	Log.i(TAG, String.format("controlSupports=%x", controlSupports));
    	for (int i = 0; i < SUPPORTS_CTRL.length; i++) {
    		Log.i(TAG, SUPPORTS_CTRL[i] + ((controlSupports & (0x1 << i)) != 0 ? "=enabled" : "=disabled"));
    	}
    }

	private static final void dumpProc(final long procSupports) {
    	Log.i(TAG, String.format("procSupports=%x", procSupports));
    	for (int i = 0; i < SUPPORTS_PROC.length; i++) {
    		Log.i(TAG, SUPPORTS_PROC[i] + ((procSupports & (0x1 << i)) != 0 ? "=enabled" : "=disabled"));
    	}
    }

	private final String getUSBFSName(final UsbControlBlock ctrlBlock) {
		String result = null;
		final String name = ctrlBlock.getDeviceName();
		final String[] v = !TextUtils.isEmpty(name) ? name.split("/") : null;
		if ((v != null) && (v.length > 2)) {
			final StringBuilder sb = new StringBuilder(v[0]);
			for (int i = 1; i < v.length - 2; i++)
				sb.append("/").append(v[i]);
			result = sb.toString();
		}
		if (TextUtils.isEmpty(result)) {
			Log.w(TAG, "failed to get USBFS path, try to use default path:" + name);
			result = DEFAULT_USBFS;
		}
		return result;
	}

    // #nativeCreate and #nativeDestroy are not static methods.
    private final native long nativeCreate();
    private final native void nativeDestroy(final long id_camera);

    private static final native int nativeConnect(final long id_camera, final int venderId, final int productId, final int fileDescriptor, String usbfs);
    private static final native int nativeRelease(final long id_camera);

	private static final native int nativeSetStatusCallback(final long mNativePtr, final IStatusCallback callback);
	private static final native int nativeSetButtonCallback(final long mNativePtr, final IButtonCallback callback);

    private static final native int nativeSetPreviewSize(final long id_camera, final int width, final int height, final int mode, final float bandwidth);
    private static final native String nativeGetSupportedSize(final long id_camera);
    private static final native int nativeStartPreview(final long id_camera);
    private static final native int nativeStopPreview(final long id_camera);
    private static final native int nativeSetPreviewDisplay(final long id_camera, final Surface surface);
    private static final native int nativeSetFrameCallback(final long mNativePtr, final IFrameCallback callback, final int pixelFormat);

//**********************************************************************
    /**
     * start movie capturing(this should call while previewing)
     * @param surface
     */
    public void startCapture(final Surface surface) {
    	if (mCtrlBlock != null && surface != null) {
    		nativeSetCaptureDisplay(mNativePtr, surface);
    	} else
    		throw new NullPointerException("startCapture");
    }

    /**
     * stop movie capturing
     */
    public void stopCapture() {
    	if (mCtrlBlock != null) {
    		nativeSetCaptureDisplay(mNativePtr, null);
    	}
    }
    private static final native int nativeSetCaptureDisplay(final long id_camera, final Surface surface);

    private static final native long nativeGetCtrlSupports(final long id_camera);
    private static final native long nativeGetProcSupports(final long id_camera);

    private final native int nativeUpdateScanningModeLimit(final long id_camera);
    private static final native int nativeSetScanningMode(final long id_camera, final int scanning_mode);
    private static final native int nativeGetScanningMode(final long id_camera);

	private final native int nativeUpdateExposureModeLimit(final long id_camera);
    private static final native int nativeSetExposureMode(final long id_camera, final int exposureMode);
    private static final native int nativeGetExposureMode(final long id_camera);

	private final native int nativeUpdateExposurePriorityLimit(final long id_camera);
    private static final native int nativeSetExposurePriority(final long id_camera, final int priority);
    private static final native int nativeGetExposurePriority(final long id_camera);

	private final native int nativeUpdateExposureLimit(final long id_camera);
    private static final native int nativeSetExposure(final long id_camera, final int exposure);
    private static final native int nativeGetExposure(final long id_camera);

	private final native int nativeUpdateExposureRelLimit(final long id_camera);
    private static final native int nativeSetExposureRel(final long id_camera, final int exposure_rel);
    private static final native int nativeGetExposureRel(final long id_camera);

	private final native int nativeUpdateAutoFocusLimit(final long id_camera);
    private static final native int nativeSetAutoFocus(final long id_camera, final boolean autofocus);
    private static final native int nativeGetAutoFocus(final long id_camera);

    private final native int nativeUpdateFocusLimit(final long id_camera);
    private static final native int nativeSetFocus(final long id_camera, final int focus);
    private static final native int nativeGetFocus(final long id_camera);

    private final native int nativeUpdateFocusRelLimit(final long id_camera);
    private static final native int nativeSetFocusRel(final long id_camera, final int focus_rel);
    private static final native int nativeGetFocusRel(final long id_camera);

    private final native int nativeUpdateIrisLimit(final long id_camera);
    private static final native int nativeSetIris(final long id_camera, final int iris);
    private static final native int nativeGetIris(final long id_camera);

    private final native int nativeUpdateIrisRelLimit(final long id_camera);
    private static final native int nativeSetIrisRel(final long id_camera, final int iris_rel);
    private static final native int nativeGetIrisRel(final long id_camera);

    private final native int nativeUpdatePanLimit(final long id_camera);
    private static final native int nativeSetPan(final long id_camera, final int pan);
    private static final native int nativeGetPan(final long id_camera);

    private final native int nativeUpdatePanRelLimit(final long id_camera);
    private static final native int nativeSetPanRel(final long id_camera, final int pan_rel);
    private static final native int nativeGetPanRel(final long id_camera);

    private final native int nativeUpdateTiltLimit(final long id_camera);
    private static final native int nativeSetTilt(final long id_camera, final int tilt);
    private static final native int nativeGetTilt(final long id_camera);

    private final native int nativeUpdateTiltRelLimit(final long id_camera);
    private static final native int nativeSetTiltRel(final long id_camera, final int tilt_rel);
    private static final native int nativeGetTiltRel(final long id_camera);

    private final native int nativeUpdateRollLimit(final long id_camera);
    private static final native int nativeSetRoll(final long id_camera, final int roll);
    private static final native int nativeGetRoll(final long id_camera);

    private final native int nativeUpdateRollRelLimit(final long id_camera);
    private static final native int nativeSetRollRel(final long id_camera, final int roll_rel);
    private static final native int nativeGetRollRel(final long id_camera);

	private final native int nativeUpdateAutoWhiteBlanceLimit(final long id_camera);
    private static final native int nativeSetAutoWhiteBlance(final long id_camera, final boolean autoWhiteBlance);
    private static final native int nativeGetAutoWhiteBlance(final long id_camera);

    private final native int nativeUpdateAutoWhiteBlanceCompoLimit(final long id_camera);
    private static final native int nativeSetAutoWhiteBlanceCompo(final long id_camera, final boolean autoWhiteBlanceCompo);
    private static final native int nativeGetAutoWhiteBlanceCompo(final long id_camera);

	private final native int nativeUpdateWhiteBlanceLimit(final long id_camera);
    private static final native int nativeSetWhiteBlance(final long id_camera, final int whiteBlance);
    private static final native int nativeGetWhiteBlance(final long id_camera);

	private final native int nativeUpdateWhiteBlanceCompoLimit(final long id_camera);
    private static final native int nativeSetWhiteBlanceCompo(final long id_camera, final int whiteBlance_compo);
    private static final native int nativeGetWhiteBlanceCompo(final long id_camera);

	private final native int nativeUpdateBacklightCompLimit(final long id_camera);
    private static final native int nativeSetBacklightComp(final long id_camera, final int backlight_comp);
    private static final native int nativeGetBacklightComp(final long id_camera);

	private final native int nativeUpdateBrightnessLimit(final long id_camera);
    private static final native int nativeSetBrightness(final long id_camera, final int brightness);
    private static final native int nativeGetBrightness(final long id_camera);

    private final native int nativeUpdateContrastLimit(final long id_camera);
    private static final native int nativeSetContrast(final long id_camera, final int contrast);
    private static final native int nativeGetContrast(final long id_camera);

	private final native int nativeUpdateAutoContrastLimit(final long id_camera);
    private static final native int nativeSetAutoContrast(final long id_camera, final boolean autocontrast);
    private static final native int nativeGetAutoContrast(final long id_camera);

	private final native int nativeUpdateSharpnessLimit(final long id_camera);
    private static final native int nativeSetSharpness(final long id_camera, final int sharpness);
    private static final native int nativeGetSharpness(final long id_camera);

    private final native int nativeUpdateGainLimit(final long id_camera);
    private static final native int nativeSetGain(final long id_camera, final int gain);
    private static final native int nativeGetGain(final long id_camera);

    private final native int nativeUpdateGammaLimit(final long id_camera);
    private static final native int nativeSetGamma(final long id_camera, final int gamma);
    private static final native int nativeGetGamma(final long id_camera);

    private final native int nativeUpdateSaturationLimit(final long id_camera);
    private static final native int nativeSetSaturation(final long id_camera, final int saturation);
    private static final native int nativeGetSaturation(final long id_camera);

    private final native int nativeUpdateHueLimit(final long id_camera);
    private static final native int nativeSetHue(final long id_camera, final int hue);
    private static final native int nativeGetHue(final long id_camera);

	private final native int nativeUpdateAutoHueLimit(final long id_camera);
	private static final native int nativeSetAutoHue(final long id_camera, final boolean autohue);
	private static final native int nativeGetAutoHue(final long id_camera);

	private final native int nativeUpdatePowerlineFrequencyLimit(final long id_camera);
    private static final native int nativeSetPowerlineFrequency(final long id_camera, final int frequency);
    private static final native int nativeGetPowerlineFrequency(final long id_camera);

    private final native int nativeUpdateZoomLimit(final long id_camera);
    private static final native int nativeSetZoom(final long id_camera, final int zoom);
    private static final native int nativeGetZoom(final long id_camera);

    private final native int nativeUpdateZoomRelLimit(final long id_camera);
    private static final native int nativeSetZoomRel(final long id_camera, final int zoom_rel);
    private static final native int nativeGetZoomRel(final long id_camera);

    private final native int nativeUpdateDigitalMultiplierLimit(final long id_camera);
    private static final native int nativeSetDigitalMultiplier(final long id_camera, final int multiplier);
    private static final native int nativeGetDigitalMultiplier(final long id_camera);

	private final native int nativeUpdateDigitalMultiplierLimitLimit(final long id_camera);
    private static final native int nativeSetDigitalMultiplierLimit(final long id_camera, final int multiplier_limit);
    private static final native int nativeGetDigitalMultiplierLimit(final long id_camera);

	private final native int nativeUpdateAnalogVideoStandardLimit(final long id_camera);
    private static final native int nativeSetAnalogVideoStandard(final long id_camera, final int standard);
    private static final native int nativeGetAnalogVideoStandard(final long id_camera);

	private final native int nativeUpdateAnalogVideoLockStateLimit(final long id_camera);
    private static final native int nativeSetAnalogVideoLoackState(final long id_camera, final int state);
    private static final native int nativeGetAnalogVideoLoackState(final long id_camera);

	private final native int nativeUpdatePrivacyLimit(final long id_camera);
    private static final native int nativeSetPrivacy(final long id_camera, final boolean privacy);
    private static final native int nativeGetPrivacy(final long id_camera);
}


UVCCameraTextureView

 

package com.serenegiant.usb.widget;
/*
 * UVCCamera
 * library and sample to access to UVC web camera on non-rooted Android device
 *
 * Copyright (c) 2015 saki t_saki@serenegiant.com
 *
 * File name: UVCCameraTextureView.java
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 * All files in the folder are under this Apache License, Version 2.0.
 * Files in the jni/libjpeg, jni/libusb, jin/libuvc, jni/rapidjson folder may have a different license, see the respective files.
*/

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.SurfaceTexture;
import android.util.AttributeSet;
import android.util.Log;
import android.view.TextureView;

import com.serenegiant.usb.encode.MediaEncoder;

/**
 * change the view size with keeping the specified aspect ratio.
 * if you set this view with in a FrameLayout and set property "android:layout_gravity="center",
 * you can show this view in the center of screen and keep the aspect ratio of content
 * XXX it is better that can set the aspect raton a a xml property
 */
public class UVCCameraTextureView extends TextureView	// API >= 14
	implements TextureView.SurfaceTextureListener, CameraViewInterface {

	private static final boolean DEBUG = true;	// TODO set false on release
	private static final String TAG = "UVCCameraTextureView";

    private double mRequestedAspect = -1.0;
    private boolean mHasSurface;
	private final Object mCaptureSync = new Object();
    private Bitmap mTempBitmap;
    private boolean mReqesutCaptureStillImage;

	public UVCCameraTextureView(final Context context) {
		this(context, null, 0);
	}

	public UVCCameraTextureView(final Context context, final AttributeSet attrs) {
		this(context, attrs, 0);
	}

	public UVCCameraTextureView(final Context context, final AttributeSet attrs, final int defStyle) {
		super(context, attrs, defStyle);
		setSurfaceTextureListener(this);
	}

	@Override
	public void onResume() {
		if (DEBUG) Log.v(TAG, "onResume:");
	}

	@Override
	public void onPause() {
		if (DEBUG) Log.v(TAG, "onPause:");
		if (mTempBitmap != null) {
			mTempBitmap.recycle();
			mTempBitmap = null;
		}
	}

	@Override
    public void setAspectRatio(final double aspectRatio) {
        if (aspectRatio < 0) {
            throw new IllegalArgumentException();
        }
        if (mRequestedAspect != aspectRatio) {
            mRequestedAspect = aspectRatio;
            requestLayout();
        }
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

		if (mRequestedAspect > 0) {
			int initialWidth = MeasureSpec.getSize(widthMeasureSpec);
			int initialHeight = MeasureSpec.getSize(heightMeasureSpec);

			final int horizPadding = getPaddingLeft() + getPaddingRight();
			final int vertPadding = getPaddingTop() + getPaddingBottom();
			initialWidth -= horizPadding;
			initialHeight -= vertPadding;

			final double viewAspectRatio = (double)initialWidth / initialHeight;
			final double aspectDiff = mRequestedAspect / viewAspectRatio - 1;

			if (Math.abs(aspectDiff) > 0.01) {
				if (aspectDiff > 0) {
					// width priority decision
					initialHeight = (int) (initialWidth / mRequestedAspect);
				} else {
					// height priority decison
					initialWidth = (int) (initialHeight * mRequestedAspect);
				}
				initialWidth += horizPadding;
				initialHeight += vertPadding;
				widthMeasureSpec = MeasureSpec.makeMeasureSpec(initialWidth, MeasureSpec.EXACTLY);
				heightMeasureSpec = MeasureSpec.makeMeasureSpec(initialHeight, MeasureSpec.EXACTLY);
			}
		}

        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }

	@Override
	public void onSurfaceTextureAvailable(final SurfaceTexture surface, final int width, final int height) {
		if (DEBUG) Log.v(TAG, "onSurfaceTextureAvailable:" + surface);
//		mRenderHandler = RenderHandler.createHandler(surface);
		mHasSurface = true;
	}

	@Override
	public void onSurfaceTextureSizeChanged(final SurfaceTexture surface, final int width, final int height) {
		if (DEBUG) Log.v(TAG, "onSurfaceTextureSizeChanged:" + surface);
		mTempBitmap = null;
	}

	@Override
	public boolean onSurfaceTextureDestroyed(final SurfaceTexture surface) {
		if (DEBUG) Log.v(TAG, "onSurfaceTextureDestroyed:" + surface);
		mHasSurface = false;
		return true;
	}

	@Override
	public void onSurfaceTextureUpdated(final SurfaceTexture surface) {
		synchronized (mCaptureSync) {
			if (mReqesutCaptureStillImage) {
				mReqesutCaptureStillImage = false;
				if (mTempBitmap == null)
					// TODO modify this to change output image size
					mTempBitmap = getBitmap(1600, 1200);//3264,2448
				else
					getBitmap(mTempBitmap);
				mCaptureSync.notifyAll();
			}
		}
	}

	@Override
	public boolean hasSurface() {
		return mHasSurface;
	}

	/**
	 * capture preview image as a bitmap
	 * this method blocks current thread until bitmap is ready
	 * if you call this method at almost same time from different thread,
	 * the returned bitmap will be changed while you are processing the bitmap
	 * (because we return same instance of bitmap on each call for memory saving)
	 * if you need to call this method from multiple thread,
	 * you should change this method(copy and return)
	 */
	@Override
	public Bitmap captureStillImage() {
		synchronized (mCaptureSync) {
			mReqesutCaptureStillImage = true;
			try {
				mCaptureSync.wait();
			} catch (final InterruptedException e) {
			}
			return mTempBitmap;
		}
	}

	@Override
	public void setVideoEncoder(final MediaEncoder encoder) {
	}

}


USBMonitor

 

package com.serenegiant.usb;
/*
 * UVCCamera
 * library and sample to access to UVC web camera on non-rooted Android device
 *
 * Copyright (c) 2014-2015 saki t_saki@serenegiant.com
 *
 * File name: USBMonitor.java
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 * All files in the folder are under this Apache License, Version 2.0.
 * Files in the jni/libjpeg, jni/libusb, jin/libuvc, jni/rapidjson folder may have a different license, see the respective files.
*/

import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbDeviceConnection;
import android.hardware.usb.UsbInterface;
import android.hardware.usb.UsbManager;
import android.os.Handler;
import android.util.Log;
import android.util.SparseArray;

public final class USBMonitor {

	private static final boolean DEBUG = false;	// TODO set false on production
	private static final String TAG = "USBMonitor";

	private static final String ACTION_USB_PERMISSION_BASE = "com.serenegiant.USB_PERMISSION.";
	private final String ACTION_USB_PERMISSION = ACTION_USB_PERMISSION_BASE + hashCode();

	public static final String ACTION_USB_DEVICE_ATTACHED = "android.hardware.usb.action.USB_DEVICE_ATTACHED";

	private final ConcurrentHashMap<UsbDevice, UsbControlBlock> mCtrlBlocks = new ConcurrentHashMap<UsbDevice, UsbControlBlock>();
	private final WeakReference<Context> mWeakContext;
	private final UsbManager mUsbManager;
	private final OnDeviceConnectListener mOnDeviceConnectListener;
	private PendingIntent mPermissionIntent = null;
	private List<DeviceFilter> mDeviceFilters = new ArrayList<DeviceFilter>();

	private final Handler mHandler = new Handler();

	public interface OnDeviceConnectListener {
		/**
		 * called when device attached
		 * @param device
		 */
		public void onAttach(UsbDevice device);
		/**
		 * called when device dettach(after onDisconnect)
		 * @param device
		 */
		public void onDettach(UsbDevice device);
		/**
		 * called after device opend
		 * @param device
		 * @param createNew
		 */
		public void onConnect(UsbDevice device, UsbControlBlock ctrlBlock, boolean createNew);
		/**
		 * called when USB device removed or its power off (this callback is called after device closing)
		 * @param device
		 * @param ctrlBlock
		 */
		public void onDisconnect(UsbDevice device, UsbControlBlock ctrlBlock);
		/**
		 * called when canceled or could not get permission from user
		 */
		public void onCancel();
	}

	public USBMonitor(final Context context, final OnDeviceConnectListener listener) {
		if (DEBUG) Log.v(TAG, "USBMonitor:Constructor");
/*		if (listener == null)
			throw new IllegalArgumentException("OnDeviceConnectListener should not null."); */
		mWeakContext = new WeakReference<Context>(context);
		mUsbManager = (UsbManager)context.getSystemService(Context.USB_SERVICE);
		mOnDeviceConnectListener = listener;
		if (DEBUG) Log.v(TAG, "USBMonitor:mUsbManager=" + mUsbManager);
	}

	public void destroy() {
		if (DEBUG) Log.i(TAG, "destroy:");
		unregister();
		final Set<UsbDevice> keys = mCtrlBlocks.keySet();
		if (keys != null) {
			UsbControlBlock ctrlBlock;
			try {
				for (final UsbDevice key: keys) {
					ctrlBlock = mCtrlBlocks.remove(key);
					ctrlBlock.close();
				}
			} catch (final Exception e) {
				Log.e(TAG, "destroy:", e);
			}
			mCtrlBlocks.clear();
		}
	}

	/**
	 * register BroadcastReceiver to monitor USB events
	 */
	public synchronized void register() {
		if (mPermissionIntent == null) {
			if (DEBUG) Log.i(TAG, "register:");
			final Context context = mWeakContext.get();
			if (context != null) {
				mPermissionIntent = PendingIntent.getBroadcast(context, 0, new Intent(ACTION_USB_PERMISSION), 0);
				final IntentFilter filter = new IntentFilter(ACTION_USB_PERMISSION);
				filter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED);
				context.registerReceiver(mUsbReceiver, filter);
			}
			mDeviceCounts = 0;
			mHandler.postDelayed(mDeviceCheckRunnable, 1000);
		}
	}

	/**
	 * unregister BroadcastReceiver
	 */
	public synchronized void unregister() {
		if (mPermissionIntent != null) {
			if (DEBUG) Log.i(TAG, "unregister:");
			final Context context = mWeakContext.get();
			if (context != null) {
				context.unregisterReceiver(mUsbReceiver);
			}
			mPermissionIntent = null;
		}
		mDeviceCounts = 0;
		mHandler.removeCallbacks(mDeviceCheckRunnable);
	}

	public synchronized boolean isRegistered() {
		return mPermissionIntent != null;
	}

	/**
	 * set device filter
	 * @param filter
	 */
	public void setDeviceFilter(final DeviceFilter filter) {
		mDeviceFilters.clear();
		mDeviceFilters.add(filter);
	}

	/**
	 * set device filters
	 * @param filters
	 */
	public void setDeviceFilter(final List<DeviceFilter> filters) {
		mDeviceFilters.clear();
		mDeviceFilters.addAll(filters);
	}

	/**
	 * return the number of connected USB devices that matched device filter
	 * @return
	 */
	public int getDeviceCount() {
		return getDeviceList().size();
	}

	/**
	 * return device list, return empty list if no device matched
	 * @return
	 */
	public List<UsbDevice> getDeviceList() {
		return getDeviceList(mDeviceFilters);
	}

	/**
	 * return device list, return empty list if no device matched
	 * @param filters
	 * @return
	 */
	public List<UsbDevice> getDeviceList(final List<DeviceFilter> filters) {
		final HashMap<String, UsbDevice> deviceList = mUsbManager.getDeviceList();
		final List<UsbDevice> result = new ArrayList<UsbDevice>();
		if (deviceList != null) {
			for (final DeviceFilter filter: filters) {
				final Iterator<UsbDevice> iterator = deviceList.values().iterator();
				UsbDevice device;
				while (iterator.hasNext()) {
					device = iterator.next();
					if ((filter == null) || (filter.matches(device))) {
						result.add(device);
					}
				}
			}
		}
		return result;
	}

	/**
	 * return device list, return empty list if no device matched
	 * @param filter
	 * @return
	 */
	public List<UsbDevice> getDeviceList(final DeviceFilter filter) {
		final HashMap<String, UsbDevice> deviceList = mUsbManager.getDeviceList();
		final List<UsbDevice> result = new ArrayList<UsbDevice>();
		if (deviceList != null) {
			final Iterator<UsbDevice> iterator = deviceList.values().iterator();
			UsbDevice device;
			while (iterator.hasNext()) {
			    device = iterator.next();
			    if ((filter == null) || (filter.matches(device))) {
					result.add(device);
				}
			}
		}
		return result;
	}
	/**
	 * get USB device list
	 * @return
	 */
	public Iterator<UsbDevice> getDevices() {
		Iterator<UsbDevice> iterator = null;
		final HashMap<String, UsbDevice> list = mUsbManager.getDeviceList();
		if (list != null)
			iterator = list.values().iterator();
		return iterator;
	}

	/**
	 * output device list to LogCat
	 */
	public final void dumpDevices() {
		final HashMap<String, UsbDevice> list = mUsbManager.getDeviceList();
		if (list != null) {
			final Set<String> keys = list.keySet();
			if (keys != null && keys.size() > 0) {
				final StringBuilder sb = new StringBuilder();
				for (final String key: keys) {
					final UsbDevice device = list.get(key);
					final int num_interface = device != null ? device.getInterfaceCount() : 0;
					sb.setLength(0);
					for (int i = 0; i < num_interface; i++) {
						sb.append(String.format("interface%d:%s", i, device.getInterface(i).toString()));
					}
					Log.i(TAG, "key=" + key + ":" + device + ":" + sb.toString());
				}
			} else {
				Log.i(TAG, "no device");
			}
		} else {
			Log.i(TAG, "no device");
		}
	}

	/**
	 * return whether the specific Usb device has permission
	 * @param device
	 * @return
	 */
	public boolean hasPermission(final UsbDevice device) {
		return device != null && mUsbManager.hasPermission(device);
	}

	/**
	 * request permission to access to USB device
	 * @param device
	 */
	public synchronized void requestPermission(final UsbDevice device) {
		if (DEBUG) Log.v(TAG, "requestPermission:device=" + device);
		if (mPermissionIntent != null) {
			if (device != null) {
				if (mUsbManager.hasPermission(device)) {
					processConnect(device);
					
				} else {
					mUsbManager.requestPermission(device, mPermissionIntent);
				}
			} else {
				processCancel(device);
			}
		} else {
			processCancel(device);
		}
	}

	/**
	 * BroadcastReceiver for USB permission
	 */
	private final BroadcastReceiver mUsbReceiver = new BroadcastReceiver() {

		@Override
		public void onReceive(final Context context, final Intent intent) {
			final String action = intent.getAction();
			if (ACTION_USB_PERMISSION.equals(action)) {
				synchronized (USBMonitor.this) {
					final UsbDevice device = (UsbDevice)intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
					if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
						if (device != null) {
							processConnect(device);
						}
					} else {
						processCancel(device);
					}
				}
			} else if (UsbManager.ACTION_USB_DEVICE_ATTACHED.equals(action)) {
				final UsbDevice device = (UsbDevice)intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
				processAttach(device);
			} else if (UsbManager.ACTION_USB_DEVICE_DETACHED.equals(action)) {
				final UsbDevice device = (UsbDevice)intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
				if (device != null) {
					UsbControlBlock ctrlBlock = null;
					ctrlBlock = mCtrlBlocks.remove(device);
					if (ctrlBlock != null) {
						ctrlBlock.close();
					}
					mDeviceCounts = 0;
					processDettach(device);
				}
			}
		}
	};

	private volatile int mDeviceCounts = 0;

	private final Runnable mDeviceCheckRunnable = new Runnable() {
		@Override
		public void run() {
			final int n = getDeviceCount();
			if (n != mDeviceCounts) {
				if (n > mDeviceCounts) {
					mDeviceCounts = n;
					if (mOnDeviceConnectListener != null)
						mOnDeviceConnectListener.onAttach(null);
				}
			}
			mHandler.postDelayed(this, 2000);	// confirm every 2 seconds
		}
	};

	private final void processConnect(final UsbDevice device) {
		if (DEBUG) Log.v(TAG, "processConnect:");
		mHandler.post(new Runnable() {
			@Override
			public void run() {
				UsbControlBlock ctrlBlock;
				final boolean createNew;
				ctrlBlock = mCtrlBlocks.get(device);
				if (ctrlBlock == null) {
					ctrlBlock = new UsbControlBlock(USBMonitor.this, device);
					mCtrlBlocks.put(device, ctrlBlock);
					createNew = true;
				} else {
					createNew = false;
				}
				if (mOnDeviceConnectListener != null) {
					final UsbControlBlock ctrlB = ctrlBlock;
					mOnDeviceConnectListener.onConnect(device, ctrlB, createNew);
				}
			}
		});
	}

	private final void processCancel(final UsbDevice device) {
		if (DEBUG) Log.v(TAG, "processCancel:");
		if (mOnDeviceConnectListener != null) {
			mHandler.post(new Runnable() {
				@Override
				public void run() {
					mOnDeviceConnectListener.onCancel();
				}
			});
		}
	}

	private final void processAttach(final UsbDevice device) {
		if (DEBUG) Log.v(TAG, "processAttach:");
		if (mOnDeviceConnectListener != null) {
			mHandler.post(new Runnable() {
				@Override
				public void run() {
					mOnDeviceConnectListener.onAttach(device);
				}
			});
		}
	}

	private final void processDettach(final UsbDevice device) {
		if (DEBUG) Log.v(TAG, "processDettach:");
		if (mOnDeviceConnectListener != null) {
			mHandler.post(new Runnable() {
				@Override
				public void run() {
					mOnDeviceConnectListener.onDettach(device);
				}
			});
		}
	}

	public static final class UsbControlBlock {
		private final WeakReference<USBMonitor> mWeakMonitor;
		private final WeakReference<UsbDevice> mWeakDevice;
		protected UsbDeviceConnection mConnection;
		private final SparseArray<UsbInterface> mInterfaces = new SparseArray<UsbInterface>();

		/**
		 * this class needs permission to access USB device before constructing
		 * @param monitor
		 * @param device
		 */
		public UsbControlBlock(final USBMonitor monitor, final UsbDevice device) {
			if (DEBUG) Log.i(TAG, "UsbControlBlock:constructor");
			mWeakMonitor = new WeakReference<USBMonitor>(monitor);
			mWeakDevice = new WeakReference<UsbDevice>(device);
			mConnection = monitor.mUsbManager.openDevice(device);
			final String name = device.getDeviceName();
			if (mConnection != null) {
				if (DEBUG) {
					final int desc = mConnection.getFileDescriptor();
					final byte[] rawDesc = mConnection.getRawDescriptors();
					Log.i(TAG, "UsbControlBlock:name=" + name + ", desc=" + desc + ", rawDesc=" + rawDesc);
				}
			} else {
				Log.e(TAG, "could not connect to device " + name);
			}
		}

		public UsbDevice getDevice() {
			return mWeakDevice.get();
		}

		public String getDeviceName() {
			final UsbDevice device = mWeakDevice.get();
			return device != null ? device.getDeviceName() : "";
		}

		public UsbDeviceConnection getUsbDeviceConnection() {
			return mConnection;
		}

		public synchronized int getFileDescriptor() {
			return mConnection != null ? mConnection.getFileDescriptor() : -1;
		}

		public byte[] getRawDescriptors() {
			return mConnection != null ? mConnection.getRawDescriptors() : null;
		}

		public int getVenderId() {
			final UsbDevice device = mWeakDevice.get();
			return device != null ? device.getVendorId() : 0;
		}

		public int getProductId() {
			final UsbDevice device = mWeakDevice.get();
			return device != null ? device.getProductId() : 0;
		}

		public synchronized String getSerial() {
			return mConnection != null ? mConnection.getSerial() : null;
		}

		/**
		 * open specific interface
		 * @param interfaceIndex
		 * @return
		 */
		public synchronized UsbInterface open(final int interfaceIndex) {
			if (DEBUG) Log.i(TAG, "UsbControlBlock#open:" + interfaceIndex);
			final UsbDevice device = mWeakDevice.get();
			UsbInterface intf = null;
			intf = mInterfaces.get(interfaceIndex);
			if (intf == null) {
				intf = device.getInterface(interfaceIndex);
				if (intf != null) {
					synchronized (mInterfaces) {
						mInterfaces.append(interfaceIndex, intf);
					}
				}
			}
			return intf;
		}

		/**
		 * close specified interface. USB device itself still keep open.
		 * @param interfaceIndex
		 */
		public void close(final int interfaceIndex) {
			UsbInterface intf = null;
			synchronized (mInterfaces) {
				intf = mInterfaces.get(interfaceIndex);
				if (intf != null) {
					mInterfaces.delete(interfaceIndex);
					mConnection.releaseInterface(intf);
				}
			}
		}

		/**
		 * close specified interface. USB device itself still keep open.
		 */
		public synchronized void close() {
			if (DEBUG) Log.i(TAG, "UsbControlBlock#close:");
			if (mConnection != null) {
				final int n = mInterfaces.size();
				int key;
				UsbInterface intf;
				for (int i = 0; i < n; i++) {
					key = mInterfaces.keyAt(i);
					intf = mInterfaces.get(key);
					mConnection.releaseInterface(intf);
				}
				mConnection.close();
				mConnection = null;
				final USBMonitor monitor = mWeakMonitor.get();
				if (monitor != null) {
					if (monitor.mOnDeviceConnectListener != null) {
						final UsbDevice device = mWeakDevice.get();
						monitor.mOnDeviceConnectListener.onDisconnect(device, this);
					}
					monitor.mCtrlBlocks.remove(getDevice());
				}
			}
		}

/*		@Override
		protected void finalize() throws Throwable {
			close();
			super.finalize();
		} */
	}

}

 

戳我下载:

CSDN下载:http://download.csdn.net/download/luzhenyuxfcy/9460896

  • 4
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 39
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 39
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值