commit c1ddd61e9bf2f3944e7f560a87c10f388f454e71 Author: jiangdongguo <765067602@qq.com> Date: Fri Sep 29 17:36:05 2017 +0800 Initial commit diff --git a/.gradle/2.14.1/taskArtifacts/cache.properties b/.gradle/2.14.1/taskArtifacts/cache.properties new file mode 100644 index 0000000..a2f0313 --- /dev/null +++ b/.gradle/2.14.1/taskArtifacts/cache.properties @@ -0,0 +1 @@ +#Fri Sep 29 14:50:34 CST 2017 diff --git a/.gradle/2.14.1/taskArtifacts/cache.properties.lock b/.gradle/2.14.1/taskArtifacts/cache.properties.lock new file mode 100644 index 0000000..3089714 Binary files /dev/null and b/.gradle/2.14.1/taskArtifacts/cache.properties.lock differ diff --git a/.gradle/2.14.1/taskArtifacts/fileHashes.bin b/.gradle/2.14.1/taskArtifacts/fileHashes.bin new file mode 100644 index 0000000..e07f308 Binary files /dev/null and b/.gradle/2.14.1/taskArtifacts/fileHashes.bin differ diff --git a/.gradle/2.14.1/taskArtifacts/fileSnapshots.bin b/.gradle/2.14.1/taskArtifacts/fileSnapshots.bin new file mode 100644 index 0000000..65ed922 Binary files /dev/null and b/.gradle/2.14.1/taskArtifacts/fileSnapshots.bin differ diff --git a/.gradle/2.14.1/taskArtifacts/fileSnapshotsToTreeSnapshotsIndex.bin b/.gradle/2.14.1/taskArtifacts/fileSnapshotsToTreeSnapshotsIndex.bin new file mode 100644 index 0000000..0c7e314 Binary files /dev/null and b/.gradle/2.14.1/taskArtifacts/fileSnapshotsToTreeSnapshotsIndex.bin differ diff --git a/.gradle/2.14.1/taskArtifacts/taskArtifacts.bin b/.gradle/2.14.1/taskArtifacts/taskArtifacts.bin new file mode 100644 index 0000000..59c5caa Binary files /dev/null and b/.gradle/2.14.1/taskArtifacts/taskArtifacts.bin differ diff --git a/.gradle/3.3/taskArtifacts/fileHashes.bin b/.gradle/3.3/taskArtifacts/fileHashes.bin new file mode 100644 index 0000000..d911fa5 Binary files /dev/null and b/.gradle/3.3/taskArtifacts/fileHashes.bin differ diff --git a/.gradle/3.3/taskArtifacts/fileSnapshots.bin b/.gradle/3.3/taskArtifacts/fileSnapshots.bin new file mode 100644 index 0000000..fc48224 Binary files /dev/null and b/.gradle/3.3/taskArtifacts/fileSnapshots.bin differ diff --git a/.gradle/3.3/taskArtifacts/taskArtifacts.bin b/.gradle/3.3/taskArtifacts/taskArtifacts.bin new file mode 100644 index 0000000..3d16c11 Binary files /dev/null and b/.gradle/3.3/taskArtifacts/taskArtifacts.bin differ diff --git a/.gradle/3.3/taskArtifacts/taskArtifacts.lock b/.gradle/3.3/taskArtifacts/taskArtifacts.lock new file mode 100644 index 0000000..c9156c0 Binary files /dev/null and b/.gradle/3.3/taskArtifacts/taskArtifacts.lock differ diff --git a/.gradle/3.3/tasks/_app_compileDebugJavaWithJavac/localClassSetAnalysis/localClassSetAnalysis.bin b/.gradle/3.3/tasks/_app_compileDebugJavaWithJavac/localClassSetAnalysis/localClassSetAnalysis.bin new file mode 100644 index 0000000..98f72eb Binary files /dev/null and b/.gradle/3.3/tasks/_app_compileDebugJavaWithJavac/localClassSetAnalysis/localClassSetAnalysis.bin differ diff --git a/.gradle/3.3/tasks/_app_compileDebugJavaWithJavac/localClassSetAnalysis/localClassSetAnalysis.lock b/.gradle/3.3/tasks/_app_compileDebugJavaWithJavac/localClassSetAnalysis/localClassSetAnalysis.lock new file mode 100644 index 0000000..8dae71e Binary files /dev/null and b/.gradle/3.3/tasks/_app_compileDebugJavaWithJavac/localClassSetAnalysis/localClassSetAnalysis.lock differ diff --git a/.gradle/3.3/tasks/_app_compileDebugJavaWithJavac/localJarClasspathSnapshot/localJarClasspathSnapshot.bin b/.gradle/3.3/tasks/_app_compileDebugJavaWithJavac/localJarClasspathSnapshot/localJarClasspathSnapshot.bin new file mode 100644 index 0000000..0423367 Binary files /dev/null and b/.gradle/3.3/tasks/_app_compileDebugJavaWithJavac/localJarClasspathSnapshot/localJarClasspathSnapshot.bin differ diff --git a/.gradle/3.3/tasks/_app_compileDebugJavaWithJavac/localJarClasspathSnapshot/localJarClasspathSnapshot.lock b/.gradle/3.3/tasks/_app_compileDebugJavaWithJavac/localJarClasspathSnapshot/localJarClasspathSnapshot.lock new file mode 100644 index 0000000..20d36ac Binary files /dev/null and b/.gradle/3.3/tasks/_app_compileDebugJavaWithJavac/localJarClasspathSnapshot/localJarClasspathSnapshot.lock differ diff --git a/.gradle/3.3/tasks/_libusbcamera_compileReleaseJavaWithJavac/localClassSetAnalysis/localClassSetAnalysis.bin b/.gradle/3.3/tasks/_libusbcamera_compileReleaseJavaWithJavac/localClassSetAnalysis/localClassSetAnalysis.bin new file mode 100644 index 0000000..a07a7a9 Binary files /dev/null and b/.gradle/3.3/tasks/_libusbcamera_compileReleaseJavaWithJavac/localClassSetAnalysis/localClassSetAnalysis.bin differ diff --git a/.gradle/3.3/tasks/_libusbcamera_compileReleaseJavaWithJavac/localClassSetAnalysis/localClassSetAnalysis.lock b/.gradle/3.3/tasks/_libusbcamera_compileReleaseJavaWithJavac/localClassSetAnalysis/localClassSetAnalysis.lock new file mode 100644 index 0000000..9a9df5f Binary files /dev/null and b/.gradle/3.3/tasks/_libusbcamera_compileReleaseJavaWithJavac/localClassSetAnalysis/localClassSetAnalysis.lock differ diff --git a/.gradle/3.3/tasks/_libusbcamera_compileReleaseJavaWithJavac/localJarClasspathSnapshot/localJarClasspathSnapshot.bin b/.gradle/3.3/tasks/_libusbcamera_compileReleaseJavaWithJavac/localJarClasspathSnapshot/localJarClasspathSnapshot.bin new file mode 100644 index 0000000..66bf0f4 Binary files /dev/null and b/.gradle/3.3/tasks/_libusbcamera_compileReleaseJavaWithJavac/localJarClasspathSnapshot/localJarClasspathSnapshot.bin differ diff --git a/.gradle/3.3/tasks/_libusbcamera_compileReleaseJavaWithJavac/localJarClasspathSnapshot/localJarClasspathSnapshot.lock b/.gradle/3.3/tasks/_libusbcamera_compileReleaseJavaWithJavac/localJarClasspathSnapshot/localJarClasspathSnapshot.lock new file mode 100644 index 0000000..1d4f344 Binary files /dev/null and b/.gradle/3.3/tasks/_libusbcamera_compileReleaseJavaWithJavac/localJarClasspathSnapshot/localJarClasspathSnapshot.lock differ diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..96cc43e --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/copyright/profiles_settings.xml b/.idea/copyright/profiles_settings.xml new file mode 100644 index 0000000..e7bedf3 --- /dev/null +++ b/.idea/copyright/profiles_settings.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml new file mode 100644 index 0000000..11c42be --- /dev/null +++ b/.idea/gradle.xml @@ -0,0 +1,20 @@ + + + + + + \ No newline at end of file diff --git a/.idea/libraries/animated_vector_drawable_25_3_1.xml b/.idea/libraries/animated_vector_drawable_25_3_1.xml new file mode 100644 index 0000000..8d7505d --- /dev/null +++ b/.idea/libraries/animated_vector_drawable_25_3_1.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/appcompat_v7_25_3_1.xml b/.idea/libraries/appcompat_v7_25_3_1.xml new file mode 100644 index 0000000..038e5c7 --- /dev/null +++ b/.idea/libraries/appcompat_v7_25_3_1.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/auto_common_0_8.xml b/.idea/libraries/auto_common_0_8.xml new file mode 100644 index 0000000..67f5310 --- /dev/null +++ b/.idea/libraries/auto_common_0_8.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/butterknife_8_8_1.xml b/.idea/libraries/butterknife_8_8_1.xml new file mode 100644 index 0000000..4bb46d5 --- /dev/null +++ b/.idea/libraries/butterknife_8_8_1.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/butterknife_annotations_8_8_1.xml b/.idea/libraries/butterknife_annotations_8_8_1.xml new file mode 100644 index 0000000..e2d12da --- /dev/null +++ b/.idea/libraries/butterknife_annotations_8_8_1.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/butterknife_compiler_8_8_1.xml b/.idea/libraries/butterknife_compiler_8_8_1.xml new file mode 100644 index 0000000..b63b0f2 --- /dev/null +++ b/.idea/libraries/butterknife_compiler_8_8_1.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/common_1_5_20.xml b/.idea/libraries/common_1_5_20.xml new file mode 100644 index 0000000..b9b9846 --- /dev/null +++ b/.idea/libraries/common_1_5_20.xml @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/espresso_core_2_2_2.xml b/.idea/libraries/espresso_core_2_2_2.xml new file mode 100644 index 0000000..5df88bb --- /dev/null +++ b/.idea/libraries/espresso_core_2_2_2.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/espresso_idling_resource_2_2_2.xml b/.idea/libraries/espresso_idling_resource_2_2_2.xml new file mode 100644 index 0000000..1b2b924 --- /dev/null +++ b/.idea/libraries/espresso_idling_resource_2_2_2.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/exposed_instrumentation_api_publish_0_5.xml b/.idea/libraries/exposed_instrumentation_api_publish_0_5.xml new file mode 100644 index 0000000..e94c107 --- /dev/null +++ b/.idea/libraries/exposed_instrumentation_api_publish_0_5.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/guava_19_0.xml b/.idea/libraries/guava_19_0.xml new file mode 100644 index 0000000..3c0bbce --- /dev/null +++ b/.idea/libraries/guava_19_0.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/hamcrest_core_1_3.xml b/.idea/libraries/hamcrest_core_1_3.xml new file mode 100644 index 0000000..157e3f3 --- /dev/null +++ b/.idea/libraries/hamcrest_core_1_3.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/hamcrest_integration_1_3.xml b/.idea/libraries/hamcrest_integration_1_3.xml new file mode 100644 index 0000000..58b2c4b --- /dev/null +++ b/.idea/libraries/hamcrest_integration_1_3.xml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/hamcrest_library_1_3.xml b/.idea/libraries/hamcrest_library_1_3.xml new file mode 100644 index 0000000..676cc63 --- /dev/null +++ b/.idea/libraries/hamcrest_library_1_3.xml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/javapoet_1_9_0.xml b/.idea/libraries/javapoet_1_9_0.xml new file mode 100644 index 0000000..efa3453 --- /dev/null +++ b/.idea/libraries/javapoet_1_9_0.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/javawriter_2_1_1.xml b/.idea/libraries/javawriter_2_1_1.xml new file mode 100644 index 0000000..a66fefb --- /dev/null +++ b/.idea/libraries/javawriter_2_1_1.xml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/javax_annotation_api_1_2.xml b/.idea/libraries/javax_annotation_api_1_2.xml new file mode 100644 index 0000000..811e73f --- /dev/null +++ b/.idea/libraries/javax_annotation_api_1_2.xml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/javax_inject_1.xml b/.idea/libraries/javax_inject_1.xml new file mode 100644 index 0000000..0d1d5fc --- /dev/null +++ b/.idea/libraries/javax_inject_1.xml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/jsr305_2_0_1.xml b/.idea/libraries/jsr305_2_0_1.xml new file mode 100644 index 0000000..cdf9878 --- /dev/null +++ b/.idea/libraries/jsr305_2_0_1.xml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/junit_4_12.xml b/.idea/libraries/junit_4_12.xml new file mode 100644 index 0000000..305df30 --- /dev/null +++ b/.idea/libraries/junit_4_12.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/recyclerview_v7_25_3_1.xml b/.idea/libraries/recyclerview_v7_25_3_1.xml new file mode 100644 index 0000000..a2e5c1e --- /dev/null +++ b/.idea/libraries/recyclerview_v7_25_3_1.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/rules_0_5.xml b/.idea/libraries/rules_0_5.xml new file mode 100644 index 0000000..4935ce1 --- /dev/null +++ b/.idea/libraries/rules_0_5.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/runner_0_5.xml b/.idea/libraries/runner_0_5.xml new file mode 100644 index 0000000..40993f6 --- /dev/null +++ b/.idea/libraries/runner_0_5.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/support_annotations_25_3_1.xml b/.idea/libraries/support_annotations_25_3_1.xml new file mode 100644 index 0000000..21d2ecc --- /dev/null +++ b/.idea/libraries/support_annotations_25_3_1.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/support_compat_25_3_1.xml b/.idea/libraries/support_compat_25_3_1.xml new file mode 100644 index 0000000..553fd37 --- /dev/null +++ b/.idea/libraries/support_compat_25_3_1.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/support_core_ui_25_3_1.xml b/.idea/libraries/support_core_ui_25_3_1.xml new file mode 100644 index 0000000..b42a139 --- /dev/null +++ b/.idea/libraries/support_core_ui_25_3_1.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/support_core_utils_25_3_1.xml b/.idea/libraries/support_core_utils_25_3_1.xml new file mode 100644 index 0000000..049c378 --- /dev/null +++ b/.idea/libraries/support_core_utils_25_3_1.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/support_fragment_25_3_1.xml b/.idea/libraries/support_fragment_25_3_1.xml new file mode 100644 index 0000000..ed1f097 --- /dev/null +++ b/.idea/libraries/support_fragment_25_3_1.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/support_media_compat_25_3_1.xml b/.idea/libraries/support_media_compat_25_3_1.xml new file mode 100644 index 0000000..527d3ea --- /dev/null +++ b/.idea/libraries/support_media_compat_25_3_1.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/support_v4_25_3_1.xml b/.idea/libraries/support_v4_25_3_1.xml new file mode 100644 index 0000000..26ee12f --- /dev/null +++ b/.idea/libraries/support_v4_25_3_1.xml @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/support_vector_drawable_25_3_1.xml b/.idea/libraries/support_vector_drawable_25_3_1.xml new file mode 100644 index 0000000..404781e --- /dev/null +++ b/.idea/libraries/support_vector_drawable_25_3_1.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..7158618 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1.8 + + + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..ca1f180 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/.idea/runConfigurations.xml b/.idea/runConfigurations.xml new file mode 100644 index 0000000..7f68460 --- /dev/null +++ b/.idea/runConfigurations.xml @@ -0,0 +1,12 @@ + + + + + + \ No newline at end of file diff --git a/AndroidUSBCamera.iml b/AndroidUSBCamera.iml new file mode 100644 index 0000000..70245ff --- /dev/null +++ b/AndroidUSBCamera.iml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/.gitignore b/app/.gitignore new file mode 100644 index 0000000..796b96d --- /dev/null +++ b/app/.gitignore @@ -0,0 +1 @@ +/build diff --git a/app/app.iml b/app/app.iml new file mode 100644 index 0000000..e03e0af --- /dev/null +++ b/app/app.iml @@ -0,0 +1,136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle new file mode 100644 index 0000000..318544d --- /dev/null +++ b/app/build.gradle @@ -0,0 +1,32 @@ +apply plugin: 'com.android.application' + +android { + compileSdkVersion 25 + buildToolsVersion "26.0.1" + defaultConfig { + applicationId "com.jiangdg.usbcamera" + minSdkVersion 15 + targetSdkVersion 25 + versionCode 1 + versionName "1.0" + testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" + } + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } +} + +dependencies { + compile fileTree(include: ['*.jar'], dir: 'libs') + androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { + exclude group: 'com.android.support', module: 'support-annotations' + }) + compile 'com.android.support:appcompat-v7:25.3.1' + testCompile 'junit:junit:4.12' + compile project(':libusbcamera') + compile 'com.jakewharton:butterknife:8.8.1' + compile 'com.jakewharton:butterknife-compiler:8.8.1' +} diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro new file mode 100644 index 0000000..492aa79 --- /dev/null +++ b/app/proguard-rules.pro @@ -0,0 +1,17 @@ +# Add project specific ProGuard rules here. +# By default, the flags in this file are appended to flags specified +# in E:\Environment\android-sdk-windows/tools/proguard/proguard-android.txt +# You can edit the include path and order by changing the proguardFiles +# directive in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# Add any project specific keep options here: + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} diff --git a/app/src/androidTest/java/com/jiangdg/usbcamera/ExampleInstrumentedTest.java b/app/src/androidTest/java/com/jiangdg/usbcamera/ExampleInstrumentedTest.java new file mode 100644 index 0000000..fb81ad9 --- /dev/null +++ b/app/src/androidTest/java/com/jiangdg/usbcamera/ExampleInstrumentedTest.java @@ -0,0 +1,26 @@ +package com.jiangdg.usbcamera; + +import android.content.Context; +import android.support.test.InstrumentationRegistry; +import android.support.test.runner.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import static org.junit.Assert.*; + +/** + * Instrumentation test, which will execute on an Android device. + * + * @see Testing documentation + */ +@RunWith(AndroidJUnit4.class) +public class ExampleInstrumentedTest { + @Test + public void useAppContext() throws Exception { + // Context of the app under test. + Context appContext = InstrumentationRegistry.getTargetContext(); + + assertEquals("com.jiangdg.androidusbcamera", appContext.getPackageName()); + } +} diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..d2146dd --- /dev/null +++ b/app/src/main/AndroidManifest.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/java/com/jiangdg/usbcamera/application/MyApplication.java b/app/src/main/java/com/jiangdg/usbcamera/application/MyApplication.java new file mode 100644 index 0000000..768242c --- /dev/null +++ b/app/src/main/java/com/jiangdg/usbcamera/application/MyApplication.java @@ -0,0 +1,22 @@ +package com.jiangdg.usbcamera.application; + +import android.app.Application; + +import com.jiangdg.usbcamera.utils.CrashHandler; + +/**全局类 + * + * Created by jianddongguo on 2017/7/20. + */ + +public class MyApplication extends Application { + private CrashHandler mCrashHandler; + + @Override + public void onCreate() { + super.onCreate(); + mCrashHandler = CrashHandler.getInstance(); + mCrashHandler.init(getApplicationContext(), getClass()); + + } +} diff --git a/app/src/main/java/com/jiangdg/usbcamera/utils/CrashHandler.java b/app/src/main/java/com/jiangdg/usbcamera/utils/CrashHandler.java new file mode 100644 index 0000000..1165523 --- /dev/null +++ b/app/src/main/java/com/jiangdg/usbcamera/utils/CrashHandler.java @@ -0,0 +1,190 @@ +package com.jiangdg.usbcamera.utils; + +import android.content.Context; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.content.pm.PackageManager.NameNotFoundException; +import android.os.Build; +import android.os.Environment; +import android.os.Looper; +import android.widget.Toast; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.lang.Thread.UncaughtExceptionHandler; +import java.lang.reflect.Field; +import java.util.HashMap; +import java.util.Map; + +/** + * UncaughtException处理类,当程序发生Uncaught异常的时候,有该类来接管程序,并记录发送错误报告. + * + * @author user + * + */ +public class CrashHandler implements UncaughtExceptionHandler { + + public static final String TAG = "CrashHandler"; + + 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 infos = new HashMap(); + + /** 保证只有一个CrashHandler实例 */ + private CrashHandler() { + } + + /** 获取CrashHandler实例 ,单例模式 */ + public static CrashHandler getInstance() { + return instance; + } + + 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); + try { + Thread.sleep(3000); + } catch (InterruptedException e) { +// Log.e("debug", "error:", e); + } +// AppManagerUtils.removeAllActivities(); +// AppManagerUtils.restartApp(mContext,mContext.getPackageName()); +// AppManagerUtils.releaseAppResource(); + } + } + + /** + * 自定义错误处理,收集错误信息 发送错误报告等操作均在此完成. + * + * @param ex + * @return true:如果处理了该异常信息;否则返回false. + */ + private boolean handleException(Throwable ex) { + if (ex == null) { + return false; + } + new Thread(new Runnable() { + @Override + public void run() { + Looper.prepare(); + Toast.makeText(mContext.getApplicationContext(), + "程序异常退出,即将重启...", Toast.LENGTH_LONG).show(); + Looper.loop(); + } + }).start(); + // 收集设备参数信息 + collectDeviceInfo(mContext.getApplicationContext()); + // 保存日志文件 + logError(ex); + return true; + } + + /** + * 收集设备参数信息 + * + * @param ctx + */ + public void collectDeviceInfo(Context ctx) { + try { + PackageManager pm = ctx.getPackageManager(); + PackageInfo pi = pm.getPackageInfo(ctx.getPackageName(), + PackageManager.GET_ACTIVITIES); + if (pi != null) { + String versionName = pi.versionName == null ? "null" + : pi.versionName; + String versionCode = pi.versionCode + ""; + infos.put("versionName", versionName); + infos.put("versionCode", versionCode); + } + } catch (NameNotFoundException e) { +// Log.e(TAG, "收集包信息出现错误", e); + } + Field[] fields = Build.class.getDeclaredFields(); + for (Field field : fields) { + try { + 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"); +// } + int num = ex.getStackTrace().length; + for (int i=0;i getMainActivityClass() { + return mainActivityClass; + } + + public void setMainActivityClass(Class mainActivityClass) { + this.mainActivityClass = mainActivityClass; + } +} diff --git a/app/src/main/java/com/jiangdg/usbcamera/view/BaseActivity.java b/app/src/main/java/com/jiangdg/usbcamera/view/BaseActivity.java new file mode 100644 index 0000000..c61b4ab --- /dev/null +++ b/app/src/main/java/com/jiangdg/usbcamera/view/BaseActivity.java @@ -0,0 +1,198 @@ +/* + * 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 new file mode 100644 index 0000000..6bc9447 --- /dev/null +++ b/app/src/main/java/com/jiangdg/usbcamera/view/MainActivity.java @@ -0,0 +1,250 @@ +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/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml new file mode 100644 index 0000000..7aff3d8 --- /dev/null +++ b/app/src/main/res/layout/activity_main.xml @@ -0,0 +1,15 @@ + + + + + + + diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher.png b/app/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 0000000..cde69bc Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher.png differ diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher.png b/app/src/main/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 0000000..c133a0c Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher.png differ diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/app/src/main/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 0000000..bfa42f0 Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 0000000..324e72c Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 0000000..aee44e1 Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/app/src/main/res/values-w820dp/dimens.xml b/app/src/main/res/values-w820dp/dimens.xml new file mode 100644 index 0000000..63fc816 --- /dev/null +++ b/app/src/main/res/values-w820dp/dimens.xml @@ -0,0 +1,6 @@ + + + 64dp + diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml new file mode 100644 index 0000000..3ab3e9c --- /dev/null +++ b/app/src/main/res/values/colors.xml @@ -0,0 +1,6 @@ + + + #3F51B5 + #303F9F + #FF4081 + diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml new file mode 100644 index 0000000..47c8224 --- /dev/null +++ b/app/src/main/res/values/dimens.xml @@ -0,0 +1,5 @@ + + + 16dp + 16dp + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml new file mode 100644 index 0000000..60b5af8 --- /dev/null +++ b/app/src/main/res/values/strings.xml @@ -0,0 +1,3 @@ + + AndroidUSBCamera + diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml new file mode 100644 index 0000000..5885930 --- /dev/null +++ b/app/src/main/res/values/styles.xml @@ -0,0 +1,11 @@ + + + + + + diff --git a/app/src/test/java/com/jiangdg/usbcamera/ExampleUnitTest.java b/app/src/test/java/com/jiangdg/usbcamera/ExampleUnitTest.java new file mode 100644 index 0000000..3fac274 --- /dev/null +++ b/app/src/test/java/com/jiangdg/usbcamera/ExampleUnitTest.java @@ -0,0 +1,17 @@ +package com.jiangdg.usbcamera; + +import org.junit.Test; + +import static org.junit.Assert.*; + +/** + * Example local unit test, which will execute on the development machine (host). + * + * @see Testing documentation + */ +public class ExampleUnitTest { + @Test + public void addition_isCorrect() throws Exception { + assertEquals(4, 2 + 2); + } +} \ No newline at end of file diff --git a/build.gradle b/build.gradle new file mode 100644 index 0000000..c8f7571 --- /dev/null +++ b/build.gradle @@ -0,0 +1,31 @@ +// Top-level build file where you can add configuration options common to all sub-projects/modules. +buildscript { + repositories { + jcenter() + } + dependencies { + classpath 'com.android.tools.build:gradle:2.3.1' + } +} + +allprojects { + repositories { + maven { url 'http://raw.github.com/saki4510t/libcommon/master/repository/' } + jcenter() + } +} + +task clean(type: Delete) { + delete rootProject.buildDir +} + +ext { + supportLibVersion = '25.3.1' // variable that can be referenced to keep support libs consistent + commonLibVersion= '1.5.20' + versionBuildTool = '25.0.2' + versionCompiler = 25 + versionTarget = 23 + versionNameString = '1.0.0' + javaSourceCompatibility = JavaVersion.VERSION_1_7 + javaTargetCompatibility = JavaVersion.VERSION_1_7 +} diff --git a/build/android-profile/profile-2017-09-29-17-33-27-872.rawproto b/build/android-profile/profile-2017-09-29-17-33-27-872.rawproto new file mode 100644 index 0000000..e8583e7 Binary files /dev/null and b/build/android-profile/profile-2017-09-29-17-33-27-872.rawproto differ diff --git a/build/generated/mockable-android-25.jar b/build/generated/mockable-android-25.jar new file mode 100644 index 0000000..c4ed2a8 Binary files /dev/null and b/build/generated/mockable-android-25.jar differ diff --git a/gradle.properties b/gradle.properties new file mode 100644 index 0000000..aac7c9b --- /dev/null +++ b/gradle.properties @@ -0,0 +1,17 @@ +# Project-wide Gradle settings. + +# IDE (e.g. Android Studio) users: +# Gradle settings configured through the IDE *will override* +# any settings specified in this file. + +# For more details on how to configure your build environment visit +# http://www.gradle.org/docs/current/userguide/build_environment.html + +# Specifies the JVM arguments used for the daemon process. +# The setting is particularly useful for tweaking memory settings. +org.gradle.jvmargs=-Xmx1536m + +# When configured, Gradle will run in incubating parallel mode. +# This option should only be used with decoupled projects. More details, visit +# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects +# org.gradle.parallel=true diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000..13372ae Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..9a778d6 --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Mon Dec 28 10:00:20 PST 2015 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-3.3-all.zip diff --git a/gradlew b/gradlew new file mode 100644 index 0000000..9d82f78 --- /dev/null +++ b/gradlew @@ -0,0 +1,160 @@ +#!/usr/bin/env bash + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn ( ) { + echo "$*" +} + +die ( ) { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; +esac + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules +function splitJvmOpts() { + JVM_OPTS=("$@") +} +eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS +JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" + +exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 0000000..8a0b282 --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,90 @@ +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windowz variants + +if not "%OS%" == "Windows_NT" goto win9xME_args +if "%@eval[2+2]" == "4" goto 4NT_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* +goto execute + +:4NT_args +@rem Get arguments from the 4NT Shell from JP Software +set CMD_LINE_ARGS=%$ + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/libusbcamera/.gitignore b/libusbcamera/.gitignore new file mode 100644 index 0000000..796b96d --- /dev/null +++ b/libusbcamera/.gitignore @@ -0,0 +1 @@ +/build diff --git a/libusbcamera/build.gradle b/libusbcamera/build.gradle new file mode 100644 index 0000000..fc0ad3a --- /dev/null +++ b/libusbcamera/build.gradle @@ -0,0 +1,35 @@ +apply plugin: 'com.android.library' + +android { + compileSdkVersion 25 + buildToolsVersion "26.0.1" + + defaultConfig { + minSdkVersion 15 + targetSdkVersion 25 + versionCode 1 + versionName "1.0" + + testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" + + } + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } +} + + +dependencies { + compile fileTree(dir: 'libs', include: ['*.jar']) + androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { + exclude group: 'com.android.support', module: 'support-annotations' + }) + compile 'com.android.support:appcompat-v7:25.3.1' + testCompile 'junit:junit:4.12' + compile("com.serenegiant:common:${commonLibVersion}") { + exclude module: 'support-v4' + } +} diff --git a/libusbcamera/libusbcamera.iml b/libusbcamera/libusbcamera.iml new file mode 100644 index 0000000..3ce8d33 --- /dev/null +++ b/libusbcamera/libusbcamera.iml @@ -0,0 +1,131 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/libusbcamera/proguard-rules.pro b/libusbcamera/proguard-rules.pro new file mode 100644 index 0000000..492aa79 --- /dev/null +++ b/libusbcamera/proguard-rules.pro @@ -0,0 +1,17 @@ +# Add project specific ProGuard rules here. +# By default, the flags in this file are appended to flags specified +# in E:\Environment\android-sdk-windows/tools/proguard/proguard-android.txt +# You can edit the include path and order by changing the proguardFiles +# directive in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# Add any project specific keep options here: + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} diff --git a/libusbcamera/src/androidTest/java/com/jiangdg/libusbcamera/ExampleInstrumentedTest.java b/libusbcamera/src/androidTest/java/com/jiangdg/libusbcamera/ExampleInstrumentedTest.java new file mode 100644 index 0000000..4f535e1 --- /dev/null +++ b/libusbcamera/src/androidTest/java/com/jiangdg/libusbcamera/ExampleInstrumentedTest.java @@ -0,0 +1,26 @@ +package com.jiangdg.libusbcamera; + +import android.content.Context; +import android.support.test.InstrumentationRegistry; +import android.support.test.runner.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import static org.junit.Assert.*; + +/** + * Instrumentation test, which will execute on an Android device. + * + * @see Testing documentation + */ +@RunWith(AndroidJUnit4.class) +public class ExampleInstrumentedTest { + @Test + public void useAppContext() throws Exception { + // Context of the app under test. + Context appContext = InstrumentationRegistry.getTargetContext(); + + assertEquals("com.jiangdg.libusbcamera.test", appContext.getPackageName()); + } +} diff --git a/libusbcamera/src/main/AndroidManifest.xml b/libusbcamera/src/main/AndroidManifest.xml new file mode 100644 index 0000000..072143f --- /dev/null +++ b/libusbcamera/src/main/AndroidManifest.xml @@ -0,0 +1,9 @@ + + + + + + + diff --git a/libusbcamera/src/main/java/com/serenegiant/usb/CameraDialog.java b/libusbcamera/src/main/java/com/serenegiant/usb/CameraDialog.java new file mode 100644 index 0000000..2fcc9fa --- /dev/null +++ b/libusbcamera/src/main/java/com/serenegiant/usb/CameraDialog.java @@ -0,0 +1,237 @@ +/* + * 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.serenegiant.usb; + +import android.app.Activity; +import android.app.AlertDialog; +import android.app.Dialog; +import android.app.DialogFragment; +import android.content.Context; +import android.content.DialogInterface; +import android.hardware.usb.UsbDevice; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.View.OnClickListener; +import android.view.ViewGroup; +import android.widget.BaseAdapter; +import android.widget.Button; +import android.widget.CheckedTextView; +import android.widget.Spinner; + +import com.jiangdg.libusbcamera.R; + +import java.util.ArrayList; +import java.util.List; + +public class CameraDialog extends DialogFragment { + private static final String TAG = CameraDialog.class.getSimpleName(); + + public interface CameraDialogParent { + public USBMonitor getUSBMonitor(); + public void onDialogResult(boolean canceled); + } + + /** + * Helper method + * @param parent FragmentActivity + * @return + */ + public static CameraDialog showDialog(final Activity parent/* add parameters here if you need */) { + CameraDialog dialog = newInstance(/* add parameters here if you need */); + try { + dialog.show(parent.getFragmentManager(), TAG); + } catch (final IllegalStateException e) { + dialog = null; + } + return dialog; + } + + public static CameraDialog newInstance(/* add parameters here if you need */) { + final CameraDialog dialog = new CameraDialog(); + final Bundle args = new Bundle(); + // add parameters here if you need + dialog.setArguments(args); + return dialog; + } + + protected USBMonitor mUSBMonitor; + private Spinner mSpinner; + private DeviceListAdapter mDeviceListAdapter; + + public CameraDialog(/* no arguments */) { + // Fragment need default constructor + } + + @SuppressWarnings("deprecation") + @Override + public void onAttach(final Activity activity) { + super.onAttach(activity); + if (mUSBMonitor == null) + try { + mUSBMonitor = ((CameraDialogParent)activity).getUSBMonitor(); + } catch (final ClassCastException e) { + } catch (final NullPointerException e) { + } + if (mUSBMonitor == null) { + throw new ClassCastException(activity.toString() + " must implement CameraDialogParent#getUSBController"); + } + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + if (savedInstanceState == null) + savedInstanceState = getArguments(); + } + + @Override + public void onSaveInstanceState(final Bundle saveInstanceState) { + final Bundle args = getArguments(); + if (args != null) + saveInstanceState.putAll(args); + super.onSaveInstanceState(saveInstanceState); + } + + @Override + public Dialog onCreateDialog(final Bundle savedInstanceState) { + final AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); + builder.setView(initView()); + builder.setTitle(R.string.select); + builder.setPositiveButton(android.R.string.ok, mOnDialogClickListener); + builder.setNegativeButton(android.R.string.cancel , mOnDialogClickListener); + builder.setNeutralButton(R.string.refresh, null); + final Dialog dialog = builder.create(); + dialog.setCancelable(true); + dialog.setCanceledOnTouchOutside(true); + return dialog; + } + + /** + * create view that this fragment shows + * @return + */ + private final View initView() { + final View rootView = getActivity().getLayoutInflater().inflate(R.layout.dialog_camera, null); + mSpinner = (Spinner)rootView.findViewById(R.id.spinner1); + final View empty = rootView.findViewById(android.R.id.empty); + mSpinner.setEmptyView(empty); + return rootView; + } + + + @Override + public void onResume() { + super.onResume(); + updateDevices(); + final Button button = (Button)getDialog().findViewById(android.R.id.button3); + if (button != null) { + button.setOnClickListener(mOnClickListener); + } + } + + private final OnClickListener mOnClickListener = new OnClickListener() { + @Override + public void onClick(final View v) { + switch (v.getId()) { + case android.R.id.button3: + updateDevices(); + break; + } + } + }; + + private final DialogInterface.OnClickListener mOnDialogClickListener = new DialogInterface.OnClickListener() { + @Override + public void onClick(final DialogInterface dialog, final int which) { + switch (which) { + case DialogInterface.BUTTON_POSITIVE: + final Object item = mSpinner.getSelectedItem(); + if (item instanceof UsbDevice) { + mUSBMonitor.requestPermission((UsbDevice)item); + ((CameraDialogParent)getActivity()).onDialogResult(false); + } + break; + case DialogInterface.BUTTON_NEGATIVE: + ((CameraDialogParent)getActivity()).onDialogResult(true); + break; + } + } + }; + + @Override + public void onCancel(final DialogInterface dialog) { + ((CameraDialogParent)getActivity()).onDialogResult(true); + super.onCancel(dialog); + } + + public void updateDevices() { +// mUSBMonitor.dumpDevices(); + final List filter = DeviceFilter.getDeviceFilters(getActivity(), R.xml.device_filter); + mDeviceListAdapter = new DeviceListAdapter(getActivity(), mUSBMonitor.getDeviceList(filter.get(0))); + mSpinner.setAdapter(mDeviceListAdapter); + } + + private static final class DeviceListAdapter extends BaseAdapter { + + private final LayoutInflater mInflater; + private final List mList; + + public DeviceListAdapter(final Context context, final Listlist) { + mInflater = LayoutInflater.from(context); + mList = list != null ? list : new ArrayList(); + } + + @Override + public int getCount() { + return mList.size(); + } + + @Override + public UsbDevice getItem(final int position) { + if ((position >= 0) && (position < mList.size())) + return mList.get(position); + else + return null; + } + + @Override + public long getItemId(final int position) { + return position; + } + + @Override + public View getView(final int position, View convertView, final ViewGroup parent) { + if (convertView == null) { + convertView = mInflater.inflate(R.layout.listitem_device, parent, false); + } + if (convertView instanceof CheckedTextView) { + final UsbDevice device = getItem(position); + ((CheckedTextView)convertView).setText( + String.format("UVC Camera:(%x:%x:%s)", device.getVendorId(), device.getProductId(), device.getDeviceName())); + } + return convertView; + } + } +} diff --git a/libusbcamera/src/main/java/com/serenegiant/usb/DeviceFilter.java b/libusbcamera/src/main/java/com/serenegiant/usb/DeviceFilter.java new file mode 100644 index 0000000..2e94263 --- /dev/null +++ b/libusbcamera/src/main/java/com/serenegiant/usb/DeviceFilter.java @@ -0,0 +1,527 @@ +/* + * 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.serenegiant.usb; + +import android.content.Context; +import android.content.res.Resources.NotFoundException; +import android.hardware.usb.UsbDevice; +import android.hardware.usb.UsbInterface; +import android.text.TextUtils; +import android.util.Log; + +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public final class DeviceFilter { + + private static final String TAG = "DeviceFilter"; + + // USB Vendor ID (or -1 for unspecified) + public final int mVendorId; + // USB Product ID (or -1 for unspecified) + public final int mProductId; + // USB device or interface class (or -1 for unspecified) + public final int mClass; + // USB device subclass (or -1 for unspecified) + public final int mSubclass; + // USB device protocol (or -1 for unspecified) + public final int mProtocol; + // USB device manufacturer name string (or null for unspecified) + public final String mManufacturerName; + // USB device product name string (or null for unspecified) + public final String mProductName; + // USB device serial number string (or null for unspecified) + public final String mSerialNumber; + // set true if specific device(s) should exclude + public final boolean isExclude; + + public DeviceFilter(final int vid, final int pid, final int clasz, final int subclass, + final int protocol, final String manufacturer, final String product, final String serialNum) { + this(vid, pid, clasz, subclass, protocol, manufacturer, product, serialNum, false); + } + + public DeviceFilter(final int vid, final int pid, final int clasz, final int subclass, + final int protocol, final String manufacturer, final String product, final String serialNum, final boolean isExclude) { + mVendorId = vid; + mProductId = pid; + mClass = clasz; + mSubclass = subclass; + mProtocol = protocol; + mManufacturerName = manufacturer; + mProductName = product; + mSerialNumber = serialNum; + this.isExclude = isExclude; +/* Log.i(TAG, String.format("vendorId=0x%04x,productId=0x%04x,class=0x%02x,subclass=0x%02x,protocol=0x%02x", + mVendorId, mProductId, mClass, mSubclass, mProtocol)); */ + } + + public DeviceFilter(final UsbDevice device) { + this(device, false); + } + + public DeviceFilter(final UsbDevice device, final boolean isExclude) { + mVendorId = device.getVendorId(); + mProductId = device.getProductId(); + mClass = device.getDeviceClass(); + mSubclass = device.getDeviceSubclass(); + mProtocol = device.getDeviceProtocol(); + mManufacturerName = null; // device.getManufacturerName(); + mProductName = null; // device.getProductName(); + mSerialNumber = null; // device.getSerialNumber(); + this.isExclude = isExclude; +/* Log.i(TAG, String.format("vendorId=0x%04x,productId=0x%04x,class=0x%02x,subclass=0x%02x,protocol=0x%02x", + mVendorId, mProductId, mClass, mSubclass, mProtocol)); */ + } + + /** + * 指定したxmlリソースからDeviceFilterリストを生成する + * @param context + * @param deviceFilterXmlId + * @return + */ + public static List getDeviceFilters(final Context context, final int deviceFilterXmlId) { + final XmlPullParser parser = context.getResources().getXml(deviceFilterXmlId); + final List deviceFilters = new ArrayList(); + try { + int eventType = parser.getEventType(); + while (eventType != XmlPullParser.END_DOCUMENT) { + if (eventType == XmlPullParser.START_TAG) { + final DeviceFilter deviceFilter = readEntryOne(context, parser); + if (deviceFilter != null) { + deviceFilters.add(deviceFilter); + } + } + eventType = parser.next(); + } + } catch (final XmlPullParserException e) { + Log.d(TAG, "XmlPullParserException", e); + } catch (final IOException e) { + Log.d(TAG, "IOException", e); + } + + return Collections.unmodifiableList(deviceFilters); + } + + /** + * read as integer values with default value from xml(w/o exception throws) + * resource integer id is also resolved into integer + * @param parser + * @param namespace + * @param name + * @param defaultValue + * @return + */ + private static final int getAttributeInteger(final Context context, final XmlPullParser parser, final String namespace, final String name, final int defaultValue) { + int result = defaultValue; + try { + String v = parser.getAttributeValue(namespace, name); + if (!TextUtils.isEmpty(v) && v.startsWith("@")) { + final String r = v.substring(1); + final int resId = context.getResources().getIdentifier(r, null, context.getPackageName()); + if (resId > 0) { + result = context.getResources().getInteger(resId); + } + } else { + int radix = 10; + if (v != null && v.length() > 2 && v.charAt(0) == '0' && + (v.charAt(1) == 'x' || v.charAt(1) == 'X')) { + // allow hex values starting with 0x or 0X + radix = 16; + v = v.substring(2); + } + result = Integer.parseInt(v, radix); + } + } catch (final NotFoundException e) { + result = defaultValue; + } catch (final NumberFormatException e) { + result = defaultValue; + } catch (final NullPointerException e) { + result = defaultValue; + } + return result; + } + + /** + * read as boolean values with default value from xml(w/o exception throws) + * resource boolean id is also resolved into boolean + * if the value is zero, return false, if the value is non-zero integer, return true + * @param context + * @param parser + * @param namespace + * @param name + * @param defaultValue + * @return + */ + private static final boolean getAttributeBoolean(final Context context, final XmlPullParser parser, final String namespace, final String name, final boolean defaultValue) { + boolean result = defaultValue; + try { + String v = parser.getAttributeValue(namespace, name); + if ("TRUE".equalsIgnoreCase(v)) { + result = true; + } else if ("FALSE".equalsIgnoreCase(v)) { + result = false; + } else if (!TextUtils.isEmpty(v) && v.startsWith("@")) { + final String r = v.substring(1); + final int resId = context.getResources().getIdentifier(r, null, context.getPackageName()); + if (resId > 0) { + result = context.getResources().getBoolean(resId); + } + } else { + int radix = 10; + if (v != null && v.length() > 2 && v.charAt(0) == '0' && + (v.charAt(1) == 'x' || v.charAt(1) == 'X')) { + // allow hex values starting with 0x or 0X + radix = 16; + v = v.substring(2); + } + final int val = Integer.parseInt(v, radix); + result = val != 0; + } + } catch (final NotFoundException e) { + result = defaultValue; + } catch (final NumberFormatException e) { + result = defaultValue; + } catch (final NullPointerException e) { + result = defaultValue; + } + return result; + } + + /** + * read as String attribute with default value from xml(w/o exception throws) + * resource string id is also resolved into string + * @param parser + * @param namespace + * @param name + * @param defaultValue + * @return + */ + private static final String getAttributeString(final Context context, final XmlPullParser parser, final String namespace, final String name, final String defaultValue) { + String result = defaultValue; + try { + result = parser.getAttributeValue(namespace, name); + if (result == null) + result = defaultValue; + if (!TextUtils.isEmpty(result) && result.startsWith("@")) { + final String r = result.substring(1); + final int resId = context.getResources().getIdentifier(r, null, context.getPackageName()); + if (resId > 0) + result = context.getResources().getString(resId); + } + } catch (final NotFoundException e) { + result = defaultValue; + } catch (final NumberFormatException e) { + result = defaultValue; + } catch (final NullPointerException e) { + result = defaultValue; + } + return result; + } + + public static DeviceFilter readEntryOne(final Context context, final XmlPullParser parser) + throws XmlPullParserException, IOException { + int vendorId = -1; + int productId = -1; + int deviceClass = -1; + int deviceSubclass = -1; + int deviceProtocol = -1; + boolean exclude = false; + String manufacturerName = null; + String productName = null; + String serialNumber = null; + boolean hasValue = false; + + String tag; + int eventType = parser.getEventType(); + while (eventType != XmlPullParser.END_DOCUMENT) { + tag = parser.getName(); + if (!TextUtils.isEmpty(tag) && (tag.equalsIgnoreCase("usb-device"))) { + if (eventType == XmlPullParser.START_TAG) { + hasValue = true; + vendorId = getAttributeInteger(context, parser, null, "vendor-id", -1); + if (vendorId == -1) { + vendorId = getAttributeInteger(context, parser, null, "vendorId", -1); + if (vendorId == -1) + vendorId = getAttributeInteger(context, parser, null, "venderId", -1); + } + productId = getAttributeInteger(context, parser, null, "product-id", -1); + if (productId == -1) + productId = getAttributeInteger(context, parser, null, "productId", -1); + deviceClass = getAttributeInteger(context, parser, null, "class", -1); + deviceSubclass = getAttributeInteger(context, parser, null, "subclass", -1); + deviceProtocol = getAttributeInteger(context, parser, null, "protocol", -1); + manufacturerName = getAttributeString(context, parser, null, "manufacturer-name", null); + if (TextUtils.isEmpty(manufacturerName)) + manufacturerName = getAttributeString(context, parser, null, "manufacture", null); + productName = getAttributeString(context, parser, null, "product-name", null); + if (TextUtils.isEmpty(productName)) + productName = getAttributeString(context, parser, null, "product", null); + serialNumber = getAttributeString(context, parser, null, "serial-number", null); + if (TextUtils.isEmpty(serialNumber)) + serialNumber = getAttributeString(context, parser, null, "serial", null); + exclude = getAttributeBoolean(context, parser, null, "exclude", false); + } else if (eventType == XmlPullParser.END_TAG) { + if (hasValue) { + return new DeviceFilter(vendorId, productId, deviceClass, + deviceSubclass, deviceProtocol, manufacturerName, productName, + serialNumber, exclude); + } + } + } + eventType = parser.next(); + } + return null; + } + +/* public void write(XmlSerializer serializer) throws IOException { + serializer.startTag(null, "usb-device"); + if (mVendorId != -1) { + serializer + .attribute(null, "vendor-id", Integer.toString(mVendorId)); + } + if (mProductId != -1) { + serializer.attribute(null, "product-id", + Integer.toString(mProductId)); + } + if (mClass != -1) { + serializer.attribute(null, "class", Integer.toString(mClass)); + } + if (mSubclass != -1) { + serializer.attribute(null, "subclass", Integer.toString(mSubclass)); + } + if (mProtocol != -1) { + serializer.attribute(null, "protocol", Integer.toString(mProtocol)); + } + if (mManufacturerName != null) { + serializer.attribute(null, "manufacturer-name", mManufacturerName); + } + if (mProductName != null) { + serializer.attribute(null, "product-name", mProductName); + } + if (mSerialNumber != null) { + serializer.attribute(null, "serial-number", mSerialNumber); + } + serializer.attribute(null, "serial-number", Boolean.toString(isExclude)); + serializer.endTag(null, "usb-device"); + } */ + + /** + * 指定したクラス・サブクラス・プロトコルがこのDeviceFilterとマッチするかどうかを返す + * mExcludeフラグは別途#isExcludeか自前でチェックすること + * @param clasz + * @param subclass + * @param protocol + * @return + */ + private boolean matches(final int clasz, final int subclass, final int protocol) { + return ((mClass == -1 || clasz == mClass) + && (mSubclass == -1 || subclass == mSubclass) && (mProtocol == -1 || protocol == mProtocol)); + } + + /** + * 指定したUsbDeviceがこのDeviceFilterにマッチするかどうかを返す + * mExcludeフラグは別途#isExcludeか自前でチェックすること + * @param device + * @return + */ + public boolean matches(final UsbDevice device) { + if (mVendorId != -1 && device.getVendorId() != mVendorId) { + return false; + } + if (mProductId != -1 && device.getProductId() != mProductId) { + return false; + } +/* if (mManufacturerName != null && device.getManufacturerName() == null) + return false; + if (mProductName != null && device.getProductName() == null) + return false; + if (mSerialNumber != null && device.getSerialNumber() == null) + return false; + if (mManufacturerName != null && device.getManufacturerName() != null + && !mManufacturerName.equals(device.getManufacturerName())) + return false; + if (mProductName != null && device.getProductName() != null + && !mProductName.equals(device.getProductName())) + return false; + if (mSerialNumber != null && device.getSerialNumber() != null + && !mSerialNumber.equals(device.getSerialNumber())) + return false; */ + + // check device class/subclass/protocol + if (matches(device.getDeviceClass(), device.getDeviceSubclass(), device.getDeviceProtocol())) { + return true; + } + + // if device doesn't match, check the interfaces + final int count = device.getInterfaceCount(); + for (int i = 0; i < count; i++) { + final UsbInterface intf = device.getInterface(i); + if (matches(intf.getInterfaceClass(), intf.getInterfaceSubclass(), intf.getInterfaceProtocol())) { + return true; + } + } + + return false; + } + + /** + * このDeviceFilterに一致してかつmExcludeがtrueならtrueを返す + * @param device + * @return + */ + public boolean isExclude(final UsbDevice device) { + return isExclude && matches(device); + } + + /** + * これって要らんかも, equalsでできる気が + * @param f + * @return + */ + public boolean matches(final DeviceFilter f) { + if (isExclude != f.isExclude) { + return false; + } + if (mVendorId != -1 && f.mVendorId != mVendorId) { + return false; + } + if (mProductId != -1 && f.mProductId != mProductId) { + return false; + } + if (f.mManufacturerName != null && mManufacturerName == null) { + return false; + } + if (f.mProductName != null && mProductName == null) { + return false; + } + if (f.mSerialNumber != null && mSerialNumber == null) { + return false; + } + if (mManufacturerName != null && f.mManufacturerName != null + && !mManufacturerName.equals(f.mManufacturerName)) { + return false; + } + if (mProductName != null && f.mProductName != null + && !mProductName.equals(f.mProductName)) { + return false; + } + if (mSerialNumber != null && f.mSerialNumber != null + && !mSerialNumber.equals(f.mSerialNumber)) { + return false; + } + + // check device class/subclass/protocol + return matches(f.mClass, f.mSubclass, f.mProtocol); + } + + @Override + public boolean equals(final Object obj) { + // can't compare if we have wildcard strings + if (mVendorId == -1 || mProductId == -1 || mClass == -1 + || mSubclass == -1 || mProtocol == -1) { + return false; + } + if (obj instanceof DeviceFilter) { + final DeviceFilter filter = (DeviceFilter) obj; + + if (filter.mVendorId != mVendorId + || filter.mProductId != mProductId + || filter.mClass != mClass || filter.mSubclass != mSubclass + || filter.mProtocol != mProtocol) { + return false; + } + if ((filter.mManufacturerName != null && mManufacturerName == null) + || (filter.mManufacturerName == null && mManufacturerName != null) + || (filter.mProductName != null && mProductName == null) + || (filter.mProductName == null && mProductName != null) + || (filter.mSerialNumber != null && mSerialNumber == null) + || (filter.mSerialNumber == null && mSerialNumber != null)) { + return false; + } + if ((filter.mManufacturerName != null && mManufacturerName != null && !mManufacturerName + .equals(filter.mManufacturerName)) + || (filter.mProductName != null && mProductName != null && !mProductName + .equals(filter.mProductName)) + || (filter.mSerialNumber != null && mSerialNumber != null && !mSerialNumber + .equals(filter.mSerialNumber))) { + return false; + } + return (filter.isExclude != isExclude); + } + if (obj instanceof UsbDevice) { + final UsbDevice device = (UsbDevice) obj; + if (isExclude + || (device.getVendorId() != mVendorId) + || (device.getProductId() != mProductId) + || (device.getDeviceClass() != mClass) + || (device.getDeviceSubclass() != mSubclass) + || (device.getDeviceProtocol() != mProtocol) ) { + return false; + } +/* if ((mManufacturerName != null && device.getManufacturerName() == null) + || (mManufacturerName == null && device + .getManufacturerName() != null) + || (mProductName != null && device.getProductName() == null) + || (mProductName == null && device.getProductName() != null) + || (mSerialNumber != null && device.getSerialNumber() == null) + || (mSerialNumber == null && device.getSerialNumber() != null)) { + return (false); + } */ +/* if ((device.getManufacturerName() != null && !mManufacturerName + .equals(device.getManufacturerName())) + || (device.getProductName() != null && !mProductName + .equals(device.getProductName())) + || (device.getSerialNumber() != null && !mSerialNumber + .equals(device.getSerialNumber()))) { + return (false); + } */ + return true; + } + return false; + } + + @Override + public int hashCode() { + return (((mVendorId << 16) | mProductId) ^ ((mClass << 16) + | (mSubclass << 8) | mProtocol)); + } + + @Override + public String toString() { + return "DeviceFilter[mVendorId=" + mVendorId + ",mProductId=" + + mProductId + ",mClass=" + mClass + ",mSubclass=" + mSubclass + + ",mProtocol=" + mProtocol + + ",mManufacturerName=" + mManufacturerName + + ",mProductName=" + mProductName + + ",mSerialNumber=" + mSerialNumber + + ",isExclude=" + isExclude + + "]"; + } + +} diff --git a/libusbcamera/src/main/java/com/serenegiant/usb/IButtonCallback.java b/libusbcamera/src/main/java/com/serenegiant/usb/IButtonCallback.java new file mode 100644 index 0000000..4025085 --- /dev/null +++ b/libusbcamera/src/main/java/com/serenegiant/usb/IButtonCallback.java @@ -0,0 +1,5 @@ +package com.serenegiant.usb; + +public interface IButtonCallback { + void onButton(int button, int state); +} diff --git a/libusbcamera/src/main/java/com/serenegiant/usb/IFrameCallback.java b/libusbcamera/src/main/java/com/serenegiant/usb/IFrameCallback.java new file mode 100644 index 0000000..f6aee75 --- /dev/null +++ b/libusbcamera/src/main/java/com/serenegiant/usb/IFrameCallback.java @@ -0,0 +1,46 @@ +/* + * 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.serenegiant.usb; + +import java.nio.ByteBuffer; + +/** + * Callback interface for UVCCamera class + * If you need frame data as ByteBuffer, you can use this callback interface with UVCCamera#setFrameCallback + */ +public interface IFrameCallback { + /** + * This method is called from native library via JNI on the same thread as UVCCamera#startCapture. + * You can use both UVCCamera#startCapture and #setFrameCallback + * but it is better to use either for better performance. + * You can also pass pixel format type to UVCCamera#setFrameCallback for this method. + * Some frames may drops if this method takes a time. + * When you use some color format like NV21, this library never execute color space conversion, + * just execute pixel format conversion. If you want to get same result as on screen, please try to + * consider to get images via texture(SurfaceTexture) and read pixel buffer from it using OpenGL|ES2/3 + * instead of using IFrameCallback(this way is much efficient in most case than using IFrameCallback). + * @param frame this is direct ByteBuffer from JNI layer and you should handle it's byte order and limitation. + */ + public void onFrame(ByteBuffer frame); +} diff --git a/libusbcamera/src/main/java/com/serenegiant/usb/IStatusCallback.java b/libusbcamera/src/main/java/com/serenegiant/usb/IStatusCallback.java new file mode 100644 index 0000000..ad74320 --- /dev/null +++ b/libusbcamera/src/main/java/com/serenegiant/usb/IStatusCallback.java @@ -0,0 +1,7 @@ +package com.serenegiant.usb; + +import java.nio.ByteBuffer; + +public interface IStatusCallback { + void onStatus(int statusClass, int event, int selector, int statusAttribute, ByteBuffer data); +} diff --git a/libusbcamera/src/main/java/com/serenegiant/usb/Size.java b/libusbcamera/src/main/java/com/serenegiant/usb/Size.java new file mode 100644 index 0000000..963a805 --- /dev/null +++ b/libusbcamera/src/main/java/com/serenegiant/usb/Size.java @@ -0,0 +1,302 @@ +/* + * 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.serenegiant.usb; + +import android.os.Parcel; +import android.os.Parcelable; + +import java.util.Locale; + +public class Size implements Parcelable { + // + /** + * native側のuvc_raw_format_tの値, こっちは主にlibuvc用 + * 9999 is still image + */ + public int type; + /** + * native側のraw_frame_tの値, androusb用, + * libuvcは対応していない + */ + public int frame_type; + public int index; + public int width; + public int height; + public int frameIntervalType; + public int frameIntervalIndex; + public int[] intervals; + // ここ以下はframeIntervalTypeとintervalsから#updateFrameRateで計算する + public float[] fps; + private String frameRates; + + /** + * コンストラクタ + * @param _type native側のraw_format_tの値, ただし9999は静止画 + * @param _frame_type native側のraw_frame_tの値 + * @param _index + * @param _width + * @param _height + */ + public Size(final int _type, final int _frame_type, final int _index, final int _width, final int _height) { + type = _type; + frame_type = _frame_type; + index = _index; + width = _width; + height = _height; + frameIntervalType = -1; + frameIntervalIndex = 0; + intervals = null; + updateFrameRate(); + } + + /** + * コンストラクタ + * @param _type native側のraw_format_tの値, ただし9999は静止画 + * @param _frame_type native側のraw_frame_tの値 + * @param _index + * @param _width + * @param _height + * @param _min_intervals + * @param _max_intervals + */ + public Size(final int _type, final int _frame_type, final int _index, final int _width, final int _height, final int _min_intervals, final int _max_intervals, final int _step) { + type = _type; + frame_type = _frame_type; + index = _index; + width = _width; + height = _height; + frameIntervalType = 0; + frameIntervalIndex = 0; + intervals = new int[3]; + intervals[0] = _min_intervals; + intervals[1] = _max_intervals; + intervals[2] = _step; + updateFrameRate(); + } + + /** + * コンストラクタ + * @param _type native側のraw_format_tの値, ただし9999は静止画 + * @param _frame_type native側のraw_frame_tの値 + * @param _index + * @param _width + * @param _height + * @param _intervals + */ + public Size(final int _type, final int _frame_type, final int _index, final int _width, final int _height, final int[] _intervals) { + type = _type; + frame_type = _frame_type; + index = _index; + width = _width; + height = _height; + final int n = _intervals != null ? _intervals.length : -1; + if (n > 0) { + frameIntervalType = n; + intervals = new int[n]; + System.arraycopy(_intervals, 0, intervals, 0, n); + } else { + frameIntervalType = -1; + intervals = null; + } + frameIntervalIndex = 0; + updateFrameRate(); + } + + /** + * コピーコンストラクタ + * @param other + */ + public Size(final Size other) { + type = other.type; + frame_type = other.frame_type; + index = other.index; + width = other.width; + height = other.height; + frameIntervalType = other.frameIntervalType; + frameIntervalIndex = other.frameIntervalIndex; + final int n = other.intervals != null ? other.intervals.length : -1; + if (n > 0) { + intervals = new int[n]; + System.arraycopy(other.intervals, 0, intervals, 0, n); + } else { + intervals = null; + } + updateFrameRate(); + } + + private Size(final Parcel source) { + // 読み取り順はwriteToParcelでの書き込み順と同じでないとダメ + type = source.readInt(); + frame_type = source.readInt(); + index = source.readInt(); + width = source.readInt(); + height = source.readInt(); + frameIntervalType = source.readInt(); + frameIntervalIndex = source.readInt(); + if (frameIntervalType >= 0) { + if (frameIntervalType > 0) { + intervals = new int[frameIntervalType]; + } else { + intervals = new int[3]; + } + source.readIntArray(intervals); + } else { + intervals = null; + } + updateFrameRate(); + } + + public Size set(final Size other) { + if (other != null) { + type = other.type; + frame_type = other.frame_type; + index = other.index; + width = other.width; + height = other.height; + frameIntervalType = other.frameIntervalType; + frameIntervalIndex = other.frameIntervalIndex; + final int n = other.intervals != null ? other.intervals.length : -1; + if (n > 0) { + intervals = new int[n]; + System.arraycopy(other.intervals, 0, intervals, 0, n); + } else { + intervals = null; + } + updateFrameRate(); + } + return this; + } + + public float getCurrentFrameRate() throws IllegalStateException { + final int n = fps != null ? fps.length : 0; + if ((frameIntervalIndex >= 0) && (frameIntervalIndex < n)) { + return fps[frameIntervalIndex]; + } + throw new IllegalStateException("unknown frame rate or not ready"); + } + + public void setCurrentFrameRate(final float frameRate) { + // 一番近いのを選ぶ + int index = -1; + final int n = fps != null ? fps.length : 0; + for (int i = 0; i < n; i++) { + if (fps[i] <= frameRate) { + index = i; + break; + } + } + frameIntervalIndex = index; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(final Parcel dest, final int flags) { + dest.writeInt(type); + dest.writeInt(frame_type); + dest.writeInt(index); + dest.writeInt(width); + dest.writeInt(height); + dest.writeInt(frameIntervalType); + dest.writeInt(frameIntervalIndex); + if (intervals != null) { + dest.writeIntArray(intervals); + } + } + + public void updateFrameRate() { + final int n = frameIntervalType; + if (n > 0) { + fps = new float[n]; + for (int i = 0; i < n; i++) { + final float _fps = fps[i] = 10000000.0f / intervals[i]; + } + } else if (n == 0) { + try { + final int min = Math.min(intervals[0], intervals[1]); + final int max = Math.max(intervals[0], intervals[1]); + final int step = intervals[2]; + if (step > 0) { + int m = 0; + for (int i = min; i <= max; i+= step) { m++; } + fps = new float[m]; + m = 0; + for (int i = min; i <= max; i+= step) { + final float _fps = fps[m++] = 10000000.0f / i; + } + } else { + final float max_fps = 10000000.0f / min; + int m = 0; + for (float fps = 10000000.0f / min; fps <= max_fps; fps += 1.0f) { m++; } + fps = new float[m]; + m = 0; + for (float fps = 10000000.0f / min; fps <= max_fps; fps += 1.0f) { + this.fps[m++] = fps; + } + } + } catch (final Exception e) { + // ignore, なんでかminとmaxが0になってるんちゃうかな + fps = null; + } + } + final int m = fps != null ? fps.length : 0; + final StringBuilder sb = new StringBuilder(); + sb.append("["); + for (int i = 0; i < m; i++) { + sb.append(String.format(Locale.US, "%4.1f", fps[i])); + if (i < m-1) { + sb.append(","); + } + } + sb.append("]"); + frameRates = sb.toString(); + if (frameIntervalIndex > m) { + frameIntervalIndex = 0; + } + } + + @Override + public String toString() { + float frame_rate = 0.0f; + try { + frame_rate = getCurrentFrameRate(); + } catch (final Exception e) { + } + return String.format(Locale.US, "Size(%dx%d@%4.1f,type:%d,frame:%d,index:%d,%s)", width, height, frame_rate, type, frame_type, index, frameRates); + } + + public static final Creator CREATOR = new Creator() { + @Override + public Size createFromParcel(final Parcel source) { + return new Size(source); + } + @Override + public Size[] newArray(final int size) { + return new Size[size]; + } + }; +} diff --git a/libusbcamera/src/main/java/com/serenegiant/usb/USBMonitor.java b/libusbcamera/src/main/java/com/serenegiant/usb/USBMonitor.java new file mode 100644 index 0000000..fe46a6c --- /dev/null +++ b/libusbcamera/src/main/java/com/serenegiant/usb/USBMonitor.java @@ -0,0 +1,1346 @@ +/* + * 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.serenegiant.usb; + +import android.annotation.SuppressLint; +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.text.TextUtils; +import android.util.Log; +import android.util.SparseArray; + +import com.serenegiant.utils.BuildCheck; +import com.serenegiant.utils.HandlerThreadHandler; + +import java.io.UnsupportedEncodingException; +import java.lang.ref.WeakReference; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Locale; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; + +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"; + + /** + * openしているUsbControlBlock + */ + private final ConcurrentHashMap mCtrlBlocks = new ConcurrentHashMap(); + private final SparseArray> mHasPermissions = new SparseArray>(); + + private final WeakReference mWeakContext; + private final UsbManager mUsbManager; + private final OnDeviceConnectListener mOnDeviceConnectListener; + private PendingIntent mPermissionIntent = null; + private List mDeviceFilters = new ArrayList(); + + /** + * コールバックをワーカースレッドで呼び出すためのハンドラー + */ + private final Handler mAsyncHandler; + private volatile boolean destroyed; + /** + * USB機器の状態変更時のコールバックリスナー + */ + 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 ctrlBlock + * @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 + * @param device + */ + public void onCancel(UsbDevice device); + } + + 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); + mUsbManager = (UsbManager)context.getSystemService(Context.USB_SERVICE); + mOnDeviceConnectListener = listener; + mAsyncHandler = HandlerThreadHandler.createHandler(TAG); + destroyed = false; + if (DEBUG) Log.v(TAG, "USBMonitor:mUsbManager=" + mUsbManager); + } + + /** + * Release all related resources, + * never reuse again + */ + public void destroy() { + if (DEBUG) Log.i(TAG, "destroy:"); + unregister(); + if (!destroyed) { + destroyed = true; + // モニターしているUSB機器を全てcloseする + final Set keys = mCtrlBlocks.keySet(); + if (keys != null) { + UsbControlBlock ctrlBlock; + try { + for (final UsbDevice key: keys) { + ctrlBlock = mCtrlBlocks.remove(key); + if (ctrlBlock != null) { + ctrlBlock.close(); + } + } + } catch (final Exception e) { + Log.e(TAG, "destroy:", e); + } + } + mCtrlBlocks.clear(); + try { + mAsyncHandler.getLooper().quit(); + } catch (final Exception e) { + Log.e(TAG, "destroy:", e); + } + } + } + + /** + * register BroadcastReceiver to monitor USB events + * @throws IllegalStateException + */ + public synchronized void register() throws IllegalStateException { + if (destroyed) throw new IllegalStateException("already destroyed"); + 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); + // ACTION_USB_DEVICE_ATTACHED never comes on some devices so it should not be added here + filter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED); + context.registerReceiver(mUsbReceiver, filter); + } + // start connection check + mDeviceCounts = 0; + mAsyncHandler.postDelayed(mDeviceCheckRunnable, 1000); + } + } + + /** + * unregister BroadcastReceiver + * @throws IllegalStateException + */ + public synchronized void unregister() throws IllegalStateException { + // 接続チェック用Runnableを削除 + mDeviceCounts = 0; + if (!destroyed) { + mAsyncHandler.removeCallbacks(mDeviceCheckRunnable); + } + if (mPermissionIntent != null) { +// if (DEBUG) Log.i(TAG, "unregister:"); + final Context context = mWeakContext.get(); + try { + if (context != null) { + context.unregisterReceiver(mUsbReceiver); + } + } catch (final Exception e) { + Log.w(TAG, e); + } + mPermissionIntent = null; + } + } + + public synchronized boolean isRegistered() { + return !destroyed && (mPermissionIntent != null); + } + + /** + * set device filter + * @param filter + * @throws IllegalStateException + */ + public void setDeviceFilter(final DeviceFilter filter) throws IllegalStateException { + if (destroyed) throw new IllegalStateException("already destroyed"); + mDeviceFilters.clear(); + mDeviceFilters.add(filter); + } + + /** + * デバイスフィルターを追加 + * @param filter + * @throws IllegalStateException + */ + public void addDeviceFilter(final DeviceFilter filter) throws IllegalStateException { + if (destroyed) throw new IllegalStateException("already destroyed"); + mDeviceFilters.add(filter); + } + + /** + * デバイスフィルターを削除 + * @param filter + * @throws IllegalStateException + */ + public void removeDeviceFilter(final DeviceFilter filter) throws IllegalStateException { + if (destroyed) throw new IllegalStateException("already destroyed"); + mDeviceFilters.remove(filter); + } + + /** + * set device filters + * @param filters + * @throws IllegalStateException + */ + public void setDeviceFilter(final List filters) throws IllegalStateException { + if (destroyed) throw new IllegalStateException("already destroyed"); + mDeviceFilters.clear(); + mDeviceFilters.addAll(filters); + } + + /** + * add device filters + * @param filters + * @throws IllegalStateException + */ + public void addDeviceFilter(final List filters) throws IllegalStateException { + if (destroyed) throw new IllegalStateException("already destroyed"); + mDeviceFilters.addAll(filters); + } + + /** + * remove device filters + * @param filters + */ + public void removeDeviceFilter(final List filters) throws IllegalStateException { + if (destroyed) throw new IllegalStateException("already destroyed"); + mDeviceFilters.removeAll(filters); + } + + /** + * return the number of connected USB devices that matched device filter + * @return + * @throws IllegalStateException + */ + public int getDeviceCount() throws IllegalStateException { + if (destroyed) throw new IllegalStateException("already destroyed"); + return getDeviceList().size(); + } + + /** + * return device list, return empty list if no device matched + * @return + * @throws IllegalStateException + */ + public List getDeviceList() throws IllegalStateException { + if (destroyed) throw new IllegalStateException("already destroyed"); + return getDeviceList(mDeviceFilters); + } + + /** + * return device list, return empty list if no device matched + * @param filters + * @return + * @throws IllegalStateException + */ + public List getDeviceList(final List filters) throws IllegalStateException { + if (destroyed) throw new IllegalStateException("already destroyed"); + final HashMap deviceList = mUsbManager.getDeviceList(); + 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); + } + break; + } + } + } + } + } + return result; + } + + /** + * return device list, return empty list if no device matched + * @param filter + * @return + * @throws IllegalStateException + */ + public List getDeviceList(final DeviceFilter filter) throws IllegalStateException { + if (destroyed) throw new IllegalStateException("already destroyed"); + final HashMap deviceList = mUsbManager.getDeviceList(); + final List result = new ArrayList(); + if (deviceList != null) { + for (final UsbDevice device: deviceList.values() ) { + if ((filter == null) || (filter.matches(device) && !filter.isExclude)) { + result.add(device); + } + } + } + return result; + } + + /** + * get USB device list, without filter + * @return + * @throws IllegalStateException + */ + public Iterator getDevices() throws IllegalStateException { + if (destroyed) throw new IllegalStateException("already destroyed"); + Iterator iterator = null; + final HashMap list = mUsbManager.getDeviceList(); + if (list != null) + iterator = list.values().iterator(); + return iterator; + } + + /** + * output device list to LogCat + */ + public final void dumpDevices() { + final HashMap list = mUsbManager.getDeviceList(); + if (list != null) { + final Set 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(Locale.US, "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 true: 指定したUsbDeviceにパーミッションがある + * @throws IllegalStateException + */ + public final boolean hasPermission(final UsbDevice device) throws IllegalStateException { + if (destroyed) throw new IllegalStateException("already destroyed"); + return updatePermission(device, device != null && mUsbManager.hasPermission(device)); + } + + /** + * 内部で保持しているパーミッション状態を更新 + * @param device + * @param hasPermission + * @return hasPermission + */ + private boolean updatePermission(final UsbDevice device, final boolean hasPermission) { + final int deviceKey = getDeviceKey(device, true); + synchronized (mHasPermissions) { + if (hasPermission) { + if (mHasPermissions.get(deviceKey) == null) { + mHasPermissions.put(deviceKey, new WeakReference(device)); + } + } else { + mHasPermissions.remove(deviceKey); + } + } + return hasPermission; + } + + /** + * request permission to access to USB device + * @param device + * @return true if fail to request permission + */ + public synchronized boolean requestPermission(final UsbDevice device) { +// if (DEBUG) Log.v(TAG, "requestPermission:device=" + device); + boolean result = false; + if (isRegistered()) { + if (device != null) { + if (mUsbManager.hasPermission(device)) { + // call onConnect if app already has permission + processConnect(device); + } else { + try { + // パーミッションがなければ要求する + mUsbManager.requestPermission(device, mPermissionIntent); + } catch (final Exception e) { + // Android5.1.xのGALAXY系でandroid.permission.sec.MDM_APP_MGMTという意味不明の例外生成するみたい + Log.w(TAG, e); + processCancel(device); + result = true; + } + } + } else { + processCancel(device); + result = true; + } + } else { + processCancel(device); + result = true; + } + return result; + } + + /** + * 指定したUsbDeviceをopenする + * @param device + * @return + * @throws SecurityException パーミッションがなければSecurityExceptionを投げる + */ + public UsbControlBlock openDevice(final UsbDevice device) throws SecurityException { + if (hasPermission(device)) { + UsbControlBlock result = mCtrlBlocks.get(device); + if (result == null) { + result = new UsbControlBlock(USBMonitor.this, device); // この中でopenDeviceする + mCtrlBlocks.put(device, result); + } + return result; + } else { + throw new SecurityException("has no permission"); + } + } + + /** + * BroadcastReceiver for USB permission + */ + private final BroadcastReceiver mUsbReceiver = new BroadcastReceiver() { + + @Override + public void onReceive(final Context context, final Intent intent) { + if (destroyed) return; + final String action = intent.getAction(); + if (ACTION_USB_PERMISSION.equals(action)) { + // when received the result of requesting USB permission + synchronized (USBMonitor.this) { + final UsbDevice device = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE); + if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) { + if (device != null) { + // get permission, call onConnect + processConnect(device); + } + } else { + // failed to get permission + processCancel(device); + } + } + } else if (UsbManager.ACTION_USB_DEVICE_ATTACHED.equals(action)) { + final UsbDevice device = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE); + updatePermission(device, hasPermission(device)); + processAttach(device); + } else if (UsbManager.ACTION_USB_DEVICE_DETACHED.equals(action)) { + // when device removed + final UsbDevice device = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE); + if (device != null) { + UsbControlBlock ctrlBlock = mCtrlBlocks.remove(device); + if (ctrlBlock != null) { + // cleanup + ctrlBlock.close(); + } + mDeviceCounts = 0; + processDettach(device); + } + } + } + }; + + /** number of connected & detected devices */ + private volatile int mDeviceCounts = 0; + /** + * periodically check connected devices and if it changed, call onAttach + */ + private final Runnable mDeviceCheckRunnable = new Runnable() { + @Override + public void run() { + if (destroyed) return; + final List devices = getDeviceList(); + final int n = devices.size(); + final int hasPermissionCounts; + final int m; + synchronized (mHasPermissions) { + hasPermissionCounts = mHasPermissions.size(); + mHasPermissions.clear(); + for (final UsbDevice device: devices) { + hasPermission(device); + } + m = mHasPermissions.size(); + } + if ((n > mDeviceCounts) || (m > hasPermissionCounts)) { + mDeviceCounts = n; + if (mOnDeviceConnectListener != null) { + for (int i = 0; i < n; i++) { + final UsbDevice device = devices.get(i); + mAsyncHandler.post(new Runnable() { + @Override + public void run() { + mOnDeviceConnectListener.onAttach(device); + } + }); + } + } + } + mAsyncHandler.postDelayed(this, 2000); // confirm every 2 seconds + } + }; + + /** + * open specific USB device + * @param device + */ + private final void processConnect(final UsbDevice device) { + if (destroyed) return; + updatePermission(device, true); + mAsyncHandler.post(new Runnable() { + @Override + public void run() { + if (DEBUG) Log.v(TAG, "processConnect:device=" + device); + 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) { + mOnDeviceConnectListener.onConnect(device, ctrlBlock, createNew); + } + } + }); + } + + private final void processCancel(final UsbDevice device) { + if (destroyed) return; + if (DEBUG) Log.v(TAG, "processCancel:"); + updatePermission(device, false); + if (mOnDeviceConnectListener != null) { + mAsyncHandler.post(new Runnable() { + @Override + public void run() { + mOnDeviceConnectListener.onCancel(device); + } + }); + } + } + + private final void processAttach(final UsbDevice device) { + if (destroyed) return; + if (DEBUG) Log.v(TAG, "processAttach:"); + if (mOnDeviceConnectListener != null) { + mAsyncHandler.post(new Runnable() { + @Override + public void run() { + mOnDeviceConnectListener.onAttach(device); + } + }); + } + } + + private final void processDettach(final UsbDevice device) { + if (destroyed) return; + if (DEBUG) Log.v(TAG, "processDettach:"); + if (mOnDeviceConnectListener != null) { + mAsyncHandler.post(new Runnable() { + @Override + public void run() { + mOnDeviceConnectListener.onDettach(device); + } + }); + } + } + + /** + * USB機器毎の設定保存用にデバイスキー名を生成する。 + * ベンダーID, プロダクトID, デバイスクラス, デバイスサブクラス, デバイスプロトコルから生成 + * 同種の製品だと同じキー名になるので注意 + * @param device nullなら空文字列を返す + * @return + */ + public static final String getDeviceKeyName(final UsbDevice device) { + return getDeviceKeyName(device, null, false); + } + + /** + * USB機器毎の設定保存用にデバイスキー名を生成する。 + * useNewAPI=falseで同種の製品だと同じデバイスキーになるので注意 + * @param device + * @param useNewAPI + * @return + */ + public static final String getDeviceKeyName(final UsbDevice device, final boolean useNewAPI) { + return getDeviceKeyName(device, null, useNewAPI); + } + /** + * USB機器毎の設定保存用にデバイスキー名を生成する。この機器名をHashMapのキーにする + * UsbDeviceがopenしている時のみ有効 + * ベンダーID, プロダクトID, デバイスクラス, デバイスサブクラス, デバイスプロトコルから生成 + * serialがnullや空文字でなければserialを含めたデバイスキー名を生成する + * useNewAPI=trueでAPIレベルを満たしていればマニュファクチャ名, バージョン, コンフィギュレーションカウントも使う + * @param device nullなら空文字列を返す + * @param serial UsbDeviceConnection#getSerialで取得したシリアル番号を渡す, nullでuseNewAPI=trueでAPI>=21なら内部で取得 + * @param useNewAPI API>=21またはAPI>=23のみで使用可能なメソッドも使用する(ただし機器によってはnullが返ってくるので有効かどうかは機器による) + * @return + */ + @SuppressLint("NewApi") + public static final String getDeviceKeyName(final UsbDevice device, final String serial, final boolean useNewAPI) { + if (device == null) return ""; + final StringBuilder sb = new StringBuilder(); + sb.append(device.getVendorId()); sb.append("#"); // API >= 12 + sb.append(device.getProductId()); sb.append("#"); // API >= 12 + sb.append(device.getDeviceClass()); sb.append("#"); // API >= 12 + sb.append(device.getDeviceSubclass()); sb.append("#"); // API >= 12 + sb.append(device.getDeviceProtocol()); // API >= 12 + if (!TextUtils.isEmpty(serial)) { + sb.append("#"); sb.append(serial); + } + if (useNewAPI && BuildCheck.isAndroid5()) { + sb.append("#"); + if (TextUtils.isEmpty(serial)) { + sb.append(device.getSerialNumber()); sb.append("#"); // API >= 21 + } + sb.append(device.getManufacturerName()); sb.append("#"); // API >= 21 + sb.append(device.getConfigurationCount()); sb.append("#"); // API >= 21 + if (BuildCheck.isMarshmallow()) { + sb.append(device.getVersion()); sb.append("#"); // API >= 23 + } + } +// if (DEBUG) Log.v(TAG, "getDeviceKeyName:" + sb.toString()); + return sb.toString(); + } + + /** + * デバイスキーを整数として取得 + * getDeviceKeyNameで得られる文字列のhasCodeを取得 + * ベンダーID, プロダクトID, デバイスクラス, デバイスサブクラス, デバイスプロトコルから生成 + * 同種の製品だと同じデバイスキーになるので注意 + * @param device nullなら0を返す + * @return + */ + public static final int getDeviceKey(final UsbDevice device) { + return device != null ? getDeviceKeyName(device, null, false).hashCode() : 0; + } + + /** + * デバイスキーを整数として取得 + * getDeviceKeyNameで得られる文字列のhasCodeを取得 + * useNewAPI=falseで同種の製品だと同じデバイスキーになるので注意 + * @param device + * @param useNewAPI + * @return + */ + public static final int getDeviceKey(final UsbDevice device, final boolean useNewAPI) { + return device != null ? getDeviceKeyName(device, null, useNewAPI).hashCode() : 0; + } + + /** + * デバイスキーを整数として取得 + * getDeviceKeyNameで得られる文字列のhasCodeを取得 + * serialがnullでuseNewAPI=falseで同種の製品だと同じデバイスキーになるので注意 + * @param device nullなら0を返す + * @param serial UsbDeviceConnection#getSerialで取得したシリアル番号を渡す, nullでuseNewAPI=trueでAPI>=21なら内部で取得 + * @param useNewAPI API>=21またはAPI>=23のみで使用可能なメソッドも使用する(ただし機器によってはnullが返ってくるので有効かどうかは機器による) + * @return + */ + public static final int getDeviceKey(final UsbDevice device, final String serial, final boolean useNewAPI) { + return device != null ? getDeviceKeyName(device, serial, useNewAPI).hashCode() : 0; + } + + public static class UsbDeviceInfo { + public String usb_version; + public String manufacturer; + public String product; + public String version; + public String serial; + + private void clear() { + usb_version = manufacturer = product = version = serial = null; + } + + @Override + public String toString() { + return String.format("UsbDevice:usb_version=%s,manufacturer=%s,product=%s,version=%s,serial=%s", + usb_version != null ? usb_version : "", + manufacturer != null ? manufacturer : "", + product != null ? product : "", + version != null ? version : "", + serial != null ? serial : ""); + } + } + + private static final int USB_DIR_OUT = 0; + private static final int USB_DIR_IN = 0x80; + private static final int USB_TYPE_MASK = (0x03 << 5); + private static final int USB_TYPE_STANDARD = (0x00 << 5); + private static final int USB_TYPE_CLASS = (0x01 << 5); + private static final int USB_TYPE_VENDOR = (0x02 << 5); + private static final int USB_TYPE_RESERVED = (0x03 << 5); + private static final int USB_RECIP_MASK = 0x1f; + private static final int USB_RECIP_DEVICE = 0x00; + private static final int USB_RECIP_INTERFACE = 0x01; + private static final int USB_RECIP_ENDPOINT = 0x02; + private static final int USB_RECIP_OTHER = 0x03; + private static final int USB_RECIP_PORT = 0x04; + private static final int USB_RECIP_RPIPE = 0x05; + private static final int USB_REQ_GET_STATUS = 0x00; + private static final int USB_REQ_CLEAR_FEATURE = 0x01; + private static final int USB_REQ_SET_FEATURE = 0x03; + private static final int USB_REQ_SET_ADDRESS = 0x05; + private static final int USB_REQ_GET_DESCRIPTOR = 0x06; + private static final int USB_REQ_SET_DESCRIPTOR = 0x07; + private static final int USB_REQ_GET_CONFIGURATION = 0x08; + private static final int USB_REQ_SET_CONFIGURATION = 0x09; + private static final int USB_REQ_GET_INTERFACE = 0x0A; + private static final int USB_REQ_SET_INTERFACE = 0x0B; + private static final int USB_REQ_SYNCH_FRAME = 0x0C; + private static final int USB_REQ_SET_SEL = 0x30; + private static final int USB_REQ_SET_ISOCH_DELAY = 0x31; + private static final int USB_REQ_SET_ENCRYPTION = 0x0D; + private static final int USB_REQ_GET_ENCRYPTION = 0x0E; + private static final int USB_REQ_RPIPE_ABORT = 0x0E; + private static final int USB_REQ_SET_HANDSHAKE = 0x0F; + private static final int USB_REQ_RPIPE_RESET = 0x0F; + private static final int USB_REQ_GET_HANDSHAKE = 0x10; + private static final int USB_REQ_SET_CONNECTION = 0x11; + private static final int USB_REQ_SET_SECURITY_DATA = 0x12; + private static final int USB_REQ_GET_SECURITY_DATA = 0x13; + private static final int USB_REQ_SET_WUSB_DATA = 0x14; + private static final int USB_REQ_LOOPBACK_DATA_WRITE = 0x15; + private static final int USB_REQ_LOOPBACK_DATA_READ = 0x16; + private static final int USB_REQ_SET_INTERFACE_DS = 0x17; + + private static final int USB_REQ_STANDARD_DEVICE_SET = (USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE); // 0x10 + private static final int USB_REQ_STANDARD_DEVICE_GET = (USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE); // 0x90 + private static final int USB_REQ_STANDARD_INTERFACE_SET = (USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_INTERFACE); // 0x11 + private static final int USB_REQ_STANDARD_INTERFACE_GET = (USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_INTERFACE); // 0x91 + private static final int USB_REQ_STANDARD_ENDPOINT_SET = (USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_ENDPOINT); // 0x12 + private static final int USB_REQ_STANDARD_ENDPOINT_GET = (USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_ENDPOINT); // 0x92 + + private static final int USB_REQ_CS_DEVICE_SET = (USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_DEVICE); // 0x20 + private static final int USB_REQ_CS_DEVICE_GET = (USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_DEVICE); // 0xa0 + private static final int USB_REQ_CS_INTERFACE_SET = (USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE); // 0x21 + private static final int USB_REQ_CS_INTERFACE_GET = (USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE); // 0xa1 + private static final int USB_REQ_CS_ENDPOINT_SET = (USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_ENDPOINT); // 0x22 + private static final int USB_REQ_CS_ENDPOINT_GET = (USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_ENDPOINT); // 0xa2 + + private static final int USB_REQ_VENDER_DEVICE_SET = (USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_DEVICE); // 0x40 + private static final int USB_REQ_VENDER_DEVICE_GET = (USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_DEVICE); // 0xc0 + private static final int USB_REQ_VENDER_INTERFACE_SET = (USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE); // 0x41 + private static final int USB_REQ_VENDER_INTERFACE_GET = (USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE); // 0xc1 + private static final int USB_REQ_VENDER_ENDPOINT_SET = (USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_ENDPOINT); // 0x42 + private static final int USB_REQ_VENDER_ENDPOINT_GET = (USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_ENDPOINT); // 0xc2 + + private static final int USB_DT_DEVICE = 0x01; + private static final int USB_DT_CONFIG = 0x02; + private static final int USB_DT_STRING = 0x03; + private static final int USB_DT_INTERFACE = 0x04; + private static final int USB_DT_ENDPOINT = 0x05; + private static final int USB_DT_DEVICE_QUALIFIER = 0x06; + private static final int USB_DT_OTHER_SPEED_CONFIG = 0x07; + private static final int USB_DT_INTERFACE_POWER = 0x08; + private static final int USB_DT_OTG = 0x09; + private static final int USB_DT_DEBUG = 0x0a; + private static final int USB_DT_INTERFACE_ASSOCIATION = 0x0b; + private static final int USB_DT_SECURITY = 0x0c; + private static final int USB_DT_KEY = 0x0d; + private static final int USB_DT_ENCRYPTION_TYPE = 0x0e; + private static final int USB_DT_BOS = 0x0f; + private static final int USB_DT_DEVICE_CAPABILITY = 0x10; + private static final int USB_DT_WIRELESS_ENDPOINT_COMP = 0x11; + private static final int USB_DT_WIRE_ADAPTER = 0x21; + private static final int USB_DT_RPIPE = 0x22; + private static final int USB_DT_CS_RADIO_CONTROL = 0x23; + private static final int USB_DT_PIPE_USAGE = 0x24; + private static final int USB_DT_SS_ENDPOINT_COMP = 0x30; + private static final int USB_DT_CS_DEVICE = (USB_TYPE_CLASS | USB_DT_DEVICE); + private static final int USB_DT_CS_CONFIG = (USB_TYPE_CLASS | USB_DT_CONFIG); + private static final int USB_DT_CS_STRING = (USB_TYPE_CLASS | USB_DT_STRING); + private static final int USB_DT_CS_INTERFACE = (USB_TYPE_CLASS | USB_DT_INTERFACE); + private static final int USB_DT_CS_ENDPOINT = (USB_TYPE_CLASS | USB_DT_ENDPOINT); + private static final int USB_DT_DEVICE_SIZE = 18; + + /** + * 指定したIDのStringディスクリプタから文字列を取得する。取得できなければnull + * @param connection + * @param id + * @param languageCount + * @param languages + * @return + */ + private static String getString(final UsbDeviceConnection connection, final int id, final int languageCount, final byte[] languages) { + final byte[] work = new byte[256]; + String result = null; + for (int i = 1; i <= languageCount; i++) { + int ret = connection.controlTransfer( + USB_REQ_STANDARD_DEVICE_GET, // USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE + USB_REQ_GET_DESCRIPTOR, + (USB_DT_STRING << 8) | id, languages[i], work, 256, 0); + if ((ret > 2) && (work[0] == ret) && (work[1] == USB_DT_STRING)) { + // skip first two bytes(bLength & bDescriptorType), and copy the rest to the string + try { + result = new String(work, 2, ret - 2, "UTF-16LE"); + if (!"Љ".equals(result)) { // 変なゴミが返ってくる時がある + break; + } else { + result = null; + } + } catch (final UnsupportedEncodingException e) { + // ignore + } + } + } + return result; + } + + /** + * ベンダー名・製品名・バージョン・シリアルを取得する + * @param device + * @return + */ + public UsbDeviceInfo getDeviceInfo(final UsbDevice device) { + return updateDeviceInfo(mUsbManager, device, null); + } + + /** + * ベンダー名・製品名・バージョン・シリアルを取得する + * #updateDeviceInfo(final UsbManager, final UsbDevice, final UsbDeviceInfo)のヘルパーメソッド + * @param context + * @param device + * @return + */ + public static UsbDeviceInfo getDeviceInfo(final Context context, final UsbDevice device) { + return updateDeviceInfo((UsbManager)context.getSystemService(Context.USB_SERVICE), device, new UsbDeviceInfo()); + } + + /** + * ベンダー名・製品名・バージョン・シリアルを取得する + * @param manager + * @param device + * @param _info + * @return + */ + public static UsbDeviceInfo updateDeviceInfo(final UsbManager manager, final UsbDevice device, final UsbDeviceInfo _info) { + final UsbDeviceInfo info = _info != null ? _info : new UsbDeviceInfo(); + info.clear(); + + if (device != null) { + if (BuildCheck.isLollipop()) { + info.manufacturer = device.getManufacturerName(); + info.product = device.getProductName(); + info.serial = device.getSerialNumber(); + } + if (BuildCheck.isMarshmallow()) { + info.usb_version = device.getVersion(); + } + if ((manager != null) && manager.hasPermission(device)) { + final UsbDeviceConnection connection = manager.openDevice(device); + final byte[] desc = connection.getRawDescriptors(); + + if (TextUtils.isEmpty(info.usb_version)) { + info.usb_version = String.format("%x.%02x", ((int)desc[3] & 0xff), ((int)desc[2] & 0xff)); + } + if (TextUtils.isEmpty(info.version)) { + info.version = String.format("%x.%02x", ((int)desc[13] & 0xff), ((int)desc[12] & 0xff)); + } + if (TextUtils.isEmpty(info.serial)) { + info.serial = connection.getSerial(); + } + + final byte[] languages = new byte[256]; + int languageCount = 0; + // controlTransfer(int requestType, int request, int value, int index, byte[] buffer, int length, int timeout) + try { + int result = connection.controlTransfer( + USB_REQ_STANDARD_DEVICE_GET, // USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE + USB_REQ_GET_DESCRIPTOR, + (USB_DT_STRING << 8) | 0, 0, languages, 256, 0); + if (result > 0) { + languageCount = (result - 2) / 2; + } + if (languageCount > 0) { + if (TextUtils.isEmpty(info.manufacturer)) { + info.manufacturer = getString(connection, desc[14], languageCount, languages); + } + if (TextUtils.isEmpty(info.product)) { + info.product = getString(connection, desc[15], languageCount, languages); + } + if (TextUtils.isEmpty(info.serial)) { + info.serial = getString(connection, desc[16], languageCount, languages); + } + } + } finally { + connection.close(); + } + } + if (TextUtils.isEmpty(info.manufacturer)) { + info.manufacturer = USBVendorId.vendorName(device.getVendorId()); + } + if (TextUtils.isEmpty(info.manufacturer)) { + info.manufacturer = String.format("%04x", device.getVendorId()); + } + if (TextUtils.isEmpty(info.product)) { + info.product = String.format("%04x", device.getProductId()); + } + } + return info; + } + + /** + * control class + * never reuse the instance when it closed + */ + public static final class UsbControlBlock implements Cloneable { + private final WeakReference mWeakMonitor; + private final WeakReference mWeakDevice; + protected UsbDeviceConnection mConnection; + protected final UsbDeviceInfo mInfo; + private final int mBusNum; + private final int mDevNum; + private final SparseArray> mInterfaces = new SparseArray>(); + + /** + * this class needs permission to access USB device before constructing + * @param monitor + * @param device + */ + private UsbControlBlock(final USBMonitor monitor, final UsbDevice device) { + if (DEBUG) Log.i(TAG, "UsbControlBlock:constructor"); + mWeakMonitor = new WeakReference(monitor); + mWeakDevice = new WeakReference(device); + mConnection = monitor.mUsbManager.openDevice(device); + mInfo = updateDeviceInfo(monitor.mUsbManager, device, null); + final String name = device.getDeviceName(); + final String[] v = !TextUtils.isEmpty(name) ? name.split("/") : null; + int busnum = 0; + int devnum = 0; + if (v != null) { + busnum = Integer.parseInt(v[v.length-2]); + devnum = Integer.parseInt(v[v.length-1]); + } + mBusNum = busnum; + mDevNum = devnum; +// if (DEBUG) { + if (mConnection != null) { + final int desc = mConnection.getFileDescriptor(); + final byte[] rawDesc = mConnection.getRawDescriptors(); + Log.i(TAG, String.format(Locale.US, "name=%s,desc=%d,busnum=%d,devnum=%d,rawDesc=", name, desc, busnum, devnum) + rawDesc); + } else { + Log.e(TAG, "could not connect to device " + name); + } +// } + } + + /** + * copy constructor + * @param src + * @throws IllegalStateException + */ + private UsbControlBlock(final UsbControlBlock src) throws IllegalStateException { + final USBMonitor monitor = src.getUSBMonitor(); + final UsbDevice device = src.getDevice(); + if (device == null) { + throw new IllegalStateException("device may already be removed"); + } + mConnection = monitor.mUsbManager.openDevice(device); + if (mConnection == null) { + throw new IllegalStateException("device may already be removed or have no permission"); + } + mInfo = updateDeviceInfo(monitor.mUsbManager, device, null); + mWeakMonitor = new WeakReference(monitor); + mWeakDevice = new WeakReference(device); + mBusNum = src.mBusNum; + mDevNum = src.mDevNum; + // FIXME USBMonitor.mCtrlBlocksに追加する(今はHashMapなので追加すると置き換わってしまうのでだめ, ListかHashMapにListをぶら下げる?) + } + + /** + * duplicate by clone + * need permission + * USBMonitor never handle cloned UsbControlBlock, you should release it after using it. + * @return + * @throws CloneNotSupportedException + */ + @Override + public UsbControlBlock clone() throws CloneNotSupportedException { + final UsbControlBlock ctrlblock; + try { + ctrlblock = new UsbControlBlock(this); + } catch (final IllegalStateException e) { + throw new CloneNotSupportedException(e.getMessage()); + } + return ctrlblock; + } + + public USBMonitor getUSBMonitor() { + return mWeakMonitor.get(); + } + + public final UsbDevice getDevice() { + return mWeakDevice.get(); + } + + /** + * get device name + * @return + */ + public String getDeviceName() { + final UsbDevice device = mWeakDevice.get(); + return device != null ? device.getDeviceName() : ""; + } + + /** + * get device id + * @return + */ + public int getDeviceId() { + final UsbDevice device = mWeakDevice.get(); + return device != null ? device.getDeviceId() : 0; + } + + /** + * get device key string + * @return same value if the devices has same vendor id, product id, device class, device subclass and device protocol + */ + public String getDeviceKeyName() { + return USBMonitor.getDeviceKeyName(mWeakDevice.get()); + } + + /** + * get device key string + * @param useNewAPI if true, try to use serial number + * @return + * @throws IllegalStateException + */ + public String getDeviceKeyName(final boolean useNewAPI) throws IllegalStateException { + if (useNewAPI) checkConnection(); + return USBMonitor.getDeviceKeyName(mWeakDevice.get(), mInfo.serial, useNewAPI); + } + + /** + * get device key + * @return + * @throws IllegalStateException + */ + public int getDeviceKey() throws IllegalStateException { + checkConnection(); + return USBMonitor.getDeviceKey(mWeakDevice.get()); + } + + /** + * get device key + * @param useNewAPI if true, try to use serial number + * @return + * @throws IllegalStateException + */ + public int getDeviceKey(final boolean useNewAPI) throws IllegalStateException { + if (useNewAPI) checkConnection(); + return USBMonitor.getDeviceKey(mWeakDevice.get(), mInfo.serial, useNewAPI); + } + + /** + * get device key string + * if device has serial number, use it + * @return + */ + public String getDeviceKeyNameWithSerial() { + return USBMonitor.getDeviceKeyName(mWeakDevice.get(), mInfo.serial, false); + } + + /** + * get device key + * if device has serial number, use it + * @return + */ + public int getDeviceKeyWithSerial() { + return getDeviceKeyNameWithSerial().hashCode(); + } + + /** + * get UsbDeviceConnection + * @return + */ + public synchronized UsbDeviceConnection getConnection() { + return mConnection; + } + + /** + * get file descriptor to access USB device + * @return + * @throws IllegalStateException + */ + public synchronized int getFileDescriptor() throws IllegalStateException { + checkConnection(); + return mConnection.getFileDescriptor(); + } + + /** + * get raw descriptor for the USB device + * @return + * @throws IllegalStateException + */ + public synchronized byte[] getRawDescriptors() throws IllegalStateException { + checkConnection(); + return mConnection.getRawDescriptors(); + } + + /** + * get vendor id + * @return + */ + public int getVenderId() { + final UsbDevice device = mWeakDevice.get(); + return device != null ? device.getVendorId() : 0; + } + + /** + * get product id + * @return + */ + public int getProductId() { + final UsbDevice device = mWeakDevice.get(); + return device != null ? device.getProductId() : 0; + } + + /** + * get version string of USB + * @return + */ + public String getUsbVersion() { + return mInfo.usb_version; + } + + /** + * get manufacture + * @return + */ + public String getManufacture() { + return mInfo.manufacturer; + } + + /** + * get product name + * @return + */ + public String getProductName() { + return mInfo.product; + } + + /** + * get version + * @return + */ + public String getVersion() { + return mInfo.version; + } + + /** + * get serial number + * @return + */ + public String getSerial() { + return mInfo.serial; + } + + public int getBusNum() { + return mBusNum; + } + + public int getDevNum() { + return mDevNum; + } + + /** + * get interface + * @param interface_id + * @throws IllegalStateException + */ + public synchronized UsbInterface getInterface(final int interface_id) throws IllegalStateException { + return getInterface(interface_id, 0); + } + + /** + * get interface + * @param interface_id + * @param altsetting + * @return + * @throws IllegalStateException + */ + public synchronized UsbInterface getInterface(final int interface_id, final int altsetting) throws IllegalStateException { + checkConnection(); + SparseArray intfs = mInterfaces.get(interface_id); + if (intfs == null) { + intfs = new SparseArray(); + mInterfaces.put(interface_id, intfs); + } + UsbInterface intf = intfs.get(altsetting); + if (intf == null) { + final UsbDevice device = mWeakDevice.get(); + final int n = device.getInterfaceCount(); + for (int i = 0; i < n; i++) { + final UsbInterface temp = device.getInterface(i); + if ((temp.getId() == interface_id) && (temp.getAlternateSetting() == altsetting)) { + intf = temp; + break; + } + } + if (intf != null) { + intfs.append(altsetting, intf); + } + } + return intf; + } + + /** + * open specific interface + * @param intf + */ + public synchronized void claimInterface(final UsbInterface intf) { + claimInterface(intf, true); + } + + public synchronized void claimInterface(final UsbInterface intf, final boolean force) { + checkConnection(); + mConnection.claimInterface(intf, force); + } + + /** + * close interface + * @param intf + * @throws IllegalStateException + */ + public synchronized void releaseInterface(final UsbInterface intf) throws IllegalStateException { + checkConnection(); + final SparseArray intfs = mInterfaces.get(intf.getId()); + if (intfs != null) { + final int index = intfs.indexOfValue(intf); + intfs.removeAt(index); + if (intfs.size() == 0) { + mInterfaces.remove(intf.getId()); + } + } + mConnection.releaseInterface(intf); + } + + /** + * Close device + * This also close interfaces if they are opened in Java side + */ + public synchronized void close() { + if (DEBUG) Log.i(TAG, "UsbControlBlock#close:"); + + if (mConnection != null) { + final int n = mInterfaces.size(); + for (int i = 0; i < n; i++) { + final SparseArray intfs = mInterfaces.valueAt(i); + if (intfs != null) { + final int m = intfs.size(); + for (int j = 0; j < m; j++) { + final UsbInterface intf = intfs.valueAt(j); + mConnection.releaseInterface(intf); + } + intfs.clear(); + } + } + mInterfaces.clear(); + mConnection.close(); + mConnection = null; + final USBMonitor monitor = mWeakMonitor.get(); + if (monitor != null) { + if (monitor.mOnDeviceConnectListener != null) { + monitor.mOnDeviceConnectListener.onDisconnect(mWeakDevice.get(), UsbControlBlock.this); + } + monitor.mCtrlBlocks.remove(getDevice()); + } + } + } + + @Override + public boolean equals(final Object o) { + if (o == null) return false; + if (o instanceof UsbControlBlock) { + final UsbDevice device = ((UsbControlBlock) o).getDevice(); + return device == null ? mWeakDevice.get() == null + : device.equals(mWeakDevice.get()); + } else if (o instanceof UsbDevice) { + return o.equals(mWeakDevice.get()); + } + return super.equals(o); + } + +// @Override +// protected void finalize() throws Throwable { +/// close(); +// super.finalize(); +// } + + private synchronized void checkConnection() throws IllegalStateException { + if (mConnection == null) { + throw new IllegalStateException("already closed"); + } + } + } + +} diff --git a/libusbcamera/src/main/java/com/serenegiant/usb/USBVendorId.java b/libusbcamera/src/main/java/com/serenegiant/usb/USBVendorId.java new file mode 100644 index 0000000..d354b66 --- /dev/null +++ b/libusbcamera/src/main/java/com/serenegiant/usb/USBVendorId.java @@ -0,0 +1,859 @@ +/* + * 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.serenegiant.usb; + +import android.util.SparseArray; + +public class USBVendorId { + private static final SparseArray IDS = new SparseArray(); + + public static String vendorName(final int vendor_id) { + return IDS.get(vendor_id); + } + + static { + IDS.put(10006, "YUEN DA ELECTRONIC PRODUCTS FACTORY"); + IDS.put(10013, "Gionee Communication Equipment Co., Ltd. ShenZhen"); + IDS.put(10022, "Universal Electronics Inc. (dba: TVIEW)"); + IDS.put(1003, "Atmel Corporation"); + IDS.put(1006, "Mitsumi"); + IDS.put(1008, "HP Inc."); + IDS.put(10112, "M31 Technology Corp."); + IDS.put(10113, "Liteconn Co., Ltd."); + IDS.put(10121, "Suzhou WEIJU Electronics Technology Co., Ltd."); + IDS.put(10144, "Mondokey Limited"); + IDS.put(10149, "Advantest Corporation"); + IDS.put(10150, "iRobot Corporation"); + IDS.put(1020, "Elitegroup Computer Systems"); + IDS.put(1021, "Xilinx Inc."); + IDS.put(10226, "Sibridge Tech."); + IDS.put(1026, "ALi Corporation"); + IDS.put(1027, "Future Technology Devices International Limited"); + IDS.put(10275, "Dongguan Jiumutong Industry Co., Ltd."); + IDS.put(10289, "Power Integrations"); + IDS.put(10291, "Oculus VR, Inc."); + IDS.put(10300, "HIGH TEK HARNESS ENTERPRISE CO., LTD."); + IDS.put(10316, "Full in Hope Co., Ltd."); + IDS.put(1032, "Quanta Computer Inc."); + IDS.put(10329, "Viconn Technology (HK) Co., Ltd."); + IDS.put(1033, "NEC Corporation"); + IDS.put(1035, "Weltrend Semiconductor"); + IDS.put(1037, "VIA Technologies, Inc."); + IDS.put(10374, "Seeed Technology Co., Ltd."); + IDS.put(10375, "Specwerkz"); + IDS.put(1038, "MCCI Corporation"); + IDS.put(10398, "Esselte Leitz GmbH & Co. KG"); + IDS.put(10406, "E-SEEK Inc."); + IDS.put(1041, "BUFFALO INC."); + IDS.put(10423, "Pleora Technologies Inc."); + IDS.put(10431, "Vitetech Int'l Co., Ltd."); + IDS.put(1044, "Giga-Byte Technology Co., Ltd."); + IDS.put(10446, "Changzhou Shi Wujin Miqi East Electronic Co., Ltd."); + IDS.put(10457, "Shenzhen Ourconn Technology Co., Ltd."); + IDS.put(10458, "G.SKILL Int'l Enterprice Co., Ltd."); + IDS.put(1046, "Nuvoton Technology Corp."); + IDS.put(10466, "Surplus Electronic Technology Co., Ltd."); + IDS.put(10470, "BIAMP SYSTEMS"); + IDS.put(10509, "IBCONN Technologies (Shenzhen) Co., Ltd."); + IDS.put(10510, "Fugoo Inc."); + IDS.put(10519, "Pan Xin Precision Electronics Co., Ltd."); + IDS.put(10530, "Dongguan Digi-in Digital Technology Co., Ltd."); + IDS.put(1054, "Creative Labs"); + IDS.put(10540, "GENUSION, Inc."); + IDS.put(10544, "Ineda Systems Inc."); + IDS.put(10545, "Jolla Ltd."); + IDS.put(10546, "Peraso Technologies, Inc."); + IDS.put(10549, "Nanjing Magewell Electronics Co., Ltd."); + IDS.put(10560, "Shenzhen Yiwanda Electronics Co., Ltd."); + IDS.put(1057, "Nokia Corporation"); + IDS.put(10575, "Dollar Connection Ltd."); + IDS.put(10595, "BIO-key International, Inc."); + IDS.put(1060, "Microchip-SMSC"); + IDS.put(10603, "Xacti Corporation"); + IDS.put(10615, "Shenzhen Zowee Technology Co., Ltd."); + IDS.put(10643, "ADPlaus Technology Limited"); + IDS.put(10646, "Unwired Technology"); + IDS.put(1065, "Cirrus Logic Inc."); + IDS.put(10657, "Union Electric Plug & Connector Corp."); + IDS.put(10674, "Canova Tech"); + IDS.put(10685, "Silicon Works"); + IDS.put(10695, "HANRICO ANFU ELECTRONICS CO., LTD."); + IDS.put(10700, "Kodak Alaris"); + IDS.put(10702, "JGR Optics Inc."); + IDS.put(10703, "Richtek Technology Corporation"); + IDS.put(10705, "Binatone Electronics Int. Ltd."); + IDS.put(1071, "Molex Inc."); + IDS.put(10715, "Shenzhen iBoard Technology Co., Ltd."); + IDS.put(10719, "SMIT(HK) Limited"); + IDS.put(1072, "Fujitsu Component Limited"); + IDS.put(10725, "Dongguan Kechenda Electronic Technology Co., Ltd."); + IDS.put(10726, "Fengshun Peiying Electro-Acoustic Co., Ltd."); + IDS.put(10744, "MD ELEKTRONIK GmbH"); + IDS.put(10749, "Bad Elf, LLC"); + IDS.put(10770, "Vreo Limited"); + IDS.put(10772, "Kanex"); + IDS.put(10781, "Oxford Nanopore Technologies"); + IDS.put(10782, "Obsidian Technology"); + IDS.put(10783, "Lucent Trans Electronics Co., Ltd."); + IDS.put(10784, "GUOGUANG GROUP CO., LTD."); + IDS.put(10788, "CNPLUS"); + IDS.put(10789, "Fourstar Group"); + IDS.put(10790, "Tragant International Co., Ltd."); + IDS.put(10791, "DongGuan LianGang Optoelectronic Technology Co., Ltd."); + IDS.put(10797, "Atrust Computer Corp."); + IDS.put(10798, "VIA Alliance Semiconductor Co., Ltd."); + IDS.put(10799, "BSUN Electronics Co., Ltd."); + IDS.put(1080, "Advanced Micro Devices"); + IDS.put(10807, "RTD Embedded Technologies, Inc."); + IDS.put(10816, "Shenzhen Choseal Industrial Co., Ltd."); + IDS.put(10817, "Canyon Semiconductor"); + IDS.put(10818, "Spectra7 Microsystems Corp."); + IDS.put(10821, "Meizu Technology Co., Ltd."); + IDS.put(10822, "Hubei Yingtong Telecommunication Cable Inc."); + IDS.put(10829, "Wilder Technologies"); + IDS.put(10837, "Diodes Inc."); + IDS.put(10846, "DuPont"); + IDS.put(1085, "Lexmark International Inc."); + IDS.put(10852, "Zhejiang Songcheng Electronics Co., Ltd."); + IDS.put(10859, "VSN Mobil"); + IDS.put(10875, "Bellwether Electronic Corp."); + IDS.put(10878, "VAIO Corporation"); + IDS.put(10879, "Perixx Computer GmbH"); + IDS.put(10885, "HANK ELECTRONICS CO., LTD"); + IDS.put(10892, "Sonnet Technologies, Inc."); + IDS.put(10893, "Keysight Technologies Inc."); + IDS.put(10895, "Manutronics Vietnam Joint Stock Company"); + IDS.put(10900, "G2 Touch Co., Ltd."); + IDS.put(10902, "Micromax Informatics Ltd"); + IDS.put(10910, "SEIKO SOLUTIONS Inc."); + IDS.put(10912, "Casco Products Corp."); + IDS.put(10922, "Virtium Technology, Inc."); + IDS.put(10923, "Field and Company LLC, dba Leef USA"); + IDS.put(10928, "GM Global Technology Operations LLC"); + IDS.put(10931, "Key Asic Inc."); + IDS.put(10943, "Revolabs, Inc."); + IDS.put(10945, "Lattice Semiconductor Corp"); + IDS.put(10947, "Foshan Nanhai Saga Audio Equipment Co., Ltd."); + IDS.put(10957, "Silergy Corp."); + IDS.put(10963, "Shenzhen Hali-Power Industrial Co., Ltd."); + IDS.put(10971, "I-PEX (Dai-ichi Seiko)"); + IDS.put(10973, "SEE-PLUS INDUSTRIAL LTD."); + IDS.put(10990, "Adapt-IP Company"); + IDS.put(10997, "Libratone A/S"); + IDS.put(10999, "Shenzhen Hazens Automotive Electronics (SZ) Co., Ltd."); + IDS.put(11000, "Jiangsu Toppower Automotive Electronics Co., Ltd."); + IDS.put(11001, "Drapho Electronics Technology Co., Ltd."); + IDS.put(1102, "Alps Electric Co., Ltd."); + IDS.put(11022, "Le Shi Zhi Xin Electronic Technology (Tian Jin) Limited"); + IDS.put(11024, "Cardiac Insight, Inc."); + IDS.put(11028, "EverPro Technologies Company, Ltd."); + IDS.put(11029, "Rosenberger Hochfrequenztechnik"); + IDS.put(11035, "Dongguan City Sanji Electronics Co., Ltd."); + IDS.put(11037, "Lintes Technology Co., Ltd."); + IDS.put(11039, "KinnexA, Inc."); + IDS.put(11042, "Metra Electronics Corp."); + IDS.put(11044, "KeepKey, LLC"); + IDS.put(11047, "FluxData Incorporated"); + IDS.put(1105, "Texas Instruments"); + IDS.put(11061, "Assem Technology Co., Ltd."); + IDS.put(11062, "Dongguan City Jianghan Electronics Co., Ltd."); + IDS.put(11063, "Huizhou Desay SV Automotive Co., Ltd."); + IDS.put(11064, "Ningbo Rixing Electronics Co., Ltd."); + IDS.put(11069, "GuangDong YuanFeng Automotive Electroics Co., Ltd."); + IDS.put(11080, "Sounding Audio Industrial Limited"); + IDS.put(11082, "Yueqing Huaxin Electronic Co., Ltd."); + IDS.put(11098, "Universal Audio, Inc."); + IDS.put(11111, "Lifesize, Inc."); + IDS.put(11123, "Pioneer DJ Corporation"); + IDS.put(11124, "Embedded Intelligence, Inc."); + IDS.put(11125, "New Matter"); + IDS.put(11126, "Shanghai Wingtech Electronic Technology Co., Ltd."); + IDS.put(11127, "Epiphan Systems Inc."); + IDS.put(11130, "Spin Master Far East Ltd."); + IDS.put(11131, "Gigaset Digital Technology (Shenzhen) Co., Ltd."); + IDS.put(11132, "Noveltek Semiconductor Corp."); + IDS.put(11139, "Silicon Line GmbH"); + IDS.put(11140, "Ever Win International Corp."); + IDS.put(11144, "Socionext Inc."); + IDS.put(11145, "Ugreen Group Limited"); + IDS.put(11146, "Shanghai Pateo Electronic Equipment Mfg. Co., Ltd."); + IDS.put(1115, "Renesas Electronics Corp."); + IDS.put(11154, "i-BLADES, Inc."); + IDS.put(11155, "Altia Systems Inc."); + IDS.put(11156, "ShenZhen Baoyuanda Electronics Co., Ltd."); + IDS.put(11157, "iST - Integrated Service Technology Inc."); + IDS.put(11158, "HYUNDAI MOBIS Co., Ltd."); + IDS.put(11161, "360fly, Inc."); + IDS.put(11162, "HUIZHOU CHENG SHUO HARDWARE PLASTIC CO., LTD."); + IDS.put(11163, "Zhongshan Aute Electronics Technology Co., Ltd."); + IDS.put(11164, "Guangdong King Link Industrial Co., Ltd."); + IDS.put(11167, "Scietera Technologies, Inc."); + IDS.put(11168, "InVue Security Products"); + IDS.put(11169, "I-Sheng Electric Wire & Cable Co., Ltd."); + IDS.put(11170, "China Daheng Group Inc Beijing Image Vision Tech Branch"); + IDS.put(11171, "Shenzhen FeiTianXia Technology Ltd."); + IDS.put(11172, "Shenzhen HengJia New Energy Auto Part Co., Ltd."); + IDS.put(11175, "77 Elektronika Kft."); + IDS.put(11176, "YUDU EASON ELECTRONIC CO., LTD."); + IDS.put(1118, "Microsoft Corporation"); + IDS.put(11181, "XIN JI (SHENZHEN) COMPUTER PARTS CO., LTD."); + IDS.put(11189, "Silk ID Systems"); + IDS.put(11190, "3D Imaging & Simulations Corp. (3DISC)"); + IDS.put(11191, "Dongguan ChengXiang Industrial Co., Ltd."); + IDS.put(11192, "OCC (Zhuhai) Electronic Co., Ltd."); + IDS.put(11194, "Sinseader Electronic Co., Ltd."); + IDS.put(11195, "DONGGUAN YELLOWKNIFE Industrial Co., Ltd."); + IDS.put(11197, "RF Creations Ltd."); + IDS.put(11198, "Chengyi Semiconductors (Shanghai) Co., Ltd."); + IDS.put(11199, "Shenzhen Shinning Electronic Co., Ltd."); + IDS.put(11200, "Shenzhen WFD Electronics Co., Ltd."); + IDS.put(11201, "Dongguan Sino Syncs Industrial Co., Ltd."); + IDS.put(11202, "JNTC Co., Ltd."); + IDS.put(11208, "DONGGUAN POLIXIN ELECTRIC CO., LTD."); + IDS.put(11209, "Tama Electric (Suzhou) Co., Ltd."); + IDS.put(1121, "Primax Electronics"); + IDS.put(11210, "Exvision, Inc."); + IDS.put(11216, "mophie, LLC"); + IDS.put(11219, "Dongguan ULT-unite electronic technology co., LTD"); + IDS.put(11220, "JL Audio, Inc."); + IDS.put(11221, "Cable Matters Inc."); + IDS.put(11222, "CoroWare, Inc."); + IDS.put(11229, "Charm Sciences Inc."); + IDS.put(1123, "EATON"); + IDS.put(11230, "Pickering Interfaces Limited"); + IDS.put(11231, "Hangzhou Hikvision Digital Technology Co., Ltd."); + IDS.put(11232, "FULLINK ELECTRONICS TECHNOLOGY (SZ) LTD"); + IDS.put(11233, "AutoChips Inc."); + IDS.put(11234, "Electric Connector Technology Co., Ltd."); + IDS.put(11237, "LELTEK"); + IDS.put(11238, "Dongguan KaiWin Electronics Co., Ltd."); + IDS.put(11239, "BEFS Co., Ltd."); + IDS.put(11240, "Archisite, Inc."); + IDS.put(11241, "Magneti Marelli S.p.A Electr BL"); + IDS.put(11246, "Ventev Mobile"); + IDS.put(11247, "Quanta Storage Inc."); + IDS.put(11248, "Tech-Top Technology Limited"); + IDS.put(11253, "Shenzhen YOOBAO Technology Co., Ltd."); + IDS.put(11254, "Shenzhen Sinotek Technology Co., Ltd."); + IDS.put(11255, "KEYW"); + IDS.put(11256, "Visual Land Inc."); + IDS.put(11264, "MEEM SL Ltd"); + IDS.put(11265, "Dongguan Arin Electronics Technology Co., Ltd."); + IDS.put(11266, "DongGuan City JianNuo Electronics Co., Ltd."); + IDS.put(11268, "Shenzhen XOX Electronics Co., Ltd."); + IDS.put(11269, "Protop International Inc."); + IDS.put(11270, "Microsemi Semiconductor (US) Inc."); + IDS.put(11271, "Webcloak LLC"); + IDS.put(11272, "INVECAS INC."); + IDS.put(11274, "ATANS Technology Inc."); + IDS.put(11275, "Triple Win Precision Technology Co., Ltd."); + IDS.put(11276, "IC Realtech"); + IDS.put(11277, "Embrava Pty Ltd"); + IDS.put(1128, "Wieson Technologies Co., Ltd."); + IDS.put(11280, "Sinotronics Co., Ltd."); + IDS.put(11281, "ALLBEST ELECTRONICS TECHNOLOGY CO., LTD."); + IDS.put(11282, "Shenzhen Xin Kai Feng Electronics Factory"); + IDS.put(11283, "MOST WELL Technology Corp."); + IDS.put(11284, "Buffalo Memory Co., Ltd."); + IDS.put(11285, "Xentris Wireless"); + IDS.put(11286, "Priferential Accessories Ltd"); + IDS.put(11289, "Sunlike Technology Co., Ltd."); + IDS.put(11290, "Young Fast Optoelectronics Co., Ltd."); + IDS.put(11291, "ISAW Camera Inc"); + IDS.put(11298, "Qanba USA, LLC"); + IDS.put(11299, "Super Micro Computer Inc."); + IDS.put(11302, "Micromax International Corporation"); + IDS.put(11304, "Granite River Labs Japan Ltd."); + IDS.put(11305, "Coagent Enterprise Limited"); + IDS.put(11306, "LEIA Inc."); + IDS.put(11309, "Shenzhen Ebull Technology Limited"); + IDS.put(1131, "American Megatrends"); + IDS.put(11310, "Hualun Technology Co., Ltd."); + IDS.put(11311, "Sensel, Inc."); + IDS.put(11319, "Shenzhen Adition Audio Science & Technology Co., Ltd."); + IDS.put(11320, "Goldenconn Electronics Technology (Suzhou) Co., Ltd."); + IDS.put(11321, "JIB Electronics Technology Co., Ltd."); + IDS.put(11322, "Changzhou Shinco Automotive Electronics Co., Ltd."); + IDS.put(11323, "Shenzhen Hangsheng Electronics Corp., Ltd."); + IDS.put(11324, "Beartooth Radio, Inc."); + IDS.put(11325, "Audience, A Knowles Company"); + IDS.put(11327, "Nextbit Systems, Inc."); + IDS.put(11328, "Leadtrend"); + IDS.put(11329, "Adaptertek Technology Co., Ltd."); + IDS.put(1133, "Logitech Inc."); + IDS.put(11330, "Feature Integration Technology Inc."); + IDS.put(11331, "Avegant Corporation"); + IDS.put(11335, "Chunghsin International Electronics Co., Ltd."); + IDS.put(11336, "Delphi Electrical Centers (Shanghai) Co., Ltd."); + IDS.put(11341, "VVETEK DOO"); + IDS.put(11347, "Huizhou Foryou General Electronics Co., Ltd."); + IDS.put(11348, "LifeWatch Technologies Ltd."); + IDS.put(11349, "Magicleap"); + IDS.put(11355, "Dongguan City Shenglan Electronics Co., LTD."); + IDS.put(11356, "Neusoft Corporation"); + IDS.put(11357, "SIP Simya Electronics Technology Co., Ltd."); + IDS.put(11358, "GNSD Automotive Co., Ltd."); + IDS.put(11359, "YOODS Co., Ltd."); + IDS.put(11360, "Sirin Mobile Technologies AG"); + IDS.put(11361, "Jadmam Corporation dba: Boytone"); + IDS.put(11373, "Gibson Innovations"); + IDS.put(11374, "Shen Zhen Xian Shuo Technology Co. LTD"); + IDS.put(11375, "PST Eletronica LTDA"); + IDS.put(11376, "PERI, Inc."); + IDS.put(11377, "Bozhou BoTong Information Technology Co., Ltd."); + IDS.put(11383, "Profindustry GmbH"); + IDS.put(11384, "BRAGI GmbH"); + IDS.put(11385, "WAWGD, Inc. (DBA: Foresight Sports)"); + IDS.put(11390, "Dongguan Allpass Electronic Co., Ltd."); + IDS.put(11391, "SHENZHEN D-VITEC INDUSTRIAL CO., LTD."); + IDS.put(11392, "motomobile AG"); + IDS.put(11393, "Indie Semiconductor"); + IDS.put(11397, "Audientes"); + IDS.put(11403, "Huizhou Dehong Technology Co., Ltd."); + IDS.put(11404, "PowerCenter Technology Limited"); + IDS.put(11405, "Mizco International, Inc."); + IDS.put(11408, "I. AM. PLUS, LLC"); + IDS.put(11409, "Corigine, Inc."); + IDS.put(11410, "Ningbo Yinzhou Shengke Electronics Co., Ltd."); + IDS.put(11417, "Prusa Research s.r.o."); + IDS.put(11423, "e-Smart Systems Pvt. Ltd."); + IDS.put(11424, "Leagtech Jiangxi Electronic Co., Ltd."); + IDS.put(11425, "Dongguan Yujia Electronics Technology Co., Ltd."); + IDS.put(11426, "GuangZhou MingPing Electronics Technology"); + IDS.put(11427, "DJI Technology Co., Ltd."); + IDS.put(11428, "Shenzhen Alex Technology Co., Ltd."); + IDS.put(11433, "JITS TECHNOLOGY CO., LIMITED"); + IDS.put(11434, "LIVV Brand llc"); + IDS.put(11444, "Ava Enterprises, Inc. dba: Boss Audio Systems"); + IDS.put(11448, "Shenzhen Sydixon Electronic Technology Co., Ltd."); + IDS.put(11449, "On-Bright Electronics (Shanghai) Co., Ltd."); + IDS.put(11450, "Dongguan Puxu Industrial Co., Ltd."); + IDS.put(11451, "Shenzhen Soling Indusrtial Co., Ltd."); + IDS.put(11453, "EGGCYTE, INC."); + IDS.put(11455, "Donggguan Yuhua Electronic Co., Ltd."); + IDS.put(11456, "Hangzhou Zero Zero Technology Co., Ltd."); + IDS.put(11462, "Prodigy Technovations Pvt Ltd"); + IDS.put(11463, "EmergiTech, Inc"); + IDS.put(11464, "Hewlett Packard Enterprise"); + IDS.put(11465, "Monolithic Power Systems Inc."); + IDS.put(11467, "USB Memory Direct"); + IDS.put(11468, "Silicon Mitus Inc."); + IDS.put(11472, "Technics Global Electronics & JCE Co., Ltd."); + IDS.put(11478, "Immersive Media"); + IDS.put(11479, "Cosemi Technologies Inc."); + IDS.put(11481, "Cambrionix Ltd"); + IDS.put(11482, "CXUN Co. Ltd."); + IDS.put(11483, "China Tsp Inc"); + IDS.put(11490, "Yanfeng Visteon (Chongqing) Automotive Electronics Co"); + IDS.put(11491, "Alcorlink Corp."); + IDS.put(11492, "ISBC Ltd."); + IDS.put(11493, "InX8 Inc dba: AKiTiO"); + IDS.put(11494, "SDAN Tecchnology Co., Ltd."); + IDS.put(11495, "Lemobile Information Technology (Beijing) Co., Ltd."); + IDS.put(11496, "GongGuan HWX Electronic Technology Co., Ltd."); + IDS.put(11497, "Suzhu Jingshi Electronic Technology Co., Ltd."); + IDS.put(11498, "Zhong Shan City Richsound Electronic Industrial Ltd."); + IDS.put(11499, "Dongguang Kangbang Electronics Co., Ltd."); + IDS.put(1151, "Plantronics, Inc."); + IDS.put(1154, "Kyocera Corporation"); + IDS.put(1155, "STMicroelectronics"); + IDS.put(1161, "Foxconn / Hon Hai"); + IDS.put(1165, "ITE Tech Inc."); + IDS.put(1177, "Yamaha Corporation"); + IDS.put(1188, "Hitachi, Ltd."); + IDS.put(1191, "Visioneer"); + IDS.put(1193, "Canon Inc."); + IDS.put(1200, "Nikon Corporation"); + IDS.put(1201, "Pan International"); + IDS.put(1204, "Cypress Semiconductor"); + IDS.put(1205, "ROHM Co., Ltd."); + IDS.put(1207, "Compal Electronics, Inc."); + IDS.put(1208, "Seiko Epson Corp."); + IDS.put(1211, "I-O Data Device, Inc."); + IDS.put(1221, "Fujitsu Ltd."); + IDS.put(1227, "FUJIFILM Corporation"); + IDS.put(1238, "Mentor Graphics"); + IDS.put(1240, "Microchip Technology Inc."); + IDS.put(1241, "Holtek Semiconductor, Inc."); + IDS.put(1242, "Panasonic Corporation"); + IDS.put(1245, "Sharp Corporation"); + IDS.put(1250, "Exar Corporation"); + IDS.put(1254, "Identiv, Inc."); + IDS.put(1256, "Samsung Electronics Co., Ltd."); + IDS.put(1260, "Tokyo Electron Device Limited"); + IDS.put(1266, "Chicony Electronics Co., Ltd."); + IDS.put(1271, "Newnex Technology Corp."); + IDS.put(1273, "Brother Industries, Ltd."); + IDS.put(1276, "SUNPLUS TECHNOLOGY CO., LTD."); + IDS.put(1278, "PFU Limited"); + IDS.put(1281, "Fujikura/DDK"); + IDS.put(1282, "Acer, Inc."); + IDS.put(1287, "Hosiden Corporation"); + IDS.put(1293, "Belkin International, Inc."); + IDS.put(1300, "FCI Electronics"); + IDS.put(1302, "Longwell Electronics/Longwell Company"); + IDS.put(1305, "Star Micronics Co., LTD"); + IDS.put(1309, "American Power Conversion"); + IDS.put(1314, "ACON, Advanced-Connectek, Inc."); + IDS.put(1343, "Synopsys, Inc."); + IDS.put(1356, "Sony Corporation"); + IDS.put(1360, "Fuji Xerox Co., Ltd."); + IDS.put(1367, "ATEN International Co. Ltd."); + IDS.put(1369, "Cadence Design Systems, Inc."); + IDS.put(1386, "WACOM Co., Ltd."); + IDS.put(1389, "EIZO Corporation"); + IDS.put(1390, "Elecom Co., Ltd."); + IDS.put(1394, "Conexant Systems, Inc."); + IDS.put(1398, "BAFO/Quality Computer Accessories"); + IDS.put(1403, "Y-E Data, Inc."); + IDS.put(1404, "AVM GmbH"); + IDS.put(1410, "Roland Corporation"); + IDS.put(1412, "RATOC Systems, Inc."); + IDS.put(1419, "Infineon Technologies"); + IDS.put(1423, "Alcor Micro, Corp."); + IDS.put(1424, "OMRON Corporation"); + IDS.put(1447, "Bose Corporation"); + IDS.put(1449, "OmniVision Technologies, Inc."); + IDS.put(1452, "Apple"); + IDS.put(1453, "Y.C. Cable U.S.A., Inc"); + IDS.put(14627, "National Instruments"); + IDS.put(1470, "Tyco Electronics Corp., a TE Connectivity Ltd. company"); + IDS.put(1473, "MegaChips Corporation"); + IDS.put(1478, "Qualcomm, Inc"); + IDS.put(1480, "Foxlink/Cheng Uei Precision Industry Co., Ltd."); + IDS.put(1482, "Ricoh Company Ltd."); + IDS.put(1498, "Microtek International Inc."); + IDS.put(1504, "Symbol Technologies"); + IDS.put(1507, "Genesys Logic, Inc."); + IDS.put(1509, "Fuji Electric Co., Ltd."); + IDS.put(1525, "Unixtar Technology Inc."); + IDS.put(1529, "Datalogic ADC"); + IDS.put(1535, "LeCroy Corporation"); + IDS.put(1539, "Novatek Microelectronics Corp."); + IDS.put(1545, "SMK Manufacturing Inc."); + IDS.put(1551, "Joinsoon Electronics Mfg. Co., Ltd."); + IDS.put(1555, "TransAct Technologies Incorporated"); + IDS.put(1561, "Seiko Instruments Inc."); + IDS.put(1582, "JPC/MAIN SUPER Inc."); + IDS.put(1583, "Sin Sheng Terminal & Machine Inc."); + IDS.put(1593, "Chrontel, Inc."); + IDS.put(1611, "Analog Devices, Inc. Development Tools"); + IDS.put(1612, "Ji-Haw Industrial Co., Ltd"); + IDS.put(1614, "Suyin Corporation"); + IDS.put(1621, "Space Shuttle Hi-Tech Co.,Ltd."); + IDS.put(1622, "Glory Mark Electronic Ltd."); + IDS.put(1623, "Tekcon Electronics Corp."); + IDS.put(1624, "Sigma Designs, Inc."); + IDS.put(1631, "Good Way Technology Co., Ltd. & GWC technology Inc"); + IDS.put(1632, "TSAY-E (BVI) International Inc."); + IDS.put(1633, "Hamamatsu Photonics K.K."); + IDS.put(1642, "Total Technologies, Ltd."); + IDS.put(1659, "Prolific Technology, Inc."); + IDS.put(16700, "Dell Inc."); + IDS.put(1680, "Golden Bridge Electech Inc."); + IDS.put(1689, "Tektronix, Inc."); + IDS.put(1690, "Askey Computer Corporation"); + IDS.put(1709, "Greatland Electronics Taiwan Ltd."); + IDS.put(1710, "Eurofins Digital Testing Belgium"); + IDS.put(1720, "Pixela Corporation"); + IDS.put(1724, "Oki Data Corporation"); + IDS.put(1727, "Leoco Corporation"); + IDS.put(1732, "Bizlink Technology, Inc."); + IDS.put(1736, "SIIG, Inc."); + IDS.put(1747, "Mitsubishi Electric Corporation"); + IDS.put(1758, "Heisei Technology Co., Ltd."); + IDS.put(1802, "Oki Electric Industry Co., Ltd."); + IDS.put(1805, "Comoss Electronic Co., Ltd."); + IDS.put(1809, "Magic Control Technology Corp."); + IDS.put(1816, "Imation Corp."); + IDS.put(1838, "Sunix Co., Ltd."); + IDS.put(1846, "Lorom Industrial Co., Ltd."); + IDS.put(1848, "Mad Catz, Inc."); + IDS.put(1899, "HID Global GmbH"); + IDS.put(1901, "Denso Corporation"); + IDS.put(1913, "Fairchild Semiconductor"); + IDS.put(1921, "SanDisk Corporation"); + IDS.put(1937, "Copartner Technology Corporation"); + IDS.put(1954, "National Technical Systems"); + IDS.put(1971, "Plustek, Inc."); + IDS.put(1972, "OLYMPUS CORPORATION"); + IDS.put(1975, "TIME Interconnect Ltd."); + IDS.put(1994, "AVerMedia Technologies, Inc."); + IDS.put(1999, "Casio Computer Co., Ltd."); + IDS.put(2015, "David Electronics Company, Ltd."); + IDS.put(2039, "Century Corporation"); + IDS.put(2058, "Evermuch Technology Co., Ltd."); + IDS.put(2101, "Action Star Enterprise Co., Ltd."); + IDS.put(2112, "Argosy Research Inc."); + IDS.put(2122, "Wipro Limited"); + IDS.put(2159, "MEC IMEX INC/HPT"); + IDS.put(2205, "Icron Technologies Corporation"); + IDS.put(2247, "TAI TWUN ENTERPRISE CO., LTD."); + IDS.put(2276, "Pioneer Corporation"); + IDS.put(2278, "Gemalto SA"); + IDS.put(2310, "FARADAY Technology Corp."); + IDS.put(2313, "Audio-Technica Corp."); + IDS.put(2316, "Silicon Motion, Inc. - Taiwan"); + IDS.put(2334, "Garmin International"); + IDS.put(2352, "Toshiba Corporation"); + IDS.put(2362, "Pixart Imaging, Inc."); + IDS.put(2363, "Plextor LLC"); + IDS.put(2366, "J.S.T. Mfg. Co., Ltd."); + IDS.put(2385, "Kingston Technology Company"); + IDS.put(2389, "NVIDIA"); + IDS.put(2395, "Medialogic Corporation"); + IDS.put(2397, "Polycom, Inc."); + IDS.put(2468, "Contech Research, Inc."); + IDS.put(2472, "Lin Shiung Enterprise Co., Ltd."); + IDS.put(2475, "Japan Cash Machine Co., Ltd."); + IDS.put(2498, "NISCA Corporation"); + IDS.put(2511, "Electronics Testing Center, Taiwan"); + IDS.put(2522, "A-FOUR TECH CO., LTD."); + IDS.put(2555, "Altera"); + IDS.put(2578, "Cambridge Silicon Radio Ltd."); + IDS.put(2583, "HOYA Corporation"); + IDS.put(2631, "Hirose Electric Co., Ltd."); + IDS.put(2636, "COMPUTEX Co., Ltd."); + IDS.put(2640, "Mimaki Engineering Co., Ltd."); + IDS.put(2652, "Broadcom Corp."); + IDS.put(2667, "Green House Co., Ltd."); + IDS.put(2702, "Japan Aviation Electronics Industry Ltd. (JAE)"); + IDS.put(2727, "Wincor Nixdorf GmbH & Co KG"); + IDS.put(2733, "Rohde & Schwarz GmbH & Co. KG"); + IDS.put(2787, "Allion Labs, Inc."); + IDS.put(2821, "ASUSTek Computer Inc."); + IDS.put(2849, "Yokogawa Electric Corporation"); + IDS.put(2851, "Pan-Asia Electronics Co., Ltd."); + IDS.put(2894, "Musical Electronics Ltd."); + IDS.put(2907, "Anritsu Corporation"); + IDS.put(2922, "Maxim Integrated Products"); + IDS.put(2965, "ASIX Electronics Corporation"); + IDS.put(2967, "O2Micro, Inc."); + IDS.put(3010, "Seagate Technology LLC"); + IDS.put(3034, "Realtek Semiconductor Corp."); + IDS.put(3035, "Ericsson AB"); + IDS.put(3044, "Elka International Ltd."); + IDS.put(3056, "Pace Micro Technology PLC"); + IDS.put(3108, "Taiyo Yuden Co., Ltd."); + IDS.put(3129, "Aeroflex"); + IDS.put(3132, "Radius Co., Ltd."); + IDS.put(3141, "Sonix Technology Co., Ltd."); + IDS.put(3158, "Billion Bright (HK) Corporation Limited"); + IDS.put(3161, "Dong Guan Shinko Wire Co., Ltd."); + IDS.put(3170, "Chant Sincere Co., Ltd"); + IDS.put(3190, "Solid State System Co., Ltd."); + IDS.put(3209, "Honda Tsushin Kogyo Co., Ltd"); + IDS.put(3245, "Motorola Solutions"); + IDS.put(3255, "Singatron Enterprise Co. Ltd."); + IDS.put(3268, "emsys Embedded Systems GmbH"); + IDS.put(32902, "Intel Corporation"); + IDS.put(3294, "Z-Com INC."); + IDS.put(3313, "e-CONN ELECTRONIC CO., LTD."); + IDS.put(3314, "ENE Technology Inc."); + IDS.put(3351, "NALTEC, Inc."); + IDS.put(3402, "NF Corporation"); + IDS.put(3403, "Grape Systems Inc."); + IDS.put(3409, "Volex (Asia) Pte Ltd"); + IDS.put(3425, "MEILU ELECTRONICS (SHENZHEN) CO., LTD."); + IDS.put(3441, "Hirakawa Hewtech Corp."); + IDS.put(3452, "Taiwan Line Tek Electronic Co., Ltd."); + IDS.put(3463, "Dolby Laboratories Inc."); + IDS.put(3468, "C-MEDIA ELECTRONICS INC."); + IDS.put(3472, "Sure-Fire Electrical Corporation"); + IDS.put(3495, "IOGEAR, Inc."); + IDS.put(3504, "Micro-Star International Co., Ltd."); + IDS.put(3537, "Contek Electronics Co., Ltd."); + IDS.put(3540, "Custom Engineering SPA"); + IDS.put(3641, "Smart Modular Technologies, Inc."); + IDS.put(3658, "Shenzhen Bao Hing Electric Wire & Cable Mfr. Co."); + IDS.put(3673, "Bourns, Inc."); + IDS.put(3690, "Megawin Technology Co., Ltd."); + IDS.put(3698, "Hsi-Chin Electronics Co., Ltd."); + IDS.put(3714, "Ching Tai Electric Wire & Cable Co., Ltd."); + IDS.put(3724, "Well Force Electronic Co., Ltd"); + IDS.put(3725, "MediaTek Inc."); + IDS.put(3728, "CRU"); + IDS.put(3744, "Ours Technology Inc."); + IDS.put(3762, "Y-S ELECTRONIC CO., LTD."); + IDS.put(3778, "Sweetray Industrial Ltd."); + IDS.put(3779, "Axell Corporation"); + IDS.put(3782, "InnoVISION Multimedia Limited"); + IDS.put(3790, "TaiSol Electronics Co., Ltd."); + IDS.put(3812, "Sunrich Technology (H.K.) Ltd."); + IDS.put(3868, "Funai Electric Co., Ltd."); + IDS.put(3873, "IOI Technology Corporation"); + IDS.put(3890, "YFC-BonEagle Electric Co., Ltd."); + IDS.put(3896, "Nien-Yi Industrial Corp."); + IDS.put(3916, "WORLDWIDE CABLE OPTO CORP."); + IDS.put(3923, "Taiyo Cable (Dongguan) Co. Ltd."); + IDS.put(3924, "Kawai Musical Instruments Mfg. Co., Ltd."); + IDS.put(3936, "GuangZhou Chief Tech Electronic Technology Co. Ltd."); + IDS.put(3944, "UQUEST, LTD."); + IDS.put(3991, "CviLux Corporation"); + IDS.put(4003, "Chief Land Electronic Co., Ltd."); + IDS.put(4046, "Sony Mobile Communications"); + IDS.put(4087, "CHI SHING COMPUTER ACCESSORIES CO., LTD."); + IDS.put(4096, "Speed Tech Corp."); + IDS.put(4100, "LG Electronics Inc."); + IDS.put(4101, "Apacer Technology Inc."); + IDS.put(4134, "Newly Corporation"); + IDS.put(4168, "Targus Group International"); + IDS.put(4172, "AMCO TEC International Inc."); + IDS.put(4183, "ON Semiconductor"); + IDS.put(4184, "Western Digital Technologies, Inc."); + IDS.put(4227, "CANON ELECTRONICS INC."); + IDS.put(4235, "Grand-tek Technology Co., Ltd."); + IDS.put(4236, "Robert Bosch GmbH"); + IDS.put(4238, "Lotes Co., Ltd."); + IDS.put(4266, "Cables To Go"); + IDS.put(4267, "Universal Global Scientific Industrial Co., Ltd."); + IDS.put(4292, "Silicon Laboratories, Inc."); + IDS.put(4301, "Kycon Inc."); + IDS.put(4362, "Moxa Inc."); + IDS.put(4370, "Golden Bright (Sichuan) Electronic Technology Co Ltd"); + IDS.put(4382, "VSO ELECTRONICS CO., LTD."); + IDS.put(4398, "Master Hill Electric Wire and Cable Co., Ltd."); + IDS.put(4477, "Santa Electronic Inc."); + IDS.put(4505, "Sierra Wireless Inc."); + IDS.put(4522, "GlobalMedia Group, LLC"); + IDS.put(4528, "ATECH FLASH TECHNOLOGY"); + IDS.put(4643, "SKYCABLE ENTERPRISE CO., LTD."); + IDS.put(4703, "ADATA Technology Co., Ltd."); + IDS.put(4716, "Aristocrat Technologies"); + IDS.put(4717, "Bel Stewart"); + IDS.put(4742, "MARVELL SEMICONDUCTOR, INC."); + IDS.put(4756, "RISO KAGAKU CORP."); + IDS.put(4792, "Zhejiang Xinya Electronic Technology Co., Ltd."); + IDS.put(4817, "Huawei Technologies Co., Ltd."); + IDS.put(4823, "Better Holdings (HK) Limited"); + IDS.put(4907, "Konica Minolta, Inc."); + IDS.put(4925, "Jasco Products Company"); + IDS.put(4989, "Pericom Semiconductor Corp."); + IDS.put(5008, "TomTom International B.V."); + IDS.put(5075, "AzureWave Technologies, Inc."); + IDS.put(5117, "Initio Corporation"); + IDS.put(5118, "Phison Electronics Corp."); + IDS.put(5134, "Telechips, Inc."); + IDS.put(5145, "ABILITY ENTERPRISE CO., LTD."); + IDS.put(5148, "Leviton Manufacturing"); + IDS.put(5271, "Panstrong Company Ltd."); + IDS.put(5293, "CTK Corporation"); + IDS.put(5296, "StarTech.com Ltd."); + IDS.put(5376, "Ellisys"); + IDS.put(5404, "VeriSilicon Holdings Co., Ltd."); + IDS.put(5421, "JMicron Technology Corp."); + IDS.put(5422, "HLDS (Hitachi-LG Data Storage, Inc.)"); + IDS.put(5440, "Phihong Technology Co., Ltd."); + IDS.put(5451, "PNY Technologies Inc."); + IDS.put(5453, "Rapid Conn, Connect County Holdings Bhd"); + IDS.put(5454, "D & M Holdings, Inc."); + IDS.put(5480, "Sunf Pu Technology Co., Ltd"); + IDS.put(5488, "ALLTOP TECHNOLOGY CO., LTD."); + IDS.put(5510, "Palconn Technology Co., Ltd."); + IDS.put(5528, "Kunshan Guoji Electronics Co., Ltd."); + IDS.put(5546, "DongGuan Ya Lian Electronics Co., Ltd."); + IDS.put(5645, "Samtec"); + IDS.put(5694, "HongLin Electronics Co., Ltd."); + IDS.put(5753, "Total Phase"); + IDS.put(5766, "ZOOM Corporation"); + IDS.put(5836, "silex technology, Inc."); + IDS.put(5946, "F. Hoffmann-La Roche AG"); + IDS.put(5960, "MQP Electronics Ltd."); + IDS.put(5964, "ASMedia Technology Inc."); + IDS.put(5998, "UD electronic corp."); + IDS.put(6001, "Shenzhen Alex Connector Co., Ltd."); + IDS.put(6002, "System Level Solutions, Inc."); + IDS.put(6018, "Spreadtrum Hong Kong Limited"); + IDS.put(6024, "ShenZhen Litkconn Technology Co., Ltd."); + IDS.put(6053, "Advanced Connection Technology Inc."); + IDS.put(6095, "Hip Hing Cable & Plug Mfy. Ltd."); + IDS.put(6121, "DisplayLink (UK) Ltd."); + IDS.put(6127, "Lenovo"); + IDS.put(6133, "K.K. Rocky"); + IDS.put(6160, "Wanshih Electronic Co., Ltd."); + IDS.put(6185, "Dongguan YuQiu Electronics Co., Ltd."); + IDS.put(6193, "Gwo Jinn Industries Co., Ltd."); + IDS.put(6297, "Linkiss Co., Ltd."); + IDS.put(6353, "Google Inc."); + IDS.put(6394, "Kuang Ying Computer Equipment Co., Ltd."); + IDS.put(6421, "Nordic Semiconductor ASA"); + IDS.put(6448, "Shenzhen Xianhe Technology Co., Ltd."); + IDS.put(6449, "Ningbo Broad Telecommunication Co., Ltd."); + IDS.put(6470, "Irisguard UK Ltd"); + IDS.put(6473, "Lab126"); + IDS.put(6481, "Hyperstone GmbH"); + IDS.put(6487, "BIOS Corporation"); + IDS.put(6626, "Solomon Systech Limited"); + IDS.put(6639, "Pak Heng Technology (Shenzhen) Co., Ltd."); + IDS.put(6655, "Best Buy China Ltd."); + IDS.put(6666, "USB-IF non-workshop"); + IDS.put(6709, "Artesyn Technologies Inc."); + IDS.put(6720, "TERMINUS TECHNOLOGY INC."); + IDS.put(6766, "Global Unichip Corp."); + IDS.put(6786, "Proconn Technology Co., Ltd."); + IDS.put(6794, "Simula Technology Inc."); + IDS.put(6795, "SGS Taiwan Ltd."); + IDS.put(6830, "Johnson Component & Equipments Co., Ltd."); + IDS.put(6834, "Allied Vision Technologies GmbH"); + IDS.put(6859, "Salcomp Plc"); + IDS.put(6865, "Desan Wire Co., Ltd."); + IDS.put(6944, "MStar Semiconductor, Inc."); + IDS.put(6984, "Plastron Precision Co., Ltd."); + IDS.put(7013, "The Hong Kong Standards and Testing Centre Ltd."); + IDS.put(7048, "ShenMing Electron (Dong Guan) Co., Ltd."); + IDS.put(7086, "Vuzix Corporation"); + IDS.put(7108, "Ford Motor Co."); + IDS.put(7118, "Contac Cable Industrial Limited"); + IDS.put(7119, "Sunplus Innovation Technology Inc."); + IDS.put(7120, "Hangzhou Riyue Electronics Co., Ltd."); + IDS.put(7158, "Orient Semiconductor Electronics, Ltd."); + IDS.put(7207, "SHENZHEN DNS INDUSTRIES CO., LTD."); + IDS.put(7217, "LS Mtron Ltd."); + IDS.put(7229, "NONIN MEDICAL INC."); + IDS.put(7275, "Philips & Lite-ON Digital Solutions Corporation"); + IDS.put(7310, "ASTRON INTERNATIONAL CORP."); + IDS.put(7320, "ALPINE ELECTRONICS, INC."); + IDS.put(7347, "Aces Electronics Co., Ltd."); + IDS.put(7348, "OPEX CORPORATION"); + IDS.put(7390, "Telecommunications Technology Association (TTA)"); + IDS.put(7434, "Visteon Corporation"); + IDS.put(7465, "Horng Tong Enterprise Co., Ltd."); + IDS.put(7501, "Pegatron Corporation"); + IDS.put(7516, "Fresco Logic Inc."); + IDS.put(7529, "Walta Electronic Co., Ltd."); + IDS.put(7543, "Yueqing Changling Electronic Instrument Corp., Ltd."); + IDS.put(7584, "Parade Technologies, Inc."); + IDS.put(7647, "L&T Technology Services"); + IDS.put(7649, "Actions Microelectronics Co., Ltd."); + IDS.put(7666, "China Telecommunication Technology Labs - Terminals"); + IDS.put(7668, "SHEN ZHEN FORMAN PRECISION INDUSTRY CO., LTD."); + IDS.put(7682, "GLOBEMASTER TECHNOLOGIES CO., LTD."); + IDS.put(7696, "Point Grey Research Inc."); + IDS.put(7751, "HUNG TA H.T.ENTERPRISE CO., LTD."); + IDS.put(7758, "Etron Technology, Inc."); + IDS.put(7795, "COMLINK ELECTRONICS CO., LTD."); + IDS.put(7818, "HIBEST Electronic (DongGuan) Co., Ltd."); + IDS.put(7825, "Other World Computing"); + IDS.put(7863, "WIN WIN PRECISION INDUSTRIAL CO., LTD."); + IDS.put(7879, "Gefen Inc."); + IDS.put(7881, "MOSER BAER INDIA LIMITED"); + IDS.put(7898, "AIRTIES WIRELESS NETWORKS"); + IDS.put(7956, "Astoria Networks GmbH"); + IDS.put(7969, "Scosche Industries"); + IDS.put(7976, "Cal-Comp Electronics & Communications"); + IDS.put(7977, "Analogix Semiconductor, Inc."); + IDS.put(7989, "Amphenol ShouhMin Industry (ShenZhen) Co., Ltd"); + IDS.put(7996, "Chang Yang Electronics Company Ltd."); + IDS.put(8073, "Dongguan Goldconn Electronics Co., Ltd."); + IDS.put(8074, "Morning Star Industrial Co., Ltd."); + IDS.put(8117, "Unify Software and Solutions GmbH & Co. KG"); + IDS.put(8137, "NXP Semiconductors"); + IDS.put(8181, "Changzhou Wujin BEST Electronic Cables Co., Ltd."); + IDS.put(8205, "Belkin Electronic (Changzhou) Co., Ltd."); + IDS.put(8220, "Freeport Resources Enterprises Corp."); + IDS.put(8222, "Qingdao Haier Telecom Co., Ltd."); + IDS.put(8284, "Shenzhen Tronixin Electronics Co., Ltd."); + IDS.put(8294, "Unicorn Electronics Components Co., Ltd."); + IDS.put(8334, "Luxshare-ICT"); + IDS.put(8341, "CE LINK LIMITED"); + IDS.put(8342, "Microconn Electronic Co., Ltd."); + IDS.put(8367, "Shenzhen CARVE Electronics Co., Ltd."); + IDS.put(8382, "BURY GmbH & Co. KG"); + IDS.put(8384, "FENGHUA KINGSUN CO., LTD."); + IDS.put(8386, "Sumitomo Electric Ind., Ltd., Optical Comm. R&D Lab"); + IDS.put(8439, "XIMEA s.r.o."); + IDS.put(8457, "VIA Labs, Inc."); + IDS.put(8492, "Shenzhen Linoya Electronic Co., Ltd."); + IDS.put(8494, "Amphenol AssembleTech (Xiamen) Co., Ltd."); + IDS.put(8524, "Y Soft Corporation"); + IDS.put(8550, "JVC KENWOOD Corporation"); + IDS.put(8564, "Transcend Information, Inc."); + IDS.put(8566, "TMC/Allion Test Labs"); + IDS.put(8613, "Genesis Technology USA, Inc."); + IDS.put(8627, "Dongguan Teconn Electronics Technology Co., Ltd."); + IDS.put(8644, "Netcom Technology (HK) Limited"); + IDS.put(8659, "Compupack Technology Co., Ltd."); + IDS.put(8667, "G-Max Technology Co., Ltd."); + IDS.put(8679, "Sagemcom Broadband SAS"); + IDS.put(8695, "Wuerth-Elektronik eiSos GmbH & Co. KG"); + IDS.put(8707, "Shin Shin Co., Ltd."); + IDS.put(8709, "3eYamaichi Electronics Co., Ltd."); + IDS.put(8710, "Wiretek International Investment Ltd."); + IDS.put(8711, "Fuzhou Rockchip Electronics Co., Ltd."); + IDS.put(8752, "Plugable Technologies"); + IDS.put(8756, "T-CONN PRECISION CORPORATION"); + IDS.put(8831, "Granite River Labs"); + IDS.put(8842, "Hotron Precision Electronic Ind. Corp."); + IDS.put(8875, "Trigence Semiconductor, Inc."); + IDS.put(8888, "Motorola Mobility Inc."); + IDS.put(8904, "Karming Electronic (Shenzhen) Co., Ltd."); + IDS.put(8981, "Avery Design Systems, Inc."); + IDS.put(8993, "iKingdom Corp. (d.b.a. iConnectivity)"); + IDS.put(9051, "KangXiang Electronic Co., Ltd."); + IDS.put(9068, "ZheJiang Chunsheng Electronics Co., Ltd."); + IDS.put(9130, "DOK (HK) Trading Limited"); + IDS.put(9132, "Marunix Electron Limited"); + IDS.put(9165, "Avconn Precise Connector Co., Ltd."); + IDS.put(9184, "BitifEye Digital Test Solutions GmbH"); + IDS.put(9205, "Speed Conn Co., Ltd."); + IDS.put(9222, "INSIDE Secure"); + IDS.put(9292, "Minebea Co., Ltd."); + IDS.put(9299, "BAANTO"); + IDS.put(9338, "Suzhou Jutze Technologies Co., Ltd"); + IDS.put(9355, "DONGGUAN SYNCONN PRECISION INDUSTRY CO. LTD."); + IDS.put(9382, "Shenzhen Pangngai Industrial Co., Ltd."); + IDS.put(9422, "Shenzhen Deren Electronic Co., Ltd."); + IDS.put(9424, "Smith Micro Software, Inc."); + IDS.put(9453, "ZEN FACTORY GROUP (ASIA) LTD."); + IDS.put(9481, "Chain-In Electronic Co., Ltd."); + IDS.put(9514, "SUZHOU KELI TECHNOLOGY DEVELOPMENT CO., LTD."); + IDS.put(9515, "TOP Exactitude Industry (ShenZhen) Co., Ltd."); + IDS.put(9525, "ShenZhen Hogend Precision Technology Co., Ltd."); + IDS.put(9527, "Norel Systems Ltd."); + IDS.put(9556, "ASSA ABLOY AB"); + IDS.put(9575, "DongGuan LongTao Electronic Co., Ltd."); + IDS.put(9577, "DongGuan City MingJi Electronics Co., Ltd."); + IDS.put(9589, "Weida Hi-Tech Co., Ltd."); + IDS.put(9593, "Dongguan Wisechamp Electronic Co., Ltd."); + IDS.put(9613, "Sequans Communications"); + IDS.put(9636, "ALGOLTEK, INC."); + IDS.put(9651, "DongGuan Elinke Industrial Co., Ltd."); + IDS.put(9679, "Corning Optical Communications LLC"); + IDS.put(9714, "Dongguan Jinyue Electronics Co., Ltd."); + IDS.put(9723, "RICOH IMAGING COMPANY, LTD."); + IDS.put(9742, "DongGuan HYX Industrial Co., Ltd."); + IDS.put(9753, "Advanced Silicon SA"); + IDS.put(9756, "EISST Limited"); + IDS.put(9771, "YTOP Electronics Technical (Kunshan) Co., Ltd."); + IDS.put(9841, "Innovative Logic"); + IDS.put(9842, "GoPro"); + IDS.put(9846, "Basler AG"); + IDS.put(9851, "Palpilot International Corp."); + IDS.put(9896, "UNIREX CORPORATION"); + IDS.put(9917, "Integral Memory Plc."); + IDS.put(9973, "Morning Star Digital Connector Co., Ltd."); + IDS.put(9984, "MITACHI CO., LTD."); + IDS.put(9999, "HGST, a Western Digital Company"); + } +} diff --git a/libusbcamera/src/main/java/com/serenegiant/usb/UVCCamera.java b/libusbcamera/src/main/java/com/serenegiant/usb/UVCCamera.java new file mode 100644 index 0000000..6dd30e2 --- /dev/null +++ b/libusbcamera/src/main/java/com/serenegiant/usb/UVCCamera.java @@ -0,0 +1,1238 @@ +/* + * 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.serenegiant.usb; + +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; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import java.util.ArrayList; +import java.util.List; + +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 = 640; + public static final int DEFAULT_PREVIEW_HEIGHT = 480; + public static final int DEFAULT_PREVIEW_MODE = 0; + public static final int DEFAULT_PREVIEW_MIN_FPS = 1; + public static final int DEFAULT_PREVIEW_MAX_FPS = 30; + 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("jpeg-turbo1500"); + System.loadLibrary("usb100"); + System.loadLibrary("uvc"); + System.loadLibrary("UVCCamera"); + isLoaded = true; + } + } + + private UsbControlBlock mCtrlBlock; + protected long mControlSupports; // カメラコントロールでサポートしている機能フラグ + protected long mProcSupports; // プロセッシングユニットでサポートしている機能フラグ + protected int mCurrentFrameFormat = FRAME_FORMAT_MJPEG; + protected int mCurrentWidth = DEFAULT_PREVIEW_WIDTH, mCurrentHeight = DEFAULT_PREVIEW_HEIGHT; + protected float mCurrentBandwidthFactor = DEFAULT_BANDWIDTH; + protected String mSupportedSize; + protected List mCurrentSizeList; + // 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 synchronized void open(final UsbControlBlock ctrlBlock) { + int result = -2; + StringBuilder sb = new StringBuilder(); + try { + mCtrlBlock = ctrlBlock.clone(); + result = nativeConnect(mNativePtr, + mCtrlBlock.getVenderId(), mCtrlBlock.getProductId(), + mCtrlBlock.getFileDescriptor(), + mCtrlBlock.getBusNum(), + mCtrlBlock.getDevNum(), + getUSBFSName(mCtrlBlock)); + sb.append("调用nativeConnect返回值:"+result); +// long id_camera, int venderId, int productId, int fileDescriptor, int busNum, int devAddr, String usbfs + } catch (final Exception e) { + Log.w(TAG, e); + for(int i = 0; i< e.getStackTrace().length; i++){ + sb.append(e.getStackTrace()[i].toString()); + sb.append("\n"); + } + sb.append("core message ->"+e.getLocalizedMessage()); + result = -1; + } + + if (result != 0) { + throw new UnsupportedOperationException("open failed:result=" + result+"----->" + + "id_camera="+mNativePtr+";venderId="+mCtrlBlock.getVenderId() + +";productId="+mCtrlBlock.getProductId()+";fileDescriptor="+mCtrlBlock.getFileDescriptor() + +";busNum="+mCtrlBlock.getBusNum()+";devAddr="+mCtrlBlock.getDevNum() + +";usbfs="+getUSBFSName(mCtrlBlock)+"\n"+"Exception:"+sb.toString()); + } + + if (mNativePtr != 0 && TextUtils.isEmpty(mSupportedSize)) { + mSupportedSize = nativeGetSupportedSize(mNativePtr); + } + nativeSetPreviewSize(mNativePtr, DEFAULT_PREVIEW_WIDTH, DEFAULT_PREVIEW_HEIGHT, + DEFAULT_PREVIEW_MIN_FPS, DEFAULT_PREVIEW_MAX_FPS, 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 synchronized void close() { + stopPreview(); + if (mNativePtr != 0) { + nativeRelease(mNativePtr); +// mNativePtr = 0; // nativeDestroyを呼ぶのでここでクリアしちゃダメ + } + if (mCtrlBlock != null) { + mCtrlBlock.close(); + mCtrlBlock = null; + } + mControlSupports = mProcSupports = 0; + mCurrentFrameFormat = -1; + mCurrentBandwidthFactor = 0; + mSupportedSize = null; + mCurrentSizeList = null; + if (DEBUG) Log.v(TAG, "close:finished"); + } + + 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 list = getSupportedSizeList(); + for (final Size sz: list) { + if ((sz.width == mCurrentWidth) + || (sz.height == mCurrentHeight)) { + result =sz; + break; + } + } + return result; + } + + /** + * Set preview size and preview mode + * @param width + @param height + */ + public void setPreviewSize(final int width, final int height) { + setPreviewSize(width, height, DEFAULT_PREVIEW_MIN_FPS, DEFAULT_PREVIEW_MAX_FPS, mCurrentFrameFormat, mCurrentBandwidthFactor); + } + + /** + * Set preview size and preview mode + * @param width + * @param height + * @param frameFormat either FRAME_FORMAT_YUYV(0) or FRAME_FORMAT_MJPEG(1) + */ + public void setPreviewSize(final int width, final int height, final int frameFormat) { + setPreviewSize(width, height, DEFAULT_PREVIEW_MIN_FPS, DEFAULT_PREVIEW_MAX_FPS, frameFormat, mCurrentBandwidthFactor); + } + + /** + * Set preview size and preview mode + * @param width + @param height + @param frameFormat either FRAME_FORMAT_YUYV(0) or FRAME_FORMAT_MJPEG(1) + @param bandwidth [0.0f,1.0f] + */ + public void setPreviewSize(final int width, final int height, final int frameFormat, final float bandwidth) { + setPreviewSize(width, height, DEFAULT_PREVIEW_MIN_FPS, DEFAULT_PREVIEW_MAX_FPS, frameFormat, bandwidth); + } + + /** + * Set preview size and preview mode + * @param width + * @param height + * @param min_fps + * @param max_fps + * @param frameFormat either FRAME_FORMAT_YUYV(0) or FRAME_FORMAT_MJPEG(1) + * @param bandwidthFactor + */ + public void setPreviewSize(final int width, final int height, final int min_fps, final int max_fps, final int frameFormat, final float bandwidthFactor) { + if ((width == 0) || (height == 0)) + throw new IllegalArgumentException("invalid preview size"); + if (mNativePtr != 0) { + final int result = nativeSetPreviewSize(mNativePtr, width, height, min_fps, max_fps, frameFormat, bandwidthFactor); + if (result != 0) + throw new IllegalArgumentException("Failed to set preview size"); + mCurrentFrameFormat = frameFormat; + mCurrentWidth = width; + mCurrentHeight = height; + mCurrentBandwidthFactor = bandwidthFactor; + } + } + + public List getSupportedSizeList() { + final int type = (mCurrentFrameFormat > 0) ? 6 : 4; + return getSupportedSize(type, mSupportedSize); + } + + public static List getSupportedSize(final int type, final String supportedSize) { + final List result = new ArrayList(); + 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); + if(format.has("type") && format.has("size")) { + final int format_type = format.getInt("type"); + if ((format_type == type) || (type == -1)) { + addSize(format, format_type, 0, result); + } + } + } + } catch (final JSONException e) { + e.printStackTrace(); + } + return result; + } + + private static final void addSize(final JSONObject format, final int formatType, final int frameType, final List 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(formatType, frameType, j, Integer.parseInt(sz[0]), Integer.parseInt(sz[1]))); + } catch (final Exception e) { + break; + } + } + } + + /** + * set preview surface with SurfaceHolder
+ * you can use SurfaceHolder came from SurfaceView/GLSurfaceView + * @param holder + */ + public synchronized void setPreviewDisplay(final SurfaceHolder holder) { + nativeSetPreviewDisplay(mNativePtr, holder.getSurface()); + } + + /** + * set preview surface with SurfaceTexture. + * this method require API >= 14 + * @param texture + */ + public synchronized 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 synchronized 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 synchronized void startPreview() { + if (mCtrlBlock != null) { + nativeStartPreview(mNativePtr); + } + } + + /** + * stop preview + */ + public synchronized void stopPreview() { + setFrameCallback(null, 0); + if (mCtrlBlock != null) { + nativeStopPreview(mNativePtr); + } + } + + /** + * destroy UVCCamera object + */ + public synchronized 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 focus[%] + */ + 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 final native int nativeConnect(long id_camera, int venderId, int productId, int fileDescriptor, int busNum, int devAddr, 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 min_fps, final int max_fps, 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); +} diff --git a/libusbcamera/src/main/jniLibs/armeabi-v7a/libUVCCamera.so b/libusbcamera/src/main/jniLibs/armeabi-v7a/libUVCCamera.so new file mode 100644 index 0000000..a88d6f8 Binary files /dev/null and b/libusbcamera/src/main/jniLibs/armeabi-v7a/libUVCCamera.so differ diff --git a/libusbcamera/src/main/jniLibs/armeabi-v7a/libjpeg-turbo1500.so b/libusbcamera/src/main/jniLibs/armeabi-v7a/libjpeg-turbo1500.so new file mode 100644 index 0000000..65b46b0 Binary files /dev/null and b/libusbcamera/src/main/jniLibs/armeabi-v7a/libjpeg-turbo1500.so differ diff --git a/libusbcamera/src/main/jniLibs/armeabi-v7a/libusb100.so b/libusbcamera/src/main/jniLibs/armeabi-v7a/libusb100.so new file mode 100644 index 0000000..b4ba0a0 Binary files /dev/null and b/libusbcamera/src/main/jniLibs/armeabi-v7a/libusb100.so differ diff --git a/libusbcamera/src/main/jniLibs/armeabi-v7a/libuvc.so b/libusbcamera/src/main/jniLibs/armeabi-v7a/libuvc.so new file mode 100644 index 0000000..37455fe Binary files /dev/null and b/libusbcamera/src/main/jniLibs/armeabi-v7a/libuvc.so differ diff --git a/libusbcamera/src/main/jniLibs/armeabi/libUVCCamera.so b/libusbcamera/src/main/jniLibs/armeabi/libUVCCamera.so new file mode 100644 index 0000000..ba285a7 Binary files /dev/null and b/libusbcamera/src/main/jniLibs/armeabi/libUVCCamera.so differ diff --git a/libusbcamera/src/main/jniLibs/armeabi/libjpeg-turbo1500.so b/libusbcamera/src/main/jniLibs/armeabi/libjpeg-turbo1500.so new file mode 100644 index 0000000..348ab5f Binary files /dev/null and b/libusbcamera/src/main/jniLibs/armeabi/libjpeg-turbo1500.so differ diff --git a/libusbcamera/src/main/jniLibs/armeabi/libusb100.so b/libusbcamera/src/main/jniLibs/armeabi/libusb100.so new file mode 100644 index 0000000..63ce300 Binary files /dev/null and b/libusbcamera/src/main/jniLibs/armeabi/libusb100.so differ diff --git a/libusbcamera/src/main/jniLibs/armeabi/libuvc.so b/libusbcamera/src/main/jniLibs/armeabi/libuvc.so new file mode 100644 index 0000000..f92428a Binary files /dev/null and b/libusbcamera/src/main/jniLibs/armeabi/libuvc.so differ diff --git a/libusbcamera/src/main/jniLibs/mips/libUVCCamera.so b/libusbcamera/src/main/jniLibs/mips/libUVCCamera.so new file mode 100644 index 0000000..cb25100 Binary files /dev/null and b/libusbcamera/src/main/jniLibs/mips/libUVCCamera.so differ diff --git a/libusbcamera/src/main/jniLibs/mips/libjpeg-turbo1500.so b/libusbcamera/src/main/jniLibs/mips/libjpeg-turbo1500.so new file mode 100644 index 0000000..af82255 Binary files /dev/null and b/libusbcamera/src/main/jniLibs/mips/libjpeg-turbo1500.so differ diff --git a/libusbcamera/src/main/jniLibs/mips/libusb100.so b/libusbcamera/src/main/jniLibs/mips/libusb100.so new file mode 100644 index 0000000..730dd5f Binary files /dev/null and b/libusbcamera/src/main/jniLibs/mips/libusb100.so differ diff --git a/libusbcamera/src/main/jniLibs/mips/libuvc.so b/libusbcamera/src/main/jniLibs/mips/libuvc.so new file mode 100644 index 0000000..9958d95 Binary files /dev/null and b/libusbcamera/src/main/jniLibs/mips/libuvc.so differ diff --git a/libusbcamera/src/main/jniLibs/x86/libUVCCamera.so b/libusbcamera/src/main/jniLibs/x86/libUVCCamera.so new file mode 100644 index 0000000..d5f9034 Binary files /dev/null and b/libusbcamera/src/main/jniLibs/x86/libUVCCamera.so differ diff --git a/libusbcamera/src/main/jniLibs/x86/libjpeg-turbo1500.so b/libusbcamera/src/main/jniLibs/x86/libjpeg-turbo1500.so new file mode 100644 index 0000000..46c87b5 Binary files /dev/null and b/libusbcamera/src/main/jniLibs/x86/libjpeg-turbo1500.so differ diff --git a/libusbcamera/src/main/jniLibs/x86/libusb100.so b/libusbcamera/src/main/jniLibs/x86/libusb100.so new file mode 100644 index 0000000..12f636e Binary files /dev/null and b/libusbcamera/src/main/jniLibs/x86/libusb100.so differ diff --git a/libusbcamera/src/main/jniLibs/x86/libuvc.so b/libusbcamera/src/main/jniLibs/x86/libuvc.so new file mode 100644 index 0000000..6889634 Binary files /dev/null and b/libusbcamera/src/main/jniLibs/x86/libuvc.so differ diff --git a/libusbcamera/src/main/res/layout/dialog_camera.xml b/libusbcamera/src/main/res/layout/dialog_camera.xml new file mode 100644 index 0000000..3d25643 --- /dev/null +++ b/libusbcamera/src/main/res/layout/dialog_camera.xml @@ -0,0 +1,31 @@ + + + + + + + + + + \ No newline at end of file diff --git a/libusbcamera/src/main/res/layout/listitem_device.xml b/libusbcamera/src/main/res/layout/listitem_device.xml new file mode 100644 index 0000000..903baff --- /dev/null +++ b/libusbcamera/src/main/res/layout/listitem_device.xml @@ -0,0 +1,10 @@ + + + + + \ No newline at end of file diff --git a/libusbcamera/src/main/res/values/dimens.xml b/libusbcamera/src/main/res/values/dimens.xml new file mode 100644 index 0000000..997fea8 --- /dev/null +++ b/libusbcamera/src/main/res/values/dimens.xml @@ -0,0 +1,30 @@ + + + + 16dp + 16dp + 48dp + 18sp + 32dp + diff --git a/libusbcamera/src/main/res/values/strings.xml b/libusbcamera/src/main/res/values/strings.xml new file mode 100644 index 0000000..c7a70e8 --- /dev/null +++ b/libusbcamera/src/main/res/values/strings.xml @@ -0,0 +1,7 @@ + + libusbcamera + 请选择USB摄像头 + 刷新 + Camera + 未搜索到可用USB Camera设备 + diff --git a/libusbcamera/src/main/res/xml/device_filter.xml b/libusbcamera/src/main/res/xml/device_filter.xml new file mode 100644 index 0000000..da573ff --- /dev/null +++ b/libusbcamera/src/main/res/xml/device_filter.xml @@ -0,0 +1,28 @@ + + + + + + + diff --git a/libusbcamera/src/test/java/com/jiangdg/libusbcamera/ExampleUnitTest.java b/libusbcamera/src/test/java/com/jiangdg/libusbcamera/ExampleUnitTest.java new file mode 100644 index 0000000..cea7b86 --- /dev/null +++ b/libusbcamera/src/test/java/com/jiangdg/libusbcamera/ExampleUnitTest.java @@ -0,0 +1,17 @@ +package com.jiangdg.libusbcamera; + +import org.junit.Test; + +import static org.junit.Assert.*; + +/** + * Example local unit test, which will execute on the development machine (host). + * + * @see Testing documentation + */ +public class ExampleUnitTest { + @Test + public void addition_isCorrect() throws Exception { + assertEquals(4, 2 + 2); + } +} \ No newline at end of file diff --git a/local.properties b/local.properties new file mode 100644 index 0000000..3ec53d5 --- /dev/null +++ b/local.properties @@ -0,0 +1,10 @@ +## This file is automatically generated by Android Studio. +# Do not modify this file -- YOUR CHANGES WILL BE ERASED! +# +# This file should *NOT* be checked into Version Control Systems, +# as it contains information specific to your local configuration. +# +# Location of the SDK. This is only used by Gradle. +# For customization when using a Version Control System, please read the +# header note. +sdk.dir=E\:\\Environment\\android-sdk-windows \ No newline at end of file diff --git a/settings.gradle b/settings.gradle new file mode 100644 index 0000000..24630ca --- /dev/null +++ b/settings.gradle @@ -0,0 +1 @@ +include ':app', ':libusbcamera'