From 6af9a1707879cf464df9c76c8b868d21ee89aff3 Mon Sep 17 00:00:00 2001 From: dogmaphobic Date: Mon, 27 Apr 2015 13:08:13 -0400 Subject: [PATCH] More Android work... --- .../qgchelper/UsbDeviceJNI.java | 4 +- .../src/qserialport_android.cpp | 305 ++++++++---------- .../src/qserialportinfo_android.cpp | 6 + src/QGCApplication.cc | 2 + src/QGCFileDialog.cc | 4 +- src/ui/MainWindow.cc | 2 + 6 files changed, 148 insertions(+), 175 deletions(-) diff --git a/android/src/org/qgroundcontrol/qgchelper/UsbDeviceJNI.java b/android/src/org/qgroundcontrol/qgchelper/UsbDeviceJNI.java index cd43b1442..f9bad7086 100644 --- a/android/src/org/qgroundcontrol/qgchelper/UsbDeviceJNI.java +++ b/android/src/org/qgroundcontrol/qgchelper/UsbDeviceJNI.java @@ -60,6 +60,7 @@ public class UsbDeviceJNI extends QtActivity // USED TO DETECT WHEN A DEVICE HAS BEEN UNPLUGGED private BroadcastReceiver m_UsbReceiver = null; private final static ExecutorService m_Executor = Executors.newSingleThreadExecutor(); + private static final String TAG = "QGC_UsbDeviceJNI"; private final static UsbIoManager.Listener m_Listener = new UsbIoManager.Listener() @@ -67,6 +68,7 @@ public class UsbDeviceJNI extends QtActivity @Override public void onRunError(Exception eA, int userDataA) { + Log.e(TAG, "onRunError Exception"); nativeDeviceException(userDataA, eA.getMessage()); } @@ -77,7 +79,6 @@ public class UsbDeviceJNI extends QtActivity } }; - private static final String TAG = "QGC_UsbDeviceJNI"; // NATIVE C++ FUNCTION THAT WILL BE CALLED IF THE DEVICE IS UNPLUGGED private static native void nativeDeviceHasDisconnected(int userDataA); @@ -120,7 +121,6 @@ public class UsbDeviceJNI extends QtActivity return true; } - ///////////////////////////////////////////////////////////////////////////////////////////////////////// // // List all available devices that are not already open. It returns the serial port info diff --git a/libs/qtandroidserialport/src/qserialport_android.cpp b/libs/qtandroidserialport/src/qserialport_android.cpp index e422fd60a..4c15cd2ea 100644 --- a/libs/qtandroidserialport/src/qserialport_android.cpp +++ b/libs/qtandroidserialport/src/qserialport_android.cpp @@ -54,8 +54,8 @@ QT_BEGIN_NAMESPACE #define BAD_PORT 0 -static const char V_jniClassName[] {"org/qgroundcontrol/qgchelper/UsbDeviceJNI"}; -static const char V_TAG[] {"QGC_QSerialPort"}; +static const char kJniClassName[] {"org/qgroundcontrol/qgchelper/UsbDeviceJNI"}; +static const char kJTag[] {"QGC_QSerialPort"}; static void jniDeviceHasDisconnected(JNIEnv *envA, jobject thizA, jint userDataA) { @@ -91,6 +91,15 @@ static void jniDeviceException(JNIEnv *envA, jobject thizA, jint userDataA, jstr } } +void cleanJavaException() +{ + QAndroidJniEnvironment env; + if (env->ExceptionCheck()) { + env->ExceptionDescribe(); + env->ExceptionClear(); + } +} + QSerialPortPrivate::QSerialPortPrivate(QSerialPort *q) : QSerialPortPrivateData(q) , descriptor(-1) @@ -109,57 +118,75 @@ QSerialPortPrivate::QSerialPortPrivate(QSerialPort *q) bool QSerialPortPrivate::open(QIODevice::OpenMode mode) { rwMode = mode; - __android_log_print(ANDROID_LOG_INFO, V_TAG, "Opening %s", systemLocation.toLatin1().data()); + __android_log_print(ANDROID_LOG_INFO, kJTag, "Opening %s", systemLocation.toLatin1().data()); + + __android_log_print(ANDROID_LOG_INFO, kJTag, "Calling Java Open"); + QAndroidJniObject jnameL = QAndroidJniObject::fromString(systemLocation); + cleanJavaException(); + deviceId = QAndroidJniObject::callStaticMethod( + kJniClassName, + "open", + "(Ljava/lang/String;I)I", + jnameL.object(), + (jint)this); + cleanJavaException(); + + isReadStopped = false; + + if (deviceId == BAD_PORT) + { + __android_log_print(ANDROID_LOG_ERROR, kJTag, "Error opening %s", systemLocation.toLatin1().data()); + q_ptr->setError(QSerialPort::DeviceNotFoundError); + return false; + } if (!hasRegisteredFunctions) { + __android_log_print(ANDROID_LOG_INFO, kJTag, "Registering Native Functions"); // REGISTER THE C++ FUNCTION WITH JNI - QAndroidJniEnvironment envL; - - JNINativeMethod methodsL[] { + JNINativeMethod javaMethods[] { {"nativeDeviceHasDisconnected", "(I)V", reinterpret_cast(jniDeviceHasDisconnected)}, {"nativeDeviceNewData", "(I[B)V", reinterpret_cast(jniDeviceNewData)}, {"nativeDeviceException", "(ILjava/lang/String;)V", reinterpret_cast(jniDeviceException)} }; - QAndroidJniObject javaClassL(V_jniClassName); - jclass objectClassL = envL->GetObjectClass(javaClassL.object()); - jint valL = envL->RegisterNatives(objectClassL, methodsL, sizeof(methodsL) / sizeof(JNINativeMethod)); - envL->DeleteLocalRef(objectClassL); + QAndroidJniEnvironment jniEnv; + if (jniEnv->ExceptionCheck()) { + jniEnv->ExceptionDescribe(); + jniEnv->ExceptionClear(); + } + + QAndroidJniObject javaClass(kJniClassName); + if(!javaClass.isValid()) { + __android_log_print(ANDROID_LOG_ERROR, kJTag, "Java class %s not valid", kJniClassName); + return false; + } + jclass objectClass = jniEnv->GetObjectClass(javaClass.object()); + jint val = jniEnv->RegisterNatives(objectClass, javaMethods, sizeof(javaMethods) / sizeof(javaMethods[0])); + jniEnv->DeleteLocalRef(objectClass); hasRegisteredFunctions = true; + __android_log_print(ANDROID_LOG_INFO, kJTag, "Native Functions Registered"); - if (envL->ExceptionCheck()) - envL->ExceptionClear(); + if (jniEnv->ExceptionCheck()) { + jniEnv->ExceptionDescribe(); + jniEnv->ExceptionClear(); + } - if(valL < 0) { - __android_log_print(ANDROID_LOG_ERROR, V_TAG, "Error registering methods"); + if(val < 0) { + __android_log_print(ANDROID_LOG_ERROR, kJTag, "Error registering methods"); q_ptr->setError(QSerialPort::OpenError); return false; } } - QAndroidJniObject jnameL = QAndroidJniObject::fromString(systemLocation); - deviceId = QAndroidJniObject::callStaticMethod( - V_jniClassName, - "open", - "(Ljava/lang/String;I)I", - jnameL.object(), - (jint)this); - - isReadStopped = false; - - if (deviceId == BAD_PORT) - { - __android_log_print(ANDROID_LOG_ERROR, V_TAG, "Error opening %s", systemLocation.toLatin1().data()); - q_ptr->setError(QSerialPort::DeviceNotFoundError); - return false; - } - + __android_log_print(ANDROID_LOG_INFO, kJTag, "Calling Java getDeviceHandle"); + cleanJavaException(); descriptor = QAndroidJniObject::callStaticMethod( - V_jniClassName, + kJniClassName, "getDeviceHandle", "(I)I", deviceId); + cleanJavaException(); if (rwMode == QIODevice::WriteOnly) stopReadThread(); @@ -172,12 +199,14 @@ void QSerialPortPrivate::close() if (deviceId == BAD_PORT) return; - __android_log_print(ANDROID_LOG_INFO, V_TAG, "Closing %s", systemLocation.toLatin1().data()); + __android_log_print(ANDROID_LOG_INFO, kJTag, "Closing %s", systemLocation.toLatin1().data()); + cleanJavaException(); jboolean resultL = QAndroidJniObject::callStaticMethod( - V_jniClassName, + kJniClassName, "close", "(I)Z", deviceId); + cleanJavaException(); descriptor = -1; isCustomBaudRateSupported = false; @@ -196,14 +225,17 @@ bool QSerialPortPrivate::setParameters(int baudRateA, int dataBitsA, int stopBit return false; } - jboolean resultL = QAndroidJniObject::callStaticMethod(V_jniClassName, - "setParameters", - "(IIIII)Z", - deviceId, - baudRateA, - dataBitsA, - stopBitsA, - parityA); + cleanJavaException(); + jboolean resultL = QAndroidJniObject::callStaticMethod( + kJniClassName, + "setParameters", + "(IIIII)Z", + deviceId, + baudRateA, + dataBitsA, + stopBitsA, + parityA); + cleanJavaException(); if(resultL) { @@ -223,11 +255,13 @@ void QSerialPortPrivate::stopReadThread() { if (isReadStopped) return; - - QAndroidJniObject::callStaticMethod(V_jniClassName, - "stopIoManager", - "(I)V", - deviceId); + cleanJavaException(); + QAndroidJniObject::callStaticMethod( + kJniClassName, + "stopIoManager", + "(I)V", + deviceId); + cleanJavaException(); isReadStopped = true; } @@ -237,26 +271,21 @@ void QSerialPortPrivate::startReadThread() { if (!isReadStopped) return; - - QAndroidJniObject::callStaticMethod(V_jniClassName, - "startIoManager", - "(I)V", - deviceId); + cleanJavaException(); + QAndroidJniObject::callStaticMethod( + kJniClassName, + "startIoManager", + "(I)V", + deviceId); + cleanJavaException(); isReadStopped = false; } - - - - QSerialPort::PinoutSignals QSerialPortPrivate::pinoutSignals() { return QSerialPort::NoSignal; } - - - bool QSerialPortPrivate::setDataTerminalReady(bool set) { if (deviceId == BAD_PORT) @@ -264,17 +293,17 @@ bool QSerialPortPrivate::setDataTerminalReady(bool set) q_ptr->setError(QSerialPort::NotOpenError); return false; } - - return QAndroidJniObject::callStaticMethod(V_jniClassName, - "setDataTerminalReady", - "(IZ)Z", - deviceId, - set); + cleanJavaException(); + bool res = QAndroidJniObject::callStaticMethod( + kJniClassName, + "setDataTerminalReady", + "(IZ)Z", + deviceId, + set); + cleanJavaException(); + return res; } - - - bool QSerialPortPrivate::setRequestToSend(bool set) { if (deviceId == BAD_PORT) @@ -282,25 +311,22 @@ bool QSerialPortPrivate::setRequestToSend(bool set) q_ptr->setError(QSerialPort::NotOpenError); return false; } - - return QAndroidJniObject::callStaticMethod(V_jniClassName, - "setRequestToSend", - "(IZ)Z", - deviceId, - set); + cleanJavaException(); + bool res = QAndroidJniObject::callStaticMethod( + kJniClassName, + "setRequestToSend", + "(IZ)Z", + deviceId, + set); + cleanJavaException(); + return res; } - - - bool QSerialPortPrivate::flush() { return writeDataOneShot(); } - - - bool QSerialPortPrivate::clear(QSerialPort::Directions directions) { if (deviceId == BAD_PORT) @@ -323,16 +349,18 @@ bool QSerialPortPrivate::clear(QSerialPort::Directions directions) outputL = true; } - return QAndroidJniObject::callStaticMethod(V_jniClassName, - "purgeBuffers", - "(IZZ)Z", - deviceId, - inputL, - outputL); -} - - + cleanJavaException(); + bool res = QAndroidJniObject::callStaticMethod( + kJniClassName, + "purgeBuffers", + "(IZZ)Z", + deviceId, + inputL, + outputL); + cleanJavaException(); + return res; +} bool QSerialPortPrivate::sendBreak(int duration) { @@ -340,26 +368,17 @@ bool QSerialPortPrivate::sendBreak(int duration) return true; } - - - bool QSerialPortPrivate::setBreakEnabled(bool set) { Q_UNUSED(set); return true; } - - - void QSerialPortPrivate::startWriting() { writeDataOneShot(); } - - - bool QSerialPortPrivate::waitForReadyRead(int msecs) { int origL = readBuffer.size(); @@ -378,41 +397,26 @@ bool QSerialPortPrivate::waitForReadyRead(int msecs) return false; } - - - - bool QSerialPortPrivate::waitForBytesWritten(int msecs) { internalWriteTimeoutMsec = msecs; bool retL = writeDataOneShot(); internalWriteTimeoutMsec = 0; - return retL; } - - - bool QSerialPortPrivate::setBaudRate() { setBaudRate(inputBaudRate, QSerialPort::AllDirections); - return true; } - - - bool QSerialPortPrivate::setBaudRate(qint32 baudRate, QSerialPort::Directions directions) { Q_UNUSED(directions); return setParameters(baudRate, jniDataBits, jniStopBits, jniParity); } - - - bool QSerialPortPrivate::setDataBits(QSerialPort::DataBits dataBits) { int numBitsL = 8; @@ -436,17 +440,12 @@ bool QSerialPortPrivate::setDataBits(QSerialPort::DataBits dataBits) numBitsL = 8; break; } - return setParameters(inputBaudRate, numBitsL, jniStopBits, jniParity); } - - - bool QSerialPortPrivate::setParity(QSerialPort::Parity parity) { int parL = 0; - switch (parity) { case QSerialPort::SpaceParity: @@ -470,17 +469,12 @@ bool QSerialPortPrivate::setParity(QSerialPort::Parity parity) parL = 0; break; } - return setParameters(inputBaudRate, jniDataBits, jniStopBits, parL); } - - - bool QSerialPortPrivate::setStopBits(QSerialPort::StopBits stopBits) { int stopL = 1; - switch (stopBits) { case QSerialPort::TwoStop: @@ -496,29 +490,21 @@ bool QSerialPortPrivate::setStopBits(QSerialPort::StopBits stopBits) stopL = 1; break; } - return setParameters(inputBaudRate, jniDataBits, stopL, jniParity); } - - - bool QSerialPortPrivate::setFlowControl(QSerialPort::FlowControl flowControl) { Q_UNUSED(flowControl); return true; } - - - bool QSerialPortPrivate::setDataErrorPolicy(QSerialPort::DataErrorPolicy policy) { this->policy = policy; return true; } - ////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void QSerialPortPrivate::newDataArrived(char *bytesA, int lengthA) { @@ -550,8 +536,6 @@ void QSerialPortPrivate::exceptionArrived(QString strA) q_ptr->setErrorString(strA); } - - /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool QSerialPortPrivate::writeDataOneShot() { @@ -580,8 +564,6 @@ bool QSerialPortPrivate::writeDataOneShot() return (pendingBytesWritten < 0)? false: true; } - - QSerialPort::SerialPortError QSerialPortPrivate::decodeSystemError() const { QSerialPort::SerialPortError error; @@ -611,8 +593,6 @@ QSerialPort::SerialPortError QSerialPortPrivate::decodeSystemError() const return error; } - - //////////////////////////////////////////////////////////////////////////////////////////////////// qint64 QSerialPortPrivate::writeToPort(const char *data, qint64 maxSize) { @@ -622,32 +602,30 @@ qint64 QSerialPortPrivate::writeToPort(const char *data, qint64 maxSize) return 0; } - QAndroidJniEnvironment envL; - jbyteArray jarrayL = envL->NewByteArray(maxSize); - envL->SetByteArrayRegion(jarrayL, 0, maxSize, (jbyte *)data); - int resultL = QAndroidJniObject::callStaticMethod(V_jniClassName, - "write", - "(I[BI)I", - deviceId, - jarrayL, - internalWriteTimeoutMsec); - - if (envL->ExceptionCheck()) + QAndroidJniEnvironment jniEnv; + jbyteArray jarrayL = jniEnv->NewByteArray(maxSize); + jniEnv->SetByteArrayRegion(jarrayL, 0, maxSize, (jbyte *)data); + if (jniEnv->ExceptionCheck()) + jniEnv->ExceptionClear(); + int resultL = QAndroidJniObject::callStaticMethod( + kJniClassName, + "write", + "(I[BI)I", + deviceId, + jarrayL, + internalWriteTimeoutMsec); + + if (jniEnv->ExceptionCheck()) { - envL->ExceptionClear(); + jniEnv->ExceptionClear(); q_ptr->setErrorString(QStringLiteral("Writing to the device threw an exception")); - envL->DeleteLocalRef(jarrayL); + jniEnv->DeleteLocalRef(jarrayL); return 0; } - - envL->DeleteLocalRef(jarrayL); - + jniEnv->DeleteLocalRef(jarrayL); return resultL; } - - - static inline bool evenParity(quint8 c) { c ^= c >> 4; //(c7 ^ c3)(c6 ^ c2)(c5 ^ c1)(c4 ^ c0) @@ -803,42 +781,27 @@ static const BaudRateMap createStandardBaudRateMap() return baudRateMap; } - - - static const BaudRateMap& standardBaudRateMap() { static const BaudRateMap baudRateMap = createStandardBaudRateMap(); return baudRateMap; } - - - qint32 QSerialPortPrivate::baudRateFromSetting(qint32 setting) { return standardBaudRateMap().key(setting); } - - - qint32 QSerialPortPrivate::settingFromBaudRate(qint32 baudRate) { return standardBaudRateMap().value(baudRate); } - - - QList QSerialPortPrivate::standardBaudRates() { return standardBaudRateMap().keys(); } - - - QSerialPort::Handle QSerialPort::handle() const { Q_D(const QSerialPort); diff --git a/libs/qtandroidserialport/src/qserialportinfo_android.cpp b/libs/qtandroidserialport/src/qserialportinfo_android.cpp index fe711088a..569be0c24 100644 --- a/libs/qtandroidserialport/src/qserialportinfo_android.cpp +++ b/libs/qtandroidserialport/src/qserialportinfo_android.cpp @@ -48,6 +48,8 @@ QT_BEGIN_NAMESPACE static const char V_jniClassName[] {"org/qgroundcontrol/qgchelper/UsbDeviceJNI"}; static const char V_TAG[] {"QGC_QSerialPortInfo"}; +extern void cleanJavaException(); + QList availablePortsByFiltersOfDevices(bool &ok) { QList serialPortInfoList; @@ -117,22 +119,26 @@ QList QSerialPortInfo::standardBaudRates() bool QSerialPortInfo::isBusy() const { QAndroidJniObject jstrL = QAndroidJniObject::fromString(d_ptr->portName); + cleanJavaException(); jboolean resultL = QAndroidJniObject::callStaticMethod( V_jniClassName, "isDeviceNameOpen", "(Ljava/lang/String;)Z", jstrL.object()); + cleanJavaException(); return resultL; } bool QSerialPortInfo::isValid() const { QAndroidJniObject jstrL = QAndroidJniObject::fromString(d_ptr->portName); + cleanJavaException(); jboolean resultL = QAndroidJniObject::callStaticMethod( V_jniClassName, "isDeviceNameValid", "(Ljava/lang/String;)Z", jstrL.object()); + cleanJavaException(); return resultL; } diff --git a/src/QGCApplication.cc b/src/QGCApplication.cc index b9ad6c733..ba87622c7 100644 --- a/src/QGCApplication.cc +++ b/src/QGCApplication.cc @@ -104,7 +104,9 @@ QGCApplication::QGCApplication(int &argc, char* argv[], bool unitTesting) : _app = this; // This prevents usage of QQuickWidget to fail since it doesn't support native widget siblings +#ifndef __android__ setAttribute(Qt::AA_DontCreateNativeWidgetSiblings); +#endif #ifdef QT_DEBUG // First thing we want to do is set up the qtlogging.ini file. If it doesn't already exist we copy diff --git a/src/QGCFileDialog.cc b/src/QGCFileDialog.cc index b3160b50c..fd9a9e04e 100644 --- a/src/QGCFileDialog.cc +++ b/src/QGCFileDialog.cc @@ -217,10 +217,10 @@ void QGCFileDialog::_validate(Options& options) Q_ASSERT(qgcApp()); Q_ASSERT_X(QThread::currentThread() == qgcApp()->thread(), "Threading issue", "QGCFileDialog can only be called from main thread"); - +#ifndef __android__ // On OSX native dialog can hang so we always use Qt dialogs options |= DontUseNativeDialog; - +#endif if (MainWindow::instance()) { MainWindow::instance()->hideSplashScreen(); } diff --git a/src/ui/MainWindow.cc b/src/ui/MainWindow.cc index b84dc7611..a10dd0101 100644 --- a/src/ui/MainWindow.cc +++ b/src/ui/MainWindow.cc @@ -183,8 +183,10 @@ MainWindow::MainWindow(QSplashScreen* splashScreen) // Qt 4 on Ubuntu does place the native menubar correctly so on Linux we revert back to in-window menu bar. // TODO: Check that this is still necessary on Qt5 on Ubuntu #ifdef Q_OS_LINUX +#ifndef __android__ menuBar()->setNativeMenuBar(false); #endif +#endif #ifdef UNITTEST_BUILD QAction* qmlTestAction = new QAction("Test QML palette and controls", NULL); -- 2.22.0