diff --git a/include/mynteye/logger.h b/include/mynteye/logger.h index daa1024..e449a26 100644 --- a/include/mynteye/logger.h +++ b/include/mynteye/logger.h @@ -77,6 +77,7 @@ struct glog_init { #include "mynteye/mynteye.h" #define MYNTEYE_MAX_LOG_LEVEL google::INFO +// #define MYNTEYE_MAX_LOG_LEVEL 2 #include "mynteye/miniglog.h" diff --git a/include/mynteye/miniglog.h b/include/mynteye/miniglog.h index 02d377a..83ca179 100644 --- a/include/mynteye/miniglog.h +++ b/include/mynteye/miniglog.h @@ -157,9 +157,6 @@ class MYNTEYE_API LogSink { // Global set of log sinks. The actual object is defined in logging.cc. MYNTEYE_API extern std::set log_sinks_global; -// Added by chachi - a runtime global maximum log level. Defined in logging.cc -MYNTEYE_API extern int log_severity_global; - inline void InitGoogleLogging(char */*argv*/) { // Do nothing; this is ignored. } @@ -315,9 +312,8 @@ class MYNTEYE_API LoggerVoidify { // Log only if condition is met. Otherwise evaluates to void. #define LOG_IF(severity, condition) \ - (static_cast(severity) > google::log_severity_global || !(condition)) ? \ - (void) 0 : LoggerVoidify() & \ - MessageLogger((char *)__FILE__, __LINE__, "native", severity).stream() + !(condition) ? (void) 0 : LoggerVoidify() & \ + MessageLogger((char *)__FILE__, __LINE__, "native", severity).stream() // Log only if condition is NOT met. Otherwise evaluates to void. #define LOG_IF_FALSE(severity, condition) LOG_IF(severity, !(condition)) 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/src/mynteye/device/device.cc b/src/mynteye/device/device.cc index d98f915..117dc30 100644 --- a/src/mynteye/device/device.cc +++ b/src/mynteye/device/device.cc @@ -617,8 +617,8 @@ void Device::ReadAllInfos() { SetIntrinsics(Stream::LEFT, img_params.in_left); SetIntrinsics(Stream::RIGHT, img_params.in_right); SetExtrinsics(Stream::LEFT, Stream::RIGHT, img_params.ex_right_to_left); - VLOG(2) << "Intrinsics left: {" << GetIntrinsics(Stream::LEFT) << "}"; - VLOG(2) << "Intrinsics right: {" << GetIntrinsics(Stream::RIGHT) << "}"; + VLOG(2) << "Intrinsics left: {" << *GetIntrinsics(Stream::LEFT) << "}"; + VLOG(2) << "Intrinsics right: {" << *GetIntrinsics(Stream::RIGHT) << "}"; VLOG(2) << "Extrinsics left to right: {" << GetExtrinsics(Stream::LEFT, Stream::RIGHT) << "}"; break; @@ -662,8 +662,8 @@ void Device::UpdateStreamIntrinsics( SetIntrinsics(Stream::LEFT, img_params.in_left); SetIntrinsics(Stream::RIGHT, img_params.in_right); SetExtrinsics(Stream::LEFT, Stream::RIGHT, img_params.ex_right_to_left); - VLOG(2) << "Intrinsics left: {" << GetIntrinsics(Stream::LEFT) << "}"; - VLOG(2) << "Intrinsics right: {" << GetIntrinsics(Stream::RIGHT) << "}"; + VLOG(2) << "Intrinsics left: {" << *GetIntrinsics(Stream::LEFT) << "}"; + VLOG(2) << "Intrinsics right: {" << *GetIntrinsics(Stream::RIGHT) << "}"; VLOG(2) << "Extrinsics left to right: {" << GetExtrinsics(Stream::LEFT, Stream::RIGHT) << "}"; break; diff --git a/src/mynteye/device/standard2/streams_adapter_s2.cc b/src/mynteye/device/standard2/streams_adapter_s2.cc index 1a2560b..ea497c4 100644 --- a/src/mynteye/device/standard2/streams_adapter_s2.cc +++ b/src/mynteye/device/standard2/streams_adapter_s2.cc @@ -120,12 +120,12 @@ bool unpack_stereo_img_data( << static_cast(img_packet.header) << " now"; return false; } - +/* std::uint8_t checksum = 0; for (std::size_t i = 2, n = packet_n - 2; i <= n; i++) { // content: [2,9] checksum = (checksum ^ packet[i]); } -/* + if (img_packet.checksum != checksum) { VLOG(2) << "Image packet checksum should be 0x" << std::hex << std::uppercase << std::setw(2) << std::setfill('0') diff --git a/src/mynteye/miniglog.cc b/src/mynteye/miniglog.cc index 0bda4be..8825038 100644 --- a/src/mynteye/miniglog.cc +++ b/src/mynteye/miniglog.cc @@ -36,6 +36,4 @@ namespace google { // that there is only one instance of this across the entire program. std::set log_sinks_global; -int log_severity_global(INFO); - } // namespace google diff --git a/src/mynteye/types.cc b/src/mynteye/types.cc index 27b6beb..4bc83f1 100644 --- a/src/mynteye/types.cc +++ b/src/mynteye/types.cc @@ -166,6 +166,7 @@ const char *to_string(const Format &value) { CASE(GREY) CASE(YUYV) CASE(BGR888) + CASE(RGB888) default: return "Format::UNKNOWN"; } diff --git a/wrappers/android/mynteye/.gitignore b/wrappers/android/mynteye/.gitignore new file mode 100644 index 0000000..0df7064 --- /dev/null +++ b/wrappers/android/mynteye/.gitignore @@ -0,0 +1,8 @@ +*.iml +.gradle +/local.properties +/.idea/ +.DS_Store +/build +/captures +.externalNativeBuild diff --git a/wrappers/android/mynteye/README.md b/wrappers/android/mynteye/README.md new file mode 100644 index 0000000..1e38ce9 --- /dev/null +++ b/wrappers/android/mynteye/README.md @@ -0,0 +1,11 @@ +# MYNT® EYE Android Wrapper + +## Prerequisites + +Android device need be rooted and support [USB3 OTG](https://en.wikipedia.org/wiki/USB_On-The-Go) feature. + +## Build & Run + +1. Download and install [Android Studio](https://developer.android.com/studio/index.html) +2. Start Android Studio and [download the NDK and build tools](https://developer.android.com/studio/projects/add-native-code) +3. Open this project using `Open an existing Android Studio project` diff --git a/wrappers/android/mynteye/app/.gitignore b/wrappers/android/mynteye/app/.gitignore new file mode 100644 index 0000000..796b96d --- /dev/null +++ b/wrappers/android/mynteye/app/.gitignore @@ -0,0 +1 @@ +/build diff --git a/wrappers/android/mynteye/app/build.gradle b/wrappers/android/mynteye/app/build.gradle new file mode 100644 index 0000000..5ba3d55 --- /dev/null +++ b/wrappers/android/mynteye/app/build.gradle @@ -0,0 +1,45 @@ +apply plugin: 'com.android.application' + +android { + compileSdkVersion xversions.compileSdk + defaultConfig { + applicationId "com.slightech.mynteye.demo" + minSdkVersion xversions.minSdk + targetSdkVersion xversions.targetSdk + versionCode 1 + versionName "1.0" + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + ndk { + abiFilters xabis + } + } + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } +} + +dependencies { + implementation fileTree(dir: 'libs', include: ['*.jar']) + + implementation 'androidx.appcompat:appcompat:1.1.0-alpha01' + implementation 'androidx.constraintlayout:constraintlayout:2.0.0-alpha3' + + implementation 'com.jakewharton.timber:timber:4.7.1' + + implementation 'com.jakewharton:butterknife:10.0.0' + annotationProcessor 'com.jakewharton:butterknife-compiler:10.0.0' + + implementation project(':libmynteye') + implementation project(':libshell') + + testImplementation 'junit:junit:4.12' + androidTestImplementation 'androidx.test:runner:1.1.1' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1' +} diff --git a/wrappers/android/mynteye/app/proguard-rules.pro b/wrappers/android/mynteye/app/proguard-rules.pro new file mode 100644 index 0000000..f1b4245 --- /dev/null +++ b/wrappers/android/mynteye/app/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile diff --git a/wrappers/android/mynteye/app/src/androidTest/java/com/slightech/mynteye/demo/ExampleInstrumentedTest.java b/wrappers/android/mynteye/app/src/androidTest/java/com/slightech/mynteye/demo/ExampleInstrumentedTest.java new file mode 100644 index 0000000..e30780b --- /dev/null +++ b/wrappers/android/mynteye/app/src/androidTest/java/com/slightech/mynteye/demo/ExampleInstrumentedTest.java @@ -0,0 +1,26 @@ +package com.slightech.mynteye.demo; + +import android.content.Context; +import androidx.test.InstrumentationRegistry; +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import static org.junit.Assert.*; + +/** + * Instrumented test, which will execute on an Android device. + * + * @see Testing documentation + */ +@RunWith(AndroidJUnit4.class) +public class ExampleInstrumentedTest { + @Test + public void useAppContext() { + // Context of the app under test. + Context appContext = InstrumentationRegistry.getTargetContext(); + + assertEquals("com.slightech.mynteye.demo", appContext.getPackageName()); + } +} diff --git a/wrappers/android/mynteye/app/src/main/AndroidManifest.xml b/wrappers/android/mynteye/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..5072b22 --- /dev/null +++ b/wrappers/android/mynteye/app/src/main/AndroidManifest.xml @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + diff --git a/wrappers/android/mynteye/app/src/main/java/com/slightech/mynteye/demo/MyApplication.java b/wrappers/android/mynteye/app/src/main/java/com/slightech/mynteye/demo/MyApplication.java new file mode 100644 index 0000000..1bddf50 --- /dev/null +++ b/wrappers/android/mynteye/app/src/main/java/com/slightech/mynteye/demo/MyApplication.java @@ -0,0 +1,35 @@ +package com.slightech.mynteye.demo; + +import android.app.Application; +import timber.log.Timber; + +//import com.stericson.RootShell.RootShell; + +public class MyApplication extends Application { + + static { + try { + System.loadLibrary("mynteye_jni"); + } catch (UnsatisfiedLinkError e) { + System.err.println("mynteye_jni library failed to load.\n" + e); + } + } + + @Override public void onCreate() { + super.onCreate(); + Timber.plant(new Timber.DebugTree()); + //RootShell.debugMode = true; + } + + @Override public void onLowMemory() { + super.onLowMemory(); + } + + @Override public void onTrimMemory(int level) { + super.onTrimMemory(level); + } + + @Override public void onTerminate() { + super.onTerminate(); + } +} diff --git a/wrappers/android/mynteye/app/src/main/java/com/slightech/mynteye/demo/camera/Mynteye.java b/wrappers/android/mynteye/app/src/main/java/com/slightech/mynteye/demo/camera/Mynteye.java new file mode 100644 index 0000000..4f3c243 --- /dev/null +++ b/wrappers/android/mynteye/app/src/main/java/com/slightech/mynteye/demo/camera/Mynteye.java @@ -0,0 +1,213 @@ +package com.slightech.mynteye.demo.camera; + +import android.os.Handler; +import android.os.HandlerThread; +import com.slightech.mynteye.Device; +import com.slightech.mynteye.DeviceUsbInfo; +import com.slightech.mynteye.Info; +import com.slightech.mynteye.MotionData; +import com.slightech.mynteye.MotionIntrinsics; +import com.slightech.mynteye.Option; +import com.slightech.mynteye.Source; +import com.slightech.mynteye.Stream; +import com.slightech.mynteye.StreamData; +import com.slightech.mynteye.StreamRequest; +import java.util.ArrayList; +import java.util.Map; +import timber.log.Timber; + +public final class Mynteye implements Runnable { + + private Device mDevice; + + private HandlerThread mBackgroundThread; + private Handler mBackgroundHandler; + + private boolean mOpened; + private boolean mImuEnabled; + + public interface OnStreamDataReceiveListener { + void onStreamDataReceive(Stream stream, StreamData data, Handler handler); + void onStreamLeftReceive(StreamData data, Handler handler); + void onStreamRightReceive(StreamData data, Handler handler); + } + + public interface OnMotionDataReceiveListener { + void onMotionDataReceive(ArrayList datas, Handler handler); + } + + private OnStreamDataReceiveListener mOnStreamDataReceiveListener; + private OnMotionDataReceiveListener mOnMotionDataReceiveListener; + + private StreamRequest mStreamRequest; + + public Mynteye(DeviceUsbInfo info) { + mDevice = Device.create(info); + mOpened = false; + mImuEnabled = false; + } + + public void setOnStreamDataReceiveListener(OnStreamDataReceiveListener l) { + mOnStreamDataReceiveListener = l; + } + + public void setOnMotionDataReceiveListener(OnMotionDataReceiveListener l) { + mOnMotionDataReceiveListener = l; + } + + public ArrayList getStreamRequests() { + return mDevice.getStreamRequests(); + } + + public String getDeviceInfos() { + StringBuffer sb = new StringBuffer(); + for (Info info : Info.values()) { + sb.append(info.toString()); + sb.append(": "); + sb.append(mDevice.getInfo(info)); + sb.append('\n'); + } + return sb.toString(); + } + + public String getImageParams() { + StringBuffer sb = new StringBuffer(); + sb.append(Stream.LEFT).append('\n').append(mDevice.getIntrinsics(Stream.LEFT)); + sb.append("\n\n"); + sb.append(Stream.RIGHT).append('\n').append(mDevice.getIntrinsics(Stream.RIGHT)); + sb.append("\n\n"); + sb.append(Stream.LEFT).append(" > ").append(Stream.RIGHT); + sb.append('\n'); + sb.append(mDevice.getExtrinsics(Stream.LEFT, Stream.RIGHT)); + return sb.toString(); + } + + public String getImuParams() { + StringBuffer sb = new StringBuffer(); + MotionIntrinsics in = mDevice.getMotionIntrinsics(); + sb.append("Accel\n").append(in.getAccel()); + sb.append("\n\n"); + sb.append("Gyro\n").append(in.getGyro()); + sb.append("\n\n"); + sb.append("Imu > ").append(Stream.LEFT).append('\n') + .append(mDevice.getMotionExtrinsics(Stream.LEFT)); + return sb.toString(); + } + + public String getOptionInfos() { + StringBuffer sb = new StringBuffer(); + for (Option op : Option.values()) { + if (!mDevice.supportsOption(op)) { + continue; + } + sb.append(op.toString()); + sb.append(": "); + sb.append(mDevice.getOptionValue(op)); + sb.append("\n "); + sb.append(mDevice.getOptionInfo(op)); + sb.append('\n'); + } + return sb.toString(); + } + + public boolean isOpened() { + return mOpened; + } + + public boolean isImuEnabled() { + return mImuEnabled; + } + + public void setImuEnabled(boolean enabled) { + mImuEnabled = enabled; + if (mOpened) { + Timber.w("Will enable imu when open next time"); + } + } + + public void open() { + if (mOpened) return; + if (mStreamRequest == null) { + Timber.w("Should open with stream request"); + return; + } + open(mStreamRequest); + } + + public void open(StreamRequest request) { + if (mOpened) return; + mOpened = true; + mStreamRequest = request; + + startBackgroundThread(); + + mDevice.configStreamRequest(request); + if (mImuEnabled) { + mDevice.enableMotionDatas(Integer.MAX_VALUE); + mDevice.start(Source.ALL); + } else { + mDevice.start(Source.VIDEO_STREAMING); + } + + mBackgroundHandler.post(this); + } + + public void close() { + if (!mOpened) return; + mOpened = false; + stopBackgroundThread(); + mDevice.stop(Source.ALL); + } + + @Override + public void run() { + //Timber.i("wait streams"); + mDevice.waitForStreams(); + + //Timber.i("get streams"); + { + StreamData data = mDevice.getStreamData(Stream.LEFT); + if (mOnStreamDataReceiveListener != null) { + mOnStreamDataReceiveListener.onStreamDataReceive(Stream.LEFT, data, mBackgroundHandler); + mOnStreamDataReceiveListener.onStreamLeftReceive(data, mBackgroundHandler); + } + } + { + StreamData data = mDevice.getStreamData(Stream.RIGHT); + if (mOnStreamDataReceiveListener != null) { + mOnStreamDataReceiveListener.onStreamDataReceive(Stream.RIGHT, data, mBackgroundHandler); + mOnStreamDataReceiveListener.onStreamRightReceive(data, mBackgroundHandler); + } + } + + //Timber.i("get motions"); + if (mImuEnabled) { + ArrayList datas = mDevice.getMotionDatas(); + if (mOnMotionDataReceiveListener != null) { + mOnMotionDataReceiveListener.onMotionDataReceive(datas, mBackgroundHandler); + } + } + + if (mOpened) mBackgroundHandler.post(this); + } + + private void startBackgroundThread() { + mBackgroundThread = new HandlerThread("MynteyeBackground"); + mBackgroundThread.start(); + mBackgroundHandler = new Handler(mBackgroundThread.getLooper()); + } + + private void stopBackgroundThread() { + mBackgroundThread.quitSafely(); + //mBackgroundThread.interrupt(); + try { + mBackgroundHandler.removeCallbacksAndMessages(null); + mBackgroundThread.join(); + mBackgroundThread = null; + mBackgroundHandler = null; + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + +} diff --git a/wrappers/android/mynteye/app/src/main/java/com/slightech/mynteye/demo/ui/BaseActivity.java b/wrappers/android/mynteye/app/src/main/java/com/slightech/mynteye/demo/ui/BaseActivity.java new file mode 100644 index 0000000..aa35d74 --- /dev/null +++ b/wrappers/android/mynteye/app/src/main/java/com/slightech/mynteye/demo/ui/BaseActivity.java @@ -0,0 +1,63 @@ +package com.slightech.mynteye.demo.ui; + +import android.annotation.SuppressLint; +import android.content.pm.PackageManager; +import android.os.Bundle; +import android.widget.Toast; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatActivity; +import androidx.core.app.ActivityCompat; +import androidx.core.content.ContextCompat; + +import static android.Manifest.permission.CAMERA; +import static android.Manifest.permission.WRITE_EXTERNAL_STORAGE; + +@SuppressLint("Registered") +public class BaseActivity extends AppCompatActivity { + + private final int REQ_PERMISSIONS = 1; + + @Override + protected void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + requestPermissions(); + } + + private void requestPermissions() { + final String[] permissions = new String[]{WRITE_EXTERNAL_STORAGE, CAMERA}; + + boolean granted = true; + for (String permission : permissions) { + if (ContextCompat.checkSelfPermission(this, permission) + != PackageManager.PERMISSION_GRANTED) { + granted = false; + } + } + if (granted) return; + + ActivityCompat.requestPermissions(this, permissions, REQ_PERMISSIONS); + } + + @Override + public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, + @NonNull int[] grantResults) { + if (requestCode == REQ_PERMISSIONS) { + boolean granted = true; + if (grantResults.length < 1) { + granted = false; + } else { + for (int result : grantResults) { + if (result != PackageManager.PERMISSION_GRANTED) { + granted = false; + } + } + } + if (!granted) { + Toast.makeText(this, "Permission denied :(", Toast.LENGTH_LONG).show(); + } + } else { + super.onRequestPermissionsResult(requestCode, permissions, grantResults); + } + } +} 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 new file mode 100644 index 0000000..96bc29c --- /dev/null +++ b/wrappers/android/mynteye/app/src/main/java/com/slightech/mynteye/demo/ui/MainActivity.java @@ -0,0 +1,323 @@ +package com.slightech.mynteye.demo.ui; + +import android.graphics.Bitmap; +import android.hardware.usb.UsbDevice; +import android.os.Bundle; +import android.os.Handler; +import android.text.TextUtils; +import android.view.Menu; +import android.view.MenuItem; +import android.widget.ArrayAdapter; +import android.widget.ImageView; +import android.widget.ListView; +import android.widget.TextView; +import android.widget.Toast; +import androidx.appcompat.app.AlertDialog; +import butterknife.BindView; +import butterknife.ButterKnife; +import com.slightech.mynteye.DeviceUsbInfo; +import com.slightech.mynteye.Frame; +import com.slightech.mynteye.ImuData; +import com.slightech.mynteye.MotionData; +import com.slightech.mynteye.Stream; +import com.slightech.mynteye.StreamData; +import com.slightech.mynteye.StreamRequest; +import com.slightech.mynteye.demo.R; +import com.slightech.mynteye.demo.camera.Mynteye; +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 com.slightech.mynteye.util.BitmapUtils; +import java.util.ArrayList; +import java.util.Locale; +import timber.log.Timber; + +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; + + private boolean mImuEnabled; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_main); + ButterKnife.bind(this); + mUSBMonitor = new USBMonitor(this, mOnDeviceConnectListener); + } + + @Override + protected void onStart() { + super.onStart(); + mUSBMonitor.register(); + if (mMynteye == null) { + //actionOpen(); + } + } + + @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); + return true; + } + + @Override + public boolean onPrepareOptionsMenu(Menu menu) { + if (mMynteye == null) { + menu.findItem(R.id.action_open).setVisible(true); + menu.findItem(R.id.action_close).setVisible(false); + } else { + menu.findItem(R.id.action_open).setVisible(!mMynteye.isOpened()); + menu.findItem(R.id.action_close).setVisible(mMynteye.isOpened()); + } + menu.findItem(R.id.check_imu_data).setChecked(mImuEnabled); + boolean featuresUsable = mMynteye != null && mMynteye.isOpened(); + menu.findItem(R.id.show_device_infos).setEnabled(featuresUsable); + menu.findItem(R.id.show_image_params).setEnabled(featuresUsable); + menu.findItem(R.id.show_imu_params).setEnabled(featuresUsable); + menu.findItem(R.id.show_option_infos).setEnabled(featuresUsable); + return super.onPrepareOptionsMenu(menu); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case R.id.action_open: + actionOpen(); + return true; + case R.id.action_close: + actionClose(); + return true; + case R.id.check_imu_data: + mImuEnabled = !mImuEnabled; + item.setChecked(mImuEnabled); + return true; + case R.id.show_device_infos: + alert(R.string.device_infos, mMynteye.getDeviceInfos()); + return true; + case R.id.show_image_params: + alert(R.string.image_params, mMynteye.getImageParams()); + return true; + case R.id.show_imu_params: + alert(R.string.imu_params, mMynteye.getImuParams()); + return true; + case R.id.show_option_infos: + alert(R.string.option_infos, mMynteye.getOptionInfos()); + return true; + default: + return super.onOptionsItemSelected(item); + } + } + + private void actionOpen() { + mTextView.setText(""); + if (mMynteye == null) { + CameraDialog.showDialog(this); + } else { + mMynteye.setImuEnabled(mImuEnabled); + mMynteye.open(); + } + } + + private void actionClose() { + if (mMynteye != null) { + mMynteye.close(); + mMynteye = null; + } + invalidateOptionsMenu(); + } + + private void openDevice(DeviceUsbInfo info) { + mMynteye = new Mynteye(info); + ArrayList requests = mMynteye.getStreamRequests(); + if (requests.isEmpty()) { + alert("Warning", "There are no streams to request :("); + mMynteye = null; + } else { + ArrayList items = new ArrayList<>(); + for (StreamRequest req : requests) { + items.add(req.toString()); + } + + AlertDialog dialog = new AlertDialog.Builder(this) + .setTitle("StreamRequests") + .create(); + ListView listView = new ListView(this); + listView.setAdapter(new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, items)); + listView.setOnItemClickListener((parent, view, position, id) -> { + dialog.dismiss(); + mMynteye.setOnStreamDataReceiveListener(this); + mMynteye.setOnMotionDataReceiveListener(this); + mMynteye.setImuEnabled(mImuEnabled); + mMynteye.open(requests.get(position)); + invalidateOptionsMenu(); + }); + dialog.setOnCancelListener(dlg -> { + mMynteye = null; + }); + dialog.setView(listView); + dialog.show(); + } + } + + @Override + public USBMonitor getUSBMonitor() { + return mUSBMonitor; + } + + @Override + public void onDialogResult(boolean canceled) { + } + + @Override + public void onStreamDataReceive(Stream stream, StreamData data, Handler handler) { + } + + @Override + public void onStreamLeftReceive(StreamData data, Handler handler) { + //Timber.i("onStreamLeftReceive"); + Frame frame = data.frame(); + if (mLeftBitmap == null) { + mLeftBitmap = Bitmap.createBitmap(frame.width(), frame.height(), Bitmap.Config.ARGB_8888); + } + BitmapUtils.copyPixels(frame, mLeftBitmap); + mLeftImageView.post(() -> mLeftImageView.setImageBitmap(mLeftBitmap)); + } + + @Override + public void onStreamRightReceive(StreamData data, Handler handler) { + //Timber.i("onStreamRightReceive"); + Frame frame = data.frame(); + if (mRightBitmap == null) { + mRightBitmap = Bitmap.createBitmap(frame.width(), frame.height(), Bitmap.Config.ARGB_8888); + } + BitmapUtils.copyPixels(frame, mRightBitmap); + mRightImageView.post(() -> mRightImageView.setImageBitmap(mRightBitmap)); + } + + @Override + public void onMotionDataReceive(ArrayList datas, Handler handler) { + if (datas.isEmpty()) return; + ImuData data = datas.get(0).imu(); + mTextView.post(() -> { + StringBuffer sb = new StringBuffer(); + final int flag = data.getFlag(); + if (flag == 0) { // accel & gyro + sb.append("Accel: ").append(data.getAccel()); + sb.append("\nGyro: ").append(data.getGyro()); + } else if (flag == 1) { // accel + sb.append("Accel: ").append(data.getAccel()); + sb.append("\nGyro: -"); + } else if (flag == 2) { // gyro + sb.append("Accel: -"); + sb.append("\nGyro: ").append(data.getGyro()); + } + mTextView.setText(sb.toString()); + }); + } + + private void toast(int textId) { + toast(getString(textId)); + } + + private void toast(CharSequence text) { + Toast.makeText(this, text, Toast.LENGTH_LONG).show(); + } + + private void alert(int titleId, CharSequence message) { + alert(getString(titleId), message); + } + + private void alert(CharSequence title, CharSequence message) { + new AlertDialog.Builder(this) + .setTitle(title) + .setMessage(message) + .setPositiveButton(android.R.string.ok, null) + .show(); + } +} diff --git a/wrappers/android/mynteye/app/src/main/java/com/slightech/mynteye/demo/util/RootUtils.java b/wrappers/android/mynteye/app/src/main/java/com/slightech/mynteye/demo/util/RootUtils.java new file mode 100644 index 0000000..36c19a4 --- /dev/null +++ b/wrappers/android/mynteye/app/src/main/java/com/slightech/mynteye/demo/util/RootUtils.java @@ -0,0 +1,76 @@ +package com.slightech.mynteye.demo.util; + +import com.stericson.RootShell.RootShell; +import com.stericson.RootShell.exceptions.RootDeniedException; +import com.stericson.RootShell.execution.Command; +import com.stericson.RootShell.execution.Shell; +import java.io.IOException; +import java.util.concurrent.TimeoutException; +import timber.log.Timber; + +public final class RootUtils { + + public interface OnRequestAccessibleListener { + void onRequestAccessible(boolean ok); + } + + public static boolean isRooted() { + if (!RootShell.isRootAvailable()) { + Timber.e("Root not found"); + return false; + } + + try { + RootShell.getShell(true); + } catch (IOException e) { + e.printStackTrace(); + return false; + } catch (TimeoutException e) { + Timber.e("TIMEOUT EXCEPTION!"); + e.printStackTrace(); + return false; + } catch (RootDeniedException e) { + Timber.e("ROOT DENIED EXCEPTION!"); + e.printStackTrace(); + return false; + } + + try { + if (!RootShell.isAccessGiven()) { + Timber.e("ERROR: No root access to this device."); + return false; + } + } catch (Exception e) { + Timber.e("ERROR: could not determine root access to this device."); + return false; + } + + return true; + } + + public static void requestAccessible(OnRequestAccessibleListener l) { + try { + Shell sh = RootShell.getShell(true); + sh.add(new Command(1, "chmod 666 /dev/video*") { + @Override + public void commandOutput(int id, String line) { + Timber.d("commandOutput: %s", line); + super.commandOutput(id, line); + } + @Override + public void commandTerminated(int id, String reason) { + Timber.d("commandTerminated: %s", reason); + } + @Override + public void commandCompleted(int id, int exitcode) { + Timber.d("commandCompleted: %s", ((exitcode == 0) ? "ok" : "fail")); + if (l != null) l.onRequestAccessible(exitcode == 0); + } + }); + sh.close(); + } catch (Exception e) { + e.printStackTrace(); + } + } + +} 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 new file mode 100644 index 0000000..764f3f0 --- /dev/null +++ b/wrappers/android/mynteye/app/src/main/res/layout/activity_main.xml @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + diff --git a/wrappers/android/mynteye/app/src/main/res/menu/menu_main.xml b/wrappers/android/mynteye/app/src/main/res/menu/menu_main.xml new file mode 100644 index 0000000..ec72d5c --- /dev/null +++ b/wrappers/android/mynteye/app/src/main/res/menu/menu_main.xml @@ -0,0 +1,36 @@ + + + + + + + + + + + + diff --git a/wrappers/android/mynteye/app/src/main/res/values/colors.xml b/wrappers/android/mynteye/app/src/main/res/values/colors.xml new file mode 100644 index 0000000..b2b4267 --- /dev/null +++ b/wrappers/android/mynteye/app/src/main/res/values/colors.xml @@ -0,0 +1,6 @@ + + + #008577 + #00574B + #D81B60 + diff --git a/wrappers/android/mynteye/app/src/main/res/values/strings.xml b/wrappers/android/mynteye/app/src/main/res/values/strings.xml new file mode 100644 index 0000000..2fe3773 --- /dev/null +++ b/wrappers/android/mynteye/app/src/main/res/values/strings.xml @@ -0,0 +1,15 @@ + + MYNTEYE-S SDK Sample + + Please \"Open\" the camera! + + Open + Close + + Imu Data + + Device Infos + Image Params + Imu Params + Option Infos + diff --git a/wrappers/android/mynteye/app/src/main/res/values/styles.xml b/wrappers/android/mynteye/app/src/main/res/values/styles.xml new file mode 100644 index 0000000..705be27 --- /dev/null +++ b/wrappers/android/mynteye/app/src/main/res/values/styles.xml @@ -0,0 +1,11 @@ + + + + + + diff --git a/wrappers/android/mynteye/app/src/test/java/com/slightech/mynteye/demo/ExampleUnitTest.java b/wrappers/android/mynteye/app/src/test/java/com/slightech/mynteye/demo/ExampleUnitTest.java new file mode 100644 index 0000000..0e0a74c --- /dev/null +++ b/wrappers/android/mynteye/app/src/test/java/com/slightech/mynteye/demo/ExampleUnitTest.java @@ -0,0 +1,17 @@ +package com.slightech.mynteye.demo; + +import org.junit.Test; + +import static org.junit.Assert.*; + +/** + * Example local unit test, which will execute on the development machine (host). + * + * @see Testing documentation + */ +public class ExampleUnitTest { + @Test + public void addition_isCorrect() { + assertEquals(4, 2 + 2); + } +} \ No newline at end of file diff --git a/wrappers/android/mynteye/build.gradle b/wrappers/android/mynteye/build.gradle new file mode 100644 index 0000000..4bf3f28 --- /dev/null +++ b/wrappers/android/mynteye/build.gradle @@ -0,0 +1,27 @@ +// Top-level build file where you can add configuration options common to all sub-projects/modules. + +buildscript { + apply from: rootProject.file('gradle/dependencies.gradle') + + repositories { + google() + jcenter() + } + dependencies { + classpath 'com.android.tools.build:gradle:3.3.1' + + // NOTE: Do not place your application dependencies here; they belong + // in the individual module build.gradle files + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/wrappers/android/mynteye/gradle.properties b/wrappers/android/mynteye/gradle.properties new file mode 100644 index 0000000..d546dea --- /dev/null +++ b/wrappers/android/mynteye/gradle.properties @@ -0,0 +1,17 @@ +# Project-wide Gradle settings. +# IDE (e.g. Android Studio) users: +# Gradle settings configured through the IDE *will override* +# any settings specified in this file. +# For more details on how to configure your build environment visit +# http://www.gradle.org/docs/current/userguide/build_environment.html +# Specifies the JVM arguments used for the daemon process. +# The setting is particularly useful for tweaking memory settings. +android.enableJetifier=true +android.useAndroidX=true +org.gradle.jvmargs=-Xmx1536m +# When configured, Gradle will run in incubating parallel mode. +# This option should only be used with decoupled projects. More details, visit +# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects +# org.gradle.parallel=true + + diff --git a/wrappers/android/mynteye/gradle/dependencies.gradle b/wrappers/android/mynteye/gradle/dependencies.gradle new file mode 100644 index 0000000..9811a55 --- /dev/null +++ b/wrappers/android/mynteye/gradle/dependencies.gradle @@ -0,0 +1,10 @@ +ext { + xversions = [ + 'compileSdk': 28, + 'minSdk': 24, + 'targetSdk': 28, + ] + + xabis = ['arm64-v8a', 'armeabi-v7a'] as String[] + //xabis = ['arm64-v8a', 'armeabi-v7a', 'x86', 'x86_64'] as String[] +} diff --git a/wrappers/android/mynteye/gradle/wrapper/gradle-wrapper.jar b/wrappers/android/mynteye/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000..f6b961f Binary files /dev/null and b/wrappers/android/mynteye/gradle/wrapper/gradle-wrapper.jar differ diff --git a/wrappers/android/mynteye/gradle/wrapper/gradle-wrapper.properties b/wrappers/android/mynteye/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..0c93efd --- /dev/null +++ b/wrappers/android/mynteye/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Tue Jan 15 14:54:17 CST 2019 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.1-all.zip diff --git a/wrappers/android/mynteye/gradlew b/wrappers/android/mynteye/gradlew new file mode 100755 index 0000000..cccdd3d --- /dev/null +++ b/wrappers/android/mynteye/gradlew @@ -0,0 +1,172 @@ +#!/usr/bin/env sh + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=$(save "$@") + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong +if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then + cd "$(dirname "$0")" +fi + +exec "$JAVACMD" "$@" diff --git a/wrappers/android/mynteye/gradlew.bat b/wrappers/android/mynteye/gradlew.bat new file mode 100644 index 0000000..f955316 --- /dev/null +++ b/wrappers/android/mynteye/gradlew.bat @@ -0,0 +1,84 @@ +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windows variants + +if not "%OS%" == "Windows_NT" goto win9xME_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/wrappers/android/mynteye/libmynteye/.gitignore b/wrappers/android/mynteye/libmynteye/.gitignore new file mode 100644 index 0000000..796b96d --- /dev/null +++ b/wrappers/android/mynteye/libmynteye/.gitignore @@ -0,0 +1 @@ +/build diff --git a/wrappers/android/mynteye/libmynteye/CMakeLists.txt b/wrappers/android/mynteye/libmynteye/CMakeLists.txt new file mode 100644 index 0000000..6f44ec6 --- /dev/null +++ b/wrappers/android/mynteye/libmynteye/CMakeLists.txt @@ -0,0 +1,122 @@ +# For more information about using CMake with Android Studio, read the +# documentation: https://d.android.com/studio/projects/add-native-code.html + +# Sets the minimum version of CMake required to build the native library. + +cmake_minimum_required(VERSION 3.4.1) + +get_filename_component(MYNTETE_ROOT "${PROJECT_SOURCE_DIR}/../../../.." ABSOLUTE) +message(STATUS "MYNTETE_ROOT: ${MYNTETE_ROOT}") + +get_filename_component(PRO_ROOT "${PROJECT_SOURCE_DIR}/.." ABSOLUTE) +message(STATUS "PRO_ROOT: ${PRO_ROOT}") + +set(LIB_ROOT "${PROJECT_SOURCE_DIR}") +message(STATUS "LIB_ROOT: ${LIB_ROOT}") + +if(NOT DJINNI_DIR) + if(DEFINED ENV{DJINNI_DIR}) + set(DJINNI_DIR $ENV{DJINNI_DIR}) + else() + set(DJINNI_DIR "${PRO_ROOT}/third_party/djinni") + endif() +endif() + +# libs + +## log + +find_library(log-lib log) + +## jnigraphics + +find_library(jnigraphics-lib jnigraphics) + +## djinni_jni + +include_directories( + ${DJINNI_DIR}/support-lib/jni +) +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 + +add_definitions(-DMYNTEYE_EXPORTS) + +set(MYNTEYE_NAMESPACE "mynteye") +#message(STATUS "Namespace: ${MYNTEYE_NAMESPACE}") + +configure_file( + ${MYNTETE_ROOT}/include/mynteye/mynteye.h.in + include/mynteye/mynteye.h @ONLY +) + +set(MYNTEYE_SRCS + #${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 + ${MYNTETE_ROOT}/src/mynteye/device/channel/bytes.cc + ${MYNTETE_ROOT}/src/mynteye/device/channel/channels.cc + ${MYNTETE_ROOT}/src/mynteye/device/channel/file_channel.cc + ${MYNTETE_ROOT}/src/mynteye/device/config.cc + ${MYNTETE_ROOT}/src/mynteye/device/context.cc + ${MYNTETE_ROOT}/src/mynteye/device/device.cc + ${MYNTETE_ROOT}/src/mynteye/device/motions.cc + ${MYNTETE_ROOT}/src/mynteye/device/standard/channels_adapter_s.cc + ${MYNTETE_ROOT}/src/mynteye/device/standard/device_s.cc + ${MYNTETE_ROOT}/src/mynteye/device/standard/streams_adapter_s.cc + ${MYNTETE_ROOT}/src/mynteye/device/standard2/channels_adapter_s2.cc + ${MYNTETE_ROOT}/src/mynteye/device/standard2/device_s2.cc + ${MYNTETE_ROOT}/src/mynteye/device/standard2/streams_adapter_s2.cc + ${MYNTETE_ROOT}/src/mynteye/device/streams.cc + ${MYNTETE_ROOT}/src/mynteye/device/types.cc + ${MYNTETE_ROOT}/src/mynteye/device/utils.cc +) + +list(APPEND MYNTEYE_SRCS ${MYNTETE_ROOT}/src/mynteye/miniglog.cc) + +add_library(mynteye STATIC ${MYNTEYE_SRCS}) +target_link_libraries(mynteye ${log-lib}) + +target_include_directories(mynteye PUBLIC + "$" + "$" + "$" + "$" +) + +## libmynteye_jni + +set(CPP_DIR "${PROJECT_SOURCE_DIR}/src/main/cpp") + +include_directories( + ${CPP_DIR}/mynteye/cpp + ${CPP_DIR}/mynteye/impl + ${CPP_DIR}/mynteye/jni +) + +set(MYNTEYE_JNI_SRCS "") +foreach(__dir cpp impl jni) + file(GLOB __srcs "${CPP_DIR}/mynteye/${__dir}/*.cpp") + list(APPEND MYNTEYE_JNI_SRCS ${__srcs}) +endforeach() +#message(STATUS "MYNTEYE_JNI_SRCS: ${MYNTEYE_JNI_SRCS}") + +add_library(mynteye_jni SHARED + ${DJINNI_DIR}/support-lib/jni/djinni_main.cpp + ${CPP_DIR}/mynteye/impl/util/jni_util.cpp + ${MYNTEYE_JNI_SRCS} +) +target_link_libraries(mynteye_jni ${log-lib} ${jnigraphics-lib} djinni_jni mynteye mynteye_internal) diff --git a/wrappers/android/mynteye/libmynteye/build.gradle b/wrappers/android/mynteye/libmynteye/build.gradle new file mode 100644 index 0000000..b5c3507 --- /dev/null +++ b/wrappers/android/mynteye/libmynteye/build.gradle @@ -0,0 +1,53 @@ +apply plugin: 'com.android.library' + +android { + compileSdkVersion xversions.compileSdk + + defaultConfig { + minSdkVersion xversions.minSdk + targetSdkVersion xversions.targetSdk + versionCode 1 + versionName "1.0" + + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + + externalNativeBuild { + // https://developer.android.com/ndk/guides/cmake + cmake { + cppFlags "-std=c++11 -frtti -fexceptions" + } + } + + ndk { + abiFilters xabis + } + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } + + externalNativeBuild { + cmake { + path "CMakeLists.txt" + } + } + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } +} + +dependencies { + implementation fileTree(dir: 'libs', include: ['*.jar']) + + implementation 'androidx.annotation:annotation:1.0.1' + + testImplementation 'junit:junit:4.12' + androidTestImplementation 'androidx.test:runner:1.1.1' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1' +} diff --git a/wrappers/android/mynteye/libmynteye/proguard-rules.pro b/wrappers/android/mynteye/libmynteye/proguard-rules.pro new file mode 100644 index 0000000..f1b4245 --- /dev/null +++ b/wrappers/android/mynteye/libmynteye/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile diff --git a/wrappers/android/mynteye/libmynteye/src/androidTest/java/com/slightech/mynteye/ExampleInstrumentedTest.java b/wrappers/android/mynteye/libmynteye/src/androidTest/java/com/slightech/mynteye/ExampleInstrumentedTest.java new file mode 100644 index 0000000..8348283 --- /dev/null +++ b/wrappers/android/mynteye/libmynteye/src/androidTest/java/com/slightech/mynteye/ExampleInstrumentedTest.java @@ -0,0 +1,26 @@ +package com.slightech.mynteye; + +import android.content.Context; +import androidx.test.InstrumentationRegistry; +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import static org.junit.Assert.*; + +/** + * Instrumented test, which will execute on an Android device. + * + * @see Testing documentation + */ +@RunWith(AndroidJUnit4.class) +public class ExampleInstrumentedTest { + @Test + public void useAppContext() { + // Context of the app under test. + Context appContext = InstrumentationRegistry.getTargetContext(); + + assertEquals("com.slightech.mynteye.test", appContext.getPackageName()); + } +} diff --git a/wrappers/android/mynteye/libmynteye/src/main/AndroidManifest.xml b/wrappers/android/mynteye/libmynteye/src/main/AndroidManifest.xml new file mode 100644 index 0000000..7db87f0 --- /dev/null +++ b/wrappers/android/mynteye/libmynteye/src/main/AndroidManifest.xml @@ -0,0 +1,2 @@ + diff --git a/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/cpp/addon.hpp b/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/cpp/addon.hpp new file mode 100644 index 0000000..8ce01b5 --- /dev/null +++ b/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/cpp/addon.hpp @@ -0,0 +1,28 @@ +// AUTOGENERATED FILE - DO NOT MODIFY! +// This file generated by Djinni from mynteye_types.djinni + +#pragma once + +#include + +namespace mynteye_jni { + +enum class Addon : int { + /** Infrared */ + INFRARED, + /** Second infrared */ + INFRARED2, +}; + +} // namespace mynteye_jni + +namespace std { + +template <> +struct hash<::mynteye_jni::Addon> { + size_t operator()(::mynteye_jni::Addon type) const { + return std::hash()(static_cast(type)); + } +}; + +} // namespace std diff --git a/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/cpp/calibration_model.hpp b/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/cpp/calibration_model.hpp new file mode 100644 index 0000000..4d7dcb7 --- /dev/null +++ b/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/cpp/calibration_model.hpp @@ -0,0 +1,30 @@ +// AUTOGENERATED FILE - DO NOT MODIFY! +// This file generated by Djinni from mynteye_types.djinni + +#pragma once + +#include + +namespace mynteye_jni { + +enum class CalibrationModel : int { + /** Pinhole */ + PINHOLE, + /** Equidistant: KANNALA_BRANDT */ + KANNALA_BRANDT, + /** Unknow */ + UNKNOW, +}; + +} // namespace mynteye_jni + +namespace std { + +template <> +struct hash<::mynteye_jni::CalibrationModel> { + size_t operator()(::mynteye_jni::CalibrationModel type) const { + return std::hash()(static_cast(type)); + } +}; + +} // namespace std diff --git a/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/cpp/capability.hpp b/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/cpp/capability.hpp new file mode 100644 index 0000000..4d62601 --- /dev/null +++ b/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/cpp/capability.hpp @@ -0,0 +1,42 @@ +// AUTOGENERATED FILE - DO NOT MODIFY! +// This file generated by Djinni from mynteye_types.djinni + +#pragma once + +#include + +namespace mynteye_jni { + +enum class Capability : int { + /** Provides stereo stream */ + STEREO, + /** Provide stereo color stream */ + STEREO_COLOR, + /** Provides color stream */ + COLOR, + /** Provides depth stream */ + DEPTH, + /** Provides point cloud stream */ + POINTS, + /** Provides fisheye stream */ + FISHEYE, + /** Provides infrared stream */ + INFRARED, + /** Provides second infrared stream */ + INFRARED2, + /** Provides IMU (accelerometer, gyroscope) data */ + IMU, +}; + +} // namespace mynteye_jni + +namespace std { + +template <> +struct hash<::mynteye_jni::Capability> { + size_t operator()(::mynteye_jni::Capability type) const { + return std::hash()(static_cast(type)); + } +}; + +} // namespace std 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 new file mode 100644 index 0000000..667ec59 --- /dev/null +++ b/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/cpp/device.hpp @@ -0,0 +1,106 @@ +// AUTOGENERATED FILE - DO NOT MODIFY! +// This file generated by Djinni from mynteye.djinni + +#pragma once + +#include "addon.hpp" +#include "capability.hpp" +#include "device_usb_info.hpp" +#include "extrinsics.hpp" +#include "info.hpp" +#include "intrinsics.hpp" +#include "model.hpp" +#include "motion_data.hpp" +#include "motion_intrinsics.hpp" +#include "option.hpp" +#include "option_info.hpp" +#include "source.hpp" +#include "stream.hpp" +#include "stream_data.hpp" +#include "stream_request.hpp" +#include +#include +#include +#include + +namespace mynteye_jni { + +/** Device class to communicate with MYNT® EYE device */ +class Device { +public: + virtual ~Device() {} + + /** Create the device instance */ + static std::shared_ptr Create(const ::mynteye_jni::DeviceUsbInfo & info); + + /** Get the model */ + virtual ::mynteye_jni::Model GetModel() = 0; + + /** Supports the stream or not */ + virtual bool SupportsStream(::mynteye_jni::Stream stream) = 0; + + /** Supports the capability or not */ + virtual bool SupportsCapability(::mynteye_jni::Capability capabilities) = 0; + + /** Supports the option or not */ + virtual bool SupportsOption(::mynteye_jni::Option option) = 0; + + /** Supports the addon or not */ + virtual bool SupportsAddon(::mynteye_jni::Addon addon) = 0; + + /** Get all stream requests */ + virtual std::vector<::mynteye_jni::StreamRequest> GetStreamRequests() = 0; + + /** Config the stream request */ + virtual void ConfigStreamRequest(const ::mynteye_jni::StreamRequest & request) = 0; + + /** Get the device info */ + virtual std::string GetInfo(::mynteye_jni::Info info) = 0; + + /** Get the intrinsics of stream */ + virtual ::mynteye_jni::Intrinsics GetIntrinsics(::mynteye_jni::Stream stream) = 0; + + /** Get the extrinsics of stream */ + virtual ::mynteye_jni::Extrinsics GetExtrinsics(::mynteye_jni::Stream from, ::mynteye_jni::Stream to) = 0; + + /** Get the intrinsics of motion */ + virtual ::mynteye_jni::MotionIntrinsics GetMotionIntrinsics() = 0; + + /** Get the extrinsics from one stream to motion */ + virtual ::mynteye_jni::Extrinsics GetMotionExtrinsics(::mynteye_jni::Stream from) = 0; + + /** Get the option info */ + virtual ::mynteye_jni::OptionInfo GetOptionInfo(::mynteye_jni::Option option) = 0; + + /** Get the option value */ + virtual int32_t GetOptionValue(::mynteye_jni::Option option) = 0; + + /** Set the option value */ + virtual void SetOptionValue(::mynteye_jni::Option option, int32_t value) = 0; + + /** Run the option value */ + virtual bool RunOptionAction(::mynteye_jni::Option option) = 0; + + /** Start capturing the source */ + virtual void Start(::mynteye_jni::Source source) = 0; + + /** Stop capturing the source */ + virtual void Stop(::mynteye_jni::Source source) = 0; + + /** Wait the streams are ready */ + virtual void WaitForStreams() = 0; + + /** Get the latest data of stream */ + virtual std::shared_ptr<::mynteye_jni::StreamData> GetStreamData(::mynteye_jni::Stream stream) = 0; + + /** Get the datas of stream */ + virtual std::vector> GetStreamDatas(::mynteye_jni::Stream stream) = 0; + + /** Enable cache motion datas until get them, otherwise using callback instead */ + virtual void EnableMotionDatas(int32_t max_size) = 0; + + /** Get the motion datas */ + virtual std::vector> GetMotionDatas() = 0; +}; + +} // namespace mynteye_jni 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 new file mode 100644 index 0000000..fc48e36 --- /dev/null +++ b/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/cpp/device_usb_info.hpp @@ -0,0 +1,50 @@ +// AUTOGENERATED FILE - DO NOT MODIFY! +// This file generated by Djinni from mynteye_types.djinni + +#pragma once + +#include +#include +#include + +namespace mynteye_jni { + +/** Device USB information */ +struct DeviceUsbInfo final { + /** 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; + /** Serial number */ + std::string serial; + + 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 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_)) + , serial(std::move(serial_)) + {} +}; + +} // namespace mynteye_jni diff --git a/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/cpp/extrinsics.hpp b/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/cpp/extrinsics.hpp new file mode 100644 index 0000000..38e4c7f --- /dev/null +++ b/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/cpp/extrinsics.hpp @@ -0,0 +1,25 @@ +// AUTOGENERATED FILE - DO NOT MODIFY! +// This file generated by Djinni from mynteye_types.djinni + +#pragma once + +#include +#include + +namespace mynteye_jni { + +/** Extrinsics, represent how the different datas are connected */ +struct Extrinsics final { + /** Rotation matrix, 3x3 */ + std::vector rotation; + /** Translation vector, 1x3 */ + std::vector translation; + + Extrinsics(std::vector rotation_, + std::vector translation_) + : rotation(std::move(rotation_)) + , translation(std::move(translation_)) + {} +}; + +} // namespace mynteye_jni diff --git a/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/cpp/format.hpp b/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/cpp/format.hpp new file mode 100644 index 0000000..69c9ee0 --- /dev/null +++ b/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/cpp/format.hpp @@ -0,0 +1,32 @@ +// AUTOGENERATED FILE - DO NOT MODIFY! +// This file generated by Djinni from mynteye_types.djinni + +#pragma once + +#include + +namespace mynteye_jni { + +enum class Format : int { + /** Greyscale, 8 bits per pixel */ + GREY, + /** YUV 4:2:2, 16 bits per pixel */ + YUYV, + /** BGR 8:8:8, 24 bits per pixel */ + BGR888, + /** RGB 8:8:8, 24 bits per pixel */ + RGB888, +}; + +} // namespace mynteye_jni + +namespace std { + +template <> +struct hash<::mynteye_jni::Format> { + size_t operator()(::mynteye_jni::Format type) const { + return std::hash()(static_cast(type)); + } +}; + +} // namespace std diff --git a/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/cpp/frame.hpp b/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/cpp/frame.hpp new file mode 100644 index 0000000..ad8dd43 --- /dev/null +++ b/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/cpp/frame.hpp @@ -0,0 +1,34 @@ +// AUTOGENERATED FILE - DO NOT MODIFY! +// This file generated by Djinni from mynteye_types.djinni + +#pragma once + +#include +#include + +namespace mynteye_jni { + +enum class Format; + +/** Frame with raw data */ +class Frame { +public: + virtual ~Frame() {} + + /** Get the width */ + virtual int32_t Width() = 0; + + /** Get the height */ + virtual int32_t Height() = 0; + + /** Get the pixel format */ + virtual ::mynteye_jni::Format Format() = 0; + + /** Get the size */ + virtual int32_t Size() = 0; + + /** Get the data */ + virtual std::vector Data() = 0; +}; + +} // namespace mynteye_jni diff --git a/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/cpp/img_data.hpp b/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/cpp/img_data.hpp new file mode 100644 index 0000000..160b314 --- /dev/null +++ b/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/cpp/img_data.hpp @@ -0,0 +1,29 @@ +// AUTOGENERATED FILE - DO NOT MODIFY! +// This file generated by Djinni from mynteye_types.djinni + +#pragma once + +#include +#include + +namespace mynteye_jni { + +/** Image data */ +struct ImgData final { + /** Image frame id */ + int64_t frame_id; + /** Image timestamp in 1us */ + int64_t timestamp; + /** Image exposure time, virtual value in [1, 480] */ + int64_t exposure_time; + + ImgData(int64_t frame_id_, + int64_t timestamp_, + int64_t exposure_time_) + : frame_id(std::move(frame_id_)) + , timestamp(std::move(timestamp_)) + , exposure_time(std::move(exposure_time_)) + {} +}; + +} // namespace mynteye_jni diff --git a/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/cpp/imu_data.hpp b/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/cpp/imu_data.hpp new file mode 100644 index 0000000..05f2a65 --- /dev/null +++ b/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/cpp/imu_data.hpp @@ -0,0 +1,47 @@ +// AUTOGENERATED FILE - DO NOT MODIFY! +// This file generated by Djinni from mynteye_types.djinni + +#pragma once + +#include +#include +#include + +namespace mynteye_jni { + +/** IMU data */ +struct ImuData final { + /** IMU frame id */ + int64_t frame_id; + /** + * IMU accel or gyro flag + * 0: accel and gyro are both valid + * 1: accel is valid + * 2: gyro is valid + */ + int32_t flag; + /** IMU timestamp in 1us */ + int64_t timestamp; + /** IMU accelerometer data for 3-axis: X, Y, Z. */ + std::vector accel; + /** IMU gyroscope data for 3-axis: X, Y, Z. */ + std::vector gyro; + /** IMU temperature */ + double temperature; + + ImuData(int64_t frame_id_, + int32_t flag_, + int64_t timestamp_, + std::vector accel_, + std::vector gyro_, + double temperature_) + : frame_id(std::move(frame_id_)) + , flag(std::move(flag_)) + , timestamp(std::move(timestamp_)) + , accel(std::move(accel_)) + , gyro(std::move(gyro_)) + , temperature(std::move(temperature_)) + {} +}; + +} // namespace mynteye_jni diff --git a/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/cpp/imu_intrinsics.hpp b/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/cpp/imu_intrinsics.hpp new file mode 100644 index 0000000..eb95676 --- /dev/null +++ b/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/cpp/imu_intrinsics.hpp @@ -0,0 +1,38 @@ +// AUTOGENERATED FILE - DO NOT MODIFY! +// This file generated by Djinni from mynteye_types.djinni + +#pragma once + +#include +#include + +namespace mynteye_jni { + +/** IMU intrinsics: scale, drift and variances */ +struct ImuIntrinsics final { + /** + * Scale matrix 3x3 + * Scale X cross axis cross axis + * cross axis Scale Y cross axis + * cross axis cross axis Scale Z + */ + std::vector scale; + /** Zero-drift: X, Y, Z 1x3 */ + std::vector drift; + /** Noise density variances 1x3 */ + std::vector noise; + /** Random walk variances 1x3 */ + std::vector bias; + + ImuIntrinsics(std::vector scale_, + std::vector drift_, + std::vector noise_, + std::vector bias_) + : scale(std::move(scale_)) + , drift(std::move(drift_)) + , noise(std::move(noise_)) + , bias(std::move(bias_)) + {} +}; + +} // namespace mynteye_jni diff --git a/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/cpp/info.hpp b/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/cpp/info.hpp new file mode 100644 index 0000000..d02c921 --- /dev/null +++ b/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/cpp/info.hpp @@ -0,0 +1,40 @@ +// AUTOGENERATED FILE - DO NOT MODIFY! +// This file generated by Djinni from mynteye_types.djinni + +#pragma once + +#include + +namespace mynteye_jni { + +enum class Info : int { + /** Device name */ + DEVICE_NAME, + /** Serial number */ + SERIAL_NUMBER, + /** Firmware version */ + FIRMWARE_VERSION, + /** Hardware version */ + HARDWARE_VERSION, + /** Spec version */ + SPEC_VERSION, + /** Lens type */ + LENS_TYPE, + /** IMU type */ + IMU_TYPE, + /** Nominal baseline */ + NOMINAL_BASELINE, +}; + +} // namespace mynteye_jni + +namespace std { + +template <> +struct hash<::mynteye_jni::Info> { + size_t operator()(::mynteye_jni::Info type) const { + return std::hash()(static_cast(type)); + } +}; + +} // namespace std diff --git a/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/cpp/intrinsics.hpp b/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/cpp/intrinsics.hpp new file mode 100644 index 0000000..549a279 --- /dev/null +++ b/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/cpp/intrinsics.hpp @@ -0,0 +1,55 @@ +// AUTOGENERATED FILE - DO NOT MODIFY! +// This file generated by Djinni from mynteye_types.djinni + +#pragma once + +#include "calibration_model.hpp" +#include +#include +#include + +namespace mynteye_jni { + +/** Stream intrinsics */ +struct Intrinsics final { + /** The calibration model */ + CalibrationModel calib_model; + /** The width of the image in pixels */ + int32_t width; + /** The height of the image in pixels */ + int32_t height; + /** The focal length of the image plane, as a multiple of pixel width (pinhole) */ + double fx; + /** The focal length of the image plane, as a multiple of pixel height (pinhole) */ + double fy; + /** The horizontal coordinate of the principal point of the image (pinhole) */ + double cx; + /** The vertical coordinate of the principal point of the image (pinhole) */ + double cy; + /** + * The distortion coefficients + * pinhole: k1,k2,p1,p2,k3 + * kannala_brandt: k2,k3,k4,k5,mu,mv,u0,v0 + */ + std::vector coeffs; + + Intrinsics(CalibrationModel calib_model_, + int32_t width_, + int32_t height_, + double fx_, + double fy_, + double cx_, + double cy_, + std::vector coeffs_) + : calib_model(std::move(calib_model_)) + , width(std::move(width_)) + , height(std::move(height_)) + , fx(std::move(fx_)) + , fy(std::move(fy_)) + , cx(std::move(cx_)) + , cy(std::move(cy_)) + , coeffs(std::move(coeffs_)) + {} +}; + +} // namespace mynteye_jni diff --git a/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/cpp/model.hpp b/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/cpp/model.hpp new file mode 100644 index 0000000..6404632 --- /dev/null +++ b/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/cpp/model.hpp @@ -0,0 +1,30 @@ +// AUTOGENERATED FILE - DO NOT MODIFY! +// This file generated by Djinni from mynteye_types.djinni + +#pragma once + +#include + +namespace mynteye_jni { + +enum class Model : int { + /** Standard */ + STANDARD, + /** Standard 2 */ + STANDARD2, + /** Standard 210a */ + STANDARD210A, +}; + +} // namespace mynteye_jni + +namespace std { + +template <> +struct hash<::mynteye_jni::Model> { + size_t operator()(::mynteye_jni::Model type) const { + return std::hash()(static_cast(type)); + } +}; + +} // namespace std diff --git a/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/cpp/motion_data.hpp b/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/cpp/motion_data.hpp new file mode 100644 index 0000000..21b66ad --- /dev/null +++ b/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/cpp/motion_data.hpp @@ -0,0 +1,18 @@ +// AUTOGENERATED FILE - DO NOT MODIFY! +// This file generated by Djinni from mynteye_types.djinni + +#pragma once + +namespace mynteye_jni { + +struct ImuData; + +/** Device motion data */ +class MotionData { +public: + virtual ~MotionData() {} + + virtual ImuData Imu() = 0; +}; + +} // namespace mynteye_jni diff --git a/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/cpp/motion_intrinsics.hpp b/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/cpp/motion_intrinsics.hpp new file mode 100644 index 0000000..cd5fbb3 --- /dev/null +++ b/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/cpp/motion_intrinsics.hpp @@ -0,0 +1,25 @@ +// AUTOGENERATED FILE - DO NOT MODIFY! +// This file generated by Djinni from mynteye_types.djinni + +#pragma once + +#include "imu_intrinsics.hpp" +#include + +namespace mynteye_jni { + +/** Motion intrinsics, including accelerometer and gyroscope */ +struct MotionIntrinsics final { + /** Accelerometer intrinsics */ + ImuIntrinsics accel; + /** Gyroscope intrinsics */ + ImuIntrinsics gyro; + + MotionIntrinsics(ImuIntrinsics accel_, + ImuIntrinsics gyro_) + : accel(std::move(accel_)) + , gyro(std::move(gyro_)) + {} +}; + +} // namespace mynteye_jni diff --git a/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/cpp/option.hpp b/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/cpp/option.hpp new file mode 100644 index 0000000..6363de9 --- /dev/null +++ b/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/cpp/option.hpp @@ -0,0 +1,115 @@ +// AUTOGENERATED FILE - DO NOT MODIFY! +// This file generated by Djinni from mynteye_types.djinni + +#pragma once + +#include + +namespace mynteye_jni { + +enum class Option : int { + /** + * Image gain, valid if manual-exposure + * range: [0,48], default: 24 + */ + GAIN, + /** + * Image brightness, valid if manual-exposure + * range: [0,240], default: 120 + */ + BRIGHTNESS, + /** + * Image contrast, valid if manual-exposure + * range: [0,255], default: 127 + */ + CONTRAST, + /** + * Image frame rate, must set IMU_FREQUENCY together + * values: {10,15,20,25,30,35,40,45,50,55,60}, default: 25 + */ + FRAME_RATE, + /** + * IMU frequency, must set FRAME_RATE together + * values: {100,200,250,333,500}, default: 200 + */ + IMU_FREQUENCY, + /** + * Exposure mode + * 0: enable auto-exposure + * 1: disable auto-exposure (manual-exposure) + */ + EXPOSURE_MODE, + /** + * Max gain, valid if auto-exposure + * range of standard 1: [0,48], default: 48 + * range of standard 2: [0,255], default: 8 + */ + MAX_GAIN, + /** + * Max exposure time, valid if auto-exposure + * range of standard 1: [0,240], default: 240 + * range of standard 2: [0,1000], default: 333 + */ + MAX_EXPOSURE_TIME, + /** + * min exposure time, valid if auto-exposure + * range: [0,1000], default: 0 + */ + MIN_EXPOSURE_TIME, + /** + * Desired brightness, valid if auto-exposure + * range of standard 1: [0,255], default: 192 + * range of standard 2: [1,255], default: 122 + */ + DESIRED_BRIGHTNESS, + /** + * IR control + * range: [0,160], default: 0 + */ + IR_CONTROL, + /** + * HDR mode + * 0: 10-bit + * 1: 12-bit + */ + HDR_MODE, + /** + * The range of accelerometer + * value of standard 1: {4,8,16,32}, default: 8 + * value of standard 2: {6,12,24,48}, default: 12 + */ + ACCELEROMETER_RANGE, + /** + * The range of gyroscope + * value of standard 1: {500,1000,2000,4000}, default: 1000 + * value of standard 2: {250,500,1000,2000,4000}, default: 1000 + */ + GYROSCOPE_RANGE, + /** + * The parameter of accelerometer low pass filter + * values: {0,1,2}, default: 2 + */ + ACCELEROMETER_LOW_PASS_FILTER, + /** + * The parameter of gyroscope low pass filter + * values: {23,64}, default: 64 + */ + GYROSCOPE_LOW_PASS_FILTER, + /** Zero drift calibration */ + ZERO_DRIFT_CALIBRATION, + /** Erase chip */ + ERASE_CHIP, +}; + +} // namespace mynteye_jni + +namespace std { + +template <> +struct hash<::mynteye_jni::Option> { + size_t operator()(::mynteye_jni::Option type) const { + return std::hash()(static_cast(type)); + } +}; + +} // namespace std diff --git a/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/cpp/option_info.hpp b/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/cpp/option_info.hpp new file mode 100644 index 0000000..d8f738d --- /dev/null +++ b/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/cpp/option_info.hpp @@ -0,0 +1,29 @@ +// AUTOGENERATED FILE - DO NOT MODIFY! +// This file generated by Djinni from mynteye_types.djinni + +#pragma once + +#include +#include + +namespace mynteye_jni { + +/** Option info */ +struct OptionInfo final { + /** Minimum value */ + int32_t min; + /** Maximum value */ + int32_t max; + /** Default value */ + int32_t def; + + OptionInfo(int32_t min_, + int32_t max_, + int32_t def_) + : min(std::move(min_)) + , max(std::move(max_)) + , def(std::move(def_)) + {} +}; + +} // namespace mynteye_jni diff --git a/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/cpp/source.hpp b/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/cpp/source.hpp new file mode 100644 index 0000000..d2bbb38 --- /dev/null +++ b/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/cpp/source.hpp @@ -0,0 +1,30 @@ +// AUTOGENERATED FILE - DO NOT MODIFY! +// This file generated by Djinni from mynteye_types.djinni + +#pragma once + +#include + +namespace mynteye_jni { + +enum class Source : int { + /** Video streaming of stereo, color, depth, etc. */ + VIDEO_STREAMING, + /** Motion tracking of IMU (accelerometer, gyroscope) */ + MOTION_TRACKING, + /** Enable everything together */ + ALL, +}; + +} // namespace mynteye_jni + +namespace std { + +template <> +struct hash<::mynteye_jni::Source> { + size_t operator()(::mynteye_jni::Source type) const { + return std::hash()(static_cast(type)); + } +}; + +} // namespace std diff --git a/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/cpp/stream.hpp b/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/cpp/stream.hpp new file mode 100644 index 0000000..e21a691 --- /dev/null +++ b/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/cpp/stream.hpp @@ -0,0 +1,28 @@ +// AUTOGENERATED FILE - DO NOT MODIFY! +// This file generated by Djinni from mynteye_types.djinni + +#pragma once + +#include + +namespace mynteye_jni { + +enum class Stream : int { + /** Left stream */ + LEFT, + /** Right stream */ + RIGHT, +}; + +} // namespace mynteye_jni + +namespace std { + +template <> +struct hash<::mynteye_jni::Stream> { + size_t operator()(::mynteye_jni::Stream type) const { + return std::hash()(static_cast(type)); + } +}; + +} // namespace std diff --git a/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/cpp/stream_data.hpp b/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/cpp/stream_data.hpp new file mode 100644 index 0000000..3f3899b --- /dev/null +++ b/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/cpp/stream_data.hpp @@ -0,0 +1,26 @@ +// AUTOGENERATED FILE - DO NOT MODIFY! +// This file generated by Djinni from mynteye_types.djinni + +#pragma once + +#include +#include + +namespace mynteye_jni { + +class Frame; +struct ImgData; + +/** Device stream data */ +class StreamData { +public: + virtual ~StreamData() {} + + virtual ImgData Img() = 0; + + virtual std::shared_ptr<::mynteye_jni::Frame> Frame() = 0; + + virtual int64_t FrameId() = 0; +}; + +} // namespace mynteye_jni diff --git a/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/cpp/stream_request.hpp b/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/cpp/stream_request.hpp new file mode 100644 index 0000000..a708025 --- /dev/null +++ b/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/cpp/stream_request.hpp @@ -0,0 +1,38 @@ +// AUTOGENERATED FILE - DO NOT MODIFY! +// This file generated by Djinni from mynteye_types.djinni + +#pragma once + +#include "format.hpp" +#include +#include + +namespace mynteye_jni { + +/** Stream request */ +struct StreamRequest final { + /** Stream index */ + int32_t index; + /** Stream width in pixels */ + int32_t width; + /** Stream height in pixels */ + int32_t height; + /** Stream pixel format */ + Format format; + /** Stream frames per second */ + int32_t fps; + + StreamRequest(int32_t index_, + int32_t width_, + int32_t height_, + Format format_, + int32_t fps_) + : index(std::move(index_)) + , width(std::move(width_)) + , height(std::move(height_)) + , format(std::move(format_)) + , fps(std::move(fps_)) + {} +}; + +} // namespace mynteye_jni 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 new file mode 100644 index 0000000..58aa44e --- /dev/null +++ b/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/impl/device_impl.cpp @@ -0,0 +1,223 @@ +#include "device_impl.hpp" + +#include "mynteye/device/context.h" +#include "mynteye/device/device.h" +#include "mynteye/logger.h" + +#include "device_usb_info.hpp" +#include "stream_request.hpp" +#include "type_conversion.hpp" + +#include "frame_impl.hpp" +#include "motion_data_impl.hpp" +#include "stream_data_impl.hpp" + +#include "mynteye/uvc/uvc.h" +#include "mynteye/util/strings.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; + + Context context; + int32_t i = 0; + for (auto&& d : context.devices()) { + infos.emplace_back(i, + d->GetInfo(Info::DEVICE_NAME), + d->GetInfo(Info::SERIAL_NUMBER)); + ++i; + } + + return infos; +} + +std::shared_ptr Device::Create(const ::mynteye_jni::DeviceUsbInfo & info) { + VLOG(2) << __func__; + Context context; + int32_t i = 0; + for (auto&& d : context.devices()) { + if (i == info.index) { + return std::make_shared(d); + } + ++i; + } + 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__; +} + +DeviceImpl::~DeviceImpl() { + VLOG(2) << __func__; +} + +::mynteye_jni::Model DeviceImpl::GetModel() { + return to_jni(device_->GetModel()); +} + +bool DeviceImpl::SupportsStream(::mynteye_jni::Stream stream) { + return device_->Supports(from_jni(stream)); +} + +bool DeviceImpl::SupportsCapability(::mynteye_jni::Capability capabilities) { + return device_->Supports(from_jni(capabilities)); +} + +bool DeviceImpl::SupportsOption(::mynteye_jni::Option option) { + return device_->Supports(from_jni(option)); +} + +bool DeviceImpl::SupportsAddon(::mynteye_jni::Addon addon) { + return device_->Supports(from_jni(addon)); +} + +std::vector<::mynteye_jni::StreamRequest> DeviceImpl::GetStreamRequests() { + VLOG(2) << __func__; + std::vector<::mynteye_jni::StreamRequest> requests; + + int32_t i = 0; + for (auto&& req : device_->GetStreamRequests()) { + requests.emplace_back(i, + req.width, req.height, to_jni(req.format), req.fps); + ++i; + } + + return requests; +} + +void DeviceImpl::ConfigStreamRequest( + const ::mynteye_jni::StreamRequest & request) { + VLOG(2) << __func__; + int32_t i = 0; + for (auto&& req : device_->GetStreamRequests()) { + if (i == request.index) { + device_->ConfigStreamRequest(req); + return; + } + ++i; + } +} + +std::string DeviceImpl::GetInfo(::mynteye_jni::Info info) { + return device_->GetInfo(from_jni(info)); +} + +::mynteye_jni::Intrinsics DeviceImpl::GetIntrinsics( + ::mynteye_jni::Stream stream) { + auto in = device_->GetIntrinsics(from_jni(stream)); + if (in->calib_model() == MYNTEYE_NAMESPACE::CalibrationModel::PINHOLE) { + auto in_p = std::dynamic_pointer_cast(in); + return {CalibrationModel::PINHOLE, in_p->width, in_p->height, + in_p->fx, in_p->fy, in_p->cx, in_p->cy, + to_vector<5>(in_p->coeffs)}; + } else if (in->calib_model() == MYNTEYE_NAMESPACE::CalibrationModel::KANNALA_BRANDT) { + auto in_k = std::dynamic_pointer_cast(in); + return {CalibrationModel::KANNALA_BRANDT, in_k->width, in_k->height, + 0, 0, 0, 0, to_vector<8>(in_k->coeffs)}; + } else { + LOG(WARNING) << "Unknown calibration model"; + return {CalibrationModel::UNKNOW, 0, 0, 0, 0, 0, 0, {}}; + } +} + +::mynteye_jni::Extrinsics DeviceImpl::GetExtrinsics( + ::mynteye_jni::Stream from, ::mynteye_jni::Stream to) { + auto ex = device_->GetExtrinsics(from_jni(from), from_jni(to)); + return {to_vector<3, 3>(ex.rotation), to_vector<3>(ex.translation)}; +} + +::mynteye_jni::MotionIntrinsics DeviceImpl::GetMotionIntrinsics() { + auto in = device_->GetMotionIntrinsics(); + auto in_to_jni = [](MYNTEYE_NAMESPACE::ImuIntrinsics& in) { + return ImuIntrinsics{ + to_vector<3, 3>(in.scale), to_vector<3>(in.drift), + to_vector<3>(in.noise), to_vector<3>(in.bias) + }; + }; + return {in_to_jni(in.accel), in_to_jni(in.gyro)}; +} + +::mynteye_jni::Extrinsics DeviceImpl::GetMotionExtrinsics( + ::mynteye_jni::Stream from) { + auto ex = device_->GetMotionExtrinsics(from_jni(from)); + return {to_vector<3, 3>(ex.rotation), to_vector<3>(ex.translation)}; +} + +::mynteye_jni::OptionInfo DeviceImpl::GetOptionInfo(::mynteye_jni::Option option) { + auto info = device_->GetOptionInfo(from_jni(option)); + return {info.min, info.max, info.def}; +} + +int32_t DeviceImpl::GetOptionValue(::mynteye_jni::Option option) { + return device_->GetOptionValue(from_jni(option)); +} + +void DeviceImpl::SetOptionValue(::mynteye_jni::Option option, int32_t value) { + return device_->SetOptionValue(from_jni(option), value); +} + +bool DeviceImpl::RunOptionAction(::mynteye_jni::Option option) { + return device_->RunOptionAction(from_jni(option)); +} + +void DeviceImpl::Start(::mynteye_jni::Source source) { + device_->Start(from_jni(source)); +} + +void DeviceImpl::Stop(::mynteye_jni::Source source) { + device_->Stop(from_jni(source)); +} + +void DeviceImpl::WaitForStreams() { + device_->WaitForStreams(); +} + +std::shared_ptr<::mynteye_jni::StreamData> DeviceImpl::GetStreamData( + ::mynteye_jni::Stream stream) { + auto&& data = device_->GetStreamData(from_jni(stream)); + return std::make_shared(data); +} + +std::vector> +DeviceImpl::GetStreamDatas(::mynteye_jni::Stream stream) { + std::vector> datas; + for (auto&& data : device_->GetStreamDatas(from_jni(stream))) { + datas.push_back(std::make_shared(data)); + } + return datas; +} + +void DeviceImpl::EnableMotionDatas(int32_t max_size) { + device_->EnableMotionDatas(max_size); +} + +std::vector> +DeviceImpl::GetMotionDatas() { + std::vector> datas; + for (auto&& data : device_->GetMotionDatas()) { + datas.push_back(std::make_shared(data)); + } + return datas; +} + +} // namespace mynteye_jni diff --git a/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/impl/device_impl.hpp b/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/impl/device_impl.hpp new file mode 100644 index 0000000..4526eb6 --- /dev/null +++ b/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/impl/device_impl.hpp @@ -0,0 +1,92 @@ +#pragma once + +#include +#include + +#include "mynteye/device/device.h" + +#include "device.hpp" + +namespace mynteye_jni { + +class DeviceImpl : public Device { + public: + using device_t = std::shared_ptr; + + explicit DeviceImpl(const device_t & device); + ~DeviceImpl(); + + /** Get the model */ + ::mynteye_jni::Model GetModel() override; + + /** Supports the stream or not */ + bool SupportsStream(::mynteye_jni::Stream stream) override; + + /** Supports the capability or not */ + bool SupportsCapability(::mynteye_jni::Capability capabilities) override; + + /** Supports the option or not */ + bool SupportsOption(::mynteye_jni::Option option) override; + + /** Supports the addon or not */ + bool SupportsAddon(::mynteye_jni::Addon addon) override; + + /** Get all stream requests */ + std::vector<::mynteye_jni::StreamRequest> GetStreamRequests() override; + + /** Config the stream request */ + void ConfigStreamRequest(const ::mynteye_jni::StreamRequest & request) override; + + /** Get the device info */ + std::string GetInfo(::mynteye_jni::Info info) override; + + /** Get the intrinsics of stream */ + ::mynteye_jni::Intrinsics GetIntrinsics(::mynteye_jni::Stream stream) override; + + /** Get the extrinsics of stream */ + ::mynteye_jni::Extrinsics GetExtrinsics(::mynteye_jni::Stream from, ::mynteye_jni::Stream to) override; + + /** Get the intrinsics of motion */ + ::mynteye_jni::MotionIntrinsics GetMotionIntrinsics() override; + + /** Get the extrinsics from one stream to motion */ + ::mynteye_jni::Extrinsics GetMotionExtrinsics(::mynteye_jni::Stream from) override; + + /** Get the option info */ + ::mynteye_jni::OptionInfo GetOptionInfo(::mynteye_jni::Option option) override; + + /** Get the option value */ + int32_t GetOptionValue(::mynteye_jni::Option option) override; + + /** Set the option value */ + void SetOptionValue(::mynteye_jni::Option option, int32_t value) override; + + /** Run the option value */ + bool RunOptionAction(::mynteye_jni::Option option) override; + + /** Start capturing the source */ + void Start(::mynteye_jni::Source source) override; + + /** Stop capturing the source */ + void Stop(::mynteye_jni::Source source) override; + + /** Wait the streams are ready */ + void WaitForStreams() override; + + /** Get the latest data of stream */ + std::shared_ptr<::mynteye_jni::StreamData> GetStreamData(::mynteye_jni::Stream stream) override; + + /** Get the datas of stream */ + std::vector> GetStreamDatas(::mynteye_jni::Stream stream) override; + + /** Enable cache motion datas until get them, otherwise using callback instead */ + void EnableMotionDatas(int32_t max_size) override; + + /** Get the motion datas */ + std::vector> GetMotionDatas() override; + + private: + device_t device_; +}; + +} // namespace mynteye_jni diff --git a/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/impl/frame_impl.hpp b/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/impl/frame_impl.hpp new file mode 100644 index 0000000..2e88380 --- /dev/null +++ b/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/impl/frame_impl.hpp @@ -0,0 +1,50 @@ +#pragma once + +#include "mynteye/device/callbacks.h" + +#include "frame.hpp" +#include "type_conversion.hpp" + +namespace mynteye_jni { + +class FrameImpl : public Frame { + public: + using frame_t = std::shared_ptr; + + explicit FrameImpl(const frame_t& frame) : frame_(frame) {} + ~FrameImpl() {} + + /** Get the width */ + int32_t Width() override { + return frame_->width(); + } + + /** Get the height */ + int32_t Height() override { + return frame_->height(); + } + + /** Get the pixel format */ + ::mynteye_jni::Format Format() override { + return to_jni(frame_->format()); + } + + /** Get the size */ + int32_t Size() override { + return frame_->size(); + } + + /** Get the data */ + std::vector Data() override { + return std::vector(frame_->data(), frame_->data() + frame_->size()); + } + + frame_t RawFrame() const { + return frame_; + } + + private: + frame_t frame_; +}; + +} // namespace mynteye_jni 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..7348659 --- /dev/null +++ b/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/impl/internal/uvc_device.h @@ -0,0 +1,17 @@ +#pragma once + +#include "usb_info.h" + +MYNTEYE_BEGIN_NAMESPACE + +namespace uvc { + +struct device; + +MYNTEYE_API std::shared_ptr create_device(UsbInfo info); + +MYNTEYE_API void set_bytes_per_packet(int bytes); + +} // namespace uvc + +MYNTEYE_END_NAMESPACE diff --git a/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/impl/motion_data_impl.hpp b/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/impl/motion_data_impl.hpp new file mode 100644 index 0000000..2508f5e --- /dev/null +++ b/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/impl/motion_data_impl.hpp @@ -0,0 +1,33 @@ +#pragma once + +#include "mynteye/device/callbacks.h" + +#include "imu_data.hpp" +#include "motion_data.hpp" + +namespace mynteye_jni { + +class MotionDataImpl : public MotionData { + public: + using motion_data_t = MYNTEYE_NAMESPACE::device::MotionData; + + explicit MotionDataImpl(const motion_data_t& data) : data_(data) {} + ~MotionDataImpl() {} + + ImuData Imu() override { + auto&& imu = data_.imu; + return { + imu->frame_id, + imu->flag, + static_cast(imu->timestamp), + std::vector(imu->accel, imu->accel + 3), + std::vector(imu->gyro, imu->gyro + 3), + imu->temperature, + }; + } + + private: + motion_data_t data_; +}; + +} // namespace mynteye_jni diff --git a/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/impl/stream_data_impl.hpp b/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/impl/stream_data_impl.hpp new file mode 100644 index 0000000..7b21ee7 --- /dev/null +++ b/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/impl/stream_data_impl.hpp @@ -0,0 +1,39 @@ +#pragma once + +#include "mynteye/device/callbacks.h" + +#include "frame_impl.hpp" +#include "img_data.hpp" +#include "stream_data.hpp" + +namespace mynteye_jni { + +class StreamDataImpl : public StreamData { + public: + using stream_data_t = MYNTEYE_NAMESPACE::device::StreamData; + + explicit StreamDataImpl(const stream_data_t& data) : data_(data) {} + ~StreamDataImpl() {} + + ImgData Img() override { + auto&& img = data_.img; + return { + img->frame_id, + static_cast(img->timestamp), + img->exposure_time, + }; + } + + std::shared_ptr<::mynteye_jni::Frame> Frame() override { + return std::make_shared<::mynteye_jni::FrameImpl>(data_.frame); + } + + int64_t FrameId() override { + return data_.frame_id; + } + + private: + stream_data_t data_; +}; + +} // namespace mynteye_jni 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 new file mode 100644 index 0000000..16ff6a9 --- /dev/null +++ b/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/impl/type_conversion.hpp @@ -0,0 +1,413 @@ +#pragma once + +#include + +#include "mynteye/logger.h" +#include "mynteye/types.h" + +#include "addon.hpp" +#include "calibration_model.hpp" +#include "capability.hpp" +#include "device_usb_info.hpp" +#include "format.hpp" +#include "info.hpp" +#include "model.hpp" +#include "option.hpp" +#include "source.hpp" +#include "stream.hpp" + +#include "internal/usb_info.h" + +namespace mynteye_jni { + +// device_usb_info + +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, + }; +} + +// model + +using RawModel = MYNTEYE_NAMESPACE::Model; +using JniModel = mynteye_jni::Model; + +inline +RawModel from_jni(const JniModel& model) { + switch (model) { + case JniModel::STANDARD: return RawModel::STANDARD; + case JniModel::STANDARD2: return RawModel::STANDARD2; + case JniModel::STANDARD210A: return RawModel::STANDARD210A; + default: + LOG(FATAL) << "Model is unknown"; + } +} + +inline +JniModel to_jni(const RawModel& model) { + switch (model) { + case RawModel::STANDARD: return JniModel::STANDARD; + case RawModel::STANDARD2: return JniModel::STANDARD2; + case RawModel::STANDARD210A: return JniModel::STANDARD210A; + default: + LOG(FATAL) << "Model is unknown"; + } +} + +// format + +using RawFormat = MYNTEYE_NAMESPACE::Format; +using JniFormat = mynteye_jni::Format; + +inline +RawFormat from_jni(const JniFormat& format) { + switch (format) { + case JniFormat::GREY: return RawFormat::GREY; + case JniFormat::YUYV: return RawFormat::YUYV; + case JniFormat::BGR888: return RawFormat::BGR888; + case JniFormat::RGB888: return RawFormat::RGB888; + default: + LOG(FATAL) << "Format is unknown"; + } +} + +inline +JniFormat to_jni(const RawFormat& format) { + switch (format) { + case RawFormat::GREY: return JniFormat::GREY; + case RawFormat::YUYV: return JniFormat::YUYV; + case RawFormat::BGR888: return JniFormat::BGR888; + case RawFormat::RGB888: return JniFormat::RGB888; + default: + LOG(FATAL) << "Format is unknown"; + } +} + +// source + +using RawSource = MYNTEYE_NAMESPACE::Source; +using JniSource = mynteye_jni::Source; + +inline +RawSource from_jni(const JniSource& source) { + switch (source) { + case JniSource::VIDEO_STREAMING: return RawSource::VIDEO_STREAMING; + case JniSource::MOTION_TRACKING: return RawSource::MOTION_TRACKING; + case JniSource::ALL: return RawSource::ALL; + default: + LOG(FATAL) << "Source is unknown"; + } +} + +inline +JniSource to_jni(const RawSource& source) { + switch (source) { + case RawSource::VIDEO_STREAMING: return JniSource::VIDEO_STREAMING; + case RawSource::MOTION_TRACKING: return JniSource::MOTION_TRACKING; + case RawSource::ALL: return JniSource::ALL; + default: + LOG(FATAL) << "Source is unknown"; + } +} + +// stream + +using RawStream = MYNTEYE_NAMESPACE::Stream; +using JniStream = mynteye_jni::Stream; + +inline +RawStream from_jni(const JniStream& stream) { + switch (stream) { + case JniStream::LEFT: return RawStream::LEFT; + case JniStream::RIGHT: return RawStream::RIGHT; + default: + LOG(FATAL) << "Stream is unknown"; + } +} + +inline +JniStream to_jni(const RawStream& stream) { + switch (stream) { + case RawStream::LEFT: return JniStream::LEFT; + case RawStream::RIGHT: return JniStream::RIGHT; + default: + LOG(FATAL) << "Stream is unknown"; + } +} + +// capability + +using RawCapability = MYNTEYE_NAMESPACE::Capabilities; +using JniCapability = mynteye_jni::Capability; + +inline +RawCapability from_jni(const JniCapability& Capability) { + switch (Capability) { + case JniCapability::STEREO: return RawCapability::STEREO; + case JniCapability::STEREO_COLOR: return RawCapability::STEREO_COLOR; + case JniCapability::COLOR: return RawCapability::COLOR; + case JniCapability::DEPTH: return RawCapability::DEPTH; + case JniCapability::POINTS: return RawCapability::POINTS; + case JniCapability::FISHEYE: return RawCapability::FISHEYE; + case JniCapability::INFRARED: return RawCapability::INFRARED; + case JniCapability::INFRARED2: return RawCapability::INFRARED2; + case JniCapability::IMU: return RawCapability::IMU; + default: + LOG(FATAL) << "Capability is unknown"; + } +} + +inline +JniCapability to_jni(const RawCapability& Capability) { + switch (Capability) { + case RawCapability::STEREO: return JniCapability::STEREO; + case RawCapability::STEREO_COLOR: return JniCapability::STEREO_COLOR; + case RawCapability::COLOR: return JniCapability::COLOR; + case RawCapability::DEPTH: return JniCapability::DEPTH; + case RawCapability::POINTS: return JniCapability::POINTS; + case RawCapability::FISHEYE: return JniCapability::FISHEYE; + case RawCapability::INFRARED: return JniCapability::INFRARED; + case RawCapability::INFRARED2: return JniCapability::INFRARED2; + case RawCapability::IMU: return JniCapability::IMU; + default: + LOG(FATAL) << "Capability is unknown"; + } +} + +// info + +using RawInfo = MYNTEYE_NAMESPACE::Info; +using JniInfo = mynteye_jni::Info; + +inline +RawInfo from_jni(const JniInfo& Info) { + switch (Info) { + case JniInfo::DEVICE_NAME: return RawInfo::DEVICE_NAME; + case JniInfo::SERIAL_NUMBER: return RawInfo::SERIAL_NUMBER; + case JniInfo::FIRMWARE_VERSION: return RawInfo::FIRMWARE_VERSION; + case JniInfo::HARDWARE_VERSION: return RawInfo::HARDWARE_VERSION; + case JniInfo::SPEC_VERSION: return RawInfo::SPEC_VERSION; + case JniInfo::LENS_TYPE: return RawInfo::LENS_TYPE; + case JniInfo::IMU_TYPE: return RawInfo::IMU_TYPE; + case JniInfo::NOMINAL_BASELINE: return RawInfo::NOMINAL_BASELINE; + default: + LOG(FATAL) << "Info is unknown"; + } +} + +inline +JniInfo to_jni(const RawInfo& Info) { + switch (Info) { + case RawInfo::DEVICE_NAME: return JniInfo::DEVICE_NAME; + case RawInfo::SERIAL_NUMBER: return JniInfo::SERIAL_NUMBER; + case RawInfo::FIRMWARE_VERSION: return JniInfo::FIRMWARE_VERSION; + case RawInfo::HARDWARE_VERSION: return JniInfo::HARDWARE_VERSION; + case RawInfo::SPEC_VERSION: return JniInfo::SPEC_VERSION; + case RawInfo::LENS_TYPE: return JniInfo::LENS_TYPE; + case RawInfo::IMU_TYPE: return JniInfo::IMU_TYPE; + case RawInfo::NOMINAL_BASELINE: return JniInfo::NOMINAL_BASELINE; + default: + LOG(FATAL) << "Info is unknown"; + } +} + +// option + +using RawOption = MYNTEYE_NAMESPACE::Option; +using JniOption = mynteye_jni::Option; + +inline +RawOption from_jni(const JniOption& Option) { + switch (Option) { + case JniOption::GAIN: + return RawOption::GAIN; + case JniOption::BRIGHTNESS: + return RawOption::BRIGHTNESS; + case JniOption::CONTRAST: + return RawOption::CONTRAST; + case JniOption::FRAME_RATE: + return RawOption::FRAME_RATE; + case JniOption::IMU_FREQUENCY: + return RawOption::IMU_FREQUENCY; + case JniOption::EXPOSURE_MODE: + return RawOption::EXPOSURE_MODE; + case JniOption::MAX_GAIN: + return RawOption::MAX_GAIN; + case JniOption::MAX_EXPOSURE_TIME: + return RawOption::MAX_EXPOSURE_TIME; + case JniOption::MIN_EXPOSURE_TIME: + return RawOption::MIN_EXPOSURE_TIME; + case JniOption::DESIRED_BRIGHTNESS: + return RawOption::DESIRED_BRIGHTNESS; + case JniOption::IR_CONTROL: + return RawOption::IR_CONTROL; + case JniOption::HDR_MODE: + return RawOption::HDR_MODE; + case JniOption::ACCELEROMETER_RANGE: + return RawOption::ACCELEROMETER_RANGE; + case JniOption::GYROSCOPE_RANGE: + return RawOption::GYROSCOPE_RANGE; + case JniOption::ACCELEROMETER_LOW_PASS_FILTER: + return RawOption::ACCELEROMETER_LOW_PASS_FILTER; + case JniOption::GYROSCOPE_LOW_PASS_FILTER: + return RawOption::GYROSCOPE_LOW_PASS_FILTER; + case JniOption::ZERO_DRIFT_CALIBRATION: + return RawOption::ZERO_DRIFT_CALIBRATION; + case JniOption::ERASE_CHIP: + return RawOption::ERASE_CHIP; + default: + LOG(FATAL) << "Option is unknown"; + } +} + +inline +JniOption to_jni(const RawOption& Option) { + switch (Option) { + case RawOption::GAIN: + return JniOption::GAIN; + case RawOption::BRIGHTNESS: + return JniOption::BRIGHTNESS; + case RawOption::CONTRAST: + return JniOption::CONTRAST; + case RawOption::FRAME_RATE: + return JniOption::FRAME_RATE; + case RawOption::IMU_FREQUENCY: + return JniOption::IMU_FREQUENCY; + case RawOption::EXPOSURE_MODE: + return JniOption::EXPOSURE_MODE; + case RawOption::MAX_GAIN: + return JniOption::MAX_GAIN; + case RawOption::MAX_EXPOSURE_TIME: + return JniOption::MAX_EXPOSURE_TIME; + case RawOption::MIN_EXPOSURE_TIME: + return JniOption::MIN_EXPOSURE_TIME; + case RawOption::DESIRED_BRIGHTNESS: + return JniOption::DESIRED_BRIGHTNESS; + case RawOption::IR_CONTROL: + return JniOption::IR_CONTROL; + case RawOption::HDR_MODE: + return JniOption::HDR_MODE; + case RawOption::ACCELEROMETER_RANGE: + return JniOption::ACCELEROMETER_RANGE; + case RawOption::GYROSCOPE_RANGE: + return JniOption::GYROSCOPE_RANGE; + case RawOption::ACCELEROMETER_LOW_PASS_FILTER: + return JniOption::ACCELEROMETER_LOW_PASS_FILTER; + case RawOption::GYROSCOPE_LOW_PASS_FILTER: + return JniOption::GYROSCOPE_LOW_PASS_FILTER; + case RawOption::ZERO_DRIFT_CALIBRATION: + return JniOption::ZERO_DRIFT_CALIBRATION; + case RawOption::ERASE_CHIP: + return JniOption::ERASE_CHIP; + default: + LOG(FATAL) << "Option is unknown"; + } +} + +// addon + +using RawAddon = MYNTEYE_NAMESPACE::AddOns; +using JniAddon = mynteye_jni::Addon; + +inline +RawAddon from_jni(const JniAddon& Addon) { + switch (Addon) { + case JniAddon::INFRARED: return RawAddon::INFRARED; + case JniAddon::INFRARED2: return RawAddon::INFRARED2; + default: + LOG(FATAL) << "Addon is unknown"; + } +} + +inline +JniAddon to_jni(const RawAddon& Addon) { + switch (Addon) { + case RawAddon::INFRARED: return JniAddon::INFRARED; + case RawAddon::INFRARED2: return JniAddon::INFRARED2; + default: + LOG(FATAL) << "Addon is unknown"; + } +} + +// calibration_model + +using RawCalibrationModel = MYNTEYE_NAMESPACE::CalibrationModel; +using JniCalibrationModel = mynteye_jni::CalibrationModel; + +inline +RawCalibrationModel from_jni(const JniCalibrationModel& CalibrationModel) { + switch (CalibrationModel) { + case JniCalibrationModel::PINHOLE: + return RawCalibrationModel::PINHOLE; + case JniCalibrationModel::KANNALA_BRANDT: + return RawCalibrationModel::KANNALA_BRANDT; + case JniCalibrationModel::UNKNOW: + return RawCalibrationModel::UNKNOW; + default: + LOG(FATAL) << "CalibrationModel is unknown"; + } +} + +inline +JniCalibrationModel to_jni(const RawCalibrationModel& CalibrationModel) { + switch (CalibrationModel) { + case RawCalibrationModel::PINHOLE: + return JniCalibrationModel::PINHOLE; + case RawCalibrationModel::KANNALA_BRANDT: + return JniCalibrationModel::KANNALA_BRANDT; + case RawCalibrationModel::UNKNOW: + return JniCalibrationModel::UNKNOW; + default: + LOG(FATAL) << "CalibrationModel is unknown"; + } +} + +// others + +template +std::vector to_vector(double (&vector)[n]) { + std::vector datas; + for (int i = 0; i < n; i++) { + datas.push_back(vector[i]); + } + return datas; +} + +template +std::vector to_vector(double (&matrix)[rows][cols]) { + std::vector datas; + for (int i = 0; i < rows; i++) { + for (int j = 0; j < cols; j++) { + datas.push_back(matrix[i][j]); + } + } + return datas; +} + +} // namespace mynteye_jni diff --git a/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/impl/util/jni_util.cpp b/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/impl/util/jni_util.cpp new file mode 100644 index 0000000..5a46c09 --- /dev/null +++ b/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/impl/util/jni_util.cpp @@ -0,0 +1,117 @@ +#include +#include +#include + +#ifndef LOG_TAG +#define LOG_TAG "native" +#endif + +#define LOGI(...) \ + ((void)__android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)) +#define LOGW(...) \ + ((void)__android_log_print(ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__)) +#define LOGE(...) \ + ((void)__android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)) + +#include "NativeFrame.hpp" + +#include "frame_impl.hpp" + +// BitmapUtils + +// RGBA +typedef struct { + uint8_t r; + uint8_t g; + uint8_t b; + uint8_t a; +} rgba_t; + +void copyPixelsGray(std::uint8_t *from, rgba_t *to, uint32_t n); +void copyPixelsBGR3(std::uint8_t *from, rgba_t *to, uint32_t n); +void copyPixelsRGB3(std::uint8_t *from, rgba_t *to, uint32_t n); + +void copyPixels(mynteye_jni::FrameImpl::frame_t from, rgba_t *to, + const AndroidBitmapInfo &info) { + if (info.width != from->width() || info.height != from->height()) { + LOGE("Frame size is not same"); + return; + } + uint32_t n = info.width * info.height; + switch (from->format()) { + case MYNTEYE_NAMESPACE::Format::GREY: + copyPixelsGray(from->data(), to, n); + return; + case MYNTEYE_NAMESPACE::Format::BGR888: + copyPixelsBGR3(from->data(), to, n); + return; + case MYNTEYE_NAMESPACE::Format::RGB888: + copyPixelsRGB3(from->data(), to, n); + return; + case MYNTEYE_NAMESPACE::Format::YUYV: + default: + LOGE("Frame format is not supported"); + return; + } +} + +CJNIEXPORT void JNICALL Java_com_slightech_mynteye_util_BitmapUtils_copyPixels( + JNIEnv *env, jclass clazz, jobject j_frame, jobject bitmap) { + auto frame = ::djinni_generated::NativeFrame::toCpp(env, j_frame); + // LOGI("frame format: %dx%d", frame->Width(), frame->Height()); + auto frame_raw = std::dynamic_pointer_cast(frame)->RawFrame(); + + AndroidBitmapInfo info; + int result; + if ((result = AndroidBitmap_getInfo(env, bitmap, &info)) < 0) { + LOGE("AndroidBitmap_getInfo() failed, error=%d", result); + return; + } + if (info.format != ANDROID_BITMAP_FORMAT_RGBA_8888) { + LOGE("Bitmap format is not RGBA_8888!"); + return; + } + + void *pixels; + if ((result = AndroidBitmap_lockPixels(env, bitmap, &pixels)) < 0) { + LOGE("AndroidBitmap_lockPixels() failed, error=%d", result); + } + rgba_t *rgba_pixels = static_cast(pixels); + + copyPixels(frame_raw, rgba_pixels, info); + + AndroidBitmap_unlockPixels(env, bitmap); +} + +void copyPixelsGray(std::uint8_t *from, rgba_t *to, uint32_t n) { + for (uint32_t i = 0; i < n; ++i) { + std::uint8_t &gray = from[i]; + rgba_t &rgba = to[i]; + rgba.r = gray; + rgba.g = gray; + rgba.b = gray; + rgba.a = 255; + } +} + +void copyPixelsBGR3(std::uint8_t *from, rgba_t *to, uint32_t n) { + for (uint32_t i = 0; i < n; ++i) { + std::uint8_t *bgr = from + (i*3); + rgba_t &rgba = to[i]; + rgba.r = *(bgr + 2); + rgba.g = *(bgr + 1); + rgba.b = *(bgr); + rgba.a = 255; + } +} + +void copyPixelsRGB3(std::uint8_t *from, rgba_t *to, uint32_t n) { + for (uint32_t i = 0; i < n; ++i) { + std::uint8_t *rgb = from + (i*3); + rgba_t &rgba = to[i]; + rgba.r = *(rgb); + rgba.g = *(rgb + 1); + rgba.b = *(rgb + 2); + rgba.a = 255; + } +} diff --git a/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/jni/NativeAddon.hpp b/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/jni/NativeAddon.hpp new file mode 100644 index 0000000..d235748 --- /dev/null +++ b/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/jni/NativeAddon.hpp @@ -0,0 +1,26 @@ +// AUTOGENERATED FILE - DO NOT MODIFY! +// This file generated by Djinni from mynteye_types.djinni + +#pragma once + +#include "addon.hpp" +#include "djinni_support.hpp" + +namespace djinni_generated { + +class NativeAddon final : ::djinni::JniEnum { +public: + using CppType = ::mynteye_jni::Addon; + using JniType = jobject; + + using Boxed = NativeAddon; + + static CppType toCpp(JNIEnv* jniEnv, JniType j) { return static_cast(::djinni::JniClass::get().ordinal(jniEnv, j)); } + static ::djinni::LocalRef fromCpp(JNIEnv* jniEnv, CppType c) { return ::djinni::JniClass::get().create(jniEnv, static_cast(c)); } + +private: + NativeAddon() : JniEnum("com/slightech/mynteye/Addon") {} + friend ::djinni::JniClass; +}; + +} // namespace djinni_generated diff --git a/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/jni/NativeCalibrationModel.hpp b/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/jni/NativeCalibrationModel.hpp new file mode 100644 index 0000000..f474c13 --- /dev/null +++ b/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/jni/NativeCalibrationModel.hpp @@ -0,0 +1,26 @@ +// AUTOGENERATED FILE - DO NOT MODIFY! +// This file generated by Djinni from mynteye_types.djinni + +#pragma once + +#include "calibration_model.hpp" +#include "djinni_support.hpp" + +namespace djinni_generated { + +class NativeCalibrationModel final : ::djinni::JniEnum { +public: + using CppType = ::mynteye_jni::CalibrationModel; + using JniType = jobject; + + using Boxed = NativeCalibrationModel; + + static CppType toCpp(JNIEnv* jniEnv, JniType j) { return static_cast(::djinni::JniClass::get().ordinal(jniEnv, j)); } + static ::djinni::LocalRef fromCpp(JNIEnv* jniEnv, CppType c) { return ::djinni::JniClass::get().create(jniEnv, static_cast(c)); } + +private: + NativeCalibrationModel() : JniEnum("com/slightech/mynteye/CalibrationModel") {} + friend ::djinni::JniClass; +}; + +} // namespace djinni_generated diff --git a/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/jni/NativeCapability.hpp b/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/jni/NativeCapability.hpp new file mode 100644 index 0000000..c827013 --- /dev/null +++ b/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/jni/NativeCapability.hpp @@ -0,0 +1,26 @@ +// AUTOGENERATED FILE - DO NOT MODIFY! +// This file generated by Djinni from mynteye_types.djinni + +#pragma once + +#include "capability.hpp" +#include "djinni_support.hpp" + +namespace djinni_generated { + +class NativeCapability final : ::djinni::JniEnum { +public: + using CppType = ::mynteye_jni::Capability; + using JniType = jobject; + + using Boxed = NativeCapability; + + static CppType toCpp(JNIEnv* jniEnv, JniType j) { return static_cast(::djinni::JniClass::get().ordinal(jniEnv, j)); } + static ::djinni::LocalRef fromCpp(JNIEnv* jniEnv, CppType c) { return ::djinni::JniClass::get().create(jniEnv, static_cast(c)); } + +private: + NativeCapability() : JniEnum("com/slightech/mynteye/Capability") {} + friend ::djinni::JniClass; +}; + +} // namespace djinni_generated 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 new file mode 100644 index 0000000..5416fe6 --- /dev/null +++ b/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/jni/NativeDevice.cpp @@ -0,0 +1,272 @@ +// AUTOGENERATED FILE - DO NOT MODIFY! +// This file generated by Djinni from mynteye.djinni + +#include "NativeDevice.hpp" // my header +#include "Marshal.hpp" +#include "NativeAddon.hpp" +#include "NativeCapability.hpp" +#include "NativeDeviceUsbInfo.hpp" +#include "NativeExtrinsics.hpp" +#include "NativeInfo.hpp" +#include "NativeIntrinsics.hpp" +#include "NativeModel.hpp" +#include "NativeMotionData.hpp" +#include "NativeMotionIntrinsics.hpp" +#include "NativeOption.hpp" +#include "NativeOptionInfo.hpp" +#include "NativeSource.hpp" +#include "NativeStream.hpp" +#include "NativeStreamData.hpp" +#include "NativeStreamRequest.hpp" + +namespace djinni_generated { + +NativeDevice::NativeDevice() : ::djinni::JniInterface<::mynteye_jni::Device, NativeDevice>("com/slightech/mynteye/Device$CppProxy") {} + +NativeDevice::~NativeDevice() = default; + + +CJNIEXPORT void JNICALL Java_com_slightech_mynteye_Device_00024CppProxy_nativeDestroy(JNIEnv* jniEnv, jobject /*this*/, jlong nativeRef) +{ + try { + DJINNI_FUNCTION_PROLOGUE1(jniEnv, nativeRef); + delete reinterpret_cast<::djinni::CppProxyHandle<::mynteye_jni::Device>*>(nativeRef); + } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, ) +} + +CJNIEXPORT jobject JNICALL Java_com_slightech_mynteye_Device_00024CppProxy_create(JNIEnv* jniEnv, jobject /*this*/, ::djinni_generated::NativeDeviceUsbInfo::JniType j_info) +{ + try { + DJINNI_FUNCTION_PROLOGUE0(jniEnv); + auto r = ::mynteye_jni::Device::Create(::djinni_generated::NativeDeviceUsbInfo::toCpp(jniEnv, j_info)); + return ::djinni::release(::djinni_generated::NativeDevice::fromCpp(jniEnv, r)); + } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */) +} + +CJNIEXPORT ::djinni_generated::NativeModel::JniType JNICALL Java_com_slightech_mynteye_Device_00024CppProxy_native_1getModel(JNIEnv* jniEnv, jobject /*this*/, jlong nativeRef) +{ + try { + DJINNI_FUNCTION_PROLOGUE1(jniEnv, nativeRef); + const auto& ref = ::djinni::objectFromHandleAddress<::mynteye_jni::Device>(nativeRef); + auto r = ref->GetModel(); + return ::djinni::release(::djinni_generated::NativeModel::fromCpp(jniEnv, r)); + } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */) +} + +CJNIEXPORT jboolean JNICALL Java_com_slightech_mynteye_Device_00024CppProxy_native_1supportsStream(JNIEnv* jniEnv, jobject /*this*/, jlong nativeRef, ::djinni_generated::NativeStream::JniType j_stream) +{ + try { + DJINNI_FUNCTION_PROLOGUE1(jniEnv, nativeRef); + const auto& ref = ::djinni::objectFromHandleAddress<::mynteye_jni::Device>(nativeRef); + auto r = ref->SupportsStream(::djinni_generated::NativeStream::toCpp(jniEnv, j_stream)); + return ::djinni::release(::djinni::Bool::fromCpp(jniEnv, r)); + } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */) +} + +CJNIEXPORT jboolean JNICALL Java_com_slightech_mynteye_Device_00024CppProxy_native_1supportsCapability(JNIEnv* jniEnv, jobject /*this*/, jlong nativeRef, ::djinni_generated::NativeCapability::JniType j_capabilities) +{ + try { + DJINNI_FUNCTION_PROLOGUE1(jniEnv, nativeRef); + const auto& ref = ::djinni::objectFromHandleAddress<::mynteye_jni::Device>(nativeRef); + auto r = ref->SupportsCapability(::djinni_generated::NativeCapability::toCpp(jniEnv, j_capabilities)); + return ::djinni::release(::djinni::Bool::fromCpp(jniEnv, r)); + } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */) +} + +CJNIEXPORT jboolean JNICALL Java_com_slightech_mynteye_Device_00024CppProxy_native_1supportsOption(JNIEnv* jniEnv, jobject /*this*/, jlong nativeRef, ::djinni_generated::NativeOption::JniType j_option) +{ + try { + DJINNI_FUNCTION_PROLOGUE1(jniEnv, nativeRef); + const auto& ref = ::djinni::objectFromHandleAddress<::mynteye_jni::Device>(nativeRef); + auto r = ref->SupportsOption(::djinni_generated::NativeOption::toCpp(jniEnv, j_option)); + return ::djinni::release(::djinni::Bool::fromCpp(jniEnv, r)); + } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */) +} + +CJNIEXPORT jboolean JNICALL Java_com_slightech_mynteye_Device_00024CppProxy_native_1supportsAddon(JNIEnv* jniEnv, jobject /*this*/, jlong nativeRef, ::djinni_generated::NativeAddon::JniType j_addon) +{ + try { + DJINNI_FUNCTION_PROLOGUE1(jniEnv, nativeRef); + const auto& ref = ::djinni::objectFromHandleAddress<::mynteye_jni::Device>(nativeRef); + auto r = ref->SupportsAddon(::djinni_generated::NativeAddon::toCpp(jniEnv, j_addon)); + return ::djinni::release(::djinni::Bool::fromCpp(jniEnv, r)); + } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */) +} + +CJNIEXPORT jobject JNICALL Java_com_slightech_mynteye_Device_00024CppProxy_native_1getStreamRequests(JNIEnv* jniEnv, jobject /*this*/, jlong nativeRef) +{ + try { + DJINNI_FUNCTION_PROLOGUE1(jniEnv, nativeRef); + const auto& ref = ::djinni::objectFromHandleAddress<::mynteye_jni::Device>(nativeRef); + auto r = ref->GetStreamRequests(); + return ::djinni::release(::djinni::List<::djinni_generated::NativeStreamRequest>::fromCpp(jniEnv, r)); + } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */) +} + +CJNIEXPORT void JNICALL Java_com_slightech_mynteye_Device_00024CppProxy_native_1configStreamRequest(JNIEnv* jniEnv, jobject /*this*/, jlong nativeRef, ::djinni_generated::NativeStreamRequest::JniType j_request) +{ + try { + DJINNI_FUNCTION_PROLOGUE1(jniEnv, nativeRef); + const auto& ref = ::djinni::objectFromHandleAddress<::mynteye_jni::Device>(nativeRef); + ref->ConfigStreamRequest(::djinni_generated::NativeStreamRequest::toCpp(jniEnv, j_request)); + } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, ) +} + +CJNIEXPORT jstring JNICALL Java_com_slightech_mynteye_Device_00024CppProxy_native_1getInfo(JNIEnv* jniEnv, jobject /*this*/, jlong nativeRef, ::djinni_generated::NativeInfo::JniType j_info) +{ + try { + DJINNI_FUNCTION_PROLOGUE1(jniEnv, nativeRef); + const auto& ref = ::djinni::objectFromHandleAddress<::mynteye_jni::Device>(nativeRef); + auto r = ref->GetInfo(::djinni_generated::NativeInfo::toCpp(jniEnv, j_info)); + return ::djinni::release(::djinni::String::fromCpp(jniEnv, r)); + } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */) +} + +CJNIEXPORT ::djinni_generated::NativeIntrinsics::JniType JNICALL Java_com_slightech_mynteye_Device_00024CppProxy_native_1getIntrinsics(JNIEnv* jniEnv, jobject /*this*/, jlong nativeRef, ::djinni_generated::NativeStream::JniType j_stream) +{ + try { + DJINNI_FUNCTION_PROLOGUE1(jniEnv, nativeRef); + const auto& ref = ::djinni::objectFromHandleAddress<::mynteye_jni::Device>(nativeRef); + auto r = ref->GetIntrinsics(::djinni_generated::NativeStream::toCpp(jniEnv, j_stream)); + return ::djinni::release(::djinni_generated::NativeIntrinsics::fromCpp(jniEnv, r)); + } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */) +} + +CJNIEXPORT ::djinni_generated::NativeExtrinsics::JniType JNICALL Java_com_slightech_mynteye_Device_00024CppProxy_native_1getExtrinsics(JNIEnv* jniEnv, jobject /*this*/, jlong nativeRef, ::djinni_generated::NativeStream::JniType j_from, ::djinni_generated::NativeStream::JniType j_to) +{ + try { + DJINNI_FUNCTION_PROLOGUE1(jniEnv, nativeRef); + const auto& ref = ::djinni::objectFromHandleAddress<::mynteye_jni::Device>(nativeRef); + auto r = ref->GetExtrinsics(::djinni_generated::NativeStream::toCpp(jniEnv, j_from), + ::djinni_generated::NativeStream::toCpp(jniEnv, j_to)); + return ::djinni::release(::djinni_generated::NativeExtrinsics::fromCpp(jniEnv, r)); + } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */) +} + +CJNIEXPORT ::djinni_generated::NativeMotionIntrinsics::JniType JNICALL Java_com_slightech_mynteye_Device_00024CppProxy_native_1getMotionIntrinsics(JNIEnv* jniEnv, jobject /*this*/, jlong nativeRef) +{ + try { + DJINNI_FUNCTION_PROLOGUE1(jniEnv, nativeRef); + const auto& ref = ::djinni::objectFromHandleAddress<::mynteye_jni::Device>(nativeRef); + auto r = ref->GetMotionIntrinsics(); + return ::djinni::release(::djinni_generated::NativeMotionIntrinsics::fromCpp(jniEnv, r)); + } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */) +} + +CJNIEXPORT ::djinni_generated::NativeExtrinsics::JniType JNICALL Java_com_slightech_mynteye_Device_00024CppProxy_native_1getMotionExtrinsics(JNIEnv* jniEnv, jobject /*this*/, jlong nativeRef, ::djinni_generated::NativeStream::JniType j_from) +{ + try { + DJINNI_FUNCTION_PROLOGUE1(jniEnv, nativeRef); + const auto& ref = ::djinni::objectFromHandleAddress<::mynteye_jni::Device>(nativeRef); + auto r = ref->GetMotionExtrinsics(::djinni_generated::NativeStream::toCpp(jniEnv, j_from)); + return ::djinni::release(::djinni_generated::NativeExtrinsics::fromCpp(jniEnv, r)); + } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */) +} + +CJNIEXPORT ::djinni_generated::NativeOptionInfo::JniType JNICALL Java_com_slightech_mynteye_Device_00024CppProxy_native_1getOptionInfo(JNIEnv* jniEnv, jobject /*this*/, jlong nativeRef, ::djinni_generated::NativeOption::JniType j_option) +{ + try { + DJINNI_FUNCTION_PROLOGUE1(jniEnv, nativeRef); + const auto& ref = ::djinni::objectFromHandleAddress<::mynteye_jni::Device>(nativeRef); + auto r = ref->GetOptionInfo(::djinni_generated::NativeOption::toCpp(jniEnv, j_option)); + return ::djinni::release(::djinni_generated::NativeOptionInfo::fromCpp(jniEnv, r)); + } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */) +} + +CJNIEXPORT jint JNICALL Java_com_slightech_mynteye_Device_00024CppProxy_native_1getOptionValue(JNIEnv* jniEnv, jobject /*this*/, jlong nativeRef, ::djinni_generated::NativeOption::JniType j_option) +{ + try { + DJINNI_FUNCTION_PROLOGUE1(jniEnv, nativeRef); + const auto& ref = ::djinni::objectFromHandleAddress<::mynteye_jni::Device>(nativeRef); + auto r = ref->GetOptionValue(::djinni_generated::NativeOption::toCpp(jniEnv, j_option)); + return ::djinni::release(::djinni::I32::fromCpp(jniEnv, r)); + } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */) +} + +CJNIEXPORT void JNICALL Java_com_slightech_mynteye_Device_00024CppProxy_native_1setOptionValue(JNIEnv* jniEnv, jobject /*this*/, jlong nativeRef, ::djinni_generated::NativeOption::JniType j_option, jint j_value) +{ + try { + DJINNI_FUNCTION_PROLOGUE1(jniEnv, nativeRef); + const auto& ref = ::djinni::objectFromHandleAddress<::mynteye_jni::Device>(nativeRef); + ref->SetOptionValue(::djinni_generated::NativeOption::toCpp(jniEnv, j_option), + ::djinni::I32::toCpp(jniEnv, j_value)); + } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, ) +} + +CJNIEXPORT jboolean JNICALL Java_com_slightech_mynteye_Device_00024CppProxy_native_1runOptionAction(JNIEnv* jniEnv, jobject /*this*/, jlong nativeRef, ::djinni_generated::NativeOption::JniType j_option) +{ + try { + DJINNI_FUNCTION_PROLOGUE1(jniEnv, nativeRef); + const auto& ref = ::djinni::objectFromHandleAddress<::mynteye_jni::Device>(nativeRef); + auto r = ref->RunOptionAction(::djinni_generated::NativeOption::toCpp(jniEnv, j_option)); + return ::djinni::release(::djinni::Bool::fromCpp(jniEnv, r)); + } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */) +} + +CJNIEXPORT void JNICALL Java_com_slightech_mynteye_Device_00024CppProxy_native_1start(JNIEnv* jniEnv, jobject /*this*/, jlong nativeRef, ::djinni_generated::NativeSource::JniType j_source) +{ + try { + DJINNI_FUNCTION_PROLOGUE1(jniEnv, nativeRef); + const auto& ref = ::djinni::objectFromHandleAddress<::mynteye_jni::Device>(nativeRef); + ref->Start(::djinni_generated::NativeSource::toCpp(jniEnv, j_source)); + } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, ) +} + +CJNIEXPORT void JNICALL Java_com_slightech_mynteye_Device_00024CppProxy_native_1stop(JNIEnv* jniEnv, jobject /*this*/, jlong nativeRef, ::djinni_generated::NativeSource::JniType j_source) +{ + try { + DJINNI_FUNCTION_PROLOGUE1(jniEnv, nativeRef); + const auto& ref = ::djinni::objectFromHandleAddress<::mynteye_jni::Device>(nativeRef); + ref->Stop(::djinni_generated::NativeSource::toCpp(jniEnv, j_source)); + } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, ) +} + +CJNIEXPORT void JNICALL Java_com_slightech_mynteye_Device_00024CppProxy_native_1waitForStreams(JNIEnv* jniEnv, jobject /*this*/, jlong nativeRef) +{ + try { + DJINNI_FUNCTION_PROLOGUE1(jniEnv, nativeRef); + const auto& ref = ::djinni::objectFromHandleAddress<::mynteye_jni::Device>(nativeRef); + ref->WaitForStreams(); + } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, ) +} + +CJNIEXPORT ::djinni_generated::NativeStreamData::JniType JNICALL Java_com_slightech_mynteye_Device_00024CppProxy_native_1getStreamData(JNIEnv* jniEnv, jobject /*this*/, jlong nativeRef, ::djinni_generated::NativeStream::JniType j_stream) +{ + try { + DJINNI_FUNCTION_PROLOGUE1(jniEnv, nativeRef); + const auto& ref = ::djinni::objectFromHandleAddress<::mynteye_jni::Device>(nativeRef); + auto r = ref->GetStreamData(::djinni_generated::NativeStream::toCpp(jniEnv, j_stream)); + return ::djinni::release(::djinni_generated::NativeStreamData::fromCpp(jniEnv, r)); + } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */) +} + +CJNIEXPORT jobject JNICALL Java_com_slightech_mynteye_Device_00024CppProxy_native_1getStreamDatas(JNIEnv* jniEnv, jobject /*this*/, jlong nativeRef, ::djinni_generated::NativeStream::JniType j_stream) +{ + try { + DJINNI_FUNCTION_PROLOGUE1(jniEnv, nativeRef); + const auto& ref = ::djinni::objectFromHandleAddress<::mynteye_jni::Device>(nativeRef); + auto r = ref->GetStreamDatas(::djinni_generated::NativeStream::toCpp(jniEnv, j_stream)); + return ::djinni::release(::djinni::List<::djinni_generated::NativeStreamData>::fromCpp(jniEnv, r)); + } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */) +} + +CJNIEXPORT void JNICALL Java_com_slightech_mynteye_Device_00024CppProxy_native_1enableMotionDatas(JNIEnv* jniEnv, jobject /*this*/, jlong nativeRef, jint j_maxSize) +{ + try { + DJINNI_FUNCTION_PROLOGUE1(jniEnv, nativeRef); + const auto& ref = ::djinni::objectFromHandleAddress<::mynteye_jni::Device>(nativeRef); + ref->EnableMotionDatas(::djinni::I32::toCpp(jniEnv, j_maxSize)); + } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, ) +} + +CJNIEXPORT jobject JNICALL Java_com_slightech_mynteye_Device_00024CppProxy_native_1getMotionDatas(JNIEnv* jniEnv, jobject /*this*/, jlong nativeRef) +{ + try { + DJINNI_FUNCTION_PROLOGUE1(jniEnv, nativeRef); + const auto& ref = ::djinni::objectFromHandleAddress<::mynteye_jni::Device>(nativeRef); + auto r = ref->GetMotionDatas(); + return ::djinni::release(::djinni::List<::djinni_generated::NativeMotionData>::fromCpp(jniEnv, r)); + } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */) +} + +} // namespace djinni_generated diff --git a/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/jni/NativeDevice.hpp b/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/jni/NativeDevice.hpp new file mode 100644 index 0000000..98629b8 --- /dev/null +++ b/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/jni/NativeDevice.hpp @@ -0,0 +1,32 @@ +// AUTOGENERATED FILE - DO NOT MODIFY! +// This file generated by Djinni from mynteye.djinni + +#pragma once + +#include "device.hpp" +#include "djinni_support.hpp" + +namespace djinni_generated { + +class NativeDevice final : ::djinni::JniInterface<::mynteye_jni::Device, NativeDevice> { +public: + using CppType = std::shared_ptr<::mynteye_jni::Device>; + using CppOptType = std::shared_ptr<::mynteye_jni::Device>; + using JniType = jobject; + + using Boxed = NativeDevice; + + ~NativeDevice(); + + static CppType toCpp(JNIEnv* jniEnv, JniType j) { return ::djinni::JniClass::get()._fromJava(jniEnv, j); } + static ::djinni::LocalRef fromCppOpt(JNIEnv* jniEnv, const CppOptType& c) { return {jniEnv, ::djinni::JniClass::get()._toJava(jniEnv, c)}; } + static ::djinni::LocalRef fromCpp(JNIEnv* jniEnv, const CppType& c) { return fromCppOpt(jniEnv, c); } + +private: + NativeDevice(); + friend ::djinni::JniClass; + friend ::djinni::JniInterface<::mynteye_jni::Device, NativeDevice>; + +}; + +} // namespace djinni_generated 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 new file mode 100644 index 0000000..fbc535d --- /dev/null +++ b/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/jni/NativeDeviceUsbInfo.cpp @@ -0,0 +1,42 @@ +// AUTOGENERATED FILE - DO NOT MODIFY! +// This file generated by Djinni from mynteye_types.djinni + +#include "NativeDeviceUsbInfo.hpp" // my header +#include "Marshal.hpp" + +namespace djinni_generated { + +NativeDeviceUsbInfo::NativeDeviceUsbInfo() = default; + +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.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.serial)))}; + ::djinni::jniExceptionCheck(jniEnv); + return r; +} + +auto NativeDeviceUsbInfo::toCpp(JNIEnv* jniEnv, JniType j) -> CppType { + ::djinni::JniLocalScope jscope(jniEnv, 9); + assert(j != nullptr); + const auto& data = ::djinni::JniClass::get(); + 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_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 new file mode 100644 index 0000000..5ded541 --- /dev/null +++ b/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/jni/NativeDeviceUsbInfo.hpp @@ -0,0 +1,39 @@ +// AUTOGENERATED FILE - DO NOT MODIFY! +// This file generated by Djinni from mynteye_types.djinni + +#pragma once + +#include "device_usb_info.hpp" +#include "djinni_support.hpp" + +namespace djinni_generated { + +class NativeDeviceUsbInfo final { +public: + using CppType = ::mynteye_jni::DeviceUsbInfo; + using JniType = jobject; + + using Boxed = NativeDeviceUsbInfo; + + ~NativeDeviceUsbInfo(); + + static CppType toCpp(JNIEnv* jniEnv, JniType j); + static ::djinni::LocalRef fromCpp(JNIEnv* jniEnv, const CppType& c); + +private: + NativeDeviceUsbInfo(); + friend ::djinni::JniClass; + + const ::djinni::GlobalRef clazz { ::djinni::jniFindClass("com/slightech/mynteye/DeviceUsbInfo") }; + 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_mSerial { ::djinni::jniGetFieldID(clazz.get(), "mSerial", "Ljava/lang/String;") }; +}; + +} // namespace djinni_generated diff --git a/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/jni/NativeExtrinsics.cpp b/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/jni/NativeExtrinsics.cpp new file mode 100644 index 0000000..1e979a1 --- /dev/null +++ b/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/jni/NativeExtrinsics.cpp @@ -0,0 +1,30 @@ +// AUTOGENERATED FILE - DO NOT MODIFY! +// This file generated by Djinni from mynteye_types.djinni + +#include "NativeExtrinsics.hpp" // my header +#include "Marshal.hpp" + +namespace djinni_generated { + +NativeExtrinsics::NativeExtrinsics() = default; + +NativeExtrinsics::~NativeExtrinsics() = default; + +auto NativeExtrinsics::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::List<::djinni::F64>::fromCpp(jniEnv, c.rotation)), + ::djinni::get(::djinni::List<::djinni::F64>::fromCpp(jniEnv, c.translation)))}; + ::djinni::jniExceptionCheck(jniEnv); + return r; +} + +auto NativeExtrinsics::toCpp(JNIEnv* jniEnv, JniType j) -> CppType { + ::djinni::JniLocalScope jscope(jniEnv, 3); + assert(j != nullptr); + const auto& data = ::djinni::JniClass::get(); + return {::djinni::List<::djinni::F64>::toCpp(jniEnv, jniEnv->GetObjectField(j, data.field_mRotation)), + ::djinni::List<::djinni::F64>::toCpp(jniEnv, jniEnv->GetObjectField(j, data.field_mTranslation))}; +} + +} // namespace djinni_generated diff --git a/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/jni/NativeExtrinsics.hpp b/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/jni/NativeExtrinsics.hpp new file mode 100644 index 0000000..0a1a047 --- /dev/null +++ b/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/jni/NativeExtrinsics.hpp @@ -0,0 +1,33 @@ +// AUTOGENERATED FILE - DO NOT MODIFY! +// This file generated by Djinni from mynteye_types.djinni + +#pragma once + +#include "djinni_support.hpp" +#include "extrinsics.hpp" + +namespace djinni_generated { + +class NativeExtrinsics final { +public: + using CppType = ::mynteye_jni::Extrinsics; + using JniType = jobject; + + using Boxed = NativeExtrinsics; + + ~NativeExtrinsics(); + + static CppType toCpp(JNIEnv* jniEnv, JniType j); + static ::djinni::LocalRef fromCpp(JNIEnv* jniEnv, const CppType& c); + +private: + NativeExtrinsics(); + friend ::djinni::JniClass; + + const ::djinni::GlobalRef clazz { ::djinni::jniFindClass("com/slightech/mynteye/Extrinsics") }; + const jmethodID jconstructor { ::djinni::jniGetMethodID(clazz.get(), "", "(Ljava/util/ArrayList;Ljava/util/ArrayList;)V") }; + const jfieldID field_mRotation { ::djinni::jniGetFieldID(clazz.get(), "mRotation", "Ljava/util/ArrayList;") }; + const jfieldID field_mTranslation { ::djinni::jniGetFieldID(clazz.get(), "mTranslation", "Ljava/util/ArrayList;") }; +}; + +} // namespace djinni_generated diff --git a/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/jni/NativeFormat.hpp b/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/jni/NativeFormat.hpp new file mode 100644 index 0000000..437505e --- /dev/null +++ b/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/jni/NativeFormat.hpp @@ -0,0 +1,26 @@ +// AUTOGENERATED FILE - DO NOT MODIFY! +// This file generated by Djinni from mynteye_types.djinni + +#pragma once + +#include "djinni_support.hpp" +#include "format.hpp" + +namespace djinni_generated { + +class NativeFormat final : ::djinni::JniEnum { +public: + using CppType = ::mynteye_jni::Format; + using JniType = jobject; + + using Boxed = NativeFormat; + + static CppType toCpp(JNIEnv* jniEnv, JniType j) { return static_cast(::djinni::JniClass::get().ordinal(jniEnv, j)); } + static ::djinni::LocalRef fromCpp(JNIEnv* jniEnv, CppType c) { return ::djinni::JniClass::get().create(jniEnv, static_cast(c)); } + +private: + NativeFormat() : JniEnum("com/slightech/mynteye/Format") {} + friend ::djinni::JniClass; +}; + +} // namespace djinni_generated diff --git a/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/jni/NativeFrame.cpp b/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/jni/NativeFrame.cpp new file mode 100644 index 0000000..c5cb443 --- /dev/null +++ b/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/jni/NativeFrame.cpp @@ -0,0 +1,73 @@ +// AUTOGENERATED FILE - DO NOT MODIFY! +// This file generated by Djinni from mynteye_types.djinni + +#include "NativeFrame.hpp" // my header +#include "Marshal.hpp" +#include "NativeFormat.hpp" + +namespace djinni_generated { + +NativeFrame::NativeFrame() : ::djinni::JniInterface<::mynteye_jni::Frame, NativeFrame>("com/slightech/mynteye/Frame$CppProxy") {} + +NativeFrame::~NativeFrame() = default; + + +CJNIEXPORT void JNICALL Java_com_slightech_mynteye_Frame_00024CppProxy_nativeDestroy(JNIEnv* jniEnv, jobject /*this*/, jlong nativeRef) +{ + try { + DJINNI_FUNCTION_PROLOGUE1(jniEnv, nativeRef); + delete reinterpret_cast<::djinni::CppProxyHandle<::mynteye_jni::Frame>*>(nativeRef); + } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, ) +} + +CJNIEXPORT jint JNICALL Java_com_slightech_mynteye_Frame_00024CppProxy_native_1width(JNIEnv* jniEnv, jobject /*this*/, jlong nativeRef) +{ + try { + DJINNI_FUNCTION_PROLOGUE1(jniEnv, nativeRef); + const auto& ref = ::djinni::objectFromHandleAddress<::mynteye_jni::Frame>(nativeRef); + auto r = ref->Width(); + return ::djinni::release(::djinni::I32::fromCpp(jniEnv, r)); + } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */) +} + +CJNIEXPORT jint JNICALL Java_com_slightech_mynteye_Frame_00024CppProxy_native_1height(JNIEnv* jniEnv, jobject /*this*/, jlong nativeRef) +{ + try { + DJINNI_FUNCTION_PROLOGUE1(jniEnv, nativeRef); + const auto& ref = ::djinni::objectFromHandleAddress<::mynteye_jni::Frame>(nativeRef); + auto r = ref->Height(); + return ::djinni::release(::djinni::I32::fromCpp(jniEnv, r)); + } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */) +} + +CJNIEXPORT jobject JNICALL Java_com_slightech_mynteye_Frame_00024CppProxy_native_1format(JNIEnv* jniEnv, jobject /*this*/, jlong nativeRef) +{ + try { + DJINNI_FUNCTION_PROLOGUE1(jniEnv, nativeRef); + const auto& ref = ::djinni::objectFromHandleAddress<::mynteye_jni::Frame>(nativeRef); + auto r = ref->Format(); + return ::djinni::release(::djinni_generated::NativeFormat::fromCpp(jniEnv, r)); + } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */) +} + +CJNIEXPORT jint JNICALL Java_com_slightech_mynteye_Frame_00024CppProxy_native_1size(JNIEnv* jniEnv, jobject /*this*/, jlong nativeRef) +{ + try { + DJINNI_FUNCTION_PROLOGUE1(jniEnv, nativeRef); + const auto& ref = ::djinni::objectFromHandleAddress<::mynteye_jni::Frame>(nativeRef); + auto r = ref->Size(); + return ::djinni::release(::djinni::I32::fromCpp(jniEnv, r)); + } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */) +} + +CJNIEXPORT jbyteArray JNICALL Java_com_slightech_mynteye_Frame_00024CppProxy_native_1data(JNIEnv* jniEnv, jobject /*this*/, jlong nativeRef) +{ + try { + DJINNI_FUNCTION_PROLOGUE1(jniEnv, nativeRef); + const auto& ref = ::djinni::objectFromHandleAddress<::mynteye_jni::Frame>(nativeRef); + auto r = ref->Data(); + return ::djinni::release(::djinni::Binary::fromCpp(jniEnv, r)); + } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */) +} + +} // namespace djinni_generated diff --git a/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/jni/NativeFrame.hpp b/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/jni/NativeFrame.hpp new file mode 100644 index 0000000..44c7216 --- /dev/null +++ b/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/jni/NativeFrame.hpp @@ -0,0 +1,32 @@ +// AUTOGENERATED FILE - DO NOT MODIFY! +// This file generated by Djinni from mynteye_types.djinni + +#pragma once + +#include "djinni_support.hpp" +#include "frame.hpp" + +namespace djinni_generated { + +class NativeFrame final : ::djinni::JniInterface<::mynteye_jni::Frame, NativeFrame> { +public: + using CppType = std::shared_ptr<::mynteye_jni::Frame>; + using CppOptType = std::shared_ptr<::mynteye_jni::Frame>; + using JniType = jobject; + + using Boxed = NativeFrame; + + ~NativeFrame(); + + static CppType toCpp(JNIEnv* jniEnv, JniType j) { return ::djinni::JniClass::get()._fromJava(jniEnv, j); } + static ::djinni::LocalRef fromCppOpt(JNIEnv* jniEnv, const CppOptType& c) { return {jniEnv, ::djinni::JniClass::get()._toJava(jniEnv, c)}; } + static ::djinni::LocalRef fromCpp(JNIEnv* jniEnv, const CppType& c) { return fromCppOpt(jniEnv, c); } + +private: + NativeFrame(); + friend ::djinni::JniClass; + friend ::djinni::JniInterface<::mynteye_jni::Frame, NativeFrame>; + +}; + +} // namespace djinni_generated diff --git a/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/jni/NativeImgData.cpp b/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/jni/NativeImgData.cpp new file mode 100644 index 0000000..cd97986 --- /dev/null +++ b/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/jni/NativeImgData.cpp @@ -0,0 +1,32 @@ +// AUTOGENERATED FILE - DO NOT MODIFY! +// This file generated by Djinni from mynteye_types.djinni + +#include "NativeImgData.hpp" // my header +#include "Marshal.hpp" + +namespace djinni_generated { + +NativeImgData::NativeImgData() = default; + +NativeImgData::~NativeImgData() = default; + +auto NativeImgData::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::I64::fromCpp(jniEnv, c.frame_id)), + ::djinni::get(::djinni::I64::fromCpp(jniEnv, c.timestamp)), + ::djinni::get(::djinni::I64::fromCpp(jniEnv, c.exposure_time)))}; + ::djinni::jniExceptionCheck(jniEnv); + return r; +} + +auto NativeImgData::toCpp(JNIEnv* jniEnv, JniType j) -> CppType { + ::djinni::JniLocalScope jscope(jniEnv, 4); + assert(j != nullptr); + const auto& data = ::djinni::JniClass::get(); + return {::djinni::I64::toCpp(jniEnv, jniEnv->GetLongField(j, data.field_mFrameId)), + ::djinni::I64::toCpp(jniEnv, jniEnv->GetLongField(j, data.field_mTimestamp)), + ::djinni::I64::toCpp(jniEnv, jniEnv->GetLongField(j, data.field_mExposureTime))}; +} + +} // namespace djinni_generated diff --git a/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/jni/NativeImgData.hpp b/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/jni/NativeImgData.hpp new file mode 100644 index 0000000..a254254 --- /dev/null +++ b/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/jni/NativeImgData.hpp @@ -0,0 +1,34 @@ +// AUTOGENERATED FILE - DO NOT MODIFY! +// This file generated by Djinni from mynteye_types.djinni + +#pragma once + +#include "djinni_support.hpp" +#include "img_data.hpp" + +namespace djinni_generated { + +class NativeImgData final { +public: + using CppType = ::mynteye_jni::ImgData; + using JniType = jobject; + + using Boxed = NativeImgData; + + ~NativeImgData(); + + static CppType toCpp(JNIEnv* jniEnv, JniType j); + static ::djinni::LocalRef fromCpp(JNIEnv* jniEnv, const CppType& c); + +private: + NativeImgData(); + friend ::djinni::JniClass; + + const ::djinni::GlobalRef clazz { ::djinni::jniFindClass("com/slightech/mynteye/ImgData") }; + const jmethodID jconstructor { ::djinni::jniGetMethodID(clazz.get(), "", "(JJJ)V") }; + const jfieldID field_mFrameId { ::djinni::jniGetFieldID(clazz.get(), "mFrameId", "J") }; + const jfieldID field_mTimestamp { ::djinni::jniGetFieldID(clazz.get(), "mTimestamp", "J") }; + const jfieldID field_mExposureTime { ::djinni::jniGetFieldID(clazz.get(), "mExposureTime", "J") }; +}; + +} // namespace djinni_generated diff --git a/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/jni/NativeImuData.cpp b/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/jni/NativeImuData.cpp new file mode 100644 index 0000000..46dce8c --- /dev/null +++ b/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/jni/NativeImuData.cpp @@ -0,0 +1,38 @@ +// AUTOGENERATED FILE - DO NOT MODIFY! +// This file generated by Djinni from mynteye_types.djinni + +#include "NativeImuData.hpp" // my header +#include "Marshal.hpp" + +namespace djinni_generated { + +NativeImuData::NativeImuData() = default; + +NativeImuData::~NativeImuData() = default; + +auto NativeImuData::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::I64::fromCpp(jniEnv, c.frame_id)), + ::djinni::get(::djinni::I32::fromCpp(jniEnv, c.flag)), + ::djinni::get(::djinni::I64::fromCpp(jniEnv, c.timestamp)), + ::djinni::get(::djinni::List<::djinni::F64>::fromCpp(jniEnv, c.accel)), + ::djinni::get(::djinni::List<::djinni::F64>::fromCpp(jniEnv, c.gyro)), + ::djinni::get(::djinni::F64::fromCpp(jniEnv, c.temperature)))}; + ::djinni::jniExceptionCheck(jniEnv); + return r; +} + +auto NativeImuData::toCpp(JNIEnv* jniEnv, JniType j) -> CppType { + ::djinni::JniLocalScope jscope(jniEnv, 7); + assert(j != nullptr); + const auto& data = ::djinni::JniClass::get(); + return {::djinni::I64::toCpp(jniEnv, jniEnv->GetLongField(j, data.field_mFrameId)), + ::djinni::I32::toCpp(jniEnv, jniEnv->GetIntField(j, data.field_mFlag)), + ::djinni::I64::toCpp(jniEnv, jniEnv->GetLongField(j, data.field_mTimestamp)), + ::djinni::List<::djinni::F64>::toCpp(jniEnv, jniEnv->GetObjectField(j, data.field_mAccel)), + ::djinni::List<::djinni::F64>::toCpp(jniEnv, jniEnv->GetObjectField(j, data.field_mGyro)), + ::djinni::F64::toCpp(jniEnv, jniEnv->GetDoubleField(j, data.field_mTemperature))}; +} + +} // namespace djinni_generated diff --git a/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/jni/NativeImuData.hpp b/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/jni/NativeImuData.hpp new file mode 100644 index 0000000..0345ff0 --- /dev/null +++ b/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/jni/NativeImuData.hpp @@ -0,0 +1,37 @@ +// AUTOGENERATED FILE - DO NOT MODIFY! +// This file generated by Djinni from mynteye_types.djinni + +#pragma once + +#include "djinni_support.hpp" +#include "imu_data.hpp" + +namespace djinni_generated { + +class NativeImuData final { +public: + using CppType = ::mynteye_jni::ImuData; + using JniType = jobject; + + using Boxed = NativeImuData; + + ~NativeImuData(); + + static CppType toCpp(JNIEnv* jniEnv, JniType j); + static ::djinni::LocalRef fromCpp(JNIEnv* jniEnv, const CppType& c); + +private: + NativeImuData(); + friend ::djinni::JniClass; + + const ::djinni::GlobalRef clazz { ::djinni::jniFindClass("com/slightech/mynteye/ImuData") }; + const jmethodID jconstructor { ::djinni::jniGetMethodID(clazz.get(), "", "(JIJLjava/util/ArrayList;Ljava/util/ArrayList;D)V") }; + const jfieldID field_mFrameId { ::djinni::jniGetFieldID(clazz.get(), "mFrameId", "J") }; + const jfieldID field_mFlag { ::djinni::jniGetFieldID(clazz.get(), "mFlag", "I") }; + const jfieldID field_mTimestamp { ::djinni::jniGetFieldID(clazz.get(), "mTimestamp", "J") }; + const jfieldID field_mAccel { ::djinni::jniGetFieldID(clazz.get(), "mAccel", "Ljava/util/ArrayList;") }; + const jfieldID field_mGyro { ::djinni::jniGetFieldID(clazz.get(), "mGyro", "Ljava/util/ArrayList;") }; + const jfieldID field_mTemperature { ::djinni::jniGetFieldID(clazz.get(), "mTemperature", "D") }; +}; + +} // namespace djinni_generated diff --git a/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/jni/NativeImuIntrinsics.cpp b/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/jni/NativeImuIntrinsics.cpp new file mode 100644 index 0000000..9c449ca --- /dev/null +++ b/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/jni/NativeImuIntrinsics.cpp @@ -0,0 +1,34 @@ +// AUTOGENERATED FILE - DO NOT MODIFY! +// This file generated by Djinni from mynteye_types.djinni + +#include "NativeImuIntrinsics.hpp" // my header +#include "Marshal.hpp" + +namespace djinni_generated { + +NativeImuIntrinsics::NativeImuIntrinsics() = default; + +NativeImuIntrinsics::~NativeImuIntrinsics() = default; + +auto NativeImuIntrinsics::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::List<::djinni::F64>::fromCpp(jniEnv, c.scale)), + ::djinni::get(::djinni::List<::djinni::F64>::fromCpp(jniEnv, c.drift)), + ::djinni::get(::djinni::List<::djinni::F64>::fromCpp(jniEnv, c.noise)), + ::djinni::get(::djinni::List<::djinni::F64>::fromCpp(jniEnv, c.bias)))}; + ::djinni::jniExceptionCheck(jniEnv); + return r; +} + +auto NativeImuIntrinsics::toCpp(JNIEnv* jniEnv, JniType j) -> CppType { + ::djinni::JniLocalScope jscope(jniEnv, 5); + assert(j != nullptr); + const auto& data = ::djinni::JniClass::get(); + return {::djinni::List<::djinni::F64>::toCpp(jniEnv, jniEnv->GetObjectField(j, data.field_mScale)), + ::djinni::List<::djinni::F64>::toCpp(jniEnv, jniEnv->GetObjectField(j, data.field_mDrift)), + ::djinni::List<::djinni::F64>::toCpp(jniEnv, jniEnv->GetObjectField(j, data.field_mNoise)), + ::djinni::List<::djinni::F64>::toCpp(jniEnv, jniEnv->GetObjectField(j, data.field_mBias))}; +} + +} // namespace djinni_generated diff --git a/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/jni/NativeImuIntrinsics.hpp b/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/jni/NativeImuIntrinsics.hpp new file mode 100644 index 0000000..f12e35e --- /dev/null +++ b/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/jni/NativeImuIntrinsics.hpp @@ -0,0 +1,35 @@ +// AUTOGENERATED FILE - DO NOT MODIFY! +// This file generated by Djinni from mynteye_types.djinni + +#pragma once + +#include "djinni_support.hpp" +#include "imu_intrinsics.hpp" + +namespace djinni_generated { + +class NativeImuIntrinsics final { +public: + using CppType = ::mynteye_jni::ImuIntrinsics; + using JniType = jobject; + + using Boxed = NativeImuIntrinsics; + + ~NativeImuIntrinsics(); + + static CppType toCpp(JNIEnv* jniEnv, JniType j); + static ::djinni::LocalRef fromCpp(JNIEnv* jniEnv, const CppType& c); + +private: + NativeImuIntrinsics(); + friend ::djinni::JniClass; + + const ::djinni::GlobalRef clazz { ::djinni::jniFindClass("com/slightech/mynteye/ImuIntrinsics") }; + const jmethodID jconstructor { ::djinni::jniGetMethodID(clazz.get(), "", "(Ljava/util/ArrayList;Ljava/util/ArrayList;Ljava/util/ArrayList;Ljava/util/ArrayList;)V") }; + const jfieldID field_mScale { ::djinni::jniGetFieldID(clazz.get(), "mScale", "Ljava/util/ArrayList;") }; + const jfieldID field_mDrift { ::djinni::jniGetFieldID(clazz.get(), "mDrift", "Ljava/util/ArrayList;") }; + const jfieldID field_mNoise { ::djinni::jniGetFieldID(clazz.get(), "mNoise", "Ljava/util/ArrayList;") }; + const jfieldID field_mBias { ::djinni::jniGetFieldID(clazz.get(), "mBias", "Ljava/util/ArrayList;") }; +}; + +} // namespace djinni_generated diff --git a/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/jni/NativeInfo.hpp b/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/jni/NativeInfo.hpp new file mode 100644 index 0000000..8b0e716 --- /dev/null +++ b/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/jni/NativeInfo.hpp @@ -0,0 +1,26 @@ +// AUTOGENERATED FILE - DO NOT MODIFY! +// This file generated by Djinni from mynteye_types.djinni + +#pragma once + +#include "djinni_support.hpp" +#include "info.hpp" + +namespace djinni_generated { + +class NativeInfo final : ::djinni::JniEnum { +public: + using CppType = ::mynteye_jni::Info; + using JniType = jobject; + + using Boxed = NativeInfo; + + static CppType toCpp(JNIEnv* jniEnv, JniType j) { return static_cast(::djinni::JniClass::get().ordinal(jniEnv, j)); } + static ::djinni::LocalRef fromCpp(JNIEnv* jniEnv, CppType c) { return ::djinni::JniClass::get().create(jniEnv, static_cast(c)); } + +private: + NativeInfo() : JniEnum("com/slightech/mynteye/Info") {} + friend ::djinni::JniClass; +}; + +} // namespace djinni_generated diff --git a/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/jni/NativeIntrinsics.cpp b/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/jni/NativeIntrinsics.cpp new file mode 100644 index 0000000..a99b966 --- /dev/null +++ b/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/jni/NativeIntrinsics.cpp @@ -0,0 +1,43 @@ +// AUTOGENERATED FILE - DO NOT MODIFY! +// This file generated by Djinni from mynteye_types.djinni + +#include "NativeIntrinsics.hpp" // my header +#include "Marshal.hpp" +#include "NativeCalibrationModel.hpp" + +namespace djinni_generated { + +NativeIntrinsics::NativeIntrinsics() = default; + +NativeIntrinsics::~NativeIntrinsics() = default; + +auto NativeIntrinsics::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_generated::NativeCalibrationModel::fromCpp(jniEnv, c.calib_model)), + ::djinni::get(::djinni::I32::fromCpp(jniEnv, c.width)), + ::djinni::get(::djinni::I32::fromCpp(jniEnv, c.height)), + ::djinni::get(::djinni::F64::fromCpp(jniEnv, c.fx)), + ::djinni::get(::djinni::F64::fromCpp(jniEnv, c.fy)), + ::djinni::get(::djinni::F64::fromCpp(jniEnv, c.cx)), + ::djinni::get(::djinni::F64::fromCpp(jniEnv, c.cy)), + ::djinni::get(::djinni::List<::djinni::F64>::fromCpp(jniEnv, c.coeffs)))}; + ::djinni::jniExceptionCheck(jniEnv); + return r; +} + +auto NativeIntrinsics::toCpp(JNIEnv* jniEnv, JniType j) -> CppType { + ::djinni::JniLocalScope jscope(jniEnv, 9); + assert(j != nullptr); + const auto& data = ::djinni::JniClass::get(); + return {::djinni_generated::NativeCalibrationModel::toCpp(jniEnv, jniEnv->GetObjectField(j, data.field_mCalibModel)), + ::djinni::I32::toCpp(jniEnv, jniEnv->GetIntField(j, data.field_mWidth)), + ::djinni::I32::toCpp(jniEnv, jniEnv->GetIntField(j, data.field_mHeight)), + ::djinni::F64::toCpp(jniEnv, jniEnv->GetDoubleField(j, data.field_mFx)), + ::djinni::F64::toCpp(jniEnv, jniEnv->GetDoubleField(j, data.field_mFy)), + ::djinni::F64::toCpp(jniEnv, jniEnv->GetDoubleField(j, data.field_mCx)), + ::djinni::F64::toCpp(jniEnv, jniEnv->GetDoubleField(j, data.field_mCy)), + ::djinni::List<::djinni::F64>::toCpp(jniEnv, jniEnv->GetObjectField(j, data.field_mCoeffs))}; +} + +} // namespace djinni_generated diff --git a/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/jni/NativeIntrinsics.hpp b/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/jni/NativeIntrinsics.hpp new file mode 100644 index 0000000..69c137e --- /dev/null +++ b/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/jni/NativeIntrinsics.hpp @@ -0,0 +1,39 @@ +// AUTOGENERATED FILE - DO NOT MODIFY! +// This file generated by Djinni from mynteye_types.djinni + +#pragma once + +#include "djinni_support.hpp" +#include "intrinsics.hpp" + +namespace djinni_generated { + +class NativeIntrinsics final { +public: + using CppType = ::mynteye_jni::Intrinsics; + using JniType = jobject; + + using Boxed = NativeIntrinsics; + + ~NativeIntrinsics(); + + static CppType toCpp(JNIEnv* jniEnv, JniType j); + static ::djinni::LocalRef fromCpp(JNIEnv* jniEnv, const CppType& c); + +private: + NativeIntrinsics(); + friend ::djinni::JniClass; + + const ::djinni::GlobalRef clazz { ::djinni::jniFindClass("com/slightech/mynteye/Intrinsics") }; + const jmethodID jconstructor { ::djinni::jniGetMethodID(clazz.get(), "", "(Lcom/slightech/mynteye/CalibrationModel;IIDDDDLjava/util/ArrayList;)V") }; + const jfieldID field_mCalibModel { ::djinni::jniGetFieldID(clazz.get(), "mCalibModel", "Lcom/slightech/mynteye/CalibrationModel;") }; + const jfieldID field_mWidth { ::djinni::jniGetFieldID(clazz.get(), "mWidth", "I") }; + const jfieldID field_mHeight { ::djinni::jniGetFieldID(clazz.get(), "mHeight", "I") }; + const jfieldID field_mFx { ::djinni::jniGetFieldID(clazz.get(), "mFx", "D") }; + const jfieldID field_mFy { ::djinni::jniGetFieldID(clazz.get(), "mFy", "D") }; + const jfieldID field_mCx { ::djinni::jniGetFieldID(clazz.get(), "mCx", "D") }; + const jfieldID field_mCy { ::djinni::jniGetFieldID(clazz.get(), "mCy", "D") }; + const jfieldID field_mCoeffs { ::djinni::jniGetFieldID(clazz.get(), "mCoeffs", "Ljava/util/ArrayList;") }; +}; + +} // namespace djinni_generated diff --git a/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/jni/NativeModel.hpp b/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/jni/NativeModel.hpp new file mode 100644 index 0000000..ebbbb88 --- /dev/null +++ b/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/jni/NativeModel.hpp @@ -0,0 +1,26 @@ +// AUTOGENERATED FILE - DO NOT MODIFY! +// This file generated by Djinni from mynteye_types.djinni + +#pragma once + +#include "djinni_support.hpp" +#include "model.hpp" + +namespace djinni_generated { + +class NativeModel final : ::djinni::JniEnum { +public: + using CppType = ::mynteye_jni::Model; + using JniType = jobject; + + using Boxed = NativeModel; + + static CppType toCpp(JNIEnv* jniEnv, JniType j) { return static_cast(::djinni::JniClass::get().ordinal(jniEnv, j)); } + static ::djinni::LocalRef fromCpp(JNIEnv* jniEnv, CppType c) { return ::djinni::JniClass::get().create(jniEnv, static_cast(c)); } + +private: + NativeModel() : JniEnum("com/slightech/mynteye/Model") {} + friend ::djinni::JniClass; +}; + +} // namespace djinni_generated diff --git a/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/jni/NativeMotionData.cpp b/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/jni/NativeMotionData.cpp new file mode 100644 index 0000000..3b634e1 --- /dev/null +++ b/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/jni/NativeMotionData.cpp @@ -0,0 +1,32 @@ +// AUTOGENERATED FILE - DO NOT MODIFY! +// This file generated by Djinni from mynteye_types.djinni + +#include "NativeMotionData.hpp" // my header +#include "NativeImuData.hpp" + +namespace djinni_generated { + +NativeMotionData::NativeMotionData() : ::djinni::JniInterface<::mynteye_jni::MotionData, NativeMotionData>("com/slightech/mynteye/MotionData$CppProxy") {} + +NativeMotionData::~NativeMotionData() = default; + + +CJNIEXPORT void JNICALL Java_com_slightech_mynteye_MotionData_00024CppProxy_nativeDestroy(JNIEnv* jniEnv, jobject /*this*/, jlong nativeRef) +{ + try { + DJINNI_FUNCTION_PROLOGUE1(jniEnv, nativeRef); + delete reinterpret_cast<::djinni::CppProxyHandle<::mynteye_jni::MotionData>*>(nativeRef); + } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, ) +} + +CJNIEXPORT jobject JNICALL Java_com_slightech_mynteye_MotionData_00024CppProxy_native_1imu(JNIEnv* jniEnv, jobject /*this*/, jlong nativeRef) +{ + try { + DJINNI_FUNCTION_PROLOGUE1(jniEnv, nativeRef); + const auto& ref = ::djinni::objectFromHandleAddress<::mynteye_jni::MotionData>(nativeRef); + auto r = ref->Imu(); + return ::djinni::release(::djinni_generated::NativeImuData::fromCpp(jniEnv, r)); + } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */) +} + +} // namespace djinni_generated diff --git a/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/jni/NativeMotionData.hpp b/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/jni/NativeMotionData.hpp new file mode 100644 index 0000000..8884a6c --- /dev/null +++ b/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/jni/NativeMotionData.hpp @@ -0,0 +1,32 @@ +// AUTOGENERATED FILE - DO NOT MODIFY! +// This file generated by Djinni from mynteye_types.djinni + +#pragma once + +#include "djinni_support.hpp" +#include "motion_data.hpp" + +namespace djinni_generated { + +class NativeMotionData final : ::djinni::JniInterface<::mynteye_jni::MotionData, NativeMotionData> { +public: + using CppType = std::shared_ptr<::mynteye_jni::MotionData>; + using CppOptType = std::shared_ptr<::mynteye_jni::MotionData>; + using JniType = jobject; + + using Boxed = NativeMotionData; + + ~NativeMotionData(); + + static CppType toCpp(JNIEnv* jniEnv, JniType j) { return ::djinni::JniClass::get()._fromJava(jniEnv, j); } + static ::djinni::LocalRef fromCppOpt(JNIEnv* jniEnv, const CppOptType& c) { return {jniEnv, ::djinni::JniClass::get()._toJava(jniEnv, c)}; } + static ::djinni::LocalRef fromCpp(JNIEnv* jniEnv, const CppType& c) { return fromCppOpt(jniEnv, c); } + +private: + NativeMotionData(); + friend ::djinni::JniClass; + friend ::djinni::JniInterface<::mynteye_jni::MotionData, NativeMotionData>; + +}; + +} // namespace djinni_generated diff --git a/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/jni/NativeMotionIntrinsics.cpp b/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/jni/NativeMotionIntrinsics.cpp new file mode 100644 index 0000000..10936a9 --- /dev/null +++ b/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/jni/NativeMotionIntrinsics.cpp @@ -0,0 +1,30 @@ +// AUTOGENERATED FILE - DO NOT MODIFY! +// This file generated by Djinni from mynteye_types.djinni + +#include "NativeMotionIntrinsics.hpp" // my header +#include "NativeImuIntrinsics.hpp" + +namespace djinni_generated { + +NativeMotionIntrinsics::NativeMotionIntrinsics() = default; + +NativeMotionIntrinsics::~NativeMotionIntrinsics() = default; + +auto NativeMotionIntrinsics::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_generated::NativeImuIntrinsics::fromCpp(jniEnv, c.accel)), + ::djinni::get(::djinni_generated::NativeImuIntrinsics::fromCpp(jniEnv, c.gyro)))}; + ::djinni::jniExceptionCheck(jniEnv); + return r; +} + +auto NativeMotionIntrinsics::toCpp(JNIEnv* jniEnv, JniType j) -> CppType { + ::djinni::JniLocalScope jscope(jniEnv, 3); + assert(j != nullptr); + const auto& data = ::djinni::JniClass::get(); + return {::djinni_generated::NativeImuIntrinsics::toCpp(jniEnv, jniEnv->GetObjectField(j, data.field_mAccel)), + ::djinni_generated::NativeImuIntrinsics::toCpp(jniEnv, jniEnv->GetObjectField(j, data.field_mGyro))}; +} + +} // namespace djinni_generated diff --git a/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/jni/NativeMotionIntrinsics.hpp b/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/jni/NativeMotionIntrinsics.hpp new file mode 100644 index 0000000..0c3f49f --- /dev/null +++ b/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/jni/NativeMotionIntrinsics.hpp @@ -0,0 +1,33 @@ +// AUTOGENERATED FILE - DO NOT MODIFY! +// This file generated by Djinni from mynteye_types.djinni + +#pragma once + +#include "djinni_support.hpp" +#include "motion_intrinsics.hpp" + +namespace djinni_generated { + +class NativeMotionIntrinsics final { +public: + using CppType = ::mynteye_jni::MotionIntrinsics; + using JniType = jobject; + + using Boxed = NativeMotionIntrinsics; + + ~NativeMotionIntrinsics(); + + static CppType toCpp(JNIEnv* jniEnv, JniType j); + static ::djinni::LocalRef fromCpp(JNIEnv* jniEnv, const CppType& c); + +private: + NativeMotionIntrinsics(); + friend ::djinni::JniClass; + + const ::djinni::GlobalRef clazz { ::djinni::jniFindClass("com/slightech/mynteye/MotionIntrinsics") }; + const jmethodID jconstructor { ::djinni::jniGetMethodID(clazz.get(), "", "(Lcom/slightech/mynteye/ImuIntrinsics;Lcom/slightech/mynteye/ImuIntrinsics;)V") }; + const jfieldID field_mAccel { ::djinni::jniGetFieldID(clazz.get(), "mAccel", "Lcom/slightech/mynteye/ImuIntrinsics;") }; + const jfieldID field_mGyro { ::djinni::jniGetFieldID(clazz.get(), "mGyro", "Lcom/slightech/mynteye/ImuIntrinsics;") }; +}; + +} // namespace djinni_generated diff --git a/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/jni/NativeOption.hpp b/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/jni/NativeOption.hpp new file mode 100644 index 0000000..a095d38 --- /dev/null +++ b/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/jni/NativeOption.hpp @@ -0,0 +1,26 @@ +// AUTOGENERATED FILE - DO NOT MODIFY! +// This file generated by Djinni from mynteye_types.djinni + +#pragma once + +#include "djinni_support.hpp" +#include "option.hpp" + +namespace djinni_generated { + +class NativeOption final : ::djinni::JniEnum { +public: + using CppType = ::mynteye_jni::Option; + using JniType = jobject; + + using Boxed = NativeOption; + + static CppType toCpp(JNIEnv* jniEnv, JniType j) { return static_cast(::djinni::JniClass::get().ordinal(jniEnv, j)); } + static ::djinni::LocalRef fromCpp(JNIEnv* jniEnv, CppType c) { return ::djinni::JniClass::get().create(jniEnv, static_cast(c)); } + +private: + NativeOption() : JniEnum("com/slightech/mynteye/Option") {} + friend ::djinni::JniClass; +}; + +} // namespace djinni_generated diff --git a/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/jni/NativeOptionInfo.cpp b/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/jni/NativeOptionInfo.cpp new file mode 100644 index 0000000..0d76aa8 --- /dev/null +++ b/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/jni/NativeOptionInfo.cpp @@ -0,0 +1,32 @@ +// AUTOGENERATED FILE - DO NOT MODIFY! +// This file generated by Djinni from mynteye_types.djinni + +#include "NativeOptionInfo.hpp" // my header +#include "Marshal.hpp" + +namespace djinni_generated { + +NativeOptionInfo::NativeOptionInfo() = default; + +NativeOptionInfo::~NativeOptionInfo() = default; + +auto NativeOptionInfo::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.min)), + ::djinni::get(::djinni::I32::fromCpp(jniEnv, c.max)), + ::djinni::get(::djinni::I32::fromCpp(jniEnv, c.def)))}; + ::djinni::jniExceptionCheck(jniEnv); + return r; +} + +auto NativeOptionInfo::toCpp(JNIEnv* jniEnv, JniType j) -> CppType { + ::djinni::JniLocalScope jscope(jniEnv, 4); + assert(j != nullptr); + const auto& data = ::djinni::JniClass::get(); + return {::djinni::I32::toCpp(jniEnv, jniEnv->GetIntField(j, data.field_mMin)), + ::djinni::I32::toCpp(jniEnv, jniEnv->GetIntField(j, data.field_mMax)), + ::djinni::I32::toCpp(jniEnv, jniEnv->GetIntField(j, data.field_mDef))}; +} + +} // namespace djinni_generated diff --git a/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/jni/NativeOptionInfo.hpp b/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/jni/NativeOptionInfo.hpp new file mode 100644 index 0000000..97b2a14 --- /dev/null +++ b/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/jni/NativeOptionInfo.hpp @@ -0,0 +1,34 @@ +// AUTOGENERATED FILE - DO NOT MODIFY! +// This file generated by Djinni from mynteye_types.djinni + +#pragma once + +#include "djinni_support.hpp" +#include "option_info.hpp" + +namespace djinni_generated { + +class NativeOptionInfo final { +public: + using CppType = ::mynteye_jni::OptionInfo; + using JniType = jobject; + + using Boxed = NativeOptionInfo; + + ~NativeOptionInfo(); + + static CppType toCpp(JNIEnv* jniEnv, JniType j); + static ::djinni::LocalRef fromCpp(JNIEnv* jniEnv, const CppType& c); + +private: + NativeOptionInfo(); + friend ::djinni::JniClass; + + const ::djinni::GlobalRef clazz { ::djinni::jniFindClass("com/slightech/mynteye/OptionInfo") }; + const jmethodID jconstructor { ::djinni::jniGetMethodID(clazz.get(), "", "(III)V") }; + const jfieldID field_mMin { ::djinni::jniGetFieldID(clazz.get(), "mMin", "I") }; + const jfieldID field_mMax { ::djinni::jniGetFieldID(clazz.get(), "mMax", "I") }; + const jfieldID field_mDef { ::djinni::jniGetFieldID(clazz.get(), "mDef", "I") }; +}; + +} // namespace djinni_generated diff --git a/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/jni/NativeSource.hpp b/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/jni/NativeSource.hpp new file mode 100644 index 0000000..ce6ad69 --- /dev/null +++ b/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/jni/NativeSource.hpp @@ -0,0 +1,26 @@ +// AUTOGENERATED FILE - DO NOT MODIFY! +// This file generated by Djinni from mynteye_types.djinni + +#pragma once + +#include "djinni_support.hpp" +#include "source.hpp" + +namespace djinni_generated { + +class NativeSource final : ::djinni::JniEnum { +public: + using CppType = ::mynteye_jni::Source; + using JniType = jobject; + + using Boxed = NativeSource; + + static CppType toCpp(JNIEnv* jniEnv, JniType j) { return static_cast(::djinni::JniClass::get().ordinal(jniEnv, j)); } + static ::djinni::LocalRef fromCpp(JNIEnv* jniEnv, CppType c) { return ::djinni::JniClass::get().create(jniEnv, static_cast(c)); } + +private: + NativeSource() : JniEnum("com/slightech/mynteye/Source") {} + friend ::djinni::JniClass; +}; + +} // namespace djinni_generated diff --git a/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/jni/NativeStream.hpp b/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/jni/NativeStream.hpp new file mode 100644 index 0000000..e899132 --- /dev/null +++ b/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/jni/NativeStream.hpp @@ -0,0 +1,26 @@ +// AUTOGENERATED FILE - DO NOT MODIFY! +// This file generated by Djinni from mynteye_types.djinni + +#pragma once + +#include "djinni_support.hpp" +#include "stream.hpp" + +namespace djinni_generated { + +class NativeStream final : ::djinni::JniEnum { +public: + using CppType = ::mynteye_jni::Stream; + using JniType = jobject; + + using Boxed = NativeStream; + + static CppType toCpp(JNIEnv* jniEnv, JniType j) { return static_cast(::djinni::JniClass::get().ordinal(jniEnv, j)); } + static ::djinni::LocalRef fromCpp(JNIEnv* jniEnv, CppType c) { return ::djinni::JniClass::get().create(jniEnv, static_cast(c)); } + +private: + NativeStream() : JniEnum("com/slightech/mynteye/Stream") {} + friend ::djinni::JniClass; +}; + +} // namespace djinni_generated diff --git a/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/jni/NativeStreamData.cpp b/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/jni/NativeStreamData.cpp new file mode 100644 index 0000000..7476d72 --- /dev/null +++ b/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/jni/NativeStreamData.cpp @@ -0,0 +1,54 @@ +// AUTOGENERATED FILE - DO NOT MODIFY! +// This file generated by Djinni from mynteye_types.djinni + +#include "NativeStreamData.hpp" // my header +#include "Marshal.hpp" +#include "NativeFrame.hpp" +#include "NativeImgData.hpp" + +namespace djinni_generated { + +NativeStreamData::NativeStreamData() : ::djinni::JniInterface<::mynteye_jni::StreamData, NativeStreamData>("com/slightech/mynteye/StreamData$CppProxy") {} + +NativeStreamData::~NativeStreamData() = default; + + +CJNIEXPORT void JNICALL Java_com_slightech_mynteye_StreamData_00024CppProxy_nativeDestroy(JNIEnv* jniEnv, jobject /*this*/, jlong nativeRef) +{ + try { + DJINNI_FUNCTION_PROLOGUE1(jniEnv, nativeRef); + delete reinterpret_cast<::djinni::CppProxyHandle<::mynteye_jni::StreamData>*>(nativeRef); + } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, ) +} + +CJNIEXPORT jobject JNICALL Java_com_slightech_mynteye_StreamData_00024CppProxy_native_1img(JNIEnv* jniEnv, jobject /*this*/, jlong nativeRef) +{ + try { + DJINNI_FUNCTION_PROLOGUE1(jniEnv, nativeRef); + const auto& ref = ::djinni::objectFromHandleAddress<::mynteye_jni::StreamData>(nativeRef); + auto r = ref->Img(); + return ::djinni::release(::djinni_generated::NativeImgData::fromCpp(jniEnv, r)); + } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */) +} + +CJNIEXPORT jobject JNICALL Java_com_slightech_mynteye_StreamData_00024CppProxy_native_1frame(JNIEnv* jniEnv, jobject /*this*/, jlong nativeRef) +{ + try { + DJINNI_FUNCTION_PROLOGUE1(jniEnv, nativeRef); + const auto& ref = ::djinni::objectFromHandleAddress<::mynteye_jni::StreamData>(nativeRef); + auto r = ref->Frame(); + return ::djinni::release(::djinni_generated::NativeFrame::fromCpp(jniEnv, r)); + } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */) +} + +CJNIEXPORT jlong JNICALL Java_com_slightech_mynteye_StreamData_00024CppProxy_native_1frameId(JNIEnv* jniEnv, jobject /*this*/, jlong nativeRef) +{ + try { + DJINNI_FUNCTION_PROLOGUE1(jniEnv, nativeRef); + const auto& ref = ::djinni::objectFromHandleAddress<::mynteye_jni::StreamData>(nativeRef); + auto r = ref->FrameId(); + return ::djinni::release(::djinni::I64::fromCpp(jniEnv, r)); + } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */) +} + +} // namespace djinni_generated diff --git a/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/jni/NativeStreamData.hpp b/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/jni/NativeStreamData.hpp new file mode 100644 index 0000000..380ab19 --- /dev/null +++ b/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/jni/NativeStreamData.hpp @@ -0,0 +1,32 @@ +// AUTOGENERATED FILE - DO NOT MODIFY! +// This file generated by Djinni from mynteye_types.djinni + +#pragma once + +#include "djinni_support.hpp" +#include "stream_data.hpp" + +namespace djinni_generated { + +class NativeStreamData final : ::djinni::JniInterface<::mynteye_jni::StreamData, NativeStreamData> { +public: + using CppType = std::shared_ptr<::mynteye_jni::StreamData>; + using CppOptType = std::shared_ptr<::mynteye_jni::StreamData>; + using JniType = jobject; + + using Boxed = NativeStreamData; + + ~NativeStreamData(); + + static CppType toCpp(JNIEnv* jniEnv, JniType j) { return ::djinni::JniClass::get()._fromJava(jniEnv, j); } + static ::djinni::LocalRef fromCppOpt(JNIEnv* jniEnv, const CppOptType& c) { return {jniEnv, ::djinni::JniClass::get()._toJava(jniEnv, c)}; } + static ::djinni::LocalRef fromCpp(JNIEnv* jniEnv, const CppType& c) { return fromCppOpt(jniEnv, c); } + +private: + NativeStreamData(); + friend ::djinni::JniClass; + friend ::djinni::JniInterface<::mynteye_jni::StreamData, NativeStreamData>; + +}; + +} // namespace djinni_generated diff --git a/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/jni/NativeStreamRequest.cpp b/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/jni/NativeStreamRequest.cpp new file mode 100644 index 0000000..7747789 --- /dev/null +++ b/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/jni/NativeStreamRequest.cpp @@ -0,0 +1,37 @@ +// AUTOGENERATED FILE - DO NOT MODIFY! +// This file generated by Djinni from mynteye_types.djinni + +#include "NativeStreamRequest.hpp" // my header +#include "Marshal.hpp" +#include "NativeFormat.hpp" + +namespace djinni_generated { + +NativeStreamRequest::NativeStreamRequest() = default; + +NativeStreamRequest::~NativeStreamRequest() = default; + +auto NativeStreamRequest::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.width)), + ::djinni::get(::djinni::I32::fromCpp(jniEnv, c.height)), + ::djinni::get(::djinni_generated::NativeFormat::fromCpp(jniEnv, c.format)), + ::djinni::get(::djinni::I32::fromCpp(jniEnv, c.fps)))}; + ::djinni::jniExceptionCheck(jniEnv); + return r; +} + +auto NativeStreamRequest::toCpp(JNIEnv* jniEnv, JniType j) -> CppType { + ::djinni::JniLocalScope jscope(jniEnv, 6); + assert(j != nullptr); + const auto& data = ::djinni::JniClass::get(); + return {::djinni::I32::toCpp(jniEnv, jniEnv->GetIntField(j, data.field_mIndex)), + ::djinni::I32::toCpp(jniEnv, jniEnv->GetIntField(j, data.field_mWidth)), + ::djinni::I32::toCpp(jniEnv, jniEnv->GetIntField(j, data.field_mHeight)), + ::djinni_generated::NativeFormat::toCpp(jniEnv, jniEnv->GetObjectField(j, data.field_mFormat)), + ::djinni::I32::toCpp(jniEnv, jniEnv->GetIntField(j, data.field_mFps))}; +} + +} // namespace djinni_generated diff --git a/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/jni/NativeStreamRequest.hpp b/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/jni/NativeStreamRequest.hpp new file mode 100644 index 0000000..35d9133 --- /dev/null +++ b/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/jni/NativeStreamRequest.hpp @@ -0,0 +1,36 @@ +// AUTOGENERATED FILE - DO NOT MODIFY! +// This file generated by Djinni from mynteye_types.djinni + +#pragma once + +#include "djinni_support.hpp" +#include "stream_request.hpp" + +namespace djinni_generated { + +class NativeStreamRequest final { +public: + using CppType = ::mynteye_jni::StreamRequest; + using JniType = jobject; + + using Boxed = NativeStreamRequest; + + ~NativeStreamRequest(); + + static CppType toCpp(JNIEnv* jniEnv, JniType j); + static ::djinni::LocalRef fromCpp(JNIEnv* jniEnv, const CppType& c); + +private: + NativeStreamRequest(); + friend ::djinni::JniClass; + + const ::djinni::GlobalRef clazz { ::djinni::jniFindClass("com/slightech/mynteye/StreamRequest") }; + const jmethodID jconstructor { ::djinni::jniGetMethodID(clazz.get(), "", "(IIILcom/slightech/mynteye/Format;I)V") }; + const jfieldID field_mIndex { ::djinni::jniGetFieldID(clazz.get(), "mIndex", "I") }; + const jfieldID field_mWidth { ::djinni::jniGetFieldID(clazz.get(), "mWidth", "I") }; + const jfieldID field_mHeight { ::djinni::jniGetFieldID(clazz.get(), "mHeight", "I") }; + const jfieldID field_mFormat { ::djinni::jniGetFieldID(clazz.get(), "mFormat", "Lcom/slightech/mynteye/Format;") }; + const jfieldID field_mFps { ::djinni::jniGetFieldID(clazz.get(), "mFps", "I") }; +}; + +} // namespace djinni_generated diff --git a/wrappers/android/mynteye/libmynteye/src/main/java/com/slightech/mynteye/Addon.java b/wrappers/android/mynteye/libmynteye/src/main/java/com/slightech/mynteye/Addon.java new file mode 100644 index 0000000..eddd323 --- /dev/null +++ b/wrappers/android/mynteye/libmynteye/src/main/java/com/slightech/mynteye/Addon.java @@ -0,0 +1,16 @@ +// AUTOGENERATED FILE - DO NOT MODIFY! +// This file generated by Djinni from mynteye_types.djinni + +package com.slightech.mynteye; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +/** Add-On are peripheral modules of our hardware */ +public enum Addon { + /** Infrared */ + INFRARED, + /** Second infrared */ + INFRARED2, + ; +} diff --git a/wrappers/android/mynteye/libmynteye/src/main/java/com/slightech/mynteye/CalibrationModel.java b/wrappers/android/mynteye/libmynteye/src/main/java/com/slightech/mynteye/CalibrationModel.java new file mode 100644 index 0000000..c99cf76 --- /dev/null +++ b/wrappers/android/mynteye/libmynteye/src/main/java/com/slightech/mynteye/CalibrationModel.java @@ -0,0 +1,18 @@ +// AUTOGENERATED FILE - DO NOT MODIFY! +// This file generated by Djinni from mynteye_types.djinni + +package com.slightech.mynteye; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +/** Camera calibration model */ +public enum CalibrationModel { + /** Pinhole */ + PINHOLE, + /** Equidistant: KANNALA_BRANDT */ + KANNALA_BRANDT, + /** Unknow */ + UNKNOW, + ; +} diff --git a/wrappers/android/mynteye/libmynteye/src/main/java/com/slightech/mynteye/Capability.java b/wrappers/android/mynteye/libmynteye/src/main/java/com/slightech/mynteye/Capability.java new file mode 100644 index 0000000..45497cc --- /dev/null +++ b/wrappers/android/mynteye/libmynteye/src/main/java/com/slightech/mynteye/Capability.java @@ -0,0 +1,33 @@ +// AUTOGENERATED FILE - DO NOT MODIFY! +// This file generated by Djinni from mynteye_types.djinni + +package com.slightech.mynteye; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +/** + * Capabilities define the full set of functionality that the device + * might provide + */ +public enum Capability { + /** Provides stereo stream */ + STEREO, + /** Provide stereo color stream */ + STEREO_COLOR, + /** Provides color stream */ + COLOR, + /** Provides depth stream */ + DEPTH, + /** Provides point cloud stream */ + POINTS, + /** Provides fisheye stream */ + FISHEYE, + /** Provides infrared stream */ + INFRARED, + /** Provides second infrared stream */ + INFRARED2, + /** Provides IMU (accelerometer, gyroscope) data */ + IMU, + ; +} 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 new file mode 100644 index 0000000..f0fa410 --- /dev/null +++ b/wrappers/android/mynteye/libmynteye/src/main/java/com/slightech/mynteye/Device.java @@ -0,0 +1,310 @@ +// AUTOGENERATED FILE - DO NOT MODIFY! +// This file generated by Djinni from mynteye.djinni + +package com.slightech.mynteye; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import java.util.ArrayList; +import java.util.concurrent.atomic.AtomicBoolean; + +/** Device class to communicate with MYNT® EYE device */ +public interface Device { + /** Get the model */ + @NonNull + public com.slightech.mynteye.Model getModel(); + + /** Supports the stream or not */ + public boolean supportsStream(@NonNull com.slightech.mynteye.Stream stream); + + /** Supports the capability or not */ + public boolean supportsCapability(@NonNull com.slightech.mynteye.Capability capabilities); + + /** Supports the option or not */ + public boolean supportsOption(@NonNull com.slightech.mynteye.Option option); + + /** Supports the addon or not */ + public boolean supportsAddon(@NonNull com.slightech.mynteye.Addon addon); + + /** Get all stream requests */ + @NonNull + public ArrayList getStreamRequests(); + + /** Config the stream request */ + public void configStreamRequest(@NonNull com.slightech.mynteye.StreamRequest request); + + /** Get the device info */ + @NonNull + public String getInfo(@NonNull com.slightech.mynteye.Info info); + + /** Get the intrinsics of stream */ + @NonNull + public com.slightech.mynteye.Intrinsics getIntrinsics(@NonNull com.slightech.mynteye.Stream stream); + + /** Get the extrinsics of stream */ + @NonNull + public com.slightech.mynteye.Extrinsics getExtrinsics(@NonNull com.slightech.mynteye.Stream from, @NonNull com.slightech.mynteye.Stream to); + + /** Get the intrinsics of motion */ + @NonNull + public com.slightech.mynteye.MotionIntrinsics getMotionIntrinsics(); + + /** Get the extrinsics from one stream to motion */ + @NonNull + public com.slightech.mynteye.Extrinsics getMotionExtrinsics(@NonNull com.slightech.mynteye.Stream from); + + /** Get the option info */ + @NonNull + public com.slightech.mynteye.OptionInfo getOptionInfo(@NonNull com.slightech.mynteye.Option option); + + /** Get the option value */ + public int getOptionValue(@NonNull com.slightech.mynteye.Option option); + + /** Set the option value */ + public void setOptionValue(@NonNull com.slightech.mynteye.Option option, int value); + + /** Run the option value */ + public boolean runOptionAction(@NonNull com.slightech.mynteye.Option option); + + /** Start capturing the source */ + public void start(@NonNull com.slightech.mynteye.Source source); + + /** Stop capturing the source */ + public void stop(@NonNull com.slightech.mynteye.Source source); + + /** Wait the streams are ready */ + public void waitForStreams(); + + /** Get the latest data of stream */ + @Nullable + public com.slightech.mynteye.StreamData getStreamData(@NonNull com.slightech.mynteye.Stream stream); + + /** Get the datas of stream */ + @NonNull + public ArrayList getStreamDatas(@NonNull com.slightech.mynteye.Stream stream); + + /** Enable cache motion datas until get them, otherwise using callback instead */ + public void enableMotionDatas(int maxSize); + + /** Get the motion datas */ + @NonNull + public ArrayList getMotionDatas(); + + /** Create the device instance */ + @Nullable + public static Device create(@NonNull com.slightech.mynteye.DeviceUsbInfo info) + { + return CppProxy.create(info); + } + + static final class CppProxy implements Device + { + private final long nativeRef; + private final AtomicBoolean destroyed = new AtomicBoolean(false); + + private CppProxy(long nativeRef) + { + if (nativeRef == 0) throw new RuntimeException("nativeRef is zero"); + this.nativeRef = nativeRef; + } + + private native void nativeDestroy(long nativeRef); + public void _djinni_private_destroy() + { + boolean destroyed = this.destroyed.getAndSet(true); + if (!destroyed) nativeDestroy(this.nativeRef); + } + protected void finalize() throws java.lang.Throwable + { + _djinni_private_destroy(); + super.finalize(); + } + + @Override + public com.slightech.mynteye.Model getModel() + { + assert !this.destroyed.get() : "trying to use a destroyed object"; + return native_getModel(this.nativeRef); + } + private native com.slightech.mynteye.Model native_getModel(long _nativeRef); + + @Override + public boolean supportsStream(com.slightech.mynteye.Stream stream) + { + assert !this.destroyed.get() : "trying to use a destroyed object"; + return native_supportsStream(this.nativeRef, stream); + } + private native boolean native_supportsStream(long _nativeRef, com.slightech.mynteye.Stream stream); + + @Override + public boolean supportsCapability(com.slightech.mynteye.Capability capabilities) + { + assert !this.destroyed.get() : "trying to use a destroyed object"; + return native_supportsCapability(this.nativeRef, capabilities); + } + private native boolean native_supportsCapability(long _nativeRef, com.slightech.mynteye.Capability capabilities); + + @Override + public boolean supportsOption(com.slightech.mynteye.Option option) + { + assert !this.destroyed.get() : "trying to use a destroyed object"; + return native_supportsOption(this.nativeRef, option); + } + private native boolean native_supportsOption(long _nativeRef, com.slightech.mynteye.Option option); + + @Override + public boolean supportsAddon(com.slightech.mynteye.Addon addon) + { + assert !this.destroyed.get() : "trying to use a destroyed object"; + return native_supportsAddon(this.nativeRef, addon); + } + private native boolean native_supportsAddon(long _nativeRef, com.slightech.mynteye.Addon addon); + + @Override + public ArrayList getStreamRequests() + { + assert !this.destroyed.get() : "trying to use a destroyed object"; + return native_getStreamRequests(this.nativeRef); + } + private native ArrayList native_getStreamRequests(long _nativeRef); + + @Override + public void configStreamRequest(com.slightech.mynteye.StreamRequest request) + { + assert !this.destroyed.get() : "trying to use a destroyed object"; + native_configStreamRequest(this.nativeRef, request); + } + private native void native_configStreamRequest(long _nativeRef, com.slightech.mynteye.StreamRequest request); + + @Override + public String getInfo(com.slightech.mynteye.Info info) + { + assert !this.destroyed.get() : "trying to use a destroyed object"; + return native_getInfo(this.nativeRef, info); + } + private native String native_getInfo(long _nativeRef, com.slightech.mynteye.Info info); + + @Override + public com.slightech.mynteye.Intrinsics getIntrinsics(com.slightech.mynteye.Stream stream) + { + assert !this.destroyed.get() : "trying to use a destroyed object"; + return native_getIntrinsics(this.nativeRef, stream); + } + private native com.slightech.mynteye.Intrinsics native_getIntrinsics(long _nativeRef, com.slightech.mynteye.Stream stream); + + @Override + public com.slightech.mynteye.Extrinsics getExtrinsics(com.slightech.mynteye.Stream from, com.slightech.mynteye.Stream to) + { + assert !this.destroyed.get() : "trying to use a destroyed object"; + return native_getExtrinsics(this.nativeRef, from, to); + } + private native com.slightech.mynteye.Extrinsics native_getExtrinsics(long _nativeRef, com.slightech.mynteye.Stream from, com.slightech.mynteye.Stream to); + + @Override + public com.slightech.mynteye.MotionIntrinsics getMotionIntrinsics() + { + assert !this.destroyed.get() : "trying to use a destroyed object"; + return native_getMotionIntrinsics(this.nativeRef); + } + private native com.slightech.mynteye.MotionIntrinsics native_getMotionIntrinsics(long _nativeRef); + + @Override + public com.slightech.mynteye.Extrinsics getMotionExtrinsics(com.slightech.mynteye.Stream from) + { + assert !this.destroyed.get() : "trying to use a destroyed object"; + return native_getMotionExtrinsics(this.nativeRef, from); + } + private native com.slightech.mynteye.Extrinsics native_getMotionExtrinsics(long _nativeRef, com.slightech.mynteye.Stream from); + + @Override + public com.slightech.mynteye.OptionInfo getOptionInfo(com.slightech.mynteye.Option option) + { + assert !this.destroyed.get() : "trying to use a destroyed object"; + return native_getOptionInfo(this.nativeRef, option); + } + private native com.slightech.mynteye.OptionInfo native_getOptionInfo(long _nativeRef, com.slightech.mynteye.Option option); + + @Override + public int getOptionValue(com.slightech.mynteye.Option option) + { + assert !this.destroyed.get() : "trying to use a destroyed object"; + return native_getOptionValue(this.nativeRef, option); + } + private native int native_getOptionValue(long _nativeRef, com.slightech.mynteye.Option option); + + @Override + public void setOptionValue(com.slightech.mynteye.Option option, int value) + { + assert !this.destroyed.get() : "trying to use a destroyed object"; + native_setOptionValue(this.nativeRef, option, value); + } + private native void native_setOptionValue(long _nativeRef, com.slightech.mynteye.Option option, int value); + + @Override + public boolean runOptionAction(com.slightech.mynteye.Option option) + { + assert !this.destroyed.get() : "trying to use a destroyed object"; + return native_runOptionAction(this.nativeRef, option); + } + private native boolean native_runOptionAction(long _nativeRef, com.slightech.mynteye.Option option); + + @Override + public void start(com.slightech.mynteye.Source source) + { + assert !this.destroyed.get() : "trying to use a destroyed object"; + native_start(this.nativeRef, source); + } + private native void native_start(long _nativeRef, com.slightech.mynteye.Source source); + + @Override + public void stop(com.slightech.mynteye.Source source) + { + assert !this.destroyed.get() : "trying to use a destroyed object"; + native_stop(this.nativeRef, source); + } + private native void native_stop(long _nativeRef, com.slightech.mynteye.Source source); + + @Override + public void waitForStreams() + { + assert !this.destroyed.get() : "trying to use a destroyed object"; + native_waitForStreams(this.nativeRef); + } + private native void native_waitForStreams(long _nativeRef); + + @Override + public com.slightech.mynteye.StreamData getStreamData(com.slightech.mynteye.Stream stream) + { + assert !this.destroyed.get() : "trying to use a destroyed object"; + return native_getStreamData(this.nativeRef, stream); + } + private native com.slightech.mynteye.StreamData native_getStreamData(long _nativeRef, com.slightech.mynteye.Stream stream); + + @Override + public ArrayList getStreamDatas(com.slightech.mynteye.Stream stream) + { + assert !this.destroyed.get() : "trying to use a destroyed object"; + return native_getStreamDatas(this.nativeRef, stream); + } + private native ArrayList native_getStreamDatas(long _nativeRef, com.slightech.mynteye.Stream stream); + + @Override + public void enableMotionDatas(int maxSize) + { + assert !this.destroyed.get() : "trying to use a destroyed object"; + native_enableMotionDatas(this.nativeRef, maxSize); + } + private native void native_enableMotionDatas(long _nativeRef, int maxSize); + + @Override + public ArrayList getMotionDatas() + { + assert !this.destroyed.get() : "trying to use a destroyed object"; + return native_getMotionDatas(this.nativeRef); + } + private native ArrayList native_getMotionDatas(long _nativeRef); + + @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 new file mode 100644 index 0000000..2ef3318 --- /dev/null +++ b/wrappers/android/mynteye/libmynteye/src/main/java/com/slightech/mynteye/DeviceUsbInfo.java @@ -0,0 +1,105 @@ +// AUTOGENERATED FILE - DO NOT MODIFY! +// This file generated by Djinni from mynteye_types.djinni + +package com.slightech.mynteye; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +/** Device USB information */ +public final class DeviceUsbInfo { + + + /*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 mSerial; + + public DeviceUsbInfo( + int vid, + int pid, + int fd, + int busNum, + int devNum, + @NonNull String usbFs, + @NonNull String name, + @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.mSerial = serial; + } + + /** Vendor id */ + public int getVid() { + return mVid; + } + + /** 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; + } + + /** Serial number */ + @NonNull + public String getSerial() { + return mSerial; + } + + @Override + public String toString() { + return "DeviceUsbInfo{" + + "mVid=" + mVid + + "," + "mPid=" + mPid + + "," + "mFd=" + mFd + + "," + "mBusNum=" + mBusNum + + "," + "mDevNum=" + mDevNum + + "," + "mUsbFs=" + mUsbFs + + "," + "mName=" + mName + + "," + "mSerial=" + mSerial + + "}"; + } + +} diff --git a/wrappers/android/mynteye/libmynteye/src/main/java/com/slightech/mynteye/Extrinsics.java b/wrappers/android/mynteye/libmynteye/src/main/java/com/slightech/mynteye/Extrinsics.java new file mode 100644 index 0000000..de57bfd --- /dev/null +++ b/wrappers/android/mynteye/libmynteye/src/main/java/com/slightech/mynteye/Extrinsics.java @@ -0,0 +1,45 @@ +// AUTOGENERATED FILE - DO NOT MODIFY! +// This file generated by Djinni from mynteye_types.djinni + +package com.slightech.mynteye; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import java.util.ArrayList; + +/** Extrinsics, represent how the different datas are connected */ +public final class Extrinsics { + + + /*package*/ final ArrayList mRotation; + + /*package*/ final ArrayList mTranslation; + + public Extrinsics( + @NonNull ArrayList rotation, + @NonNull ArrayList translation) { + this.mRotation = rotation; + this.mTranslation = translation; + } + + /** Rotation matrix, 3x3 */ + @NonNull + public ArrayList getRotation() { + return mRotation; + } + + /** Translation vector, 1x3 */ + @NonNull + public ArrayList getTranslation() { + return mTranslation; + } + + @Override + public String toString() { + return "Extrinsics{" + + "mRotation=" + mRotation + + "," + "mTranslation=" + mTranslation + + "}"; + } + +} diff --git a/wrappers/android/mynteye/libmynteye/src/main/java/com/slightech/mynteye/Format.java b/wrappers/android/mynteye/libmynteye/src/main/java/com/slightech/mynteye/Format.java new file mode 100644 index 0000000..7f7b7c9 --- /dev/null +++ b/wrappers/android/mynteye/libmynteye/src/main/java/com/slightech/mynteye/Format.java @@ -0,0 +1,20 @@ +// AUTOGENERATED FILE - DO NOT MODIFY! +// This file generated by Djinni from mynteye_types.djinni + +package com.slightech.mynteye; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +/** Formats define how each stream can be encoded */ +public enum Format { + /** Greyscale, 8 bits per pixel */ + GREY, + /** YUV 4:2:2, 16 bits per pixel */ + YUYV, + /** BGR 8:8:8, 24 bits per pixel */ + BGR888, + /** RGB 8:8:8, 24 bits per pixel */ + RGB888, + ; +} diff --git a/wrappers/android/mynteye/libmynteye/src/main/java/com/slightech/mynteye/Frame.java b/wrappers/android/mynteye/libmynteye/src/main/java/com/slightech/mynteye/Frame.java new file mode 100644 index 0000000..f7aae46 --- /dev/null +++ b/wrappers/android/mynteye/libmynteye/src/main/java/com/slightech/mynteye/Frame.java @@ -0,0 +1,92 @@ +// AUTOGENERATED FILE - DO NOT MODIFY! +// This file generated by Djinni from mynteye_types.djinni + +package com.slightech.mynteye; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import java.util.concurrent.atomic.AtomicBoolean; + +/** Frame with raw data */ +public interface Frame { + /** Get the width */ + public int width(); + + /** Get the height */ + public int height(); + + /** Get the pixel format */ + @NonNull + public Format format(); + + /** Get the size */ + public int size(); + + /** Get the data */ + @NonNull + public byte[] data(); + + static final class CppProxy implements Frame + { + private final long nativeRef; + private final AtomicBoolean destroyed = new AtomicBoolean(false); + + private CppProxy(long nativeRef) + { + if (nativeRef == 0) throw new RuntimeException("nativeRef is zero"); + this.nativeRef = nativeRef; + } + + private native void nativeDestroy(long nativeRef); + public void _djinni_private_destroy() + { + boolean destroyed = this.destroyed.getAndSet(true); + if (!destroyed) nativeDestroy(this.nativeRef); + } + protected void finalize() throws java.lang.Throwable + { + _djinni_private_destroy(); + super.finalize(); + } + + @Override + public int width() + { + assert !this.destroyed.get() : "trying to use a destroyed object"; + return native_width(this.nativeRef); + } + private native int native_width(long _nativeRef); + + @Override + public int height() + { + assert !this.destroyed.get() : "trying to use a destroyed object"; + return native_height(this.nativeRef); + } + private native int native_height(long _nativeRef); + + @Override + public Format format() + { + assert !this.destroyed.get() : "trying to use a destroyed object"; + return native_format(this.nativeRef); + } + private native Format native_format(long _nativeRef); + + @Override + public int size() + { + assert !this.destroyed.get() : "trying to use a destroyed object"; + return native_size(this.nativeRef); + } + private native int native_size(long _nativeRef); + + @Override + public byte[] data() + { + assert !this.destroyed.get() : "trying to use a destroyed object"; + return native_data(this.nativeRef); + } + private native byte[] native_data(long _nativeRef); + } +} diff --git a/wrappers/android/mynteye/libmynteye/src/main/java/com/slightech/mynteye/ImgData.java b/wrappers/android/mynteye/libmynteye/src/main/java/com/slightech/mynteye/ImgData.java new file mode 100644 index 0000000..cddfd00 --- /dev/null +++ b/wrappers/android/mynteye/libmynteye/src/main/java/com/slightech/mynteye/ImgData.java @@ -0,0 +1,52 @@ +// AUTOGENERATED FILE - DO NOT MODIFY! +// This file generated by Djinni from mynteye_types.djinni + +package com.slightech.mynteye; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +/** Image data */ +public final class ImgData { + + + /*package*/ final long mFrameId; + + /*package*/ final long mTimestamp; + + /*package*/ final long mExposureTime; + + public ImgData( + long frameId, + long timestamp, + long exposureTime) { + this.mFrameId = frameId; + this.mTimestamp = timestamp; + this.mExposureTime = exposureTime; + } + + /** Image frame id */ + public long getFrameId() { + return mFrameId; + } + + /** Image timestamp in 1us */ + public long getTimestamp() { + return mTimestamp; + } + + /** Image exposure time, virtual value in [1, 480] */ + public long getExposureTime() { + return mExposureTime; + } + + @Override + public String toString() { + return "ImgData{" + + "mFrameId=" + mFrameId + + "," + "mTimestamp=" + mTimestamp + + "," + "mExposureTime=" + mExposureTime + + "}"; + } + +} diff --git a/wrappers/android/mynteye/libmynteye/src/main/java/com/slightech/mynteye/ImuData.java b/wrappers/android/mynteye/libmynteye/src/main/java/com/slightech/mynteye/ImuData.java new file mode 100644 index 0000000..b850829 --- /dev/null +++ b/wrappers/android/mynteye/libmynteye/src/main/java/com/slightech/mynteye/ImuData.java @@ -0,0 +1,90 @@ +// AUTOGENERATED FILE - DO NOT MODIFY! +// This file generated by Djinni from mynteye_types.djinni + +package com.slightech.mynteye; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import java.util.ArrayList; + +/** IMU data */ +public final class ImuData { + + + /*package*/ final long mFrameId; + + /*package*/ final int mFlag; + + /*package*/ final long mTimestamp; + + /*package*/ final ArrayList mAccel; + + /*package*/ final ArrayList mGyro; + + /*package*/ final double mTemperature; + + public ImuData( + long frameId, + int flag, + long timestamp, + @NonNull ArrayList accel, + @NonNull ArrayList gyro, + double temperature) { + this.mFrameId = frameId; + this.mFlag = flag; + this.mTimestamp = timestamp; + this.mAccel = accel; + this.mGyro = gyro; + this.mTemperature = temperature; + } + + /** IMU frame id */ + public long getFrameId() { + return mFrameId; + } + + /** + * IMU accel or gyro flag + * 0: accel and gyro are both valid + * 1: accel is valid + * 2: gyro is valid + */ + public int getFlag() { + return mFlag; + } + + /** IMU timestamp in 1us */ + public long getTimestamp() { + return mTimestamp; + } + + /** IMU accelerometer data for 3-axis: X, Y, Z. */ + @NonNull + public ArrayList getAccel() { + return mAccel; + } + + /** IMU gyroscope data for 3-axis: X, Y, Z. */ + @NonNull + public ArrayList getGyro() { + return mGyro; + } + + /** IMU temperature */ + public double getTemperature() { + return mTemperature; + } + + @Override + public String toString() { + return "ImuData{" + + "mFrameId=" + mFrameId + + "," + "mFlag=" + mFlag + + "," + "mTimestamp=" + mTimestamp + + "," + "mAccel=" + mAccel + + "," + "mGyro=" + mGyro + + "," + "mTemperature=" + mTemperature + + "}"; + } + +} diff --git a/wrappers/android/mynteye/libmynteye/src/main/java/com/slightech/mynteye/ImuIntrinsics.java b/wrappers/android/mynteye/libmynteye/src/main/java/com/slightech/mynteye/ImuIntrinsics.java new file mode 100644 index 0000000..e26c167 --- /dev/null +++ b/wrappers/android/mynteye/libmynteye/src/main/java/com/slightech/mynteye/ImuIntrinsics.java @@ -0,0 +1,72 @@ +// AUTOGENERATED FILE - DO NOT MODIFY! +// This file generated by Djinni from mynteye_types.djinni + +package com.slightech.mynteye; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import java.util.ArrayList; + +/** IMU intrinsics: scale, drift and variances */ +public final class ImuIntrinsics { + + + /*package*/ final ArrayList mScale; + + /*package*/ final ArrayList mDrift; + + /*package*/ final ArrayList mNoise; + + /*package*/ final ArrayList mBias; + + public ImuIntrinsics( + @NonNull ArrayList scale, + @NonNull ArrayList drift, + @NonNull ArrayList noise, + @NonNull ArrayList bias) { + this.mScale = scale; + this.mDrift = drift; + this.mNoise = noise; + this.mBias = bias; + } + + /** + * Scale matrix 3x3 + * Scale X cross axis cross axis + * cross axis Scale Y cross axis + * cross axis cross axis Scale Z + */ + @NonNull + public ArrayList getScale() { + return mScale; + } + + /** Zero-drift: X, Y, Z 1x3 */ + @NonNull + public ArrayList getDrift() { + return mDrift; + } + + /** Noise density variances 1x3 */ + @NonNull + public ArrayList getNoise() { + return mNoise; + } + + /** Random walk variances 1x3 */ + @NonNull + public ArrayList getBias() { + return mBias; + } + + @Override + public String toString() { + return "ImuIntrinsics{" + + "mScale=" + mScale + + "," + "mDrift=" + mDrift + + "," + "mNoise=" + mNoise + + "," + "mBias=" + mBias + + "}"; + } + +} diff --git a/wrappers/android/mynteye/libmynteye/src/main/java/com/slightech/mynteye/Info.java b/wrappers/android/mynteye/libmynteye/src/main/java/com/slightech/mynteye/Info.java new file mode 100644 index 0000000..a406565 --- /dev/null +++ b/wrappers/android/mynteye/libmynteye/src/main/java/com/slightech/mynteye/Info.java @@ -0,0 +1,28 @@ +// AUTOGENERATED FILE - DO NOT MODIFY! +// This file generated by Djinni from mynteye_types.djinni + +package com.slightech.mynteye; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +/** Camera info fields are read-only strings that can be queried from the device */ +public enum Info { + /** Device name */ + DEVICE_NAME, + /** Serial number */ + SERIAL_NUMBER, + /** Firmware version */ + FIRMWARE_VERSION, + /** Hardware version */ + HARDWARE_VERSION, + /** Spec version */ + SPEC_VERSION, + /** Lens type */ + LENS_TYPE, + /** IMU type */ + IMU_TYPE, + /** Nominal baseline */ + NOMINAL_BASELINE, + ; +} diff --git a/wrappers/android/mynteye/libmynteye/src/main/java/com/slightech/mynteye/Intrinsics.java b/wrappers/android/mynteye/libmynteye/src/main/java/com/slightech/mynteye/Intrinsics.java new file mode 100644 index 0000000..504db06 --- /dev/null +++ b/wrappers/android/mynteye/libmynteye/src/main/java/com/slightech/mynteye/Intrinsics.java @@ -0,0 +1,109 @@ +// AUTOGENERATED FILE - DO NOT MODIFY! +// This file generated by Djinni from mynteye_types.djinni + +package com.slightech.mynteye; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import java.util.ArrayList; + +/** Stream intrinsics */ +public final class Intrinsics { + + + /*package*/ final CalibrationModel mCalibModel; + + /*package*/ final int mWidth; + + /*package*/ final int mHeight; + + /*package*/ final double mFx; + + /*package*/ final double mFy; + + /*package*/ final double mCx; + + /*package*/ final double mCy; + + /*package*/ final ArrayList mCoeffs; + + public Intrinsics( + @NonNull CalibrationModel calibModel, + int width, + int height, + double fx, + double fy, + double cx, + double cy, + @NonNull ArrayList coeffs) { + this.mCalibModel = calibModel; + this.mWidth = width; + this.mHeight = height; + this.mFx = fx; + this.mFy = fy; + this.mCx = cx; + this.mCy = cy; + this.mCoeffs = coeffs; + } + + /** The calibration model */ + @NonNull + public CalibrationModel getCalibModel() { + return mCalibModel; + } + + /** The width of the image in pixels */ + public int getWidth() { + return mWidth; + } + + /** The height of the image in pixels */ + public int getHeight() { + return mHeight; + } + + /** The focal length of the image plane, as a multiple of pixel width (pinhole) */ + public double getFx() { + return mFx; + } + + /** The focal length of the image plane, as a multiple of pixel height (pinhole) */ + public double getFy() { + return mFy; + } + + /** The horizontal coordinate of the principal point of the image (pinhole) */ + public double getCx() { + return mCx; + } + + /** The vertical coordinate of the principal point of the image (pinhole) */ + public double getCy() { + return mCy; + } + + /** + * The distortion coefficients + * pinhole: k1,k2,p1,p2,k3 + * kannala_brandt: k2,k3,k4,k5,mu,mv,u0,v0 + */ + @NonNull + public ArrayList getCoeffs() { + return mCoeffs; + } + + @Override + public String toString() { + return "Intrinsics{" + + "mCalibModel=" + mCalibModel + + "," + "mWidth=" + mWidth + + "," + "mHeight=" + mHeight + + "," + "mFx=" + mFx + + "," + "mFy=" + mFy + + "," + "mCx=" + mCx + + "," + "mCy=" + mCy + + "," + "mCoeffs=" + mCoeffs + + "}"; + } + +} diff --git a/wrappers/android/mynteye/libmynteye/src/main/java/com/slightech/mynteye/Model.java b/wrappers/android/mynteye/libmynteye/src/main/java/com/slightech/mynteye/Model.java new file mode 100644 index 0000000..2124342 --- /dev/null +++ b/wrappers/android/mynteye/libmynteye/src/main/java/com/slightech/mynteye/Model.java @@ -0,0 +1,18 @@ +// AUTOGENERATED FILE - DO NOT MODIFY! +// This file generated by Djinni from mynteye_types.djinni + +package com.slightech.mynteye; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +/** Device model */ +public enum Model { + /** Standard */ + STANDARD, + /** Standard 2 */ + STANDARD2, + /** Standard 210a */ + STANDARD210A, + ; +} diff --git a/wrappers/android/mynteye/libmynteye/src/main/java/com/slightech/mynteye/MotionData.java b/wrappers/android/mynteye/libmynteye/src/main/java/com/slightech/mynteye/MotionData.java new file mode 100644 index 0000000..37c247c --- /dev/null +++ b/wrappers/android/mynteye/libmynteye/src/main/java/com/slightech/mynteye/MotionData.java @@ -0,0 +1,46 @@ +// AUTOGENERATED FILE - DO NOT MODIFY! +// This file generated by Djinni from mynteye_types.djinni + +package com.slightech.mynteye; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import java.util.concurrent.atomic.AtomicBoolean; + +/** Device motion data */ +public interface MotionData { + @NonNull + public ImuData imu(); + + static final class CppProxy implements MotionData + { + private final long nativeRef; + private final AtomicBoolean destroyed = new AtomicBoolean(false); + + private CppProxy(long nativeRef) + { + if (nativeRef == 0) throw new RuntimeException("nativeRef is zero"); + this.nativeRef = nativeRef; + } + + private native void nativeDestroy(long nativeRef); + public void _djinni_private_destroy() + { + boolean destroyed = this.destroyed.getAndSet(true); + if (!destroyed) nativeDestroy(this.nativeRef); + } + protected void finalize() throws java.lang.Throwable + { + _djinni_private_destroy(); + super.finalize(); + } + + @Override + public ImuData imu() + { + assert !this.destroyed.get() : "trying to use a destroyed object"; + return native_imu(this.nativeRef); + } + private native ImuData native_imu(long _nativeRef); + } +} diff --git a/wrappers/android/mynteye/libmynteye/src/main/java/com/slightech/mynteye/MotionIntrinsics.java b/wrappers/android/mynteye/libmynteye/src/main/java/com/slightech/mynteye/MotionIntrinsics.java new file mode 100644 index 0000000..1ed8d08 --- /dev/null +++ b/wrappers/android/mynteye/libmynteye/src/main/java/com/slightech/mynteye/MotionIntrinsics.java @@ -0,0 +1,44 @@ +// AUTOGENERATED FILE - DO NOT MODIFY! +// This file generated by Djinni from mynteye_types.djinni + +package com.slightech.mynteye; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +/** Motion intrinsics, including accelerometer and gyroscope */ +public final class MotionIntrinsics { + + + /*package*/ final ImuIntrinsics mAccel; + + /*package*/ final ImuIntrinsics mGyro; + + public MotionIntrinsics( + @NonNull ImuIntrinsics accel, + @NonNull ImuIntrinsics gyro) { + this.mAccel = accel; + this.mGyro = gyro; + } + + /** Accelerometer intrinsics */ + @NonNull + public ImuIntrinsics getAccel() { + return mAccel; + } + + /** Gyroscope intrinsics */ + @NonNull + public ImuIntrinsics getGyro() { + return mGyro; + } + + @Override + public String toString() { + return "MotionIntrinsics{" + + "mAccel=" + mAccel + + "," + "mGyro=" + mGyro + + "}"; + } + +} diff --git a/wrappers/android/mynteye/libmynteye/src/main/java/com/slightech/mynteye/Option.java b/wrappers/android/mynteye/libmynteye/src/main/java/com/slightech/mynteye/Option.java new file mode 100644 index 0000000..121f421 --- /dev/null +++ b/wrappers/android/mynteye/libmynteye/src/main/java/com/slightech/mynteye/Option.java @@ -0,0 +1,103 @@ +// AUTOGENERATED FILE - DO NOT MODIFY! +// This file generated by Djinni from mynteye_types.djinni + +package com.slightech.mynteye; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +/** Camera control options define general configuration controls */ +public enum Option { + /** + * Image gain, valid if manual-exposure + * range: [0,48], default: 24 + */ + GAIN, + /** + * Image brightness, valid if manual-exposure + * range: [0,240], default: 120 + */ + BRIGHTNESS, + /** + * Image contrast, valid if manual-exposure + * range: [0,255], default: 127 + */ + CONTRAST, + /** + * Image frame rate, must set IMU_FREQUENCY together + * values: {10,15,20,25,30,35,40,45,50,55,60}, default: 25 + */ + FRAME_RATE, + /** + * IMU frequency, must set FRAME_RATE together + * values: {100,200,250,333,500}, default: 200 + */ + IMU_FREQUENCY, + /** + * Exposure mode + * 0: enable auto-exposure + * 1: disable auto-exposure (manual-exposure) + */ + EXPOSURE_MODE, + /** + * Max gain, valid if auto-exposure + * range of standard 1: [0,48], default: 48 + * range of standard 2: [0,255], default: 8 + */ + MAX_GAIN, + /** + * Max exposure time, valid if auto-exposure + * range of standard 1: [0,240], default: 240 + * range of standard 2: [0,1000], default: 333 + */ + MAX_EXPOSURE_TIME, + /** + * min exposure time, valid if auto-exposure + * range: [0,1000], default: 0 + */ + MIN_EXPOSURE_TIME, + /** + * Desired brightness, valid if auto-exposure + * range of standard 1: [0,255], default: 192 + * range of standard 2: [1,255], default: 122 + */ + DESIRED_BRIGHTNESS, + /** + * IR control + * range: [0,160], default: 0 + */ + IR_CONTROL, + /** + * HDR mode + * 0: 10-bit + * 1: 12-bit + */ + HDR_MODE, + /** + * The range of accelerometer + * value of standard 1: {4,8,16,32}, default: 8 + * value of standard 2: {6,12,24,48}, default: 12 + */ + ACCELEROMETER_RANGE, + /** + * The range of gyroscope + * value of standard 1: {500,1000,2000,4000}, default: 1000 + * value of standard 2: {250,500,1000,2000,4000}, default: 1000 + */ + GYROSCOPE_RANGE, + /** + * The parameter of accelerometer low pass filter + * values: {0,1,2}, default: 2 + */ + ACCELEROMETER_LOW_PASS_FILTER, + /** + * The parameter of gyroscope low pass filter + * values: {23,64}, default: 64 + */ + GYROSCOPE_LOW_PASS_FILTER, + /** Zero drift calibration */ + ZERO_DRIFT_CALIBRATION, + /** Erase chip */ + ERASE_CHIP, + ; +} diff --git a/wrappers/android/mynteye/libmynteye/src/main/java/com/slightech/mynteye/OptionInfo.java b/wrappers/android/mynteye/libmynteye/src/main/java/com/slightech/mynteye/OptionInfo.java new file mode 100644 index 0000000..e35946c --- /dev/null +++ b/wrappers/android/mynteye/libmynteye/src/main/java/com/slightech/mynteye/OptionInfo.java @@ -0,0 +1,52 @@ +// AUTOGENERATED FILE - DO NOT MODIFY! +// This file generated by Djinni from mynteye_types.djinni + +package com.slightech.mynteye; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +/** Option info */ +public final class OptionInfo { + + + /*package*/ final int mMin; + + /*package*/ final int mMax; + + /*package*/ final int mDef; + + public OptionInfo( + int min, + int max, + int def) { + this.mMin = min; + this.mMax = max; + this.mDef = def; + } + + /** Minimum value */ + public int getMin() { + return mMin; + } + + /** Maximum value */ + public int getMax() { + return mMax; + } + + /** Default value */ + public int getDef() { + return mDef; + } + + @Override + public String toString() { + return "OptionInfo{" + + "mMin=" + mMin + + "," + "mMax=" + mMax + + "," + "mDef=" + mDef + + "}"; + } + +} diff --git a/wrappers/android/mynteye/libmynteye/src/main/java/com/slightech/mynteye/Source.java b/wrappers/android/mynteye/libmynteye/src/main/java/com/slightech/mynteye/Source.java new file mode 100644 index 0000000..da4bb00 --- /dev/null +++ b/wrappers/android/mynteye/libmynteye/src/main/java/com/slightech/mynteye/Source.java @@ -0,0 +1,18 @@ +// AUTOGENERATED FILE - DO NOT MODIFY! +// This file generated by Djinni from mynteye_types.djinni + +package com.slightech.mynteye; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +/** Source allows the user to choose which data to be captured */ +public enum Source { + /** Video streaming of stereo, color, depth, etc. */ + VIDEO_STREAMING, + /** Motion tracking of IMU (accelerometer, gyroscope) */ + MOTION_TRACKING, + /** Enable everything together */ + ALL, + ; +} diff --git a/wrappers/android/mynteye/libmynteye/src/main/java/com/slightech/mynteye/Stream.java b/wrappers/android/mynteye/libmynteye/src/main/java/com/slightech/mynteye/Stream.java new file mode 100644 index 0000000..89f6083 --- /dev/null +++ b/wrappers/android/mynteye/libmynteye/src/main/java/com/slightech/mynteye/Stream.java @@ -0,0 +1,16 @@ +// AUTOGENERATED FILE - DO NOT MODIFY! +// This file generated by Djinni from mynteye_types.djinni + +package com.slightech.mynteye; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +/** Streams define different type of data */ +public enum Stream { + /** Left stream */ + LEFT, + /** Right stream */ + RIGHT, + ; +} diff --git a/wrappers/android/mynteye/libmynteye/src/main/java/com/slightech/mynteye/StreamData.java b/wrappers/android/mynteye/libmynteye/src/main/java/com/slightech/mynteye/StreamData.java new file mode 100644 index 0000000..ebc6203 --- /dev/null +++ b/wrappers/android/mynteye/libmynteye/src/main/java/com/slightech/mynteye/StreamData.java @@ -0,0 +1,67 @@ +// AUTOGENERATED FILE - DO NOT MODIFY! +// This file generated by Djinni from mynteye_types.djinni + +package com.slightech.mynteye; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import java.util.concurrent.atomic.AtomicBoolean; + +/** Device stream data */ +public interface StreamData { + @NonNull + public ImgData img(); + + @Nullable + public Frame frame(); + + public long frameId(); + + static final class CppProxy implements StreamData + { + private final long nativeRef; + private final AtomicBoolean destroyed = new AtomicBoolean(false); + + private CppProxy(long nativeRef) + { + if (nativeRef == 0) throw new RuntimeException("nativeRef is zero"); + this.nativeRef = nativeRef; + } + + private native void nativeDestroy(long nativeRef); + public void _djinni_private_destroy() + { + boolean destroyed = this.destroyed.getAndSet(true); + if (!destroyed) nativeDestroy(this.nativeRef); + } + protected void finalize() throws java.lang.Throwable + { + _djinni_private_destroy(); + super.finalize(); + } + + @Override + public ImgData img() + { + assert !this.destroyed.get() : "trying to use a destroyed object"; + return native_img(this.nativeRef); + } + private native ImgData native_img(long _nativeRef); + + @Override + public Frame frame() + { + assert !this.destroyed.get() : "trying to use a destroyed object"; + return native_frame(this.nativeRef); + } + private native Frame native_frame(long _nativeRef); + + @Override + public long frameId() + { + assert !this.destroyed.get() : "trying to use a destroyed object"; + return native_frameId(this.nativeRef); + } + private native long native_frameId(long _nativeRef); + } +} diff --git a/wrappers/android/mynteye/libmynteye/src/main/java/com/slightech/mynteye/StreamRequest.java b/wrappers/android/mynteye/libmynteye/src/main/java/com/slightech/mynteye/StreamRequest.java new file mode 100644 index 0000000..be2c89d --- /dev/null +++ b/wrappers/android/mynteye/libmynteye/src/main/java/com/slightech/mynteye/StreamRequest.java @@ -0,0 +1,73 @@ +// AUTOGENERATED FILE - DO NOT MODIFY! +// This file generated by Djinni from mynteye_types.djinni + +package com.slightech.mynteye; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +/** Stream request */ +public final class StreamRequest { + + + /*package*/ final int mIndex; + + /*package*/ final int mWidth; + + /*package*/ final int mHeight; + + /*package*/ final Format mFormat; + + /*package*/ final int mFps; + + public StreamRequest( + int index, + int width, + int height, + @NonNull Format format, + int fps) { + this.mIndex = index; + this.mWidth = width; + this.mHeight = height; + this.mFormat = format; + this.mFps = fps; + } + + /** Stream index */ + public int getIndex() { + return mIndex; + } + + /** Stream width in pixels */ + public int getWidth() { + return mWidth; + } + + /** Stream height in pixels */ + public int getHeight() { + return mHeight; + } + + /** Stream pixel format */ + @NonNull + public Format getFormat() { + return mFormat; + } + + /** Stream frames per second */ + public int getFps() { + return mFps; + } + + @Override + public String toString() { + return "StreamRequest{" + + "mIndex=" + mIndex + + "," + "mWidth=" + mWidth + + "," + "mHeight=" + mHeight + + "," + "mFormat=" + mFormat + + "," + "mFps=" + mFps + + "}"; + } + +} 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..225b7e3 --- /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.util.BuildCheck; +import com.slightech.mynteye.util.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/util/BitmapUtils.java b/wrappers/android/mynteye/libmynteye/src/main/java/com/slightech/mynteye/util/BitmapUtils.java new file mode 100644 index 0000000..377407c --- /dev/null +++ b/wrappers/android/mynteye/libmynteye/src/main/java/com/slightech/mynteye/util/BitmapUtils.java @@ -0,0 +1,10 @@ +package com.slightech.mynteye.util; + +import android.graphics.Bitmap; +import com.slightech.mynteye.Frame; + +public class BitmapUtils { + + public static native void copyPixels(Frame from, Bitmap to); + +} diff --git a/wrappers/android/mynteye/libmynteye/src/main/java/com/slightech/mynteye/util/BuildCheck.java b/wrappers/android/mynteye/libmynteye/src/main/java/com/slightech/mynteye/util/BuildCheck.java new file mode 100644 index 0000000..312553b --- /dev/null +++ b/wrappers/android/mynteye/libmynteye/src/main/java/com/slightech/mynteye/util/BuildCheck.java @@ -0,0 +1,476 @@ +package com.slightech.mynteye.util; +/* + * 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/util/HandlerThreadHandler.java b/wrappers/android/mynteye/libmynteye/src/main/java/com/slightech/mynteye/util/HandlerThreadHandler.java new file mode 100644 index 0000000..1774cf8 --- /dev/null +++ b/wrappers/android/mynteye/libmynteye/src/main/java/com/slightech/mynteye/util/HandlerThreadHandler.java @@ -0,0 +1,58 @@ +package com.slightech.mynteye.util; +/* + * 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..e8db888 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..991addf 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/libmynteye/src/test/java/com/slightech/mynteye/ExampleUnitTest.java b/wrappers/android/mynteye/libmynteye/src/test/java/com/slightech/mynteye/ExampleUnitTest.java new file mode 100644 index 0000000..6d3ba42 --- /dev/null +++ b/wrappers/android/mynteye/libmynteye/src/test/java/com/slightech/mynteye/ExampleUnitTest.java @@ -0,0 +1,17 @@ +package com.slightech.mynteye; + +import org.junit.Test; + +import static org.junit.Assert.*; + +/** + * Example local unit test, which will execute on the development machine (host). + * + * @see Testing documentation + */ +public class ExampleUnitTest { + @Test + public void addition_isCorrect() { + assertEquals(4, 2 + 2); + } +} \ No newline at end of file diff --git a/wrappers/android/mynteye/libshell/.gitignore b/wrappers/android/mynteye/libshell/.gitignore new file mode 100644 index 0000000..796b96d --- /dev/null +++ b/wrappers/android/mynteye/libshell/.gitignore @@ -0,0 +1 @@ +/build diff --git a/wrappers/android/mynteye/libshell/README.md b/wrappers/android/mynteye/libshell/README.md new file mode 100644 index 0000000..d9948a7 --- /dev/null +++ b/wrappers/android/mynteye/libshell/README.md @@ -0,0 +1,2 @@ + +* [RootShell](https://github.com/Stericson/RootShell) diff --git a/wrappers/android/mynteye/libshell/build.gradle b/wrappers/android/mynteye/libshell/build.gradle new file mode 100644 index 0000000..f996e9a --- /dev/null +++ b/wrappers/android/mynteye/libshell/build.gradle @@ -0,0 +1,29 @@ +apply plugin: 'com.android.library' + +android { + compileSdkVersion xversions.compileSdk + + defaultConfig { + minSdkVersion xversions.minSdk + targetSdkVersion xversions.targetSdk + versionCode 1 + versionName "1.0" + + testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + } + } +} + +dependencies { + implementation fileTree(dir: 'libs', include: ['*.jar']) + + testImplementation 'junit:junit:4.12' + androidTestImplementation 'androidx.test:runner:1.1.1' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1' +} diff --git a/wrappers/android/mynteye/libshell/proguard-rules.pro b/wrappers/android/mynteye/libshell/proguard-rules.pro new file mode 100644 index 0000000..f1b4245 --- /dev/null +++ b/wrappers/android/mynteye/libshell/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile diff --git a/wrappers/android/mynteye/libshell/src/main/AndroidManifest.xml b/wrappers/android/mynteye/libshell/src/main/AndroidManifest.xml new file mode 100644 index 0000000..11442a8 --- /dev/null +++ b/wrappers/android/mynteye/libshell/src/main/AndroidManifest.xml @@ -0,0 +1,2 @@ + diff --git a/wrappers/android/mynteye/libshell/src/main/java/com/stericson/RootShell/RootShell.java b/wrappers/android/mynteye/libshell/src/main/java/com/stericson/RootShell/RootShell.java new file mode 100644 index 0000000..d959e88 --- /dev/null +++ b/wrappers/android/mynteye/libshell/src/main/java/com/stericson/RootShell/RootShell.java @@ -0,0 +1,610 @@ +/* + * This file is part of the RootShell Project: http://code.google.com/p/RootShell/ + * + * Copyright (c) 2014 Stephen Erickson, Chris Ravenscroft + * + * This code is dual-licensed under the terms of the Apache License Version 2.0 and + * the terms of the General Public License (GPL) Version 2. + * You may use this code according to either of these licenses as is most appropriate + * for your project on a case-by-case basis. + * + * The terms of each license can be found in the root directory of this project's repository as well as at: + * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * http://www.gnu.org/licenses/gpl-2.0.txt + * + * Unless required by applicable law or agreed to in writing, software + * distributed under these Licenses is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See each License for the specific language governing permissions and + * limitations under that License. + */ +package com.stericson.RootShell; + + +import com.stericson.RootShell.exceptions.RootDeniedException; +import com.stericson.RootShell.execution.Command; +import com.stericson.RootShell.execution.Shell; + +import android.util.Log; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.concurrent.TimeoutException; + +public class RootShell { + + // -------------------- + // # Public Variables # + // -------------------- + + public static boolean debugMode = false; + + public static final String version = "RootShell v1.6"; + + /** + * Setting this to false will disable the handler that is used + * by default for the 3 callback methods for Command. + *

+ * By disabling this all callbacks will be called from a thread other than + * the main UI thread. + */ + public static boolean handlerEnabled = true; + + + /** + * Setting this will change the default command timeout. + *

+ * The default is 20000ms + */ + public static int defaultCommandTimeout = 20000; + + public static enum LogLevel { + VERBOSE, + ERROR, + DEBUG, + WARN + } + // -------------------- + // # Public Methods # + // -------------------- + + /** + * This will close all open shells. + */ + public static void closeAllShells() throws IOException { + Shell.closeAll(); + } + + /** + * This will close the custom shell that you opened. + */ + public static void closeCustomShell() throws IOException { + Shell.closeCustomShell(); + } + + /** + * This will close either the root shell or the standard shell depending on what you specify. + * + * @param root a boolean to specify whether to close the root shell or the standard shell. + */ + public static void closeShell(boolean root) throws IOException { + if (root) { + Shell.closeRootShell(); + } else { + Shell.closeShell(); + } + } + + /** + * Use this to check whether or not a file exists on the filesystem. + * + * @param file String that represent the file, including the full path to the + * file and its name. + * @return a boolean that will indicate whether or not the file exists. + */ + public static boolean exists(final String file) { + return exists(file, false); + } + + /** + * Use this to check whether or not a file OR directory exists on the filesystem. + * + * @param file String that represent the file OR the directory, including the full path to the + * file and its name. + * @param isDir boolean that represent whether or not we are looking for a directory + * @return a boolean that will indicate whether or not the file exists. + */ + public static boolean exists(final String file, boolean isDir) { + final List result = new ArrayList(); + + String cmdToExecute = "ls " + (isDir ? "-d " : " "); + + Command command = new Command(0, false, cmdToExecute + file) { + @Override + public void commandOutput(int id, String line) { + RootShell.log(line); + result.add(line); + + super.commandOutput(id, line); + } + }; + + try { + //Try without root... + RootShell.getShell(false).add(command); + commandWait(RootShell.getShell(false), command); + + } catch (Exception e) { + RootShell.log("Exception: " + e); + return false; + } + + for (String line : result) { + if (line.trim().equals(file)) { + return true; + } + } + + result.clear(); + + command = new Command(0, false, cmdToExecute + file) { + @Override + public void commandOutput(int id, String line) { + RootShell.log(line); + result.add(line); + + super.commandOutput(id, line); + } + }; + + try { + RootShell.getShell(true).add(command); + commandWait(RootShell.getShell(true), command); + + } catch (Exception e) { + RootShell.log("Exception: " + e); + return false; + } + + //Avoid concurrent modification... + List final_result = new ArrayList(); + final_result.addAll(result); + + for (String line : final_result) { + if (line.trim().equals(file)) { + return true; + } + } + + return false; + + } + + /** + * @param binaryName String that represent the binary to find. + * @param singlePath boolean that represents whether to return a single path or multiple. + * + * @return List containing the locations the binary was found at. + */ + public static List findBinary(String binaryName, boolean singlePath) { + return findBinary(binaryName, null, singlePath); + } + + /** + * @param binaryName String that represent the binary to find. + * @param searchPaths List which contains the paths to search for this binary in. + * @param singlePath boolean that represents whether to return a single path or multiple. + * + * @return List containing the locations the binary was found at. + */ + public static List findBinary(final String binaryName, List searchPaths, boolean singlePath) { + + final List foundPaths = new ArrayList(); + + boolean found = false; + + if(searchPaths == null) + { + searchPaths = RootShell.getPath(); + } + + RootShell.log("Checking for " + binaryName); + + //Try to use stat first + try { + for (String path : searchPaths) { + + if(!path.endsWith("/")) + { + path += "/"; + } + + final String currentPath = path; + + Command cc = new Command(0, false, "stat " + path + binaryName) { + @Override + public void commandOutput(int id, String line) { + if (line.contains("File: ") && line.contains(binaryName)) { + foundPaths.add(currentPath); + + RootShell.log(binaryName + " was found here: " + currentPath); + } + + RootShell.log(line); + + super.commandOutput(id, line); + } + }; + + cc = RootShell.getShell(false).add(cc); + commandWait(RootShell.getShell(false), cc); + + if(foundPaths.size() > 0 && singlePath) { + break; + } + } + + found = !foundPaths.isEmpty(); + + } catch (Exception e) { + RootShell.log(binaryName + " was not found, more information MAY be available with Debugging on."); + } + + if (!found) { + RootShell.log("Trying second method"); + + for (String path : searchPaths) { + + if(!path.endsWith("/")) + { + path += "/"; + } + + if (RootShell.exists(path + binaryName)) { + RootShell.log(binaryName + " was found here: " + path); + foundPaths.add(path); + + if(foundPaths.size() > 0 && singlePath) { + break; + } + + } else { + RootShell.log(binaryName + " was NOT found here: " + path); + } + } + } + + Collections.reverse(foundPaths); + + return foundPaths; + } + + /** + * This will open or return, if one is already open, a custom shell, you are responsible for managing the shell, reading the output + * and for closing the shell when you are done using it. + * + * @param shellPath a String to Indicate the path to the shell that you want to open. + * @param timeout an int to Indicate the length of time before giving up on opening a shell. + * @throws TimeoutException + * @throws com.stericson.RootShell.exceptions.RootDeniedException + * @throws IOException + */ + public static Shell getCustomShell(String shellPath, int timeout) throws IOException, TimeoutException, RootDeniedException + { + return Shell.startCustomShell(shellPath, timeout); + } + + /** + * This will return the environment variable PATH + * + * @return List A List of Strings representing the environment variable $PATH + */ + public static List getPath() { + return Arrays.asList(System.getenv("PATH").split(":")); + } + + /** + * This will open or return, if one is already open, a shell, you are responsible for managing the shell, reading the output + * and for closing the shell when you are done using it. + * + * @param root a boolean to Indicate whether or not you want to open a root shell or a standard shell + * @param timeout an int to Indicate the length of time to wait before giving up on opening a shell. + * @param shellContext the context to execute the shell with + * @param retry a int to indicate how many times the ROOT shell should try to open with root priviliges... + */ + public static Shell getShell(boolean root, int timeout, Shell.ShellContext shellContext, int retry) throws IOException, TimeoutException, RootDeniedException { + if (root) { + return Shell.startRootShell(timeout, shellContext, retry); + } else { + return Shell.startShell(timeout); + } + } + + /** + * This will open or return, if one is already open, a shell, you are responsible for managing the shell, reading the output + * and for closing the shell when you are done using it. + * + * @param root a boolean to Indicate whether or not you want to open a root shell or a standard shell + * @param timeout an int to Indicate the length of time to wait before giving up on opening a shell. + * @param shellContext the context to execute the shell with + */ + public static Shell getShell(boolean root, int timeout, Shell.ShellContext shellContext) throws IOException, TimeoutException, RootDeniedException { + return getShell(root, timeout, shellContext, 3); + } + + /** + * This will open or return, if one is already open, a shell, you are responsible for managing the shell, reading the output + * and for closing the shell when you are done using it. + * + * @param root a boolean to Indicate whether or not you want to open a root shell or a standard shell + * @param shellContext the context to execute the shell with + */ + public static Shell getShell(boolean root, Shell.ShellContext shellContext) throws IOException, TimeoutException, RootDeniedException { + return getShell(root, 0, shellContext, 3); + } + + /** + * This will open or return, if one is already open, a shell, you are responsible for managing the shell, reading the output + * and for closing the shell when you are done using it. + * + * @param root a boolean to Indicate whether or not you want to open a root shell or a standard shell + * @param timeout an int to Indicate the length of time to wait before giving up on opening a shell. + */ + public static Shell getShell(boolean root, int timeout) throws IOException, TimeoutException, RootDeniedException { + return getShell(root, timeout, Shell.defaultContext, 3); + } + + /** + * This will open or return, if one is already open, a shell, you are responsible for managing the shell, reading the output + * and for closing the shell when you are done using it. + * + * @param root a boolean to Indicate whether or not you want to open a root shell or a standard shell + */ + public static Shell getShell(boolean root) throws IOException, TimeoutException, RootDeniedException { + return RootShell.getShell(root, 0); + } + + /** + * @return true if your app has been given root access. + * @throws TimeoutException if this operation times out. (cannot determine if access is given) + */ + public static boolean isAccessGiven() { + return isAccessGiven(0, 3); + } + + /** + * Control how many time of retries should request + * + * @param timeout The timeout + * @param retries The number of retries + * + * @return true if your app has been given root access. + * @throws TimeoutException if this operation times out. (cannot determine if access is given) + */ + public static boolean isAccessGiven(int timeout, int retries) { + final Set ID = new HashSet(); + final int IAG = 158; + + try { + RootShell.log("Checking for Root access"); + + Command command = new Command(IAG, false, "id") { + @Override + public void commandOutput(int id, String line) { + if (id == IAG) { + ID.addAll(Arrays.asList(line.split(" "))); + } + + super.commandOutput(id, line); + } + }; + + Shell shell = Shell.startRootShell(timeout, retries); + shell.add(command); + commandWait(shell, command); + + //parse the userid + for (String userid : ID) { + RootShell.log(userid); + + if (userid.toLowerCase().contains("uid=0")) { + RootShell.log("Access Given"); + return true; + } + } + + return false; + } catch (Exception e) { + e.printStackTrace(); + return false; + } + } + + /** + * @return true if BusyBox was found. + */ + public static boolean isBusyboxAvailable() + { + return isBusyboxAvailable(false); + } + + /** + * @return true if BusyBox or Toybox was found. + */ + public static boolean isBusyboxAvailable(boolean includeToybox) + { + if(includeToybox) { + return (findBinary("busybox", true)).size() > 0 || (findBinary("toybox", true)).size() > 0; + } else { + return (findBinary("busybox", true)).size() > 0; + } + } + + /** + * @return true if su was found. + */ + public static boolean isRootAvailable() { + return (findBinary("su", true)).size() > 0; + } + + /** + * This method allows you to output debug messages only when debugging is on. This will allow + * you to add a debug option to your app, which by default can be left off for performance. + * However, when you need debugging information, a simple switch can enable it and provide you + * with detailed logging. + *

+ * This method handles whether or not to log the information you pass it depending whether or + * not RootShell.debugMode is on. So you can use this and not have to worry about handling it + * yourself. + * + * @param msg The message to output. + */ + public static void log(String msg) { + log(null, msg, LogLevel.DEBUG, null); + } + + /** + * This method allows you to output debug messages only when debugging is on. This will allow + * you to add a debug option to your app, which by default can be left off for performance. + * However, when you need debugging information, a simple switch can enable it and provide you + * with detailed logging. + *

+ * This method handles whether or not to log the information you pass it depending whether or + * not RootShell.debugMode is on. So you can use this and not have to worry about handling it + * yourself. + * + * @param TAG Optional parameter to define the tag that the Log will use. + * @param msg The message to output. + */ + public static void log(String TAG, String msg) { + log(TAG, msg, LogLevel.DEBUG, null); + } + + /** + * This method allows you to output debug messages only when debugging is on. This will allow + * you to add a debug option to your app, which by default can be left off for performance. + * However, when you need debugging information, a simple switch can enable it and provide you + * with detailed logging. + *

+ * This method handles whether or not to log the information you pass it depending whether or + * not RootShell.debugMode is on. So you can use this and not have to worry about handling it + * yourself. + * + * @param msg The message to output. + * @param type The type of log, 1 for verbose, 2 for error, 3 for debug, 4 for warn + * @param e The exception that was thrown (Needed for errors) + */ + public static void log(String msg, LogLevel type, Exception e) { + log(null, msg, type, e); + } + + /** + * This method allows you to check whether logging is enabled. + * Yes, it has a goofy name, but that's to keep it as short as possible. + * After all writing logging calls should be painless. + * This method exists to save Android going through the various Java layers + * that are traversed any time a string is created (i.e. what you are logging) + *

+ * Example usage: + * if(islog) { + * StrinbBuilder sb = new StringBuilder(); + * // ... + * // build string + * // ... + * log(sb.toString()); + * } + * + * @return true if logging is enabled + */ + public static boolean islog() { + return debugMode; + } + + /** + * This method allows you to output debug messages only when debugging is on. This will allow + * you to add a debug option to your app, which by default can be left off for performance. + * However, when you need debugging information, a simple switch can enable it and provide you + * with detailed logging. + *

+ * This method handles whether or not to log the information you pass it depending whether or + * not RootShell.debugMode is on. So you can use this and not have to worry about handling it + * yourself. + * + * @param TAG Optional parameter to define the tag that the Log will use. + * @param msg The message to output. + * @param type The type of log, 1 for verbose, 2 for error, 3 for debug + * @param e The exception that was thrown (Needed for errors) + */ + public static void log(String TAG, String msg, LogLevel type, Exception e) { + if (msg != null && !msg.equals("")) { + if (debugMode) { + if (TAG == null) { + TAG = version; + } + + switch (type) { + case VERBOSE: + Log.v(TAG, msg); + break; + case ERROR: + Log.e(TAG, msg, e); + break; + case DEBUG: + Log.d(TAG, msg); + break; + case WARN: + Log.w(TAG, msg); + break; + } + } + } + } + + // -------------------- + // # Public Methods # + // -------------------- + + private static void commandWait(Shell shell, Command cmd) throws Exception { + while (!cmd.isFinished()) { + + RootShell.log(version, shell.getCommandQueuePositionString(cmd)); + RootShell.log(version, "Processed " + cmd.totalOutputProcessed + " of " + cmd.totalOutput + " output from command."); + + synchronized (cmd) { + try { + if (!cmd.isFinished()) { + cmd.wait(2000); + } + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + + if (!cmd.isExecuting() && !cmd.isFinished()) { + if (!shell.isExecuting && !shell.isReading) { + RootShell.log(version, "Waiting for a command to be executed in a shell that is not executing and not reading! \n\n Command: " + cmd.getCommand()); + Exception e = new Exception(); + e.setStackTrace(Thread.currentThread().getStackTrace()); + e.printStackTrace(); + } else if (shell.isExecuting && !shell.isReading) { + RootShell.log(version, "Waiting for a command to be executed in a shell that is executing but not reading! \n\n Command: " + cmd.getCommand()); + Exception e = new Exception(); + e.setStackTrace(Thread.currentThread().getStackTrace()); + e.printStackTrace(); + } else { + RootShell.log(version, "Waiting for a command to be executed in a shell that is not reading! \n\n Command: " + cmd.getCommand()); + Exception e = new Exception(); + e.setStackTrace(Thread.currentThread().getStackTrace()); + e.printStackTrace(); + } + } + + } + } +} diff --git a/wrappers/android/mynteye/libshell/src/main/java/com/stericson/RootShell/containers/RootClass.java b/wrappers/android/mynteye/libshell/src/main/java/com/stericson/RootShell/containers/RootClass.java new file mode 100644 index 0000000..9cf7659 --- /dev/null +++ b/wrappers/android/mynteye/libshell/src/main/java/com/stericson/RootShell/containers/RootClass.java @@ -0,0 +1,348 @@ +package com.stericson.RootShell.containers; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileFilter; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.FilenameFilter; +import java.io.IOException; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/* #ANNOTATIONS @SupportedAnnotationTypes("com.stericson.RootShell.containers.RootClass.Candidate") */ +/* #ANNOTATIONS @SupportedSourceVersion(SourceVersion.RELEASE_6) */ +public class RootClass /* #ANNOTATIONS extends AbstractProcessor */ { + + /* #ANNOTATIONS + @Override + public boolean process(Set typeElements, RoundEnvironment roundEnvironment) { + processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE, "I was invoked!!!"); + + return false; + } + */ + + static String PATH_TO_DX = "/Users/Chris/Projects/android-sdk-macosx/build-tools/18.0.1/dx"; + + enum READ_STATE { + STARTING, FOUND_ANNOTATION; + } + + public RootClass(String[] args) throws ClassNotFoundException, NoSuchMethodException, + IllegalAccessException, InvocationTargetException, InstantiationException { + + // Note: rather than calling System.load("/system/lib/libandroid_runtime.so"); + // which would leave a bunch of unresolved JNI references, + // we are using the 'withFramework' class as a preloader. + // So, yeah, russian dolls: withFramework > RootClass > actual method + + String className = args[0]; + RootArgs actualArgs = new RootArgs(); + actualArgs.args = new String[args.length - 1]; + System.arraycopy(args, 1, actualArgs.args, 0, args.length - 1); + Class classHandler = Class.forName(className); + Constructor classConstructor = classHandler.getConstructor(RootArgs.class); + classConstructor.newInstance(actualArgs); + } + + public @interface Candidate { + + } + + ; + + public class RootArgs { + + public String args[]; + } + + static void displayError(Exception e) { + // Not using system.err to make it easier to capture from + // calling library. + System.out.println("##ERR##" + e.getMessage() + "##"); + e.printStackTrace(); + } + + // I reckon it would be better to investigate classes using getAttribute() + // however this method allows the developer to simply select "Run" on RootClass + // and immediately re-generate the necessary jar file. + static public class AnnotationsFinder { + + private final String AVOIDDIRPATH = "stericson" + File.separator + "RootShell" + File.separator; + + private List classFiles; + + public AnnotationsFinder() throws IOException { + System.out.println("Discovering root class annotations..."); + classFiles = new ArrayList(); + lookup(new File("src"), classFiles); + System.out.println("Done discovering annotations. Building jar file."); + File builtPath = getBuiltPath(); + if (null != builtPath) { + // Android! Y U no have com.google.common.base.Joiner class? + String rc1 = "com" + File.separator + + "stericson" + File.separator + + "RootShell" + File.separator + + "containers" + File.separator + + "RootClass.class"; + String rc2 = "com" + File.separator + + "stericson" + File.separator + + "RootShell" + File.separator + + "containers" + File.separator + + "RootClass$RootArgs.class"; + String rc3 = "com" + File.separator + + "stericson" + File.separator + + "RootShell" + File.separator + + "containers" + File.separator + + "RootClass$AnnotationsFinder.class"; + String rc4 = "com" + File.separator + + "stericson" + File.separator + + "RootShell" + File.separator + + "containers" + File.separator + + "RootClass$AnnotationsFinder$1.class"; + String rc5 = "com" + File.separator + + "stericson" + File.separator + + "RootShell" + File.separator + + "containers" + File.separator + + "RootClass$AnnotationsFinder$2.class"; + String[] cmd; + boolean onWindows = (-1 != System.getProperty("os.name").toLowerCase().indexOf("win")); + if (onWindows) { + StringBuilder sb = new StringBuilder( + " " + rc1 + " " + rc2 + " " + rc3 + " " + rc4 + " " + rc5 + ); + for (File file : classFiles) { + sb.append(" " + file.getPath()); + } + cmd = new String[]{ + "cmd", "/C", + "jar cvf" + + " anbuild.jar" + + sb.toString() + }; + } else { + ArrayList al = new ArrayList(); + al.add("jar"); + al.add("cf"); + al.add("anbuild.jar"); + al.add(rc1); + al.add(rc2); + al.add(rc3); + al.add(rc4); + al.add(rc5); + for (File file : classFiles) { + al.add(file.getPath()); + } + cmd = al.toArray(new String[al.size()]); + } + ProcessBuilder jarBuilder = new ProcessBuilder(cmd); + jarBuilder.directory(builtPath); + try { + jarBuilder.start().waitFor(); + } catch (IOException e) { + } catch (InterruptedException e) { + } + + String strRawFolder = "res" + File.separator + "raw"; + if (builtPath.toString().startsWith("build")); //Check if running in AndroidStudio + strRawFolder = "src" + File.separator + "main" + File.separator + "res" + File.separator + "raw"; + + File rawFolder = new File(strRawFolder); + if (!rawFolder.exists()) { + rawFolder.mkdirs(); + } + + System.out.println("Done building jar file. Creating dex file."); + if (onWindows) { + cmd = new String[]{ + "cmd", "/C", + "dx --dex --output=" + strRawFolder + File.separator + "anbuild.dex " + + builtPath + File.separator + "anbuild.jar" + }; + } else { + cmd = new String[]{ + getPathToDx(), + "--dex", + "--output=" + strRawFolder + File.separator + "anbuild.dex", + builtPath + File.separator + "anbuild.jar" + }; + } + ProcessBuilder dexBuilder = new ProcessBuilder(cmd); + try { + dexBuilder.start().waitFor(); + } catch (IOException e) { + } catch (InterruptedException e) { + } + } + System.out.println("All done. ::: anbuild.dex should now be in your project's src" + File.separator + "main" + File.separator + "res" + File.separator + "raw" + File.separator + " folder :::"); + } + + protected void lookup(File path, List fileList) { + String desourcedPath = path.toString().replace("src" + File.separator, "").replace("main" + File.separator + "java" + File.separator, ""); + + File[] files = path.listFiles(new FileFilter() { + @Override + public boolean accept(File file) { + return true; + } + }); + for (File file : files) { + if (file.isDirectory()) { + if (-1 == file.getAbsolutePath().indexOf(AVOIDDIRPATH)) { + lookup(file, fileList); + } + } else { + if (file.getName().endsWith(".java")) { + if (hasClassAnnotation(file)) { + final String fileNamePrefix = file.getName().replace(".java", ""); + final File compiledPath = new File(getBuiltPath().toString() + File.separator + desourcedPath); + File[] classAndInnerClassFiles = compiledPath.listFiles(new FilenameFilter() { + @Override + public boolean accept(File dir, String filename) { + return filename.startsWith(fileNamePrefix); + } + }); + for (final File matchingFile : classAndInnerClassFiles) { + fileList.add(new File(desourcedPath + File.separator + matchingFile.getName())); + } + + } + } + } + } + } + + protected boolean hasClassAnnotation(File file) { + READ_STATE readState = READ_STATE.STARTING; + Pattern p = Pattern.compile(" class ([A-Za-z0-9_]+)"); + try { + BufferedReader reader = new BufferedReader(new FileReader(file)); + String line; + while (null != (line = reader.readLine())) { + switch (readState) { + case STARTING: + if (-1 < line.indexOf("@RootClass.Candidate")) { + readState = READ_STATE.FOUND_ANNOTATION; + } + break; + case FOUND_ANNOTATION: + Matcher m = p.matcher(line); + if (m.find()) { + System.out.println(" Found annotated class: " + m.group(0)); + return true; + } else { + System.err.println("Error: unmatched annotation in " + + file.getAbsolutePath()); + readState = READ_STATE.STARTING; + } + break; + } + } + } catch (FileNotFoundException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } + return false; + } + + protected String getPathToDx() throws IOException { + String androidHome = System.getenv("ANDROID_HOME"); + if (null == androidHome) { + throw new IOException("Error: you need to set $ANDROID_HOME globally"); + } + String dxPath = null; + File[] files = new File(androidHome + File.separator + "build-tools").listFiles(); + int recentSdkVersion = 0; + for (File file : files) { + + String fileName = null; + if (file.getName().contains("-")) { + String[] splitFileName = file.getName().split("-"); + if (splitFileName[1].contains("W")) { + char[] fileNameChars = splitFileName[1].toCharArray(); + fileName = String.valueOf(fileNameChars[0]); + } else if (splitFileName[1].contains("rc")) { + continue; //Do not use release candidates + } else { + fileName = splitFileName[1]; + } + } else { + fileName = file.getName(); + } + + int sdkVersion; + + String[] sdkVersionBits = fileName.split("[.]"); + sdkVersion = Integer.parseInt(sdkVersionBits[0]) * 10000; + if (sdkVersionBits.length > 1) { + sdkVersion += Integer.parseInt(sdkVersionBits[1]) * 100; + if (sdkVersionBits.length > 2) { + sdkVersion += Integer.parseInt(sdkVersionBits[2]); + } + } + if (sdkVersion > recentSdkVersion) { + String tentativePath = file.getAbsolutePath() + File.separator + "dx"; + if (new File(tentativePath).exists()) { + recentSdkVersion = sdkVersion; + dxPath = tentativePath; + } + } + } + if (dxPath == null) { + throw new IOException("Error: unable to find dx binary in $ANDROID_HOME"); + } + return dxPath; + } + + protected File getBuiltPath() { + File foundPath = null; + + File ideaPath = new File("out" + File.separator + "production"); // IntelliJ + if (ideaPath.isDirectory()) { + File[] children = ideaPath.listFiles(new FileFilter() { + @Override + public boolean accept(File pathname) { + return pathname.isDirectory(); + } + }); + if (children.length > 0) { + foundPath = new File(ideaPath.getAbsolutePath() + File.separator + children[0].getName()); + } + } + if (null == foundPath) { + File eclipsePath = new File("bin" + File.separator + "classes"); // Eclipse IDE + if (eclipsePath.isDirectory()) { + foundPath = eclipsePath; + } + } + if (null == foundPath) { + File androidStudioPath = new File("build" + File.separator + "intermediates" + File.separator + "classes" + File.separator + "debug"); // Android Studio + if (androidStudioPath.isDirectory()) { + foundPath = androidStudioPath; + } + } + + return foundPath; + } + + + } + + public static void main(String[] args) { + try { + if (args.length == 0) { + new AnnotationsFinder(); + } else { + new RootClass(args); + } + } catch (Exception e) { + displayError(e); + } + } +} \ No newline at end of file diff --git a/wrappers/android/mynteye/libshell/src/main/java/com/stericson/RootShell/exceptions/RootDeniedException.java b/wrappers/android/mynteye/libshell/src/main/java/com/stericson/RootShell/exceptions/RootDeniedException.java new file mode 100644 index 0000000..758ba8c --- /dev/null +++ b/wrappers/android/mynteye/libshell/src/main/java/com/stericson/RootShell/exceptions/RootDeniedException.java @@ -0,0 +1,32 @@ +/* + * This file is part of the RootShell Project: https://github.com/Stericson/RootShell + * + * Copyright (c) 2014 Stephen Erickson, Chris Ravenscroft + * + * This code is dual-licensed under the terms of the Apache License Version 2.0 and + * the terms of the General Public License (GPL) Version 2. + * You may use this code according to either of these licenses as is most appropriate + * for your project on a case-by-case basis. + * + * The terms of each license can be found in the root directory of this project's repository as well as at: + * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * http://www.gnu.org/licenses/gpl-2.0.txt + * + * Unless required by applicable law or agreed to in writing, software + * distributed under these Licenses is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See each License for the specific language governing permissions and + * limitations under that License. + */ + +package com.stericson.RootShell.exceptions; + +public class RootDeniedException extends Exception { + + private static final long serialVersionUID = -8713947214162841310L; + + public RootDeniedException(String error) { + super(error); + } +} diff --git a/wrappers/android/mynteye/libshell/src/main/java/com/stericson/RootShell/execution/Command.java b/wrappers/android/mynteye/libshell/src/main/java/com/stericson/RootShell/execution/Command.java new file mode 100644 index 0000000..edb7bad --- /dev/null +++ b/wrappers/android/mynteye/libshell/src/main/java/com/stericson/RootShell/execution/Command.java @@ -0,0 +1,350 @@ +/* + * This file is part of the RootShell Project: http://code.google.com/p/RootShell/ + * + * Copyright (c) 2014 Stephen Erickson, Chris Ravenscroft + * + * This code is dual-licensed under the terms of the Apache License Version 2.0 and + * the terms of the General Public License (GPL) Version 2. + * You may use this code according to either of these licenses as is most appropriate + * for your project on a case-by-case basis. + * + * The terms of each license can be found in the root directory of this project's repository as well as at: + * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * http://www.gnu.org/licenses/gpl-2.0.txt + * + * Unless required by applicable law or agreed to in writing, software + * distributed under these Licenses is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See each License for the specific language governing permissions and + * limitations under that License. + */ + +package com.stericson.RootShell.execution; + +import com.stericson.RootShell.RootShell; + +import android.content.Context; +import android.os.Build; +import android.os.Bundle; +import android.os.Handler; +import android.os.Looper; +import android.os.Message; + +import java.io.IOException; + +public class Command { + + //directly modified by JavaCommand + protected boolean javaCommand = false; + protected Context context = null; + + public int totalOutput = 0; + + public int totalOutputProcessed = 0; + + ExecutionMonitor executionMonitor = null; + + Handler mHandler = null; + + //Has this command already been used? + protected boolean used = false; + + boolean executing = false; + + String[] command = {}; + + boolean finished = false; + + boolean terminated = false; + + boolean handlerEnabled = true; + + int exitCode = -1; + + int id = 0; + + int timeout = RootShell.defaultCommandTimeout; + + /** + * Constructor for executing a normal shell command + * + * @param id the id of the command being executed + * @param command the command, or commands, to be executed. + */ + public Command(int id, String... command) { + this.command = command; + this.id = id; + + createHandler(RootShell.handlerEnabled); + } + + /** + * Constructor for executing a normal shell command + * + * @param id the id of the command being executed + * @param handlerEnabled when true the handler will be used to call the + * callback methods if possible. + * @param command the command, or commands, to be executed. + */ + public Command(int id, boolean handlerEnabled, String... command) { + this.command = command; + this.id = id; + + createHandler(handlerEnabled); + } + + /** + * Constructor for executing a normal shell command + * + * @param id the id of the command being executed + * @param timeout the time allowed before the shell will give up executing the command + * and throw a TimeoutException. + * @param command the command, or commands, to be executed. + */ + public Command(int id, int timeout, String... command) { + this.command = command; + this.id = id; + this.timeout = timeout; + + createHandler(RootShell.handlerEnabled); + } + + //If you override this you MUST make a final call + //to the super method. The super call should be the last line of this method. + public void commandOutput(int id, String line) { + RootShell.log("Command", "ID: " + id + ", " + line); + totalOutputProcessed++; + } + + public void commandTerminated(int id, String reason) { + //pass + } + + public void commandCompleted(int id, int exitcode) { + //pass + } + + protected final void commandFinished() { + if (!terminated) { + synchronized (this) { + if (mHandler != null && handlerEnabled) { + Message msg = mHandler.obtainMessage(); + Bundle bundle = new Bundle(); + bundle.putInt(CommandHandler.ACTION, CommandHandler.COMMAND_COMPLETED); + msg.setData(bundle); + mHandler.sendMessage(msg); + } else { + commandCompleted(id, exitCode); + } + + RootShell.log("Command " + id + " finished."); + finishCommand(); + } + } + } + + private void createHandler(boolean handlerEnabled) { + + this.handlerEnabled = handlerEnabled; + + if (Looper.myLooper() != null && handlerEnabled) { + RootShell.log("CommandHandler created"); + mHandler = new CommandHandler(); + } else { + RootShell.log("CommandHandler not created"); + } + } + + public final void finish() + { + RootShell.log("Command finished at users request!"); + commandFinished(); + } + + protected final void finishCommand() { + this.executing = false; + this.finished = true; + this.notifyAll(); + } + + + public final String getCommand() { + StringBuilder sb = new StringBuilder(); + + if(javaCommand) { + String filePath = context.getFilesDir().getPath(); + + for (int i = 0; i < command.length; i++) { + /* + * TODO Make withFramework optional for applications + * that do not require access to the fw. -CFR + */ + //export CLASSPATH=/data/user/0/ch.masshardt.emailnotification/files/anbuild.dex ; app_process /system/bin + if (Build.VERSION.SDK_INT > 22) { + //dalvikvm command is not working in Android Marshmallow + sb.append( + "export CLASSPATH=" + filePath + "/anbuild.dex;" + + " app_process /system/bin " + + command[i]); + } else { + sb.append( + "dalvikvm -cp " + filePath + "/anbuild.dex" + + " com.android.internal.util.WithFramework" + + " com.stericson.RootTools.containers.RootClass " + + command[i]); + } + + sb.append('\n'); + } + } + else { + for (int i = 0; i < command.length; i++) { + sb.append(command[i]); + sb.append('\n'); + } + } + + return sb.toString(); + } + + public final boolean isExecuting() { + return executing; + } + + public final boolean isHandlerEnabled() { + return handlerEnabled; + } + + public final boolean isFinished() { + return finished; + } + + public final int getExitCode() { + return this.exitCode; + } + + protected final void setExitCode(int code) { + synchronized (this) { + exitCode = code; + } + } + + protected final void startExecution() { + this.used = true; + executionMonitor = new ExecutionMonitor(this); + executionMonitor.setPriority(Thread.MIN_PRIORITY); + executionMonitor.start(); + executing = true; + } + + public final void terminate() + { + RootShell.log("Terminating command at users request!"); + terminated("Terminated at users request!"); + } + + protected final void terminate(String reason) { + try { + Shell.closeAll(); + RootShell.log("Terminating all shells."); + terminated(reason); + } catch (IOException e) { + } + } + + protected final void terminated(String reason) { + synchronized (Command.this) { + + if (mHandler != null && handlerEnabled) { + Message msg = mHandler.obtainMessage(); + Bundle bundle = new Bundle(); + bundle.putInt(CommandHandler.ACTION, CommandHandler.COMMAND_TERMINATED); + bundle.putString(CommandHandler.TEXT, reason); + msg.setData(bundle); + mHandler.sendMessage(msg); + } else { + commandTerminated(id, reason); + } + + RootShell.log("Command " + id + " did not finish because it was terminated. Termination reason: " + reason); + setExitCode(-1); + terminated = true; + finishCommand(); + } + } + + protected final void output(int id, String line) { + totalOutput++; + + if (mHandler != null && handlerEnabled) { + Message msg = mHandler.obtainMessage(); + Bundle bundle = new Bundle(); + bundle.putInt(CommandHandler.ACTION, CommandHandler.COMMAND_OUTPUT); + bundle.putString(CommandHandler.TEXT, line); + msg.setData(bundle); + mHandler.sendMessage(msg); + } else { + commandOutput(id, line); + } + } + + private class ExecutionMonitor extends Thread { + + private final Command command; + + public ExecutionMonitor(Command command) { + this.command = command; + } + + public void run() { + + if(command.timeout > 0) + { + synchronized (command) { + try { + RootShell.log("Command " + command.id + " is waiting for: " + command.timeout); + command.wait(command.timeout); + } catch (InterruptedException e) { + RootShell.log("Exception: " + e); + } + + if (!command.isFinished()) { + RootShell.log("Timeout Exception has occurred for command: " + command.id + "."); + terminate("Timeout Exception"); + } + } + } + } + } + + private class CommandHandler extends Handler { + + static final public String ACTION = "action"; + + static final public String TEXT = "text"; + + static final public int COMMAND_OUTPUT = 0x01; + + static final public int COMMAND_COMPLETED = 0x02; + + static final public int COMMAND_TERMINATED = 0x03; + + public final void handleMessage(Message msg) { + int action = msg.getData().getInt(ACTION); + String text = msg.getData().getString(TEXT); + + switch (action) { + case COMMAND_OUTPUT: + commandOutput(id, text); + break; + case COMMAND_COMPLETED: + commandCompleted(id, exitCode); + break; + case COMMAND_TERMINATED: + commandTerminated(id, text); + break; + } + } + } +} diff --git a/wrappers/android/mynteye/libshell/src/main/java/com/stericson/RootShell/execution/JavaCommand.java b/wrappers/android/mynteye/libshell/src/main/java/com/stericson/RootShell/execution/JavaCommand.java new file mode 100644 index 0000000..032569e --- /dev/null +++ b/wrappers/android/mynteye/libshell/src/main/java/com/stericson/RootShell/execution/JavaCommand.java @@ -0,0 +1,58 @@ +package com.stericson.RootShell.execution; + +import android.content.Context; + +public class JavaCommand extends Command +{ + /** + * Constructor for executing Java commands rather than binaries + * + * @param context needed to execute java command. + */ + public JavaCommand(int id, Context context, String... command) { + super(id, command); + this.context = context; + this.javaCommand = true; + } + + /** + * Constructor for executing Java commands rather than binaries + * + * @param context needed to execute java command. + */ + public JavaCommand(int id, boolean handlerEnabled, Context context, String... command) { + super(id, handlerEnabled, command); + this.context = context; + this.javaCommand = true; + } + + /** + * Constructor for executing Java commands rather than binaries + * + * @param context needed to execute java command. + */ + public JavaCommand(int id, int timeout, Context context, String... command) { + super(id, timeout, command); + this.context = context; + this.javaCommand = true; + } + + + @Override + public void commandOutput(int id, String line) + { + super.commandOutput(id, line); + } + + @Override + public void commandTerminated(int id, String reason) + { + // pass + } + + @Override + public void commandCompleted(int id, int exitCode) + { + // pass + } +} diff --git a/wrappers/android/mynteye/libshell/src/main/java/com/stericson/RootShell/execution/Shell.java b/wrappers/android/mynteye/libshell/src/main/java/com/stericson/RootShell/execution/Shell.java new file mode 100644 index 0000000..b64923e --- /dev/null +++ b/wrappers/android/mynteye/libshell/src/main/java/com/stericson/RootShell/execution/Shell.java @@ -0,0 +1,1038 @@ +/* + * This file is part of the RootShell Project: http://code.google.com/p/RootShell/ + * + * Copyright (c) 2014 Stephen Erickson, Chris Ravenscroft + * + * This code is dual-licensed under the terms of the Apache License Version 2.0 and + * the terms of the General Public License (GPL) Version 2. + * You may use this code according to either of these licenses as is most appropriate + * for your project on a case-by-case basis. + * + * The terms of each license can be found in the root directory of this project's repository as well as at: + * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * http://www.gnu.org/licenses/gpl-2.0.txt + * + * Unless required by applicable law or agreed to in writing, software + * distributed under these Licenses is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See each License for the specific language governing permissions and + * limitations under that License. + */ +package com.stericson.RootShell.execution; + +import com.stericson.RootShell.RootShell; +import com.stericson.RootShell.exceptions.RootDeniedException; + +import android.content.Context; +import android.util.Log; + +import java.io.BufferedReader; +import java.io.EOFException; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStreamWriter; +import java.io.Reader; +import java.io.Writer; +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.TimeoutException; + +public class Shell { + + public static enum ShellType { + NORMAL, + ROOT, + CUSTOM + } + + //this is only used with root shells + public static enum ShellContext { + NORMAL("normal"), //The normal context... + SHELL("u:r:shell:s0"), //unprivileged shell (such as an adb shell) + SYSTEM_SERVER("u:r:system_server:s0"), // system_server, u:r:system:s0 on some firmwares + SYSTEM_APP("u:r:system_app:s0"), // System apps + PLATFORM_APP("u:r:platform_app:s0"), // System apps + UNTRUSTED_APP("u:r:untrusted_app:s0"), // Third-party apps + RECOVERY("u:r:recovery:s0"), //Recovery + SUPERSU("u:r:supersu:s0"); //SUPER SU default + + private String value; + + private ShellContext(String value) { + this.value = value; + } + + public String getValue() { + return this.value; + } + + } + + //Statics -- visible to all + private static final String token = "F*D^W@#FGF"; + + private static Shell rootShell = null; + + private static Shell shell = null; + + private static Shell customShell = null; + + private static String[] suVersion = new String[]{ + null, null + }; + + //the default context for root shells... + public static ShellContext defaultContext = ShellContext.NORMAL; + + //per shell + private int shellTimeout = 25000; + + private ShellType shellType = null; + + private ShellContext shellContext = Shell.ShellContext.NORMAL; + + private String error = ""; + + private final Process proc; + + private final BufferedReader inputStream; + + private final BufferedReader errorStream; + + private final OutputStreamWriter outputStream; + + private final List commands = new ArrayList(); + + //indicates whether or not to close the shell + private boolean close = false; + + private Boolean isSELinuxEnforcing = null; + + public boolean isExecuting = false; + + public boolean isReading = false; + + public boolean isClosed = false; + + private int maxCommands = 5000; + + private int read = 0; + + private int write = 0; + + private int totalExecuted = 0; + + private int totalRead = 0; + + private boolean isCleaning = false; + + private Shell(String cmd, ShellType shellType, ShellContext shellContext, int shellTimeout) throws IOException, TimeoutException, RootDeniedException { + + RootShell.log("Starting shell: " + cmd); + RootShell.log("Context: " + shellContext.getValue()); + RootShell.log("Timeout: " + shellTimeout); + + this.shellType = shellType; + this.shellTimeout = shellTimeout > 0 ? shellTimeout : this.shellTimeout; + this.shellContext = shellContext; + + if (this.shellContext == ShellContext.NORMAL) { + this.proc = Runtime.getRuntime().exec(cmd); + } else { + String display = getSuVersion(false); + String internal = getSuVersion(true); + + //only done for root shell... + //Right now only SUPERSU supports the --context switch + if (isSELinuxEnforcing() && + (display != null) && + (internal != null) && + (display.endsWith("SUPERSU")) && + (Integer.valueOf(internal) >= 190)) { + cmd += " --context " + this.shellContext.getValue(); + } else { + RootShell.log("Su binary --context switch not supported!"); + RootShell.log("Su binary display version: " + display); + RootShell.log("Su binary internal version: " + internal); + RootShell.log("SELinuxEnforcing: " + isSELinuxEnforcing()); + } + + this.proc = Runtime.getRuntime().exec(cmd); + + } + + this.inputStream = new BufferedReader(new InputStreamReader(this.proc.getInputStream(), "UTF-8")); + this.errorStream = new BufferedReader(new InputStreamReader(this.proc.getErrorStream(), "UTF-8")); + this.outputStream = new OutputStreamWriter(this.proc.getOutputStream(), "UTF-8"); + + /** + * Thread responsible for carrying out the requested operations + */ + Worker worker = new Worker(this); + worker.start(); + + try { + /** + * The flow of execution will wait for the thread to die or wait until the + * given timeout has expired. + * + * The result of the worker, which is determined by the exit code of the worker, + * will tell us if the operation was completed successfully or it the operation + * failed. + */ + worker.join(this.shellTimeout); + + /** + * The operation could not be completed before the timeout occurred. + */ + if (worker.exit == -911) { + + try { + this.proc.destroy(); + } catch (Exception e) { + } + + closeQuietly(this.inputStream); + closeQuietly(this.errorStream); + closeQuietly(this.outputStream); + + throw new TimeoutException(this.error); + } + /** + * Root access denied? + */ + else if (worker.exit == -42) { + + try { + this.proc.destroy(); + } catch (Exception e) { + } + + closeQuietly(this.inputStream); + closeQuietly(this.errorStream); + closeQuietly(this.outputStream); + + throw new RootDeniedException("Root Access Denied"); + } + /** + * Normal exit + */ + else { + /** + * The shell is open. + * + * Start two threads, one to handle the input and one to handle the output. + * + * input, and output are runnables that the threads execute. + */ + Thread si = new Thread(this.input, "Shell Input"); + si.setPriority(Thread.NORM_PRIORITY); + si.start(); + + Thread so = new Thread(this.output, "Shell Output"); + so.setPriority(Thread.NORM_PRIORITY); + so.start(); + } + } catch (InterruptedException ex) { + worker.interrupt(); + Thread.currentThread().interrupt(); + throw new TimeoutException(); + } + } + + + public Command add(Command command) throws IOException { + if (this.close) { + throw new IllegalStateException( + "Unable to add commands to a closed shell"); + } + + if(command.used) { + //The command has been used, don't re-use... + throw new IllegalStateException( + "This command has already been executed. (Don't re-use command instances.)"); + } + + while (this.isCleaning) { + //Don't add commands while cleaning + ; + } + + this.commands.add(command); + + this.notifyThreads(); + + return command; + } + + public final void useCWD(Context context) throws IOException, TimeoutException, RootDeniedException { + add( + new Command( + -1, + false, + "cd " + context.getApplicationInfo().dataDir) + ); + } + + private void cleanCommands() { + this.isCleaning = true; + int toClean = Math.abs(this.maxCommands - (this.maxCommands / 4)); + RootShell.log("Cleaning up: " + toClean); + + for (int i = 0; i < toClean; i++) { + this.commands.remove(0); + } + + this.read = this.commands.size() - 1; + this.write = this.commands.size() - 1; + this.isCleaning = false; + } + + private void closeQuietly(final Reader input) { + try { + if (input != null) { + input.close(); + } + } catch (Exception ignore) { + } + } + + private void closeQuietly(final Writer output) { + try { + if (output != null) { + output.close(); + } + } catch (Exception ignore) { + } + } + + public void close() throws IOException { + RootShell.log("Request to close shell!"); + + int count = 0; + while (isExecuting) { + RootShell.log("Waiting on shell to finish executing before closing..."); + count++; + + //fail safe + if (count > 10000) { + break; + } + + } + + synchronized (this.commands) { + /** + * instruct the two threads monitoring input and output + * of the shell to close. + */ + this.close = true; + this.notifyThreads(); + } + + RootShell.log("Shell Closed!"); + + if (this == Shell.rootShell) { + Shell.rootShell = null; + } else if (this == Shell.shell) { + Shell.shell = null; + } else if (this == Shell.customShell) { + Shell.customShell = null; + } + } + + public static void closeCustomShell() throws IOException { + RootShell.log("Request to close custom shell!"); + + if (Shell.customShell == null) { + return; + } + + Shell.customShell.close(); + } + + public static void closeRootShell() throws IOException { + RootShell.log("Request to close root shell!"); + + if (Shell.rootShell == null) { + return; + } + Shell.rootShell.close(); + } + + public static void closeShell() throws IOException { + RootShell.log("Request to close normal shell!"); + + if (Shell.shell == null) { + return; + } + Shell.shell.close(); + } + + public static void closeAll() throws IOException { + RootShell.log("Request to close all shells!"); + + Shell.closeShell(); + Shell.closeRootShell(); + Shell.closeCustomShell(); + } + + public int getCommandQueuePosition(Command cmd) { + return this.commands.indexOf(cmd); + } + + public String getCommandQueuePositionString(Command cmd) { + return "Command is in position " + getCommandQueuePosition(cmd) + " currently executing command at position " + this.write + " and the number of commands is " + commands.size(); + } + + public static Shell getOpenShell() { + if (Shell.customShell != null) { + return Shell.customShell; + } else if (Shell.rootShell != null) { + return Shell.rootShell; + } else { + return Shell.shell; + } + } + + /** + * From libsuperuser. + * + *

+ * Detects the version of the su binary installed (if any), if supported + * by the binary. Most binaries support two different version numbers, + * the public version that is displayed to users, and an internal + * version number that is used for version number comparisons. Returns + * null if su not available or retrieving the version isn't supported. + *

+ *

+ * Note that su binary version and GUI (APK) version can be completely + * different. + *

+ *

+ * This function caches its result to improve performance on multiple + * calls + *

+ * + * @param internal Request human-readable version or application + * internal version + * @return String containing the su version or null + */ + private synchronized String getSuVersion(boolean internal) { + int idx = internal ? 0 : 1; + if (suVersion[idx] == null) { + String version = null; + + // Replace libsuperuser:Shell.run with manual process execution + Process process; + try { + process = Runtime.getRuntime().exec(internal ? "su -V" : "su -v", null); + process.waitFor(); + } catch (IOException e) { + e.printStackTrace(); + return null; + } catch (InterruptedException e) { + e.printStackTrace(); + return null; + } + + // From libsuperuser:StreamGobbler + List stdout = new ArrayList(); + + BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream())); + try { + String line = null; + while ((line = reader.readLine()) != null) { + stdout.add(line); + } + } catch (IOException e) { + } + // make sure our stream is closed and resources will be freed + try { + reader.close(); + } catch (IOException e) { + } + + process.destroy(); + + List ret = stdout; + + if (ret != null) { + for (String line : ret) { + if (!internal) { + if (line.contains(".")) { + version = line; + break; + } + } else { + try { + if (Integer.parseInt(line) > 0) { + version = line; + break; + } + } catch (NumberFormatException e) { + } + } + } + } + + suVersion[idx] = version; + } + return suVersion[idx]; + } + + public static boolean isShellOpen() { + return Shell.shell == null; + } + + public static boolean isCustomShellOpen() { + return Shell.customShell == null; + } + + public static boolean isRootShellOpen() { + return Shell.rootShell == null; + } + + public static boolean isAnyShellOpen() { + return Shell.shell != null || Shell.rootShell != null || Shell.customShell != null; + } + + /** + * From libsuperuser. + * + * Detect if SELinux is set to enforcing, caches result + * + * @return true if SELinux set to enforcing, or false in the case of + * permissive or not present + */ + public synchronized boolean isSELinuxEnforcing() { + if (isSELinuxEnforcing == null) { + Boolean enforcing = null; + + // First known firmware with SELinux built-in was a 4.2 (17) + // leak + if (android.os.Build.VERSION.SDK_INT >= 17) { + + // Detect enforcing through sysfs, not always present + File f = new File("/sys/fs/selinux/enforce"); + if (f.exists()) { + try { + InputStream is = new FileInputStream("/sys/fs/selinux/enforce"); + try { + enforcing = (is.read() == '1'); + } finally { + is.close(); + } + } catch (Exception e) { + } + } + + // 4.4+ builds are enforcing by default, take the gamble + if (enforcing == null) { + enforcing = (android.os.Build.VERSION.SDK_INT >= 19); + } + } + + if (enforcing == null) { + enforcing = false; + } + + isSELinuxEnforcing = enforcing; + } + return isSELinuxEnforcing; + } + + /** + * Runnable to write commands to the open shell. + *

+ * When writing commands we stay in a loop and wait for new + * commands to added to "commands" + *

+ * The notification of a new command is handled by the method add in this class + */ + private Runnable input = new Runnable() { + public void run() { + + try { + while (true) { + + synchronized (commands) { + /** + * While loop is used in the case that notifyAll is called + * and there are still no commands to be written, a rare + * case but one that could happen. + */ + while (!close && write >= commands.size()) { + isExecuting = false; + commands.wait(); + } + } + + if (write >= maxCommands) { + + /** + * wait for the read to catch up. + */ + while (read != write) { + RootShell.log("Waiting for read and write to catch up before cleanup."); + } + /** + * Clean up the commands, stay neat. + */ + cleanCommands(); + } + + /** + * Write the new command + * + * We write the command followed by the token to indicate + * the end of the command execution + */ + if (write < commands.size()) { + isExecuting = true; + Command cmd = commands.get(write); + + if(null != cmd) + { + cmd.startExecution(); + RootShell.log("Executing: " + cmd.getCommand() + " with context: " + shellContext); + + //write the command + outputStream.write(cmd.getCommand()); + outputStream.flush(); + + //write the token... + String line = "\necho " + token + " " + totalExecuted + " $?\n"; + outputStream.write(line); + outputStream.flush(); + + write++; + totalExecuted++; + } + } else if (close) { + /** + * close the thread, the shell is closing. + */ + isExecuting = false; + outputStream.write("\nexit 0\n"); + outputStream.flush(); + RootShell.log("Closing shell"); + return; + } + } + } catch (IOException | InterruptedException e) { + RootShell.log(e.getMessage(), RootShell.LogLevel.ERROR, e); + } + finally { + write = 0; + closeQuietly(outputStream); + } + } + }; + + protected void notifyThreads() { + Thread t = new Thread() { + public void run() { + synchronized (commands) { + commands.notifyAll(); + } + } + }; + + t.start(); + } + + /** + * Runnable to monitor the responses from the open shell. + * + * This include the output and error stream + */ + private Runnable output = new Runnable() { + public void run() { + try { + Command command = null; + + //as long as there is something to read, we will keep reading. + while (!close || inputStream.ready() || read < commands.size()) { + isReading = false; + String outputLine = inputStream.readLine(); + isReading = true; + + /** + * If we receive EOF then the shell closed? + */ + if (outputLine == null) { + break; + } + + if (command == null) { + if (read >= commands.size()) { + if (close) { + break; + } + + continue; + } + + command = commands.get(read); + } + + /** + * trying to determine if all commands have been completed. + * + * if the token is present then the command has finished execution. + */ + int pos = -1; + + pos = outputLine.indexOf(token); + + if (pos == -1) { + /** + * send the output for the implementer to process + */ + command.output(command.id, outputLine); + } else if (pos > 0) { + /** + * token is suffix of output, send output part to implementer + */ + RootShell.log("Found token, line: " + outputLine); + command.output(command.id, outputLine.substring(0, pos)); + } + + if (pos >= 0) { + outputLine = outputLine.substring(pos); + String fields[] = outputLine.split(" "); + + if (fields.length >= 2 && fields[1] != null) { + int id = 0; + + try { + id = Integer.parseInt(fields[1]); + } catch (NumberFormatException e) { + } + + int exitCode = -1; + + try { + exitCode = Integer.parseInt(fields[2]); + } catch (NumberFormatException e) { + } + + if (id == totalRead) { + processErrors(command); + + + /** + * wait for output to be processed... + * + */ + int iterations = 0; + while (command.totalOutput > command.totalOutputProcessed) { + + if(iterations == 0) + { + iterations++; + RootShell.log("Waiting for output to be processed. " + command.totalOutputProcessed + " Of " + command.totalOutput); + } + + try { + + synchronized (this) + { + this.wait(2000); + } + } catch (Exception e) { + RootShell.log(e.getMessage()); + } + } + + RootShell.log("Read all output"); + + command.setExitCode(exitCode); + command.commandFinished(); + + command = null; + + read++; + totalRead++; + continue; + } + } + } + } + + try { + proc.waitFor(); + proc.destroy(); + } catch (Exception e) { + } + + while (read < commands.size()) { + if (command == null) { + command = commands.get(read); + } + + if(command.totalOutput < command.totalOutputProcessed) + { + command.terminated("All output not processed!"); + command.terminated("Did you forget the super.commandOutput call or are you waiting on the command object?"); + } + else + { + command.terminated("Unexpected Termination."); + } + + command = null; + read++; + } + + read = 0; + + } catch (IOException e) { + RootShell.log(e.getMessage(), RootShell.LogLevel.ERROR, e); + } finally { + closeQuietly(outputStream); + closeQuietly(errorStream); + closeQuietly(inputStream); + + RootShell.log("Shell destroyed"); + isClosed = true; + isReading = false; + } + } + }; + + public void processErrors(Command command) { + try { + while (errorStream.ready() && command != null) { + String line = errorStream.readLine(); + + /** + * If we recieve EOF then the shell closed? + */ + if (line == null) { + break; + } + + /** + * send the output for the implementer to process + */ + command.output(command.id, line); + } + } catch (Exception e) { + RootShell.log(e.getMessage(), RootShell.LogLevel.ERROR, e); + } + } + + public static Command runRootCommand(Command command) throws IOException, TimeoutException, RootDeniedException { + return Shell.startRootShell().add(command); + } + + public static Command runCommand(Command command) throws IOException, TimeoutException { + return Shell.startShell().add(command); + } + + public static Shell startRootShell() throws IOException, TimeoutException, RootDeniedException { + return Shell.startRootShell(0, 3); + } + + public static Shell startRootShell(int timeout) throws IOException, TimeoutException, RootDeniedException { + return Shell.startRootShell(timeout, 3); + } + + public static Shell startRootShell(int timeout, int retry) throws IOException, TimeoutException, RootDeniedException { + return Shell.startRootShell(timeout, Shell.defaultContext, retry); + } + + public static Shell startRootShell(int timeout, ShellContext shellContext, int retry) throws IOException, TimeoutException, RootDeniedException { + // keep prompting the user until they accept for x amount of times... + int retries = 0; + + if (Shell.rootShell == null) { + + RootShell.log("Starting Root Shell!"); + String cmd = "su"; + while (Shell.rootShell == null) { + try { + RootShell.log("Trying to open Root Shell, attempt #" + retries); + Shell.rootShell = new Shell(cmd, ShellType.ROOT, shellContext, timeout); + } catch (IOException e) { + if (retries++ >= retry) { + RootShell.log("IOException, could not start shell"); + throw e; + } + } catch (RootDeniedException e) { + if (retries++ >= retry) { + RootShell.log("RootDeniedException, could not start shell"); + throw e; + } + } catch (TimeoutException e) { + if (retries++ >= retry) { + RootShell.log("TimeoutException, could not start shell"); + throw e; + } + } + } + } else if (Shell.rootShell.shellContext != shellContext) { + try { + RootShell.log("Context is different than open shell, switching context... " + Shell.rootShell.shellContext + " VS " + shellContext); + Shell.rootShell.switchRootShellContext(shellContext); + } catch (IOException e) { + if (retries++ >= retry) { + RootShell.log("IOException, could not switch context!"); + throw e; + } + } catch (RootDeniedException e) { + if (retries++ >= retry) { + RootShell.log("RootDeniedException, could not switch context!"); + throw e; + } + } catch (TimeoutException e) { + if (retries++ >= retry) { + RootShell.log("TimeoutException, could not switch context!"); + throw e; + } + } + } else { + RootShell.log("Using Existing Root Shell!"); + } + + return Shell.rootShell; + } + + public static Shell startCustomShell(String shellPath) throws IOException, TimeoutException, RootDeniedException { + return Shell.startCustomShell(shellPath, 0); + } + + public static Shell startCustomShell(String shellPath, int timeout) throws IOException, TimeoutException, RootDeniedException { + + if (Shell.customShell == null) { + RootShell.log("Starting Custom Shell!"); + Shell.customShell = new Shell(shellPath, ShellType.CUSTOM, ShellContext.NORMAL, timeout); + } else { + RootShell.log("Using Existing Custom Shell!"); + } + + return Shell.customShell; + } + + public static Shell startShell() throws IOException, TimeoutException { + return Shell.startShell(0); + } + + public static Shell startShell(int timeout) throws IOException, TimeoutException { + + try { + if (Shell.shell == null) { + RootShell.log("Starting Shell!"); + Shell.shell = new Shell("/system/bin/sh", ShellType.NORMAL, ShellContext.NORMAL, timeout); + } else { + RootShell.log("Using Existing Shell!"); + } + return Shell.shell; + } catch (RootDeniedException e) { + //Root Denied should never be thrown. + throw new IOException(); + } + } + + public Shell switchRootShellContext(ShellContext shellContext) throws IOException, TimeoutException, RootDeniedException { + if (this.shellType == ShellType.ROOT) { + try { + Shell.closeRootShell(); + } catch (Exception e) { + RootShell.log("Problem closing shell while trying to switch context..."); + } + + //create new root shell with new context... + + return Shell.startRootShell(this.shellTimeout, shellContext, 3); + } else { + //can only switch context on a root shell... + RootShell.log("Can only switch context on a root shell!"); + return this; + } + } + + protected static class Worker extends Thread { + + public int exit = -911; + + public Shell shell; + + private Worker(Shell shell) { + this.shell = shell; + } + + public void run() { + + /** + * Trying to open the shell. + * + * We echo "Started" and we look for it in the output. + * + * If we find the output then the shell is open and we return. + * + * If we do not find it then we determine the error and report + * it by setting the value of the variable exit + */ + try { + shell.outputStream.write("echo Started\n"); + shell.outputStream.flush(); + + while (true) { + String line = shell.inputStream.readLine(); + + if (line == null) { + throw new EOFException(); + } else if ("".equals(line)) { + continue; + } else if ("Started".equals(line)) { + this.exit = 1; + setShellOom(); + break; + } + + shell.error = "unknown error occurred."; + } + } catch (IOException e) { + exit = -42; + if (e.getMessage() != null) { + shell.error = e.getMessage(); + } else { + shell.error = "RootAccess denied?."; + } + } + + } + + /* + * setOom for shell processes (sh and su if root shell) and discard outputs + * Negative values make the process LESS likely to be killed in an OOM situation + * Positive values make the process MORE likely to be killed in an OOM situation + */ + private void setShellOom() { + try { + Class processClass = shell.proc.getClass(); + Field field; + try { + field = processClass.getDeclaredField("pid"); + } catch (NoSuchFieldException e) { + field = processClass.getDeclaredField("id"); + } + field.setAccessible(true); + int pid = (Integer) field.get(shell.proc); + shell.outputStream.write("(echo -17 > /proc/" + pid + "/oom_adj) &> /dev/null\n"); + shell.outputStream.write("(echo -17 > /proc/$$/oom_adj) &> /dev/null\n"); + shell.outputStream.flush(); + } catch (Exception e) { + e.printStackTrace(); + } + } + } +} diff --git a/wrappers/android/mynteye/scripts/.gitignore b/wrappers/android/mynteye/scripts/.gitignore new file mode 100644 index 0000000..2340a45 --- /dev/null +++ b/wrappers/android/mynteye/scripts/.gitignore @@ -0,0 +1,2 @@ +/djinni-output-temp/ +/*.yaml \ No newline at end of file diff --git a/wrappers/android/mynteye/scripts/mynteye.djinni b/wrappers/android/mynteye/scripts/mynteye.djinni new file mode 100644 index 0000000..63d94d5 --- /dev/null +++ b/wrappers/android/mynteye/scripts/mynteye.djinni @@ -0,0 +1,66 @@ +@extern "mynteye_types.yaml" + +# Device class to communicate with MYNT® EYE device +device = interface +c { + # Create the device instance + static create(info: device_usb_info): device; + + # Get the model + get_model(): model; + + # Supports the stream or not + supports_stream(stream: stream): bool; + # Supports the capability or not + supports_capability(capabilities: capability): bool; + # Supports the option or not + supports_option(option: option): bool; + # Supports the addon or not + supports_addon(addon: addon): bool; + + # Get all stream requests + get_stream_requests(): list; + # Config the stream request + config_stream_request(request: stream_request); + + # Get the device info + get_info(info: info): string; + + # Get the intrinsics of stream + get_intrinsics(stream: stream): intrinsics; + # Get the extrinsics of stream + get_extrinsics(from: stream, to: stream): extrinsics; + + # Get the intrinsics of motion + get_motion_intrinsics(): motion_intrinsics; + # Get the extrinsics from one stream to motion + get_motion_extrinsics(from: stream): extrinsics; + + # Get the option info + get_option_info(option: option): option_info; + + # Get the option value + get_option_value(option: option): i32; + # Set the option value + set_option_value(option: option, value: i32); + + # Run the option value + run_option_action(option: option): bool; + + # Start capturing the source + start(source: source); + # Stop capturing the source + stop(source: source); + + # Wait the streams are ready + wait_for_streams(); + + # Get the latest data of stream + get_stream_data(stream: stream): stream_data; + # Get the datas of stream + get_stream_datas(stream: stream): list; + + # Enable cache motion datas until get them, otherwise using callback instead + enable_motion_datas(max_size: i32); + # Get the motion datas + get_motion_datas(): list; +} diff --git a/wrappers/android/mynteye/scripts/mynteye_types.djinni b/wrappers/android/mynteye/scripts/mynteye_types.djinni new file mode 100644 index 0000000..e6681eb --- /dev/null +++ b/wrappers/android/mynteye/scripts/mynteye_types.djinni @@ -0,0 +1,323 @@ + +# Device USB information +device_usb_info = record { + # 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; + # Serial number + serial: string; +} + +# Device model +model = enum { + # Standard + standard; + # Standard 2 + standard2; + # Standard 210a + standard210a; +} + +# Formats define how each stream can be encoded +format = enum { + # Greyscale, 8 bits per pixel + grey; + # YUV 4:2:2, 16 bits per pixel + yuyv; + # BGR 8:8:8, 24 bits per pixel + bgr888; + # RGB 8:8:8, 24 bits per pixel + rgb888; +} + +# Stream request +stream_request = record { + # Stream index + index: i32; + # Stream width in pixels + width: i32; + # Stream height in pixels + height: i32; + # Stream pixel format + format: format; + # Stream frames per second + fps: i32; +} + +# Source allows the user to choose which data to be captured +source = enum { + # Video streaming of stereo, color, depth, etc. + video_streaming; + # Motion tracking of IMU (accelerometer, gyroscope) + motion_tracking; + # Enable everything together + all; +} + +# Streams define different type of data +stream = enum { + # Left stream + left; + # Right stream + right; +} + +# Capabilities define the full set of functionality that the device +# might provide +capability = enum { + # Provides stereo stream + stereo; + # Provide stereo color stream + stereo_color; + # Provides color stream + color; + # Provides depth stream + depth; + # Provides point cloud stream + points; + # Provides fisheye stream + fisheye; + # Provides infrared stream + infrared; + # Provides second infrared stream + infrared2; + # Provides IMU (accelerometer, gyroscope) data + imu; +} + +# Camera info fields are read-only strings that can be queried from the device +info = enum { + # Device name + device_name; + # Serial number + serial_number; + # Firmware version + firmware_version; + # Hardware version + hardware_version; + # Spec version + spec_version; + # Lens type + lens_type; + # IMU type + imu_type; + # Nominal baseline + nominal_baseline; +} + +# Camera control options define general configuration controls +option = enum { + # Image gain, valid if manual-exposure + # range: [0,48], default: 24 + gain; + # Image brightness, valid if manual-exposure + # range: [0,240], default: 120 + brightness; + # Image contrast, valid if manual-exposure + # range: [0,255], default: 127 + contrast; + + # Image frame rate, must set IMU_FREQUENCY together + # values: {10,15,20,25,30,35,40,45,50,55,60}, default: 25 + frame_rate; + # IMU frequency, must set FRAME_RATE together + # values: {100,200,250,333,500}, default: 200 + imu_frequency; + + # Exposure mode + # 0: enable auto-exposure + # 1: disable auto-exposure (manual-exposure) + exposure_mode; + # Max gain, valid if auto-exposure + # range of standard 1: [0,48], default: 48 + # range of standard 2: [0,255], default: 8 + max_gain; + # Max exposure time, valid if auto-exposure + # range of standard 1: [0,240], default: 240 + # range of standard 2: [0,1000], default: 333 + max_exposure_time; + # min exposure time, valid if auto-exposure + # range: [0,1000], default: 0 + min_exposure_time; + # Desired brightness, valid if auto-exposure + # range of standard 1: [0,255], default: 192 + # range of standard 2: [1,255], default: 122 + desired_brightness; + + # IR control + # range: [0,160], default: 0 + ir_control; + # HDR mode + # 0: 10-bit + # 1: 12-bit + hdr_mode; + + # The range of accelerometer + # value of standard 1: {4,8,16,32}, default: 8 + # value of standard 2: {6,12,24,48}, default: 12 + accelerometer_range; + # The range of gyroscope + # value of standard 1: {500,1000,2000,4000}, default: 1000 + # value of standard 2: {250,500,1000,2000,4000}, default: 1000 + gyroscope_range; + # The parameter of accelerometer low pass filter + # values: {0,1,2}, default: 2 + accelerometer_low_pass_filter; + # The parameter of gyroscope low pass filter + # values: {23,64}, default: 64 + gyroscope_low_pass_filter; + + # Zero drift calibration + zero_drift_calibration; + # Erase chip + erase_chip; +} + +# Add-On are peripheral modules of our hardware +addon = enum { + # Infrared + infrared; + # Second infrared + infrared2; +} + +# Frame with raw data +frame = interface +c { + # Get the width + width(): i32; + # Get the height + height(): i32; + # Get the pixel format + format(): format; + # Get the size + size(): i32; + # Get the data + data(): binary; +} + +# Image data +img_data = record { + # Image frame id + frame_id: i64; + # Image timestamp in 1us + timestamp: i64; + # Image exposure time, virtual value in [1, 480] + exposure_time: i64; +} + +# IMU data +imu_data = record { + # IMU frame id + frame_id: i64; + # IMU accel or gyro flag + # 0: accel and gyro are both valid + # 1: accel is valid + # 2: gyro is valid + flag: i32; + # IMU timestamp in 1us + timestamp: i64; + # IMU accelerometer data for 3-axis: X, Y, Z. + accel: list; + # IMU gyroscope data for 3-axis: X, Y, Z. + gyro: list; + # IMU temperature + temperature: f64; +} + +# Device stream data +stream_data = interface +c { + img(): img_data; + frame(): frame; + frame_id(): i64; +} + +# Device motion data +motion_data = interface +c { + imu(): imu_data; +} + +# Camera calibration model +calibration_model = enum { + # Pinhole + pinhole; + # Equidistant: KANNALA_BRANDT + kannala_brandt; + # Unknow + unknow; +} + +# Stream intrinsics +intrinsics = record { + # The calibration model + calib_model: calibration_model; + # The width of the image in pixels + width: i32; + # The height of the image in pixels + height: i32; + + # The focal length of the image plane, as a multiple of pixel width (pinhole) + fx: f64; + # The focal length of the image plane, as a multiple of pixel height (pinhole) + fy: f64; + # The horizontal coordinate of the principal point of the image (pinhole) + cx: f64; + # The vertical coordinate of the principal point of the image (pinhole) + cy: f64; + + # The distortion coefficients + # pinhole: k1,k2,p1,p2,k3 + # kannala_brandt: k2,k3,k4,k5,mu,mv,u0,v0 + coeffs: list; +} + +# IMU intrinsics: scale, drift and variances +imu_intrinsics = record { + # Scale matrix 3x3 + # Scale X cross axis cross axis + # cross axis Scale Y cross axis + # cross axis cross axis Scale Z + scale: list; + # Zero-drift: X, Y, Z 1x3 + drift: list; + # Noise density variances 1x3 + noise: list; + # Random walk variances 1x3 + bias: list; +} + +# Motion intrinsics, including accelerometer and gyroscope +motion_intrinsics = record { + # Accelerometer intrinsics + accel: imu_intrinsics; + # Gyroscope intrinsics + gyro: imu_intrinsics; +} + +# Extrinsics, represent how the different datas are connected +extrinsics = record { + # Rotation matrix, 3x3 + rotation: list; + # Translation vector, 1x3 + translation: list; +} + +# Option info +option_info = record { + # Minimum value + min: i32; + # Maximum value + max: i32; + # Default value + def: i32; +} diff --git a/wrappers/android/mynteye/scripts/run_djinni.sh b/wrappers/android/mynteye/scripts/run_djinni.sh new file mode 100755 index 0000000..75d6dd0 --- /dev/null +++ b/wrappers/android/mynteye/scripts/run_djinni.sh @@ -0,0 +1,90 @@ +#! /usr/bin/env bash +set -e +shopt -s nullglob + +base_dir=$(cd "$(dirname "$0")" && pwd) + +# options + +while getopts "d:" opt; do + case "$opt" in + d) djinni_dir="$OPTARG" ;; + ?) echo "Usage: $0 <-d DJINNI_DIR>" + exit 2 ;; + esac +done + +if [ -z "$djinni_dir" ]; then + echo "<-d DJINNI_DIR> option is required" 1>&2 + exit 2 +fi + +# generate + +djinni_run="$djinni_dir/src/run-assume-built" +if [ ! -x "$djinni_run" ]; then + echo "djinni run file not found: $djinni_run" 1>&2 + exit 2 +fi + +temp_out="$base_dir/djinni-output-temp" + +java_package="com.slightech.mynteye" +cpp_namespace="mynteye_jni" + +[ ! -e "$temp_out" ] || rm -r "$temp_out" + +djinni_build() { + local in_idl="$1"; shift + "$djinni_run" \ + --java-out "$temp_out/java" \ + --java-package "$java_package" \ + --java-class-access-modifier "public" \ + --java-generate-interfaces true \ + --java-nullable-annotation "androidx.annotation.Nullable" \ + --java-nonnull-annotation "androidx.annotation.NonNull" \ + --ident-java-field mFooBar \ + \ + --cpp-out "$temp_out/cpp" \ + --cpp-namespace "$cpp_namespace" \ + --ident-cpp-enum-type FooBar \ + --ident-cpp-method FooBar \ + \ + --jni-out "$temp_out/jni" \ + --ident-jni-class NativeFooBar \ + --ident-jni-file NativeFooBar \ + \ + --yaml-out $(dirname "$in_idl") \ + --yaml-out-file "$(basename "$in_idl" .djinni).yaml" \ + \ + --idl "$in_idl" +} + +djinni_build "$base_dir/mynteye_types.djinni" +djinni_build "$base_dir/mynteye.djinni" + +# copy + +mirror() { + local prefix="$1" ; shift + local src="$1" ; shift + local dest="$1" ; shift + mkdir -p "$dest" + rsync -r --delete --checksum --itemize-changes "$src"/ "$dest" | sed "s/^/[$prefix]/" +} + +dst_dir="$base_dir/../libmynteye/src/main" +cpp_out="$dst_dir/cpp/mynteye/cpp" +jni_out="$dst_dir/cpp/mynteye/jni" +java_out="$dst_dir/java/com/slightech/mynteye" + +gen_stamp="$temp_out/gen.stamp" + +echo "Copying generated code to final directories..." +mirror "cpp" "$temp_out/cpp" "$cpp_out" +mirror "jni" "$temp_out/jni" "$jni_out" +mirror "java" "$temp_out/java" "$java_out" + +date > "$gen_stamp" + +echo "djinni completed." diff --git a/wrappers/android/mynteye/settings.gradle b/wrappers/android/mynteye/settings.gradle new file mode 100644 index 0000000..7804b01 --- /dev/null +++ b/wrappers/android/mynteye/settings.gradle @@ -0,0 +1 @@ +include ':app', ':libmynteye', ':libshell' diff --git a/wrappers/android/mynteye/third_party/djinni/support-lib/djinni_common.hpp b/wrappers/android/mynteye/third_party/djinni/support-lib/djinni_common.hpp new file mode 100644 index 0000000..0892a32 --- /dev/null +++ b/wrappers/android/mynteye/third_party/djinni/support-lib/djinni_common.hpp @@ -0,0 +1,33 @@ +// +// Copyright 2015 Dropbox, Inc. +// +// 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. +// + +#pragma once + +#ifdef _MSC_VER + #define DJINNI_WEAK_DEFINITION // weak attribute not supported by MSVC + #define DJINNI_NORETURN_DEFINITION __declspec(noreturn) + #if _MSC_VER < 1900 // snprintf not implemented prior to VS2015 + #define DJINNI_SNPRINTF snprintf + #define noexcept _NOEXCEPT // work-around for missing noexcept VS2015 + #define constexpr // work-around for missing constexpr VS2015 + #else + #define DJINNI_SNPRINTF _snprintf + #endif +#else + #define DJINNI_WEAK_DEFINITION __attribute__((weak)) + #define DJINNI_NORETURN_DEFINITION __attribute__((noreturn)) + #define DJINNI_SNPRINTF snprintf +#endif diff --git a/wrappers/android/mynteye/third_party/djinni/support-lib/jni/Marshal.hpp b/wrappers/android/mynteye/third_party/djinni/support-lib/jni/Marshal.hpp new file mode 100644 index 0000000..fcced9b --- /dev/null +++ b/wrappers/android/mynteye/third_party/djinni/support-lib/jni/Marshal.hpp @@ -0,0 +1,536 @@ +// +// Copyright 2014 Dropbox, Inc. +// +// 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. +// + +#pragma once + +#include "djinni_support.hpp" +#include +#include +#include +#include +#include +#include +#include + +namespace djinni +{ + template + class Primitive + { + public: + using CppType = CppT; + using JniType = JniT; + + static CppType toCpp(JNIEnv* /*jniEnv*/, JniType j) noexcept { return static_cast(j); } + static JniType fromCpp(JNIEnv* /*jniEnv*/, CppType c) noexcept { return static_cast(c); } + + struct Boxed + { + using JniType = jobject; + static CppType toCpp(JNIEnv* jniEnv, JniType j) + { + assert(j != nullptr); + const auto& data = JniClass::get(); + assert(jniEnv->IsInstanceOf(j, data.clazz.get())); + auto ret = Primitive::toCpp(jniEnv, Self::unbox(jniEnv, data.method_unbox, j)); + jniExceptionCheck(jniEnv); + return ret; + } + static LocalRef fromCpp(JNIEnv* jniEnv, CppType c) + { + const auto& data = JniClass::get(); + auto ret = jniEnv->CallStaticObjectMethod(data.clazz.get(), data.method_box, Primitive::fromCpp(jniEnv, c)); + jniExceptionCheck(jniEnv); + return {jniEnv, ret}; + } + }; + + protected: + Primitive(const char* javaClassSpec, + const char* staticBoxMethod, + const char* staticBoxMethodSignature, + const char* unboxMethod, + const char* unboxMethodSignature) + : clazz(jniFindClass(javaClassSpec)) + , method_box(jniGetStaticMethodID(clazz.get(), staticBoxMethod, staticBoxMethodSignature)) + , method_unbox(jniGetMethodID(clazz.get(), unboxMethod, unboxMethodSignature)) + {} + + private: + const GlobalRef clazz; + const jmethodID method_box; + const jmethodID method_unbox; + }; + + class Bool : public Primitive + { + Bool() : Primitive("java/lang/Boolean", "valueOf", "(Z)Ljava/lang/Boolean;", "booleanValue", "()Z") {} + friend JniClass; + friend Primitive; + static JniType unbox(JNIEnv* jniEnv, jmethodID method, jobject j) { + auto result = jniEnv->CallBooleanMethod(j, method); + jniExceptionCheck(jniEnv); + return result; + } + }; + + class I8 : public Primitive + { + I8() : Primitive("java/lang/Byte", "valueOf", "(B)Ljava/lang/Byte;", "byteValue", "()B") {} + friend JniClass; + friend Primitive; + static JniType unbox(JNIEnv* jniEnv, jmethodID method, jobject j) { + auto result = jniEnv->CallByteMethod(j, method); + jniExceptionCheck(jniEnv); + return result; + } + }; + + class I16 : public Primitive + { + I16() : Primitive("java/lang/Short", "valueOf", "(S)Ljava/lang/Short;", "shortValue", "()S") {} + friend JniClass; + friend Primitive; + static JniType unbox(JNIEnv* jniEnv, jmethodID method, jobject j) { + auto result = jniEnv->CallShortMethod(j, method); + jniExceptionCheck(jniEnv); + return result; + } + }; + + class I32 : public Primitive + { + I32() : Primitive("java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;", "intValue", "()I") {} + friend JniClass; + friend Primitive; + static JniType unbox(JNIEnv* jniEnv, jmethodID method, jobject j) { + auto result = jniEnv->CallIntMethod(j, method); + jniExceptionCheck(jniEnv); + return result; + } + }; + + class I64 : public Primitive + { + I64() : Primitive("java/lang/Long", "valueOf", "(J)Ljava/lang/Long;", "longValue", "()J") {} + friend JniClass; + friend Primitive; + static JniType unbox(JNIEnv* jniEnv, jmethodID method, jobject j) { + auto result = jniEnv->CallLongMethod(j, method); + jniExceptionCheck(jniEnv); + return result; + } + }; + + class F32 : public Primitive + { + F32() : Primitive("java/lang/Float", "valueOf", "(F)Ljava/lang/Float;", "floatValue", "()F") {} + friend JniClass; + friend Primitive; + static JniType unbox(JNIEnv* jniEnv, jmethodID method, jobject j) { + auto result = jniEnv->CallFloatMethod(j, method); + jniExceptionCheck(jniEnv); + return result; + } + }; + + class F64 : public Primitive + { + F64() : Primitive("java/lang/Double", "valueOf", "(D)Ljava/lang/Double;", "doubleValue", "()D") {} + friend JniClass; + friend Primitive; + static JniType unbox(JNIEnv* jniEnv, jmethodID method, jobject j) { + auto result = jniEnv->CallDoubleMethod(j, method); + jniExceptionCheck(jniEnv); + return result; + } + }; + + struct String + { + using CppType = std::string; + using JniType = jstring; + + using Boxed = String; + + static CppType toCpp(JNIEnv* jniEnv, JniType j) + { + assert(j != nullptr); + return jniUTF8FromString(jniEnv, j); + } + + static LocalRef fromCpp(JNIEnv* jniEnv, const CppType& c) + { + return {jniEnv, jniStringFromUTF8(jniEnv, c)}; + } + }; + + struct WString + { + using CppType = std::wstring; + using JniType = jstring; + + using Boxed = WString; + + static CppType toCpp(JNIEnv* jniEnv, JniType j) + { + assert(j != nullptr); + return jniWStringFromString(jniEnv, j); + } + + static LocalRef fromCpp(JNIEnv* jniEnv, const CppType& c) + { + return {jniEnv, jniStringFromWString(jniEnv, c)}; + } + }; + + struct Binary + { + using CppType = std::vector; + using JniType = jbyteArray; + + using Boxed = Binary; + + static CppType toCpp(JNIEnv* jniEnv, JniType j) + { + assert(j != nullptr); + + std::vector ret; + jsize length = jniEnv->GetArrayLength(j); + jniExceptionCheck(jniEnv); + + if (!length) { + return ret; + } + + { + auto deleter = [jniEnv, j] (void* c) { + if (c) { + jniEnv->ReleasePrimitiveArrayCritical(j, c, JNI_ABORT); + } + }; + + std::unique_ptr ptr( + reinterpret_cast(jniEnv->GetPrimitiveArrayCritical(j, nullptr)), + deleter + ); + + if (ptr) { + // Construct and then move-assign. This copies the elements only once, + // and avoids having to initialize before filling (as with resize()) + ret = std::vector{ptr.get(), ptr.get() + length}; + } else { + // Something failed... + jniExceptionCheck(jniEnv); + } + } + + return ret; + } + + static LocalRef fromCpp(JNIEnv* jniEnv, const CppType& c) + { + assert(c.size() <= std::numeric_limits::max()); + auto j = LocalRef(jniEnv, jniEnv->NewByteArray(static_cast(c.size()))); + jniExceptionCheck(jniEnv); + // Using .data() on an empty vector is UB + if(!c.empty()) + { + jniEnv->SetByteArrayRegion(j.get(), 0, jsize(c.size()), reinterpret_cast(c.data())); + } + return j; + } + }; + + struct Date + { + using CppType = std::chrono::system_clock::time_point; + using JniType = jobject; + + using Boxed = Date; + + static CppType toCpp(JNIEnv* jniEnv, JniType j) + { + static const auto POSIX_EPOCH = std::chrono::system_clock::from_time_t(0); + assert(j != nullptr); + const auto & data = JniClass::get(); + assert(jniEnv->IsInstanceOf(j, data.clazz.get())); + auto time_millis = jniEnv->CallLongMethod(j, data.method_get_time); + jniExceptionCheck(jniEnv); + return POSIX_EPOCH + std::chrono::milliseconds{time_millis}; + } + + static LocalRef fromCpp(JNIEnv* jniEnv, const CppType& c) + { + static const auto POSIX_EPOCH = std::chrono::system_clock::from_time_t(0); + const auto & data = JniClass::get(); + const auto cpp_millis = std::chrono::duration_cast(c - POSIX_EPOCH); + const jlong millis = static_cast(cpp_millis.count()); + auto j = LocalRef(jniEnv, jniEnv->NewObject(data.clazz.get(), data.constructor, millis)); + jniExceptionCheck(jniEnv); + return j; + } + + private: + Date() = default; + friend ::djinni::JniClass; + + const GlobalRef clazz { jniFindClass("java/util/Date") }; + const jmethodID constructor { jniGetMethodID(clazz.get(), "", "(J)V") }; + const jmethodID method_get_time { jniGetMethodID(clazz.get(), "getTime", "()J") }; + }; + + template