feat(android): view mynteye datas

This commit is contained in:
John Zhao 2019-01-27 23:34:47 +08:00
parent 74b71dc161
commit 6988ae803b
12 changed files with 288 additions and 27 deletions

View File

@ -1,6 +1,7 @@
package com.slightech.mynteye.demo;
import android.app.Application;
//import com.stericson.RootShell.RootShell;
import timber.log.Timber;
public class MyApplication extends Application {
@ -16,6 +17,7 @@ public class MyApplication extends Application {
@Override public void onCreate() {
super.onCreate();
Timber.plant(new Timber.DebugTree());
//RootShell.debugMode = true;
}
@Override public void onLowMemory() {

View File

@ -0,0 +1,123 @@
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.MotionData;
import com.slightech.mynteye.Source;
import com.slightech.mynteye.Stream;
import com.slightech.mynteye.StreamData;
import com.slightech.mynteye.StreamRequest;
import java.util.ArrayList;
public final class Mynteye implements Runnable {
private Device mDevice;
private HandlerThread mBackgroundThread;
private Handler mBackgroundHandler;
private boolean mOpened;
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<MotionData> datas, Handler handler);
}
private OnStreamDataReceiveListener mOnStreamDataReceiveListener;
private OnMotionDataReceiveListener mOnMotionDataReceiveListener;
public Mynteye(DeviceUsbInfo info) {
mDevice = Device.create(info);
mOpened = false;
}
public void setOnStreamDataReceiveListener(OnStreamDataReceiveListener l) {
mOnStreamDataReceiveListener = l;
}
public void setOnMotionDataReceiveListener(OnMotionDataReceiveListener l) {
mOnMotionDataReceiveListener = l;
}
public ArrayList<StreamRequest> getStreamRequests() {
return mDevice.getStreamRequests();
}
public void open(StreamRequest request) {
if (mOpened) return;
mOpened = true;
startBackgroundThread();
mDevice.configStreamRequest(request);
mDevice.enableMotionDatas(Integer.MAX_VALUE);
mDevice.start(Source.ALL);
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");
{
ArrayList<MotionData> 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();
}
}
}

View File

@ -1,21 +1,43 @@
package com.slightech.mynteye.demo.ui;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.os.Handler;
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.Device;
import com.slightech.mynteye.DeviceUsbInfo;
import com.slightech.mynteye.Frame;
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.demo.util.RootUtils;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Locale;
import timber.log.Timber;
public class MainActivity extends BaseActivity {
public class MainActivity extends BaseActivity implements 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 Mynteye mMynteye;
private Bitmap mLeftBitmap, mRightBitmap;
@Override
protected void onCreate(Bundle savedInstanceState) {
@ -90,6 +112,83 @@ public class MainActivity extends BaseActivity {
}
private void openDevice(DeviceUsbInfo info) {
mMynteye = new Mynteye(info);
ArrayList<StreamRequest> requests = mMynteye.getStreamRequests();
if (requests.isEmpty()) {
alert("Warning", "There are no streams to request :(");
} else {
ArrayList<String> 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.open(requests.get(position));
});
dialog.setView(listView);
dialog.show();
}
}
@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) {
Bitmap.Config config;
switch (frame.format()) {
case GREY: config = Bitmap.Config.ALPHA_8; break;
case RGB888: config = Bitmap.Config.ARGB_8888; break;
default: Timber.e("Unaccepted stream format"); return;
}
mLeftBitmap = Bitmap.createBitmap(frame.width(), frame.height(), config);
}
mLeftBitmap.copyPixelsFromBuffer(ByteBuffer.wrap(frame.data()));
mLeftImageView.post(() -> mLeftImageView.setImageBitmap(mLeftBitmap));
}
@Override
public void onStreamRightReceive(StreamData data, Handler handler) {
//Timber.i("onStreamRightReceive");
Frame frame = data.frame();
if (mRightBitmap == null) {
Bitmap.Config config;
switch (frame.format()) {
case GREY: config = Bitmap.Config.ALPHA_8; break;
case RGB888: config = Bitmap.Config.ARGB_8888; break;
default: Timber.e("Unaccepted stream format"); return;
}
mRightBitmap = Bitmap.createBitmap(frame.width(), frame.height(), config);
}
mRightBitmap.copyPixelsFromBuffer(ByteBuffer.wrap(frame.data()));
mRightImageView.post(() -> mRightImageView.setImageBitmap(mRightBitmap));
}
@Override
public void onMotionDataReceive(ArrayList<MotionData> datas, Handler handler) {
if (datas.isEmpty()) return;
mTextView.post(() -> mTextView.setText(datas.get(0).imu().toString()));
}
@Override
protected void onDestroy() {
if (mMynteye != null) {
mMynteye.close();
mMynteye = null;
}
super.onDestroy();
}
private void toast(CharSequence text) {

View File

@ -12,11 +12,35 @@
android:id="@+id/text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
android:layout_marginStart="8dp"
android:text="Hello World!"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintBottom_toTopOf="@+id/image_left"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
/>
<ImageView
android:id="@+id/image_left"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toTopOf="@+id/image_right"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/text"
app:layout_constraintVertical_weight="1"
/>
<ImageView
android:id="@+id/image_right"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/image_left"
app:layout_constraintVertical_weight="1"
/>
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -47,8 +47,8 @@ public:
/** Get the datas of stream */
virtual std::vector<std::shared_ptr<::mynteye_jni::StreamData>> GetStreamDatas(::mynteye_jni::Stream stream) = 0;
/** Enable cache motion datas */
virtual void EnableCacheMotionDatas(int32_t max_size) = 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<std::shared_ptr<::mynteye_jni::MotionData>> GetMotionDatas() = 0;

View File

@ -81,30 +81,43 @@ void DeviceImpl::ConfigStreamRequest(
}
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) {
return nullptr;
auto&& data = device_->GetStreamData(from_jni(stream));
return std::make_shared<StreamDataImpl>(data);
}
std::vector<std::shared_ptr<::mynteye_jni::StreamData>>
DeviceImpl::GetStreamDatas(::mynteye_jni::Stream stream) {
return {};
std::vector<std::shared_ptr<::mynteye_jni::StreamData>> datas;
for (auto&& data : device_->GetStreamDatas(from_jni(stream))) {
datas.push_back(std::make_shared<StreamDataImpl>(data));
}
return datas;
}
void DeviceImpl::EnableCacheMotionDatas(int32_t max_size) {
void DeviceImpl::EnableMotionDatas(int32_t max_size) {
device_->EnableMotionDatas(max_size);
}
std::vector<std::shared_ptr<::mynteye_jni::MotionData>>
DeviceImpl::GetMotionDatas() {
return {};
std::vector<std::shared_ptr<::mynteye_jni::MotionData>> datas;
for (auto&& data : device_->GetMotionDatas()) {
datas.push_back(std::make_shared<MotionDataImpl>(data));
}
return datas;
}
} // namespace mynteye_jni

View File

@ -37,8 +37,8 @@ class DeviceImpl : public Device {
/** Get the datas of stream */
std::vector<std::shared_ptr<::mynteye_jni::StreamData>> GetStreamDatas(::mynteye_jni::Stream stream) override;
/** Enable cache motion datas */
void EnableCacheMotionDatas(int32_t max_size) 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<std::shared_ptr<::mynteye_jni::MotionData>> GetMotionDatas() override;

View File

@ -9,13 +9,13 @@ namespace mynteye_jni {
class MotionDataImpl : public MotionData {
public:
using motion_data_t = std::shared_ptr<MYNTEYE_NAMESPACE::device::MotionData>;
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;
auto&& imu = data_.imu;
return {
imu->frame_id,
imu->flag,

View File

@ -10,13 +10,13 @@ namespace mynteye_jni {
class StreamDataImpl : public StreamData {
public:
using stream_data_t = std::shared_ptr<MYNTEYE_NAMESPACE::device::StreamData>;
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;
auto&& img = data_.img;
return {
img->frame_id,
static_cast<int64_t>(img->timestamp),
@ -25,11 +25,11 @@ class StreamDataImpl : public StreamData {
}
std::shared_ptr<::mynteye_jni::Frame> Frame() override {
return std::make_shared<::mynteye_jni::FrameImpl>(data_->frame);
return std::make_shared<::mynteye_jni::FrameImpl>(data_.frame);
}
int64_t FrameId() override {
return data_->frame_id;
return data_.frame_id;
}
private:

View File

@ -109,12 +109,12 @@ CJNIEXPORT jobject JNICALL Java_com_slightech_mynteye_Device_00024CppProxy_nativ
} JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */)
}
CJNIEXPORT void JNICALL Java_com_slightech_mynteye_Device_00024CppProxy_native_1enableCacheMotionDatas(JNIEnv* jniEnv, jobject /*this*/, jlong nativeRef, jint j_maxSize)
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->EnableCacheMotionDatas(::djinni::I32::toCpp(jniEnv, j_maxSize));
ref->EnableMotionDatas(::djinni::I32::toCpp(jniEnv, j_maxSize));
} JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, )
}

View File

@ -34,8 +34,8 @@ public interface Device {
@NonNull
public ArrayList<com.slightech.mynteye.StreamData> getStreamDatas(@NonNull com.slightech.mynteye.Stream stream);
/** Enable cache motion datas */
public void enableCacheMotionDatas(int maxSize);
/** Enable cache motion datas until get them, otherwise using callback instead */
public void enableMotionDatas(int maxSize);
/** Get the motion datas */
@NonNull
@ -135,12 +135,12 @@ public interface Device {
private native ArrayList<com.slightech.mynteye.StreamData> native_getStreamDatas(long _nativeRef, com.slightech.mynteye.Stream stream);
@Override
public void enableCacheMotionDatas(int maxSize)
public void enableMotionDatas(int maxSize)
{
assert !this.destroyed.get() : "trying to use a destroyed object";
native_enableCacheMotionDatas(this.nativeRef, maxSize);
native_enableMotionDatas(this.nativeRef, maxSize);
}
private native void native_enableCacheMotionDatas(long _nativeRef, int maxSize);
private native void native_enableMotionDatas(long _nativeRef, int maxSize);
@Override
public ArrayList<com.slightech.mynteye.MotionData> getMotionDatas()

View File

@ -26,8 +26,8 @@ device = interface +c {
# Get the datas of stream
get_stream_datas(stream: stream): list<stream_data>;
# Enable cache motion datas
enable_cache_motion_datas(max_size: i32);
# 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<motion_data>;
}