diff --git a/app/build.gradle b/app/build.gradle index 171f70e..a32ac10 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -6,7 +6,7 @@ android { defaultConfig { applicationId "com.jiangdg.usbcamera" minSdkVersion 18 - targetSdkVersion 25 + targetSdkVersion 22 versionCode 1 versionName "1.0" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" @@ -29,4 +29,6 @@ dependencies { compile project(':libusbcamera') compile 'com.jakewharton:butterknife:8.8.1' compile 'com.jakewharton:butterknife-compiler:8.8.1' + compile 'com.jakewharton:butterknife:8.8.1' + compile 'com.jakewharton:butterknife-compiler:8.8.1' } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index d2146dd..5bece02 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -2,8 +2,10 @@ + + - + diff --git a/app/src/main/java/com/jiangdg/usbcamera/view/BaseActivity.java b/app/src/main/java/com/jiangdg/usbcamera/view/BaseActivity.java deleted file mode 100644 index c61b4ab..0000000 --- a/app/src/main/java/com/jiangdg/usbcamera/view/BaseActivity.java +++ /dev/null @@ -1,198 +0,0 @@ -/* - * UVCCamera - * library and sample to access to UVC web camera on non-rooted Android device - * - * Copyright (c) 2014-2017 saki t_saki@serenegiant.com - * - * 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 libjpeg-turbo, libusb, libuvc, rapidjson folder - * may have a different license, see the respective files. - */ - -package com.jiangdg.usbcamera.view; - -import android.Manifest; -import android.annotation.SuppressLint; -import android.app.Activity; -import android.content.pm.PackageManager; -import android.os.Bundle; -import android.os.Handler; -import android.os.Looper; -import android.support.annotation.NonNull; -import android.support.annotation.StringRes; -import android.support.v7.app.AppCompatActivity; -import android.util.Log; -import android.widget.Toast; - -import com.serenegiant.dialog.MessageDialogFragment; -import com.serenegiant.utils.BuildCheck; -import com.serenegiant.utils.HandlerThreadHandler; -import com.serenegiant.utils.PermissionCheck; - -/** - * Created by saki on 2016/11/18. - * - */ -public class BaseActivity extends AppCompatActivity { - - private static boolean DEBUG = false; - private static final String TAG = BaseActivity.class.getSimpleName(); - - // 处理UI的Handler - private final Handler mUIHandler = new Handler(Looper.getMainLooper()); - private final Thread mUiThread = mUIHandler.getLooper().getThread(); - // 工作线程Handler - private Handler mWorkerHandler; - private long mWorkerThreadID = -1; - - @Override - protected void onCreate(final Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - // 创建工作线程 - if (mWorkerHandler == null) { - mWorkerHandler = HandlerThreadHandler.createHandler(TAG); - mWorkerThreadID = mWorkerHandler.getLooper().getThread().getId(); - } - } - - @Override - protected void onPause() { - clearToast(); - super.onPause(); - } - - @Override - protected synchronized void onDestroy() { - // 释放线程资源 - if (mWorkerHandler != null) { - try { - mWorkerHandler.getLooper().quit(); - } catch (final Exception e) { - // - } - mWorkerHandler = null; - } - super.onDestroy(); - } - -//================================================================================ - /** - * - * 子线程中更新UI,duration为延迟多久执行 - * - */ - public final void runOnUiThread(final Runnable task, final long duration) { - if (task == null) return; - mUIHandler.removeCallbacks(task); - if ((duration > 0) || Thread.currentThread() != mUiThread) { - mUIHandler.postDelayed(task, duration); - } else { - try { - task.run(); - } catch (final Exception e) { - Log.w(TAG, e); - } - } - } - - /** - * 移除更新UI task - * @param task - */ - public final void removeFromUiThread(final Runnable task) { - if (task == null) return; - mUIHandler.removeCallbacks(task); - } - - /** - * 工作子线程中执行的任务 - */ - protected final synchronized void queueEvent(final Runnable task, final long delayMillis) { - if ((task == null) || (mWorkerHandler == null)) return; - try { - mWorkerHandler.removeCallbacks(task); - if (delayMillis > 0) { - mWorkerHandler.postDelayed(task, delayMillis); - } else if (mWorkerThreadID == Thread.currentThread().getId()) { - task.run(); - } else { - mWorkerHandler.post(task); - } - } catch (final Exception e) { - // ignore - } - } - - protected final synchronized void removeEvent(final Runnable task) { - if (task == null) return; - try { - mWorkerHandler.removeCallbacks(task); - } catch (final Exception e) { - // ignore - } - } - -//================================================================================ - private Toast mToast; - - protected void showToast(@StringRes final int msg, final Object... args) { - removeFromUiThread(mShowToastTask); - mShowToastTask = new ShowToastTask(msg, args); - runOnUiThread(mShowToastTask, 0); - } - - - protected void clearToast() { - removeFromUiThread(mShowToastTask); - mShowToastTask = null; - try { - if (mToast != null) { - mToast.cancel(); - mToast = null; - } - } catch (final Exception e) { - // ignore - } - } - - private ShowToastTask mShowToastTask; - private final class ShowToastTask implements Runnable { - final int msg; - final Object args; - private ShowToastTask(@StringRes final int msg, final Object... args) { - this.msg = msg; - this.args = args; - } - - @Override - public void run() { - try { - if (mToast != null) { - mToast.cancel(); - mToast = null; - } - if (args != null) { - final String _msg = getString(msg, args); - mToast = Toast.makeText(BaseActivity.this, _msg, Toast.LENGTH_SHORT); - } else { - mToast = Toast.makeText(BaseActivity.this, msg, Toast.LENGTH_SHORT); - } - mToast.show(); - } catch (final Exception e) { - // ignore - } - } - } -} diff --git a/app/src/main/java/com/jiangdg/usbcamera/view/MainActivity.java b/app/src/main/java/com/jiangdg/usbcamera/view/MainActivity.java deleted file mode 100644 index 6bc9447..0000000 --- a/app/src/main/java/com/jiangdg/usbcamera/view/MainActivity.java +++ /dev/null @@ -1,250 +0,0 @@ -package com.jiangdg.usbcamera.view; - -import android.hardware.usb.UsbDevice; -import android.os.Bundle; -import android.util.Log; -import android.view.Surface; -import android.view.SurfaceHolder; -import android.view.SurfaceView; -import android.view.View; -import android.view.View.OnClickListener; -import android.widget.ImageButton; -import android.widget.Toast; - -import com.jiangdg.usbcamera.R; -import com.serenegiant.usb.CameraDialog; -import com.serenegiant.usb.USBMonitor; -import com.serenegiant.usb.USBMonitor.OnDeviceConnectListener; -import com.serenegiant.usb.USBMonitor.UsbControlBlock; -import com.serenegiant.usb.UVCCamera; - -import butterknife.BindView; -import butterknife.ButterKnife; -import butterknife.OnClick; - -public class MainActivity extends BaseActivity implements CameraDialog.CameraDialogParent { - private static final boolean DEBUG = true; - private static final String TAG = "MainActivity"; - @BindView(R.id.camera_surface_view) - public SurfaceView mUVCCameraView; - - private final Object mSync = new Object(); - // USB和USB Camera访问管理类 - private USBMonitor mUSBMonitor; - private UVCCamera mUVCCamera; - - private Surface mPreviewSurface; - private boolean isActive, isPreview; - - private final SurfaceHolder.Callback mSurfaceViewCallback = new SurfaceHolder.Callback() { - @Override - public void surfaceCreated(final SurfaceHolder holder) { - if (DEBUG) Log.v(TAG, "surfaceCreated:"); - } - - @Override - public void surfaceChanged(final SurfaceHolder holder, final int format, final int width, final int height) { - if ((width == 0) || (height == 0)) return; - if (DEBUG) Log.v(TAG, "surfaceChanged:"); - mPreviewSurface = holder.getSurface(); - synchronized (mSync) { - if (isActive && !isPreview && (mUVCCamera != null)) { - mUVCCamera.setPreviewDisplay(mPreviewSurface); - mUVCCamera.startPreview(); - isPreview = true; - } - } - } - - @Override - public void surfaceDestroyed(final SurfaceHolder holder) { - if (DEBUG) Log.v(TAG, "surfaceDestroyed:"); - synchronized (mSync) { - if (mUVCCamera != null) { - mUVCCamera.stopPreview(); - } - isPreview = false; - } - mPreviewSurface = null; - } - }; - - @Override - protected void onCreate(final Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_main); - // 绑定Activity - ButterKnife.bind(this); - mUVCCameraView.getHolder().addCallback(mSurfaceViewCallback); - - // 初始化USBMonitor - // 注册USB设备监听器 - mUSBMonitor = new USBMonitor(this, new OnDeviceConnectListener() { - @Override - public void onAttach(final UsbDevice device) { - if (DEBUG) Log.v(TAG, "onAttach:"); - Toast.makeText(MainActivity.this, "检测到USB设备", Toast.LENGTH_SHORT).show(); - } - - @Override - public void onConnect(final UsbDevice device, final UsbControlBlock ctrlBlock, final boolean createNew) { - if (DEBUG) Log.v(TAG, "onConnect:"); - Toast.makeText(MainActivity.this, "成功连接到USB设备", Toast.LENGTH_SHORT).show(); - synchronized (mSync) { - if (mUVCCamera != null) { - mUVCCamera.destroy(); - } - isActive = isPreview = false; - } - queueEvent(new Runnable() { - @Override - public void run() { - synchronized (mSync) { - final UVCCamera camera = new UVCCamera(); - camera.open(ctrlBlock); - if (DEBUG) Log.i(TAG, "supportedSize:" + camera.getSupportedSize()); - try { - camera.setPreviewSize(UVCCamera.DEFAULT_PREVIEW_WIDTH, UVCCamera.DEFAULT_PREVIEW_HEIGHT, UVCCamera.FRAME_FORMAT_MJPEG); - } catch (final IllegalArgumentException e) { - try { - // fallback to YUV mode - camera.setPreviewSize(UVCCamera.DEFAULT_PREVIEW_WIDTH, UVCCamera.DEFAULT_PREVIEW_HEIGHT, UVCCamera.DEFAULT_PREVIEW_MODE); - } catch (final IllegalArgumentException e1) { - camera.destroy(); - return; - } - } - mPreviewSurface = mUVCCameraView.getHolder().getSurface(); - if (mPreviewSurface != null) { - isActive = true; - camera.setPreviewDisplay(mPreviewSurface); - camera.startPreview(); - isPreview = true; - } - synchronized (mSync) { - mUVCCamera = camera; - } - } - } - }, 0); - } - - @Override - public void onDisconnect(final UsbDevice device, final UsbControlBlock ctrlBlock) { - if (DEBUG) Log.v(TAG, "onDisconnect:"); - Toast.makeText(MainActivity.this, "与USB设备断开连接", Toast.LENGTH_SHORT).show(); - // XXX you should check whether the comming device equal to camera device that currently using - queueEvent(new Runnable() { - @Override - public void run() { - synchronized (mSync) { - if (mUVCCamera != null) { - mUVCCamera.close(); - if (mPreviewSurface != null) { - mPreviewSurface.release(); - mPreviewSurface = null; - } - isActive = isPreview = false; - } - } - } - }, 0); - } - - @Override - public void onDettach(final UsbDevice device) { - if (DEBUG) Log.v(TAG, "onDettach:"); - Toast.makeText(MainActivity.this, "未检测到USB设备", Toast.LENGTH_SHORT).show(); - } - - @Override - public void onCancel(final UsbDevice device) { - } - }); - } - - @Override - protected void onStart() { - super.onStart(); - if (DEBUG) Log.v(TAG, "onStart:"); - synchronized (mSync) { - // 注册 - if (mUSBMonitor != null) { - mUSBMonitor.register(); - } - } - } - - @Override - protected void onStop() { - if (DEBUG) Log.v(TAG, "onStop:"); - synchronized (mSync) { - // 注销 - if (mUSBMonitor != null) { - mUSBMonitor.unregister(); - } - } - super.onStop(); - } - - @Override - protected void onDestroy() { - if (DEBUG) Log.v(TAG, "onDestroy:"); - synchronized (mSync) { - isActive = isPreview = false; - if (mUVCCamera != null) { - mUVCCamera.destroy(); - mUVCCamera = null; - } - // 释放资源 - if (mUSBMonitor != null) { - mUSBMonitor.destroy(); - mUSBMonitor = null; - } - } - mUVCCameraView = null; - super.onDestroy(); - } - - @OnClick({R.id.camera_surface_view}) - public void onViewClicked(View view){ - int vId= view.getId(); - switch (vId){ - case R.id.camera_surface_view: - if (mUVCCamera == null) { - // XXX calling CameraDialog.showDialog is necessary at only first time(only when app has no permission). - // 当APP访问USB设备没有被授权时,弹出对话框 - CameraDialog.showDialog(MainActivity.this); - } else { - synchronized (mSync) { - mUVCCamera.destroy(); - mUVCCamera = null; - isActive = isPreview = false; - } - } - break; - } - } - - - /** - * to access from CameraDialog - * @return - */ - @Override - public USBMonitor getUSBMonitor() { - return mUSBMonitor; - } - - @Override - public void onDialogResult(boolean canceled) { - if (canceled) { - runOnUiThread(new Runnable() { - @Override - public void run() { - // FIXME - } - }, 0); - } - } -} diff --git a/app/src/main/java/com/jiangdg/usbcamera/view/USBCameraActivity.java b/app/src/main/java/com/jiangdg/usbcamera/view/USBCameraActivity.java new file mode 100644 index 0000000..f12b719 --- /dev/null +++ b/app/src/main/java/com/jiangdg/usbcamera/view/USBCameraActivity.java @@ -0,0 +1,169 @@ +package com.jiangdg.usbcamera.view; + +import android.hardware.usb.UsbDevice; +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.support.v7.app.AppCompatActivity; +import android.view.View; +import android.widget.Button; +import android.widget.Toast; + +import com.jiangdg.usbcamera.R; +import com.jiangdg.usbcamera.USBCameraManager; +import com.serenegiant.usb.CameraDialog; +import com.serenegiant.usb.USBMonitor; +import com.serenegiant.usb.widget.CameraViewInterface; + +import butterknife.BindView; +import butterknife.ButterKnife; +import butterknife.OnClick; + +/** + * AndroidUSBCamera引擎使用Demo + * + * Created by jiangdongguo on 2017/9/30. + */ + +public class USBCameraActivity extends AppCompatActivity implements CameraDialog.CameraDialogParent{ + @BindView(R.id.camera_view) + public View mTextureView; + @BindView(R.id.btn_capture_pic) + public Button mBtnCapture; + @BindView(R.id.btn_rec_video) + public Button mBtnRecord; + + private USBCameraManager mUSBManager; + private CameraViewInterface mUVCCameraView; + + // USB设备监听器 + private USBCameraManager.OnMyDevConnectListener listener = new USBCameraManager.OnMyDevConnectListener() { + @Override + public void onAttachDev(UsbDevice device) { + showShortMsg("检测到设备:"+device.getDeviceName()); + } + + @Override + public void onDettachDev(UsbDevice device) { + showShortMsg(device.getDeviceName()+"已拨出"); + } + + @Override + public void onConnectDev(UsbDevice device) { + // 处理连接到设备后的逻辑 + } + + @Override + public void onDisConnectDev(UsbDevice device) { + // 处理与设备断开后的逻辑 + } + }; + + @Override + protected void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_usbcamera); + ButterKnife.bind(this); + // 初始化引擎 + mUSBManager = USBCameraManager.getInstance(); + mUVCCameraView = (CameraViewInterface) mTextureView; + mUSBManager.init(this, mUVCCameraView, listener); + } + + @Override + protected void onStart() { + super.onStart(); + // 注册USB事件广播监听器 + if(mUSBManager != null){ + mUSBManager.registerUSB(); + } + // 恢复Camera预览 + if(mUVCCameraView != null){ + mUVCCameraView.onResume(); + } + } + + @Override + protected void onStop() { + super.onStop(); + // 注销USB事件广播监听器 + if(mUSBManager != null){ + mUSBManager.unregisterUSB(); + } + // 暂停Camera预览 + if(mUVCCameraView != null){ + mUVCCameraView.onPause(); + } + } + + @OnClick({R.id.camera_view, R.id.btn_capture_pic, R.id.btn_rec_video}) + public void onViewClick(View view) { + int vId = view.getId(); + switch (vId) { + // 开启或关闭Camera + case R.id.camera_view: + if(mUSBManager != null){ + boolean isOpened = mUSBManager.isCameraOpened(); + if(! isOpened){ + CameraDialog.showDialog(USBCameraActivity.this); + }else { + mUSBManager.closeCamera(); + } + } + + break; + case R.id.btn_capture_pic: + if(mUSBManager == null || ! mUSBManager.isCameraOpened()){ + showShortMsg("抓拍异常,摄像头未开启"); + return; + } + String picPath = USBCameraManager.ROOT_PATH+System.currentTimeMillis() + +USBCameraManager.SUFFIX_PNG; + mUSBManager.capturePicture(picPath); + + showShortMsg("保存路径:"+picPath); + break; + case R.id.btn_rec_video: + if(mUSBManager == null || ! mUSBManager.isCameraOpened()){ + showShortMsg("录制异常,摄像头未开启"); + return; + } + if(! mUSBManager.isRecording()){ + String videoPath = USBCameraManager.ROOT_PATH+System.currentTimeMillis() + +USBCameraManager.SUFFIX_MP4; + mUSBManager.startRecording(videoPath); + + mBtnRecord.setText("正在录制"); + } else { + mUSBManager.stopRecording(); + + mBtnRecord.setText("开始录制"); + } + break; + } + } + + @Override + protected void onDestroy() { + super.onDestroy(); + // 释放资源 + if(mUSBManager != null){ + mUSBManager.release(); + } + } + + private void showShortMsg(String msg) { + Toast.makeText(this, msg, Toast.LENGTH_SHORT).show(); + } + + @Override + public USBMonitor getUSBMonitor() { + return mUSBManager.getUSBMonitor(); + } + + @Override + public void onDialogResult(boolean canceled) { + if(canceled){ + showShortMsg("取消操作"); + } + } +} diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml deleted file mode 100644 index 7aff3d8..0000000 --- a/app/src/main/res/layout/activity_main.xml +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - diff --git a/app/src/main/res/layout/activity_usbcamera.xml b/app/src/main/res/layout/activity_usbcamera.xml new file mode 100644 index 0000000..32f05b8 --- /dev/null +++ b/app/src/main/res/layout/activity_usbcamera.xml @@ -0,0 +1,39 @@ + + + + + +