From 9092e8c9e041471f520f31c2d716f0f14b44d7fb Mon Sep 17 00:00:00 2001 From: Jiangdg <765067602@qq.com> Date: Mon, 17 Jun 2019 15:26:32 +0800 Subject: [PATCH] supporting Android9.0 and fixing capture image failed --- app/src/main/AndroidManifest.xml | 5 +- .../usbcamera/application/MyApplication.java | 3 +- .../jiangdg/usbcamera/utils/CrashHandler.java | 69 +++++------------- .../usbcamera/view/SplashActivity.java | 2 +- .../usbcamera/view/USBCameraActivity.java | 7 +- app/src/main/res/values/strings.xml | 2 +- build.gradle | 2 +- .../jiangdg/usbcamera/UVCCameraHelper.java | 16 +++-- .../java/com/serenegiant/usb/USBMonitor.java | 72 ++++++++++++++++--- .../usb/common/AbstractUVCCameraHandler.java | 20 ++---- .../src/main/res/xml/device_filter.xml | 7 ++ 11 files changed, 114 insertions(+), 91 deletions(-) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 0c032c2..0e44b31 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -3,7 +3,10 @@ package="com.jiangdg.usbcamera"> - + + + + mainActivityClass; - // 用来存储设备信息和异常信息 private Map infos = new HashMap(); - /** 保证只有一个CrashHandler实例 */ + private CrashHandler() { } - /** 获取CrashHandler实例 ,单例模式 */ public static CrashHandler getInstance() { return instance; } @@ -56,22 +50,16 @@ public class CrashHandler implements UncaughtExceptionHandler { public void init(Context context, Class activityClass) { mContext = context; this.setMainActivityClass(activityClass); - // 获取系统默认的UncaughtException处理器 mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler(); - // 设置该CrashHandler为程序的默认处理器 Thread.setDefaultUncaughtExceptionHandler(this); } - /** - * 当UncaughtException发生时会转入该函数来处理 - */ + @Override public void uncaughtException(Thread thread, Throwable ex) { if (!handleException(ex) && mDefaultHandler != null) { - // 如果用户没有处理则让系统默认的异常处理器来处理 mDefaultHandler.uncaughtException(thread, ex); } else { - //重启应用,释放资源 System.out.println("uncaughtException--->" + ex.getMessage()); // Log.e(TAG, ex.getMessage()); logError(ex); @@ -80,18 +68,10 @@ public class CrashHandler implements UncaughtExceptionHandler { } catch (InterruptedException e) { // Log.e("debug", "error:", e); } -// AppManagerUtils.removeAllActivities(); -// AppManagerUtils.restartApp(mContext,mContext.getPackageName()); -// AppManagerUtils.releaseAppResource(); + exitApp(); } } - /** - * 自定义错误处理,收集错误信息 发送错误报告等操作均在此完成. - * - * @param ex - * @return true:如果处理了该异常信息;否则返回false. - */ private boolean handleException(Throwable ex) { if (ex == null) { return false; @@ -101,25 +81,20 @@ public class CrashHandler implements UncaughtExceptionHandler { public void run() { Looper.prepare(); Toast.makeText(mContext.getApplicationContext(), - "unknown exception!Please checking logs in sd card.", Toast.LENGTH_LONG).show(); + "unknown exception and exiting...Please checking logs in sd card!", Toast.LENGTH_LONG).show(); Looper.loop(); - - android.os.Process.killProcess(android.os.Process.myPid()); - System.exit(0); } }).start(); - // 收集设备参数信息 collectDeviceInfo(mContext.getApplicationContext()); - // 保存日志文件 logError(ex); return true; } - /** - * 收集设备参数信息 - * - * @param ctx - */ + private void exitApp() { + android.os.Process.killProcess(android.os.Process.myPid()); + System.exit(0); + } + public void collectDeviceInfo(Context ctx) { try { PackageManager pm = ctx.getPackageManager(); @@ -133,7 +108,6 @@ public class CrashHandler implements UncaughtExceptionHandler { infos.put("versionCode", versionCode); } } catch (NameNotFoundException e) { -// Log.e(TAG, "收集包信息出现错误", e); } Field[] fields = Build.class.getDeclaredFields(); for (Field field : fields) { @@ -141,25 +115,19 @@ public class CrashHandler implements UncaughtExceptionHandler { field.setAccessible(true); infos.put(field.getName(), field.get(null).toString()); } catch (Exception e) { -// Log.e(TAG, "收集系统信息出现错误", e); } } } - /** - * 保存错误信息到文件中 - * - * @param ex - * @return 返回文件名称,便于将文件传送到服务器 - */ + private void logError(Throwable ex) { StringBuffer sb = new StringBuffer(); -// for (Map.Entry entry : infos.entrySet()) { -// String key = entry.getKey(); -// String value = entry.getValue(); -// sb.append(key + "=" + value + "\n"); -// } + for (Map.Entry entry : infos.entrySet()) { + String key = entry.getKey(); + String value = entry.getValue(); + sb.append(key + "=" + value + "\n"); + } int num = ex.getStackTrace().length; for (int i=0;i getMainActivityClass() { diff --git a/app/src/main/java/com/jiangdg/usbcamera/view/SplashActivity.java b/app/src/main/java/com/jiangdg/usbcamera/view/SplashActivity.java index 1887139..1214394 100644 --- a/app/src/main/java/com/jiangdg/usbcamera/view/SplashActivity.java +++ b/app/src/main/java/com/jiangdg/usbcamera/view/SplashActivity.java @@ -46,7 +46,7 @@ public class SplashActivity extends AppCompatActivity { } private boolean isVersionM() { - return Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP; + return Build.VERSION.SDK_INT >= Build.VERSION_CODES.M; } private void checkAndRequestPermissions() { diff --git a/app/src/main/java/com/jiangdg/usbcamera/view/USBCameraActivity.java b/app/src/main/java/com/jiangdg/usbcamera/view/USBCameraActivity.java index d76a0ac..5e527ec 100644 --- a/app/src/main/java/com/jiangdg/usbcamera/view/USBCameraActivity.java +++ b/app/src/main/java/com/jiangdg/usbcamera/view/USBCameraActivity.java @@ -35,6 +35,7 @@ import com.serenegiant.usb.common.AbstractUVCCameraHandler; import com.serenegiant.usb.encoder.RecordParams; import com.serenegiant.usb.widget.CameraViewInterface; +import java.io.File; import java.util.ArrayList; import java.util.List; @@ -147,7 +148,7 @@ public class USBCameraActivity extends AppCompatActivity implements CameraDialog mCameraHelper.setOnPreviewFrameListener(new AbstractUVCCameraHandler.OnPreViewResultListener() { @Override public void onPreviewResult(byte[] nv21Yuv) { - + Log.d(TAG, "onPreviewResult: "+nv21Yuv.length); } }); } @@ -227,7 +228,7 @@ public class USBCameraActivity extends AppCompatActivity implements CameraDialog showShortMsg("sorry,camera open failed"); return super.onOptionsItemSelected(item); } - String picPath = UVCCameraHelper.ROOT_PATH + MyApplication.DIRECTORY_NAME +"images/"+ System.currentTimeMillis() + String picPath = UVCCameraHelper.ROOT_PATH + MyApplication.DIRECTORY_NAME +"/images/"+ System.currentTimeMillis() + UVCCameraHelper.SUFFIX_JPEG; mCameraHelper.capturePicture(picPath, new AbstractUVCCameraHandler.OnCaptureListener() { @Override @@ -243,7 +244,7 @@ public class USBCameraActivity extends AppCompatActivity implements CameraDialog return super.onOptionsItemSelected(item); } if (!mCameraHelper.isPushing()) { - String videoPath = UVCCameraHelper.ROOT_PATH + MyApplication.DIRECTORY_NAME +"videos/"+ System.currentTimeMillis(); + String videoPath = UVCCameraHelper.ROOT_PATH + MyApplication.DIRECTORY_NAME +"/videos/"+ System.currentTimeMillis(); FileUtils.createfile(FileUtils.ROOT_PATH + "test666.h264"); // if you want to record,please create RecordParams like this RecordParams params = new RecordParams(); diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 60b5af8..b68d7e4 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1,3 +1,3 @@ - AndroidUSBCamera + USBCamera diff --git a/build.gradle b/build.gradle index 22ea390..d7e2a20 100644 --- a/build.gradle +++ b/build.gradle @@ -27,7 +27,7 @@ ext { commonLibVersion= '2.12.4' versionCompiler = 27 versionTarget = 27 - minSdkVersion = 23 + minSdkVersion = 21 versionNameString = '1.0.0' javaSourceCompatibility = JavaVersion.VERSION_1_8 javaTargetCompatibility = JavaVersion.VERSION_1_8 diff --git a/libusbcamera/src/main/java/com/jiangdg/usbcamera/UVCCameraHelper.java b/libusbcamera/src/main/java/com/jiangdg/usbcamera/UVCCameraHelper.java index efe105a..20e20b7 100644 --- a/libusbcamera/src/main/java/com/jiangdg/usbcamera/UVCCameraHelper.java +++ b/libusbcamera/src/main/java/com/jiangdg/usbcamera/UVCCameraHelper.java @@ -32,9 +32,10 @@ public class UVCCameraHelper { private static final String TAG = "UVCCameraHelper"; private int previewWidth = 640; private int previewHeight = 480; - // 高分辨率YUV格式帧率较低 public static final int FRAME_FORMAT_YUYV = UVCCamera.FRAME_FORMAT_YUYV; - // 默认使用MJPEG + // Default using MJPEG + // if your device is connected,but have no images + // please try to change it to FRAME_FORMAT_YUYV public static final int FRAME_FORMAT_MJPEG = UVCCamera.FRAME_FORMAT_MJPEG; public static final int MODE_BRIGHTNESS = UVCCamera.PU_BRIGHTNESS; public static final int MODE_CONTRAST = UVCCamera.PU_CONTRAST; @@ -108,13 +109,13 @@ public class UVCCameraHelper { new Thread(new Runnable() { @Override public void run() { - // 休眠500ms,等待Camera创建完毕 + // wait for camera created try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } - // 开启预览 + // start previewing startPreview(mCamView); } }).start(); @@ -172,13 +173,13 @@ public class UVCCameraHelper { new Thread(new Runnable() { @Override public void run() { - // 休眠500ms,等待Camera创建完毕 + // wait for camera created try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } - // 开启预览 + // start previewing startPreview(mCamView); } }).start(); @@ -238,7 +239,8 @@ public class UVCCameraHelper { .getDeviceFilters(mActivity.getApplicationContext(), R.xml.device_filter); if (mUSBMonitor == null || deviceFilters == null) return null; - return mUSBMonitor.getDeviceList(deviceFilters.get(0)); + // matching all of filter devices + return mUSBMonitor.getDeviceList(deviceFilters); } public void capturePicture(String savePath,AbstractUVCCameraHandler.OnCaptureListener listener) { diff --git a/libusbcamera/src/main/java/com/serenegiant/usb/USBMonitor.java b/libusbcamera/src/main/java/com/serenegiant/usb/USBMonitor.java index 5766184..c51e567 100644 --- a/libusbcamera/src/main/java/com/serenegiant/usb/USBMonitor.java +++ b/libusbcamera/src/main/java/com/serenegiant/usb/USBMonitor.java @@ -30,11 +30,14 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; import android.hardware.usb.UsbDevice; import android.hardware.usb.UsbDeviceConnection; import android.hardware.usb.UsbInterface; import android.hardware.usb.UsbManager; import android.os.Build; +import android.os.Environment; import android.os.Handler; import android.text.TextUtils; import android.util.Log; @@ -43,9 +46,15 @@ import android.util.SparseArray; import com.serenegiant.utils.BuildCheck; import com.serenegiant.utils.HandlerThreadHandler; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.io.PrintWriter; import java.io.UnsupportedEncodingException; import java.lang.ref.WeakReference; +import java.text.SimpleDateFormat; import java.util.ArrayList; +import java.util.Date; import java.util.HashMap; import java.util.Iterator; import java.util.List; @@ -298,24 +307,65 @@ public final class USBMonitor { */ public List getDeviceList(final List filters) throws IllegalStateException { if (destroyed) throw new IllegalStateException("already destroyed"); + // get detected devices final HashMap deviceList = mUsbManager.getDeviceList(); + // store those devices info before matching filter xml file + String fileName = Environment.getExternalStorageDirectory()+ "/USBCamera/failed_devices.txt"; + File logFile = new File(fileName); + FileWriter fw = null; + PrintWriter pw = null; final List result = new ArrayList(); - if (deviceList != null) { - if ((filters == null) || filters.isEmpty()) { - result.addAll(deviceList.values()); - } else { - for (final UsbDevice device: deviceList.values() ) { - for (final DeviceFilter filter: filters) { - if ((filter != null) && filter.matches(device)) { - // when filter matches - if (!filter.isExclude) { - result.add(device); + try { + fw = new FileWriter(logFile, true); + pw = new PrintWriter(fw); + if (deviceList != null) { + if ((filters == null) || filters.isEmpty()) { + result.addAll(deviceList.values()); + } else { + for (final UsbDevice device: deviceList.values() ) { + // match devices + for (final DeviceFilter filter: filters) { + if ((filter != null) && filter.matches(device) || (filter != null && filter.mSubclass == device.getDeviceSubclass())) { + // when filter matches + if (!filter.isExclude) { + result.add(device); + } + break; + } else { + // collection failed dev's class and subclass + String devModel = android.os.Build.MODEL; + String devSystemVersion = android.os.Build.VERSION.RELEASE; + String devClass = String.valueOf(device.getDeviceClass()); + String subClass = String.valueOf(device.getDeviceSubclass()); + if(pw != null) { + StringBuilder sb = new StringBuilder(); + sb.append(devModel); + sb.append("/"); + sb.append(devSystemVersion); + sb.append(":"); + sb.append("class="+devClass+", subclass="+subClass); + pw.println(sb.toString()); + pw.flush(); + fw.flush(); + } } - break; } } } } + } catch (IOException e) { + e.printStackTrace(); + } finally { + if (pw != null) { + pw.close(); + } + if (fw != null) { + try { + fw.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } } return result; } diff --git a/libusbcamera/src/main/java/com/serenegiant/usb/common/AbstractUVCCameraHandler.java b/libusbcamera/src/main/java/com/serenegiant/usb/common/AbstractUVCCameraHandler.java index ee62f38..62f0a3e 100644 --- a/libusbcamera/src/main/java/com/serenegiant/usb/common/AbstractUVCCameraHandler.java +++ b/libusbcamera/src/main/java/com/serenegiant/usb/common/AbstractUVCCameraHandler.java @@ -813,8 +813,6 @@ public abstract class AbstractUVCCameraHandler extends Handler { saveYuv2Jpeg(picPath, yuv); } }).start(); - - isCaptureStill = false; } // 视频 if (mH264Consumer != null) { @@ -829,27 +827,23 @@ public abstract class AbstractUVCCameraHandler extends Handler { ByteArrayOutputStream bos = new ByteArrayOutputStream(data.length); boolean result = yuvImage.compressToJpeg(new Rect(0, 0, mWidth, mHeight), 100, bos); if (result) { - byte[] buffer = bos.toByteArray(); - Bitmap bmp = BitmapFactory.decodeByteArray(buffer, 0, buffer.length); + byte[] buffer = bos.toByteArray(); File file = new File(path); FileOutputStream fos = null; try { fos = new FileOutputStream(file); + // fixing bm is null bug instead of using BitmapFactory.decodeByteArray + fos.write(buffer); + fos.close(); } catch (FileNotFoundException e) { e.printStackTrace(); - } - bmp.compress(Bitmap.CompressFormat.JPEG, 100, fos); - try { - fos.flush(); - fos.close(); - bmp.recycle(); - if (mCaptureListener != null) { - mCaptureListener.onCaptureResult(path); - } } catch (IOException e) { e.printStackTrace(); } + if (mCaptureListener != null) { + mCaptureListener.onCaptureResult(path); + } } try { bos.close(); diff --git a/libusbcamera/src/main/res/xml/device_filter.xml b/libusbcamera/src/main/res/xml/device_filter.xml index da573ff..2ac246c 100644 --- a/libusbcamera/src/main/res/xml/device_filter.xml +++ b/libusbcamera/src/main/res/xml/device_filter.xml @@ -25,4 +25,11 @@ + + + + + + +