Browse Source

supporting Android9.0 and fixing capture image failed

main 2.3.0
Jiangdg 5 years ago
parent
commit
9092e8c9e0
  1. 5
      app/src/main/AndroidManifest.xml
  2. 3
      app/src/main/java/com/jiangdg/usbcamera/application/MyApplication.java
  3. 69
      app/src/main/java/com/jiangdg/usbcamera/utils/CrashHandler.java
  4. 2
      app/src/main/java/com/jiangdg/usbcamera/view/SplashActivity.java
  5. 7
      app/src/main/java/com/jiangdg/usbcamera/view/USBCameraActivity.java
  6. 2
      app/src/main/res/values/strings.xml
  7. 2
      build.gradle
  8. 16
      libusbcamera/src/main/java/com/jiangdg/usbcamera/UVCCameraHelper.java
  9. 72
      libusbcamera/src/main/java/com/serenegiant/usb/USBMonitor.java
  10. 20
      libusbcamera/src/main/java/com/serenegiant/usb/common/AbstractUVCCameraHandler.java
  11. 7
      libusbcamera/src/main/res/xml/device_filter.xml

5
app/src/main/AndroidManifest.xml

@ -3,7 +3,10 @@
package="com.jiangdg.usbcamera">
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-feature android:name="android.hardware.usb.host"/>
<application
android:name=".application.MyApplication"

3
app/src/main/java/com/jiangdg/usbcamera/application/MyApplication.java

@ -13,13 +13,12 @@ import com.jiangdg.usbcamera.utils.CrashHandler;
public class MyApplication extends Application {
private CrashHandler mCrashHandler;
// File Directory in sd card
public static final String DIRECTORY_NAME = "UVCCamera";
public static final String DIRECTORY_NAME = "USBCamera";
@Override
public void onCreate() {
super.onCreate();
mCrashHandler = CrashHandler.getInstance();
mCrashHandler.init(getApplicationContext(), getClass());
}
}

69
app/src/main/java/com/jiangdg/usbcamera/utils/CrashHandler.java

@ -22,9 +22,9 @@ import java.util.HashMap;
import java.util.Map;
/**
* UncaughtException处理类,当程序发生Uncaught异常的时候,有该类来接管程序,并记录发送错误报告.
* UncaughtException handler class
*
* @author user
* @author jiangdg on 2017/6/27.
*
*/
public class CrashHandler implements UncaughtExceptionHandler {
@ -33,22 +33,16 @@ public class CrashHandler implements UncaughtExceptionHandler {
public static final String PROGRAM_BROKEN_ACTION = "com.teligen.wccp.PROGRAM_BROKEN";
// 系统默认的UncaughtException处理类
private UncaughtExceptionHandler mDefaultHandler;
// CrashHandler实例
private static CrashHandler instance = new CrashHandler();
// 程序的Context对象
private Context mContext;
// 程序的主Activity的class
private Class<?> mainActivityClass;
// 用来存储设备信息和异常信息
private Map<String, String> infos = new HashMap<String, String>();
/** 保证只有一个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<String, String> entry : infos.entrySet()) {
// String key = entry.getKey();
// String value = entry.getValue();
// sb.append(key + "=" + value + "\n");
// }
for (Map.Entry<String, String> 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<num;i++){
sb.append(ex.getStackTrace()[i].toString());
@ -170,7 +138,7 @@ public class CrashHandler implements UncaughtExceptionHandler {
FileOutputStream fos = null;
try {
fos = new FileOutputStream(file);
fos.write((sb.toString()+"异常:"+ex.getLocalizedMessage()).getBytes());
fos.write((sb.toString()+"exception:"+ex.getLocalizedMessage()).getBytes());
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
@ -182,7 +150,6 @@ public class CrashHandler implements UncaughtExceptionHandler {
e.printStackTrace();
}
}
// Log.e(TAG, "出现未捕捉异常,程序异常退出!", ex);
}
public Class<?> getMainActivityClass() {

2
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() {

7
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();

2
app/src/main/res/values/strings.xml

@ -1,3 +1,3 @@
<resources>
<string name="app_name">AndroidUSBCamera</string>
<string name="app_name">USBCamera</string>
</resources>

2
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

16
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) {

72
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<UsbDevice> getDeviceList(final List<DeviceFilter> filters) throws IllegalStateException {
if (destroyed) throw new IllegalStateException("already destroyed");
// get detected devices
final HashMap<String, UsbDevice> 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<UsbDevice> result = new ArrayList<UsbDevice>();
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;
}

20
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();

7
libusbcamera/src/main/res/xml/device_filter.xml

@ -25,4 +25,11 @@
<usb>
<usb-device class="239" subclass="2" /> <!-- all device of UVC -->
<!-- a few android 9.0 -->
<usb-device class="14" subclass="9" />
<usb-device class="2" subclass="0" />
<usb-device class="6" subclass="-1" />
<usb-device product-id="4836" vendor-id="9573" />
<usb-device product-id="2229" vendor-id="1133" />
<usb-device product-id="640" vendor-id="1409" />
</usb>

Loading…
Cancel
Save