diff --git a/include/mynteye/mynteye.h.in b/include/mynteye/mynteye.h.in index 7872768..50b55f9 100644 --- a/include/mynteye/mynteye.h.in +++ b/include/mynteye/mynteye.h.in @@ -27,9 +27,9 @@ # endif #endif -#define MYNTEYE_API_VERSION_MAJOR @PROJECT_VERSION_MAJOR@ -#define MYNTEYE_API_VERSION_MINOR @PROJECT_VERSION_MINOR@ -#define MYNTEYE_API_VERSION_PATCH @PROJECT_VERSION_PATCH@ +#define MYNTEYE_API_VERSION_MAJOR @mynteye_VERSION_MAJOR@ +#define MYNTEYE_API_VERSION_MINOR @mynteye_VERSION_MINOR@ +#define MYNTEYE_API_VERSION_PATCH @mynteye_VERSION_PATCH@ /* MYNTEYE_API_VERSION is (major << 16) + (minor << 8) + patch */ #define MYNTEYE_API_VERSION \ diff --git a/wrappers/android/mynteye/app/src/main/AndroidManifest.xml b/wrappers/android/mynteye/app/src/main/AndroidManifest.xml index 3633dae..5072b22 100644 --- a/wrappers/android/mynteye/app/src/main/AndroidManifest.xml +++ b/wrappers/android/mynteye/app/src/main/AndroidManifest.xml @@ -14,7 +14,8 @@ android:supportsRtl="true" android:theme="@style/AppTheme" tools:ignore="GoogleAppIndexingWarning"> - + diff --git a/wrappers/android/mynteye/app/src/main/java/com/slightech/mynteye/demo/ui/MainActivity.java b/wrappers/android/mynteye/app/src/main/java/com/slightech/mynteye/demo/ui/MainActivity.java index 55c422c..cfa4742 100644 --- a/wrappers/android/mynteye/app/src/main/java/com/slightech/mynteye/demo/ui/MainActivity.java +++ b/wrappers/android/mynteye/app/src/main/java/com/slightech/mynteye/demo/ui/MainActivity.java @@ -2,8 +2,11 @@ package com.slightech.mynteye.demo.ui; import android.graphics.Bitmap; import android.graphics.BitmapFactory; +import android.hardware.usb.UsbDevice; import android.os.Bundle; import android.os.Handler; +import android.text.TextUtils; +import android.util.Log; import android.view.Menu; import android.view.MenuItem; import android.widget.ArrayAdapter; @@ -12,6 +15,7 @@ import android.widget.ListView; import android.widget.TextView; import android.widget.Toast; import androidx.appcompat.app.AlertDialog; +import androidx.fragment.app.FragmentActivity; import butterknife.BindView; import butterknife.ButterKnife; import com.slightech.mynteye.Device; @@ -24,18 +28,24 @@ import com.slightech.mynteye.StreamRequest; import com.slightech.mynteye.demo.R; import com.slightech.mynteye.demo.camera.Mynteye; import com.slightech.mynteye.demo.util.RootUtils; +import com.slightech.mynteye.usb.CameraDialog; +import com.slightech.mynteye.usb.USBMonitor; +import com.slightech.mynteye.usb.USBMonitor.OnDeviceConnectListener; +import com.slightech.mynteye.usb.USBMonitor.UsbControlBlock; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.Locale; import timber.log.Timber; -public class MainActivity extends BaseActivity implements Mynteye.OnStreamDataReceiveListener, - Mynteye.OnMotionDataReceiveListener{ +public class MainActivity extends BaseActivity implements CameraDialog.CameraDialogParent, + Mynteye.OnStreamDataReceiveListener, Mynteye.OnMotionDataReceiveListener { @BindView(R.id.text) TextView mTextView; @BindView(R.id.image_left) ImageView mLeftImageView; @BindView(R.id.image_right) ImageView mRightImageView; + private USBMonitor mUSBMonitor; + private Mynteye mMynteye; private Bitmap mLeftBitmap, mRightBitmap; @@ -44,8 +54,92 @@ public class MainActivity extends BaseActivity implements Mynteye.OnStreamDataRe super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ButterKnife.bind(this); + + mUSBMonitor = new USBMonitor(this, mOnDeviceConnectListener); } + @Override + protected void onStart() { + super.onStart(); + mUSBMonitor.register(); + } + + @Override + protected void onStop() { + super.onStop(); + if (mUSBMonitor != null) { + mUSBMonitor.unregister(); + } + } + + @Override + protected void onDestroy() { + if (mMynteye != null) { + mMynteye.close(); + mMynteye = null; + } + if (mUSBMonitor != null) { + mUSBMonitor.destroy(); + mUSBMonitor = null; + } + super.onDestroy(); + } + + private final OnDeviceConnectListener mOnDeviceConnectListener = new OnDeviceConnectListener() { + + @Override + public void onAttach(final UsbDevice device) { + toast("USB_DEVICE_ATTACHED"); + } + + @Override + public void onConnect(final UsbDevice device, final UsbControlBlock ctrlBlock, final boolean createNew) { + toast(String.format(Locale.getDefault(), "CONNECT, %s: %s", ctrlBlock.getProductName(), ctrlBlock.getSerial())); + openDevice(new DeviceUsbInfo( + ctrlBlock.getVenderId(), + ctrlBlock.getProductId(), + ctrlBlock.getFileDescriptor(), + ctrlBlock.getBusNum(), + ctrlBlock.getDevNum(), + getUSBFSName(ctrlBlock), + ctrlBlock.getProductName(), + ctrlBlock.getSerial())); + } + + @Override + public void onDisconnect(final UsbDevice device, final UsbControlBlock ctrlBlock) { + toast(String.format(Locale.getDefault(), "DISCONNECT, %s: %s", ctrlBlock.getProductName(), ctrlBlock.getSerial())); + } + + @Override + public void onDetach(final UsbDevice device) { + toast("USB_DEVICE_DETACHED"); + } + + @Override + public void onCancel(final UsbDevice device) { + } + + private static final String DEFAULT_USBFS = "/dev/bus/usb"; + + 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)) { + Timber.w("failed to get USBFS path, try to use default path: %s", name); + result = DEFAULT_USBFS; + } + return result; + } + }; + @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.menu_main, menu); @@ -70,6 +164,9 @@ public class MainActivity extends BaseActivity implements Mynteye.OnStreamDataRe } private void actionOpen(final Runnable completeEvent) { + if (completeEvent != null) completeEvent.run(); + CameraDialog.showDialog(this); + /* if (!RootUtils.isRooted()) { if (completeEvent != null) completeEvent.run(); alert("Warning", "Root denied :("); @@ -84,8 +181,10 @@ public class MainActivity extends BaseActivity implements Mynteye.OnStreamDataRe alert("Warning", "There are no devices accessible."); } }); + */ } + /* private void showDevices() { ArrayList infos = Device.query(); if (infos.isEmpty()) { @@ -110,6 +209,7 @@ public class MainActivity extends BaseActivity implements Mynteye.OnStreamDataRe dialog.show(); } } + */ private void openDevice(DeviceUsbInfo info) { mMynteye = new Mynteye(info); @@ -138,6 +238,15 @@ public class MainActivity extends BaseActivity implements Mynteye.OnStreamDataRe } } + @Override + public USBMonitor getUSBMonitor() { + return mUSBMonitor; + } + + @Override + public void onDialogResult(boolean canceled) { + } + @Override public void onStreamDataReceive(Stream stream, StreamData data, Handler handler) { } @@ -182,15 +291,6 @@ public class MainActivity extends BaseActivity implements Mynteye.OnStreamDataRe mTextView.post(() -> mTextView.setText(datas.get(0).imu().toString())); } - @Override - protected void onDestroy() { - if (mMynteye != null) { - mMynteye.close(); - mMynteye = null; - } - super.onDestroy(); - } - private void toast(CharSequence text) { Toast.makeText(this, text, Toast.LENGTH_LONG).show(); } diff --git a/wrappers/android/mynteye/app/src/main/res/layout/activity_main.xml b/wrappers/android/mynteye/app/src/main/res/layout/activity_main.xml index ecf855f..c7cbd70 100644 --- a/wrappers/android/mynteye/app/src/main/res/layout/activity_main.xml +++ b/wrappers/android/mynteye/app/src/main/res/layout/activity_main.xml @@ -5,6 +5,7 @@ xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" + android:orientation="horizontal" tools:context=".ui.MainActivity" > @@ -15,32 +16,44 @@ android:layout_marginEnd="8dp" android:layout_marginStart="8dp" android:text="Hello World!" - app:layout_constraintBottom_toTopOf="@+id/image_left" + app:layout_constraintBottom_toTopOf="@id/layout_image" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> - - - + app:layout_constraintTop_toBottomOf="@id/text" + > - \ No newline at end of file + + + + + + + diff --git a/wrappers/android/mynteye/libmynteye/CMakeLists.txt b/wrappers/android/mynteye/libmynteye/CMakeLists.txt index 4f84689..eefcdad 100644 --- a/wrappers/android/mynteye/libmynteye/CMakeLists.txt +++ b/wrappers/android/mynteye/libmynteye/CMakeLists.txt @@ -37,6 +37,13 @@ add_library(djinni_jni STATIC ${DJINNI_DIR}/support-lib/jni/djinni_support.cpp ) +## mynteye_internal + +add_library(mynteye_internal SHARED IMPORTED) +set_target_properties(mynteye_internal PROPERTIES + IMPORTED_LOCATION "${LIB_ROOT}/src/main/jniLibs/${ANDROID_ABI}/libmynteye_internal.so" +) + # targets ## libmynteye @@ -52,7 +59,7 @@ configure_file( ) set(MYNTEYE_SRCS - ${MYNTETE_ROOT}/src/mynteye/uvc/linux/uvc-v4l2.cc + #${MYNTETE_ROOT}/src/mynteye/uvc/linux/uvc-v4l2.cc ${MYNTETE_ROOT}/src/mynteye/types.cc ${MYNTETE_ROOT}/src/mynteye/util/files.cc ${MYNTETE_ROOT}/src/mynteye/util/strings.cc @@ -110,4 +117,4 @@ add_library(mynteye_jni SHARED ${DJINNI_DIR}/support-lib/jni/djinni_main.cpp ${MYNTEYE_JNI_SRCS} ) -target_link_libraries(mynteye_jni ${log-lib} djinni_jni mynteye) +target_link_libraries(mynteye_jni ${log-lib} djinni_jni mynteye mynteye_internal) diff --git a/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/cpp/device.hpp b/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/cpp/device.hpp index 63fb43e..b36fa90 100644 --- a/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/cpp/device.hpp +++ b/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/cpp/device.hpp @@ -20,9 +20,6 @@ class Device { public: virtual ~Device() {} - /** Query devices */ - static std::vector<::mynteye_jni::DeviceUsbInfo> Query(); - /** Create the device instance */ static std::shared_ptr Create(const ::mynteye_jni::DeviceUsbInfo & info); diff --git a/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/cpp/device_usb_info.hpp b/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/cpp/device_usb_info.hpp index 3ba215d..fc48e36 100644 --- a/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/cpp/device_usb_info.hpp +++ b/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/cpp/device_usb_info.hpp @@ -11,19 +11,39 @@ namespace mynteye_jni { /** Device USB information */ struct DeviceUsbInfo final { - /** Device index */ - int32_t index; - /** Device name */ + /** Vendor id */ + int32_t vid; + /** Product id */ + int32_t pid; + /** File descriptor */ + int32_t fd; + /** Bus number */ + int32_t bus_num; + /** Dev number */ + int32_t dev_num; + /** Usb file system path */ + std::string usb_fs; + /** Product name */ std::string name; - /** Device serial number */ - std::string sn; + /** Serial number */ + std::string serial; - DeviceUsbInfo(int32_t index_, + DeviceUsbInfo(int32_t vid_, + int32_t pid_, + int32_t fd_, + int32_t bus_num_, + int32_t dev_num_, + std::string usb_fs_, std::string name_, - std::string sn_) - : index(std::move(index_)) + std::string serial_) + : vid(std::move(vid_)) + , pid(std::move(pid_)) + , fd(std::move(fd_)) + , bus_num(std::move(bus_num_)) + , dev_num(std::move(dev_num_)) + , usb_fs(std::move(usb_fs_)) , name(std::move(name_)) - , sn(std::move(sn_)) + , serial(std::move(serial_)) {} }; diff --git a/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/impl/device_impl.cpp b/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/impl/device_impl.cpp index b00e49e..a5e4ee0 100644 --- a/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/impl/device_impl.cpp +++ b/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/impl/device_impl.cpp @@ -12,10 +12,14 @@ #include "motion_data_impl.hpp" #include "stream_data_impl.hpp" +#include "mynteye/uvc/uvc.h" +#include "internal/uvc_device.h" + MYNTEYE_USE_NAMESPACE namespace mynteye_jni { +/* std::vector<::mynteye_jni::DeviceUsbInfo> Device::Query() { VLOG(2) << __func__; std::vector infos; @@ -44,6 +48,19 @@ std::shared_ptr Device::Create(const ::mynteye_jni::DeviceUsbInfo & info } return nullptr; } +*/ + +std::shared_ptr Device::Create(const ::mynteye_jni::DeviceUsbInfo & info) { + VLOG(2) << __func__; + auto device = uvc::create_device(from_jni(info)); + auto name = uvc::get_name(*device); + auto vid = uvc::get_vendor_id(*device); + auto pid = uvc::get_product_id(*device); + VLOG(2) << "UVC device detected, name: " << name << ", vid: 0x" << std::hex + << vid << ", pid: 0x" << std::hex << pid; + return std::make_shared( + MYNTEYE_NAMESPACE::Device::Create(name, device)); +} DeviceImpl::DeviceImpl(const device_t & device) : Device(), device_(device) { VLOG(2) << __func__; diff --git a/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/impl/internal/usb_info.h b/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/impl/internal/usb_info.h new file mode 100644 index 0000000..c2d44e9 --- /dev/null +++ b/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/impl/internal/usb_info.h @@ -0,0 +1,24 @@ +#pragma once + +#include "mynteye/mynteye.h" + +#include +#include + +MYNTEYE_BEGIN_NAMESPACE + +struct MYNTEYE_API UsbInfo { + int vid; + int pid; + int fd; + int busnum; + int devaddr; + std::string usbfs; + std::string name; + std::string serial; +}; + +MYNTEYE_API void set_usb_infos(const std::vector &infos); +MYNTEYE_API std::vector get_usb_infos(); + +MYNTEYE_END_NAMESPACE diff --git a/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/impl/internal/uvc_device.h b/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/impl/internal/uvc_device.h new file mode 100644 index 0000000..0e5b9ed --- /dev/null +++ b/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/impl/internal/uvc_device.h @@ -0,0 +1,15 @@ +#pragma once + +#include "usb_info.h" + +MYNTEYE_BEGIN_NAMESPACE + +namespace uvc { + +struct device; + +MYNTEYE_API std::shared_ptr create_device(UsbInfo info); + +} // namespace uvc + +MYNTEYE_END_NAMESPACE diff --git a/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/impl/type_conversion.hpp b/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/impl/type_conversion.hpp index f4b600b..b68c6b7 100644 --- a/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/impl/type_conversion.hpp +++ b/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/impl/type_conversion.hpp @@ -5,11 +5,14 @@ #include "mynteye/logger.h" #include "mynteye/types.h" +#include "device_usb_info.hpp" #include "format.hpp" #include "model.hpp" #include "source.hpp" #include "stream.hpp" +#include "internal/usb_info.h" + namespace mynteye_jni { using RawModel = MYNTEYE_NAMESPACE::Model; @@ -112,4 +115,35 @@ JniStream to_jni(const RawStream& stream) { } } +using RawUsbInfo = MYNTEYE_NAMESPACE::UsbInfo; +using JniUsbInfo = mynteye_jni::DeviceUsbInfo; + +inline +RawUsbInfo from_jni(const JniUsbInfo& info) { + RawUsbInfo raw; + raw.vid = info.vid; + raw.pid = info.pid; + raw.fd = info.fd; + raw.busnum = info.bus_num; + raw.devaddr = info.dev_num; + raw.usbfs = info.usb_fs; + raw.name = info.name; + raw.serial = info.serial; + return std::move(raw); +} + +inline +JniUsbInfo to_jni(const RawUsbInfo& info) { + return JniUsbInfo{ + info.vid, + info.pid, + info.fd, + info.busnum, + info.devaddr, + info.usbfs, + info.name, + info.serial, + }; +} + } // namespace mynteye_jni diff --git a/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/jni/NativeDevice.cpp b/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/jni/NativeDevice.cpp index bc12a52..178c70f 100644 --- a/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/jni/NativeDevice.cpp +++ b/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/jni/NativeDevice.cpp @@ -25,15 +25,6 @@ CJNIEXPORT void JNICALL Java_com_slightech_mynteye_Device_00024CppProxy_nativeDe } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, ) } -CJNIEXPORT jobject JNICALL Java_com_slightech_mynteye_Device_00024CppProxy_query(JNIEnv* jniEnv, jobject /*this*/) -{ - try { - DJINNI_FUNCTION_PROLOGUE0(jniEnv); - auto r = ::mynteye_jni::Device::Query(); - return ::djinni::release(::djinni::List<::djinni_generated::NativeDeviceUsbInfo>::fromCpp(jniEnv, r)); - } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */) -} - CJNIEXPORT jobject JNICALL Java_com_slightech_mynteye_Device_00024CppProxy_create(JNIEnv* jniEnv, jobject /*this*/, ::djinni_generated::NativeDeviceUsbInfo::JniType j_info) { try { diff --git a/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/jni/NativeDeviceUsbInfo.cpp b/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/jni/NativeDeviceUsbInfo.cpp index b26ee82..fbc535d 100644 --- a/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/jni/NativeDeviceUsbInfo.cpp +++ b/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/jni/NativeDeviceUsbInfo.cpp @@ -13,20 +13,30 @@ NativeDeviceUsbInfo::~NativeDeviceUsbInfo() = default; auto NativeDeviceUsbInfo::fromCpp(JNIEnv* jniEnv, const CppType& c) -> ::djinni::LocalRef { const auto& data = ::djinni::JniClass::get(); auto r = ::djinni::LocalRef{jniEnv->NewObject(data.clazz.get(), data.jconstructor, - ::djinni::get(::djinni::I32::fromCpp(jniEnv, c.index)), + ::djinni::get(::djinni::I32::fromCpp(jniEnv, c.vid)), + ::djinni::get(::djinni::I32::fromCpp(jniEnv, c.pid)), + ::djinni::get(::djinni::I32::fromCpp(jniEnv, c.fd)), + ::djinni::get(::djinni::I32::fromCpp(jniEnv, c.bus_num)), + ::djinni::get(::djinni::I32::fromCpp(jniEnv, c.dev_num)), + ::djinni::get(::djinni::String::fromCpp(jniEnv, c.usb_fs)), ::djinni::get(::djinni::String::fromCpp(jniEnv, c.name)), - ::djinni::get(::djinni::String::fromCpp(jniEnv, c.sn)))}; + ::djinni::get(::djinni::String::fromCpp(jniEnv, c.serial)))}; ::djinni::jniExceptionCheck(jniEnv); return r; } auto NativeDeviceUsbInfo::toCpp(JNIEnv* jniEnv, JniType j) -> CppType { - ::djinni::JniLocalScope jscope(jniEnv, 4); + ::djinni::JniLocalScope jscope(jniEnv, 9); assert(j != nullptr); const auto& data = ::djinni::JniClass::get(); - return {::djinni::I32::toCpp(jniEnv, jniEnv->GetIntField(j, data.field_mIndex)), + return {::djinni::I32::toCpp(jniEnv, jniEnv->GetIntField(j, data.field_mVid)), + ::djinni::I32::toCpp(jniEnv, jniEnv->GetIntField(j, data.field_mPid)), + ::djinni::I32::toCpp(jniEnv, jniEnv->GetIntField(j, data.field_mFd)), + ::djinni::I32::toCpp(jniEnv, jniEnv->GetIntField(j, data.field_mBusNum)), + ::djinni::I32::toCpp(jniEnv, jniEnv->GetIntField(j, data.field_mDevNum)), + ::djinni::String::toCpp(jniEnv, (jstring)jniEnv->GetObjectField(j, data.field_mUsbFs)), ::djinni::String::toCpp(jniEnv, (jstring)jniEnv->GetObjectField(j, data.field_mName)), - ::djinni::String::toCpp(jniEnv, (jstring)jniEnv->GetObjectField(j, data.field_mSn))}; + ::djinni::String::toCpp(jniEnv, (jstring)jniEnv->GetObjectField(j, data.field_mSerial))}; } } // namespace djinni_generated diff --git a/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/jni/NativeDeviceUsbInfo.hpp b/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/jni/NativeDeviceUsbInfo.hpp index f29492b..5ded541 100644 --- a/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/jni/NativeDeviceUsbInfo.hpp +++ b/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/jni/NativeDeviceUsbInfo.hpp @@ -25,10 +25,15 @@ private: friend ::djinni::JniClass; const ::djinni::GlobalRef clazz { ::djinni::jniFindClass("com/slightech/mynteye/DeviceUsbInfo") }; - const jmethodID jconstructor { ::djinni::jniGetMethodID(clazz.get(), "", "(ILjava/lang/String;Ljava/lang/String;)V") }; - const jfieldID field_mIndex { ::djinni::jniGetFieldID(clazz.get(), "mIndex", "I") }; + const jmethodID jconstructor { ::djinni::jniGetMethodID(clazz.get(), "", "(IIIIILjava/lang/String;Ljava/lang/String;Ljava/lang/String;)V") }; + const jfieldID field_mVid { ::djinni::jniGetFieldID(clazz.get(), "mVid", "I") }; + const jfieldID field_mPid { ::djinni::jniGetFieldID(clazz.get(), "mPid", "I") }; + const jfieldID field_mFd { ::djinni::jniGetFieldID(clazz.get(), "mFd", "I") }; + const jfieldID field_mBusNum { ::djinni::jniGetFieldID(clazz.get(), "mBusNum", "I") }; + const jfieldID field_mDevNum { ::djinni::jniGetFieldID(clazz.get(), "mDevNum", "I") }; + const jfieldID field_mUsbFs { ::djinni::jniGetFieldID(clazz.get(), "mUsbFs", "Ljava/lang/String;") }; const jfieldID field_mName { ::djinni::jniGetFieldID(clazz.get(), "mName", "Ljava/lang/String;") }; - const jfieldID field_mSn { ::djinni::jniGetFieldID(clazz.get(), "mSn", "Ljava/lang/String;") }; + const jfieldID field_mSerial { ::djinni::jniGetFieldID(clazz.get(), "mSerial", "Ljava/lang/String;") }; }; } // namespace djinni_generated diff --git a/wrappers/android/mynteye/libmynteye/src/main/java/com/slightech/mynteye/Device.java b/wrappers/android/mynteye/libmynteye/src/main/java/com/slightech/mynteye/Device.java index 0095978..8126805 100644 --- a/wrappers/android/mynteye/libmynteye/src/main/java/com/slightech/mynteye/Device.java +++ b/wrappers/android/mynteye/libmynteye/src/main/java/com/slightech/mynteye/Device.java @@ -41,13 +41,6 @@ public interface Device { @NonNull public ArrayList getMotionDatas(); - /** Query devices */ - @NonNull - public static ArrayList query() - { - return CppProxy.query(); - } - /** Create the device instance */ @Nullable public static Device create(@NonNull com.slightech.mynteye.DeviceUsbInfo info) @@ -150,9 +143,6 @@ public interface Device { } private native ArrayList native_getMotionDatas(long _nativeRef); - @NonNull - public static native ArrayList query(); - @Nullable public static native Device create(@NonNull com.slightech.mynteye.DeviceUsbInfo info); } diff --git a/wrappers/android/mynteye/libmynteye/src/main/java/com/slightech/mynteye/DeviceUsbInfo.java b/wrappers/android/mynteye/libmynteye/src/main/java/com/slightech/mynteye/DeviceUsbInfo.java index 7e4ec6e..2ef3318 100644 --- a/wrappers/android/mynteye/libmynteye/src/main/java/com/slightech/mynteye/DeviceUsbInfo.java +++ b/wrappers/android/mynteye/libmynteye/src/main/java/com/slightech/mynteye/DeviceUsbInfo.java @@ -10,44 +10,95 @@ import androidx.annotation.Nullable; public final class DeviceUsbInfo { - /*package*/ final int mIndex; + /*package*/ final int mVid; + + /*package*/ final int mPid; + + /*package*/ final int mFd; + + /*package*/ final int mBusNum; + + /*package*/ final int mDevNum; + + /*package*/ final String mUsbFs; /*package*/ final String mName; - /*package*/ final String mSn; + /*package*/ final String mSerial; public DeviceUsbInfo( - int index, + int vid, + int pid, + int fd, + int busNum, + int devNum, + @NonNull String usbFs, @NonNull String name, - @NonNull String sn) { - this.mIndex = index; + @NonNull String serial) { + this.mVid = vid; + this.mPid = pid; + this.mFd = fd; + this.mBusNum = busNum; + this.mDevNum = devNum; + this.mUsbFs = usbFs; this.mName = name; - this.mSn = sn; + this.mSerial = serial; } - /** Device index */ - public int getIndex() { - return mIndex; + /** Vendor id */ + public int getVid() { + return mVid; } - /** Device name */ + /** Product id */ + public int getPid() { + return mPid; + } + + /** File descriptor */ + public int getFd() { + return mFd; + } + + /** Bus number */ + public int getBusNum() { + return mBusNum; + } + + /** Dev number */ + public int getDevNum() { + return mDevNum; + } + + /** Usb file system path */ + @NonNull + public String getUsbFs() { + return mUsbFs; + } + + /** Product name */ @NonNull public String getName() { return mName; } - /** Device serial number */ + /** Serial number */ @NonNull - public String getSn() { - return mSn; + public String getSerial() { + return mSerial; } @Override public String toString() { return "DeviceUsbInfo{" + - "mIndex=" + mIndex + + "mVid=" + mVid + + "," + "mPid=" + mPid + + "," + "mFd=" + mFd + + "," + "mBusNum=" + mBusNum + + "," + "mDevNum=" + mDevNum + + "," + "mUsbFs=" + mUsbFs + "," + "mName=" + mName + - "," + "mSn=" + mSn + + "," + "mSerial=" + mSerial + "}"; } diff --git a/wrappers/android/mynteye/libmynteye/src/main/java/com/slightech/mynteye/usb/CameraDialog.java b/wrappers/android/mynteye/libmynteye/src/main/java/com/slightech/mynteye/usb/CameraDialog.java new file mode 100644 index 0000000..e1f2b86 --- /dev/null +++ b/wrappers/android/mynteye/libmynteye/src/main/java/com/slightech/mynteye/usb/CameraDialog.java @@ -0,0 +1,236 @@ +/* + * 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.slightech.mynteye.usb; + +import com.slightech.mynteye.R; +import java.util.ArrayList; +import java.util.List; + +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; + +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/wrappers/android/mynteye/libmynteye/src/main/java/com/slightech/mynteye/usb/DeviceFilter.java b/wrappers/android/mynteye/libmynteye/src/main/java/com/slightech/mynteye/usb/DeviceFilter.java new file mode 100644 index 0000000..369e17b --- /dev/null +++ b/wrappers/android/mynteye/libmynteye/src/main/java/com/slightech/mynteye/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.slightech.mynteye.usb; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; + +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; + +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/wrappers/android/mynteye/libmynteye/src/main/java/com/slightech/mynteye/usb/USBMonitor.java b/wrappers/android/mynteye/libmynteye/src/main/java/com/slightech/mynteye/usb/USBMonitor.java new file mode 100644 index 0000000..3cf202e --- /dev/null +++ b/wrappers/android/mynteye/libmynteye/src/main/java/com/slightech/mynteye/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.slightech.mynteye.usb; + +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; + +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.slightech.mynteye.utils.BuildCheck; +import com.slightech.mynteye.utils.HandlerThreadHandler; + +public final class USBMonitor { + + private static final boolean DEBUG = false; + private static final String TAG = "USBMonitor"; + + private static final String ACTION_USB_PERMISSION_BASE = "com.slightech.mynteye.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 detach(after onDisconnect) + * @param device + */ + public void onDetach(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; + processDetach(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 processDetach(final UsbDevice device) { + if (destroyed) return; + if (DEBUG) Log.v(TAG, "processDetach:"); + if (mOnDeviceConnectListener != null) { + mAsyncHandler.post(new Runnable() { + @Override + public void run() { + mOnDeviceConnectListener.onDetach(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/wrappers/android/mynteye/libmynteye/src/main/java/com/slightech/mynteye/usb/USBVendorId.java b/wrappers/android/mynteye/libmynteye/src/main/java/com/slightech/mynteye/usb/USBVendorId.java new file mode 100644 index 0000000..f3b58d6 --- /dev/null +++ b/wrappers/android/mynteye/libmynteye/src/main/java/com/slightech/mynteye/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.slightech.mynteye.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/wrappers/android/mynteye/libmynteye/src/main/java/com/slightech/mynteye/utils/BuildCheck.java b/wrappers/android/mynteye/libmynteye/src/main/java/com/slightech/mynteye/utils/BuildCheck.java new file mode 100644 index 0000000..aac84e7 --- /dev/null +++ b/wrappers/android/mynteye/libmynteye/src/main/java/com/slightech/mynteye/utils/BuildCheck.java @@ -0,0 +1,476 @@ +package com.slightech.mynteye.utils; +/* + * libcommon + * utility/helper classes for myself + * + * Copyright (c) 2014-2018 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. +*/ + +import android.os.Build; + +public final class BuildCheck { + + private static final boolean check(final int value) { + return (Build.VERSION.SDK_INT >= value); + } + + /** + * Magic version number for a current development build, + * which has not yet turned into an official release. API=10000 + * @return + */ + public static boolean isCurrentDevelopment() { + return (Build.VERSION.SDK_INT == Build.VERSION_CODES.CUR_DEVELOPMENT); + } + + /** + * October 2008: The original, first, version of Android. Yay!, API>=1 + * @return + */ + public static boolean isBase() { + return check(Build.VERSION_CODES.BASE); + } + + /** + * February 2009: First Android update, officially called 1.1., API>=2 + * @return + */ + public static boolean isBase11() { + return check(Build.VERSION_CODES.BASE_1_1); + } + + /** + * May 2009: Android 1.5., API>=3 + * @return + */ + public static boolean isCupcake() { + return check(Build.VERSION_CODES.CUPCAKE); + } + + /** + * May 2009: Android 1.5., API>=3 + * @return + */ + public static boolean isAndroid1_5() { + return check(Build.VERSION_CODES.CUPCAKE); + } + + /** + * September 2009: Android 1.6., API>=4 + * @return + */ + public static boolean isDonut() { + return check(Build.VERSION_CODES.DONUT); + } + + /** + * September 2009: Android 1.6., API>=4 + * @return + */ + public static boolean isAndroid1_6() { + return check(Build.VERSION_CODES.DONUT); + } + + /** + * November 2009: Android 2.0, API>=5 + * @return + */ + public static boolean isEclair() { + return check(Build.VERSION_CODES.ECLAIR); + } + + /** + * November 2009: Android 2.0, API>=5 + * @return + */ + public static boolean isAndroid2_0() { + return check(Build.VERSION_CODES.ECLAIR); + } + + /** + * December 2009: Android 2.0.1, API>=6 + * @return + */ + public static boolean isEclair01() { + return check(Build.VERSION_CODES.ECLAIR_0_1); + } + + /** + * January 2010: Android 2.1, API>=7 + * @return + */ + public static boolean isEclairMR1() { + return check(Build.VERSION_CODES.ECLAIR_MR1); + } + + /** + * June 2010: Android 2.2, API>=8 + * @return + */ + public static boolean isFroyo() { + return check(Build.VERSION_CODES.FROYO); + } + + /** + * June 2010: Android 2.2, API>=8 + * @return + */ + public static boolean isAndroid2_2() { + return check(Build.VERSION_CODES.FROYO); + } + + /** + * November 2010: Android 2.3, API>=9 + * @return + */ + public static boolean isGingerBread() { + return check(Build.VERSION_CODES.GINGERBREAD); + } + + /** + * November 2010: Android 2.3, API>=9 + * @return + */ + public static boolean isAndroid2_3() { + return check(Build.VERSION_CODES.GINGERBREAD); + } + + /** + * February 2011: Android 2.3.3., API>=10 + * @return + */ + public static boolean isGingerBreadMR1() { + return check(Build.VERSION_CODES.GINGERBREAD_MR1); + } + + /** + * February 2011: Android 2.3.3., API>=10 + * @return + */ + public static boolean isAndroid2_3_3() { + return check(Build.VERSION_CODES.GINGERBREAD_MR1); + } + + /** + * February 2011: Android 3.0., API>=11 + * @return + */ + public static boolean isHoneyComb() { + return check(Build.VERSION_CODES.HONEYCOMB); + } + + /** + * February 2011: Android 3.0., API>=11 + * @return + */ + public static boolean isAndroid3() { + return check(Build.VERSION_CODES.HONEYCOMB); + } + + /** + * May 2011: Android 3.1., API>=12 + * @return + */ + public static boolean isHoneyCombMR1() { + return check(Build.VERSION_CODES.HONEYCOMB_MR1); + } + + /** + * May 2011: Android 3.1., API>=12 + * @return + */ + public static boolean isAndroid3_1() { + return check(Build.VERSION_CODES.HONEYCOMB_MR1); + } + + /** + * June 2011: Android 3.2., API>=13 + * @return + */ + public static boolean isHoneyCombMR2() { + return check(Build.VERSION_CODES.HONEYCOMB_MR2); + } + + /** + * June 2011: Android 3.2., API>=13 + * @return + */ + public static boolean isAndroid3_2() { + return check(Build.VERSION_CODES.HONEYCOMB_MR2); + } + + /** + * October 2011: Android 4.0., API>=14 + * @return + */ + public static boolean isIcecreamSandwich() { + return check(Build.VERSION_CODES.ICE_CREAM_SANDWICH); + } + + /** + * October 2011: Android 4.0., API>=14 + * @return + */ + public static boolean isAndroid4() { + return check(Build.VERSION_CODES.ICE_CREAM_SANDWICH); + } + + /** + * December 2011: Android 4.0.3., API>=15 + * @return + */ + public static boolean isIcecreamSandwichMR1() { + return check(Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1); + } + + /** + * December 2011: Android 4.0.3., API>=15 + * @return + */ + public static boolean isAndroid4_0_3() { + return check(Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1); + } + + /** + * June 2012: Android 4.1., API>=16 + * @return + */ + public static boolean isJellyBean() { + return check(Build.VERSION_CODES.JELLY_BEAN); + } + + /** + * June 2012: Android 4.1., API>=16 + * @return + */ + public static boolean isAndroid4_1() { + return check(Build.VERSION_CODES.JELLY_BEAN); + } + + /** + * November 2012: Android 4.2, Moar jelly beans!, API>=17 + * @return + */ + public static boolean isJellyBeanMr1() { + return check(Build.VERSION_CODES.JELLY_BEAN_MR1); + } + + /** + * November 2012: Android 4.2, Moar jelly beans!, API>=17 + * @return + */ + public static boolean isAndroid4_2() { + return check(Build.VERSION_CODES.JELLY_BEAN_MR1); + } + + /** + * July 2013: Android 4.3, the revenge of the beans., API>=18 + * @return + */ + public static boolean isJellyBeanMR2() { + return check(Build.VERSION_CODES.JELLY_BEAN_MR2); + } + + /** + * July 2013: Android 4.3, the revenge of the beans., API>=18 + * @return + */ + public static boolean isAndroid4_3() { + return check(Build.VERSION_CODES.JELLY_BEAN_MR2); + } + + /** + * October 2013: Android 4.4, KitKat, another tasty treat., API>=19 + * @return + */ + public static boolean isKitKat() { + return check(Build.VERSION_CODES.KITKAT); + } + + /** + * October 2013: Android 4.4, KitKat, another tasty treat., API>=19 + * @return + */ + public static boolean isAndroid4_4() { + return check(Build.VERSION_CODES.KITKAT); + } + + /** + * Android 4.4W: KitKat for watches, snacks on the run., API>=20 + * @return + */ + public static boolean isKitKatWatch() { + return (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT_WATCH); + } + + /** + * Lollipop. A flat one with beautiful shadows. But still tasty., API>=21 + * @return + */ + public static boolean isL() { + return (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP); + } + + /** + * Lollipop. A flat one with beautiful shadows. But still tasty., API>=21 + * @return + */ + public static boolean isLollipop() { + return (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP); + } + + /** + * Lollipop. A flat one with beautiful shadows. But still tasty., API>=21 + * @return + */ + public static boolean isAndroid5() { + return check(Build.VERSION_CODES.LOLLIPOP); + } + + /** + * Lollipop with an extra sugar coating on the outside!, API>=22 + * @return + */ + public static boolean isLollipopMR1() { + return (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1); + } + + /** + * Marshmallow. A flat one with beautiful shadows. But still tasty., API>=23 + * @return + */ + public static boolean isM() { + return check(Build.VERSION_CODES.M); + } + + /** + * Marshmallow. A flat one with beautiful shadows. But still tasty., API>=23 + * @return + */ + public static boolean isMarshmallow() { + return check(Build.VERSION_CODES.M); + } + + /** + * Marshmallow. A flat one with beautiful shadows. But still tasty., API>=23 + * @return + */ + public static boolean isAndroid6() { + return check(Build.VERSION_CODES.M); + } + + /** + * 虫歯の元, API >= 24 + * @return + */ + public static boolean isN() { + return check(Build.VERSION_CODES.N); + } + + /** + * 歯にくっつくやつ, API >= 24 + * @return + */ + public static boolean isNougat() { + return check(Build.VERSION_CODES.N); + } + /** + * API >= 24 + * @return + */ + public static boolean isAndroid7() { + return check(Build.VERSION_CODES.N); + } + + /** + * API>=25 + * @return + */ + public static boolean isNMR1() { + return check(Build.VERSION_CODES.N_MR1); + } + + /** + * API>=25 + * @return + */ + public static boolean isNougatMR1() { + return check(Build.VERSION_CODES.N_MR1); + } + + /** + * おれおれぇー API>=26 + * @return + */ + public static boolean isO() { + return check(Build.VERSION_CODES.O); + } + + /** + * おれおれぇー API>=26 + * @return + */ + public static boolean isOreo() { + return check(Build.VERSION_CODES.O); + } + + /** + * おれおれぇー API>=26 + * @return + */ + public static boolean isAndroid8() { + return check(Build.VERSION_CODES.O); + } + + /** + * おれおれぇー API>=27 + * @return + */ + public static boolean isOMR1() { + return check(Build.VERSION_CODES.O_MR1); + } + + /** + * おれおれぇー MR1 API>=27 + * @return + */ + public static boolean isOreoMR1() { + return check((Build.VERSION_CODES.O_MR1)); + } + + /** + * おっ!ぱい API>=28 + * @return + */ + public static boolean isP() { + return check((Build.VERSION_CODES.P)); + } + + /** + * おっ!ぱい API>=28 + * @return + */ + public static boolean isPie() { + return check((Build.VERSION_CODES.P)); + } + + /** + * おっ!ぱい API>=28 + * @return + */ + public static boolean isAndroid9() { + return check((Build.VERSION_CODES.P)); + } +} diff --git a/wrappers/android/mynteye/libmynteye/src/main/java/com/slightech/mynteye/utils/HandlerThreadHandler.java b/wrappers/android/mynteye/libmynteye/src/main/java/com/slightech/mynteye/utils/HandlerThreadHandler.java new file mode 100644 index 0000000..0660316 --- /dev/null +++ b/wrappers/android/mynteye/libmynteye/src/main/java/com/slightech/mynteye/utils/HandlerThreadHandler.java @@ -0,0 +1,58 @@ +package com.slightech.mynteye.utils; +/* + * libcommon + * utility/helper classes for myself + * + * Copyright (c) 2014-2018 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. +*/ + +import android.os.Handler; +import android.os.HandlerThread; +import android.os.Looper; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +public class HandlerThreadHandler extends Handler { + private static final String TAG = "HandlerThreadHandler"; + + public static final HandlerThreadHandler createHandler() { + return createHandler(TAG); + } + + public static final HandlerThreadHandler createHandler(final String name) { + final HandlerThread thread = new HandlerThread(name); + thread.start(); + return new HandlerThreadHandler(thread.getLooper()); + } + + public static final HandlerThreadHandler createHandler(@Nullable final Callback callback) { + return createHandler(TAG, callback); + } + + public static final HandlerThreadHandler createHandler(final String name, @Nullable final Callback callback) { + final HandlerThread thread = new HandlerThread(name); + thread.start(); + return new HandlerThreadHandler(thread.getLooper(), callback); + } + + private HandlerThreadHandler(@NonNull final Looper looper) { + super(looper); + } + + private HandlerThreadHandler(@NonNull final Looper looper, @Nullable final Callback callback) { + super(looper, callback); + } + +} diff --git a/wrappers/android/mynteye/libmynteye/src/main/jniLibs/arm64-v8a/libmynteye_internal.so b/wrappers/android/mynteye/libmynteye/src/main/jniLibs/arm64-v8a/libmynteye_internal.so new file mode 100755 index 0000000..f08ea76 Binary files /dev/null and b/wrappers/android/mynteye/libmynteye/src/main/jniLibs/arm64-v8a/libmynteye_internal.so differ diff --git a/wrappers/android/mynteye/libmynteye/src/main/jniLibs/armeabi-v7a/libmynteye_internal.so b/wrappers/android/mynteye/libmynteye/src/main/jniLibs/armeabi-v7a/libmynteye_internal.so new file mode 100755 index 0000000..9dbcabf Binary files /dev/null and b/wrappers/android/mynteye/libmynteye/src/main/jniLibs/armeabi-v7a/libmynteye_internal.so differ diff --git a/wrappers/android/mynteye/libmynteye/src/main/res/layout/dialog_camera.xml b/wrappers/android/mynteye/libmynteye/src/main/res/layout/dialog_camera.xml new file mode 100644 index 0000000..4e95f4c --- /dev/null +++ b/wrappers/android/mynteye/libmynteye/src/main/res/layout/dialog_camera.xml @@ -0,0 +1,53 @@ + + + + + + + + + + + diff --git a/wrappers/android/mynteye/libmynteye/src/main/res/layout/listitem_device.xml b/wrappers/android/mynteye/libmynteye/src/main/res/layout/listitem_device.xml new file mode 100644 index 0000000..8ef0529 --- /dev/null +++ b/wrappers/android/mynteye/libmynteye/src/main/res/layout/listitem_device.xml @@ -0,0 +1,31 @@ + + + + + \ No newline at end of file diff --git a/wrappers/android/mynteye/libmynteye/src/main/res/values/dimens.xml b/wrappers/android/mynteye/libmynteye/src/main/res/values/dimens.xml new file mode 100644 index 0000000..ac50bf1 --- /dev/null +++ b/wrappers/android/mynteye/libmynteye/src/main/res/values/dimens.xml @@ -0,0 +1,30 @@ + + + + 16dp + 16dp + 48dp + 18sp + 32dp + diff --git a/wrappers/android/mynteye/libmynteye/src/main/res/values/strings.xml b/wrappers/android/mynteye/libmynteye/src/main/res/values/strings.xml new file mode 100644 index 0000000..d7f3541 --- /dev/null +++ b/wrappers/android/mynteye/libmynteye/src/main/res/values/strings.xml @@ -0,0 +1,29 @@ + + + + Select USB Camera + Camera + Refresh + No USB camera found + diff --git a/wrappers/android/mynteye/libmynteye/src/main/res/xml/device_filter.xml b/wrappers/android/mynteye/libmynteye/src/main/res/xml/device_filter.xml new file mode 100644 index 0000000..e937299 --- /dev/null +++ b/wrappers/android/mynteye/libmynteye/src/main/res/xml/device_filter.xml @@ -0,0 +1,28 @@ + + + + + + + diff --git a/wrappers/android/mynteye/scripts/mynteye.djinni b/wrappers/android/mynteye/scripts/mynteye.djinni index 473d68a..1f20091 100644 --- a/wrappers/android/mynteye/scripts/mynteye.djinni +++ b/wrappers/android/mynteye/scripts/mynteye.djinni @@ -2,9 +2,6 @@ # Device class to communicate with MYNT® EYE device device = interface +c { - # Query devices - static query(): list; - # Create the device instance static create(info: device_usb_info): device; diff --git a/wrappers/android/mynteye/scripts/mynteye_types.djinni b/wrappers/android/mynteye/scripts/mynteye_types.djinni index a2cec16..7f8520c 100644 --- a/wrappers/android/mynteye/scripts/mynteye_types.djinni +++ b/wrappers/android/mynteye/scripts/mynteye_types.djinni @@ -1,12 +1,22 @@ # Device USB information device_usb_info = record { - # Device index - index: i32; - # Device name + # Vendor id + vid: i32; + # Product id + pid: i32; + # File descriptor + fd: i32; + # Bus number + bus_num: i32; + # Dev number + dev_num: i32; + # Usb file system path + usb_fs: string; + # Product name name: string; - # Device serial number - sn: string; + # Serial number + serial: string; } # Device model