Skip to content

Commit

Permalink
Separate Out Android Init
Browse files Browse the repository at this point in the history
  • Loading branch information
HTRamsey authored and DonLakeFlyer committed Apr 11, 2024
1 parent f87af3f commit 38eeeac
Show file tree
Hide file tree
Showing 3 changed files with 167 additions and 121 deletions.
145 changes: 145 additions & 0 deletions android/src/AndroidInit.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
#include "AndroidInterface.h"
#ifndef NO_SERIAL_LINK
#include "qserialport.h"
#endif
#include "JoystickAndroid.h"

#include <QtCore/QJniEnvironment>
#include <QtCore/QJniObject>
#include <QtCore/QDebug>
#include <QtCore/QLoggingCategory>

#include <jni.h>
#include <android/log.h>

//-----------------------------------------------------------------------------

extern int main(int argc, char *argv[]);
static const char kJniQGCActivityClassName[] {"org/mavlink/qgroundcontrol/QGCActivity"};
static Q_LOGGING_CATEGORY(AndroidInitLog, "qgc.android.init");
static jobject _context = nullptr;
static jobject _class_loader = nullptr;

//-----------------------------------------------------------------------------

extern "C"
{
void gst_amc_jni_set_java_vm(JavaVM *java_vm);

jobject gst_android_get_application_class_loader(void)
{
return _class_loader;
}
}

//-----------------------------------------------------------------------------

static void cleanJavaException()
{
QJniEnvironment env;
if (env->ExceptionCheck())
{
env->ExceptionDescribe();
env->ExceptionClear();
}
}

//-----------------------------------------------------------------------------

static void jniInit(JNIEnv* env, jobject context)
{
qCDebug(AndroidInitLog) << Q_FUNC_INFO;

const jclass context_cls = env->GetObjectClass(context);
if(!context_cls)
{
return;
}

const jmethodID get_class_loader_id = env->GetMethodID(context_cls, "getClassLoader", "()Ljava/lang/ClassLoader;");
if(env->ExceptionCheck())
{
env->ExceptionDescribe();
env->ExceptionClear();
return;
}

const jobject class_loader = env->CallObjectMethod(context, get_class_loader_id);
if (env->ExceptionCheck())
{
env->ExceptionDescribe();
env->ExceptionClear();
return;
}

_context = env->NewGlobalRef(context);
_class_loader = env->NewGlobalRef(class_loader);
}

//-----------------------------------------------------------------------------

static jint jniSetNativeMethods(void)
{
qCDebug(AndroidInitLog) << Q_FUNC_INFO;

const JNINativeMethod javaMethods[]
{
{"nativeInit", "()V", reinterpret_cast<void *>(jniInit)}
};

cleanJavaException();

QJniEnvironment jniEnv;
jclass objectClass = jniEnv->FindClass(kJniQGCActivityClassName);
if(!objectClass)
{
qCWarning(AndroidInitLog) << "Couldn't find class:" << kJniQGCActivityClassName;
return JNI_ERR;
}

const jint val = jniEnv->RegisterNatives(objectClass, javaMethods, sizeof(javaMethods) / sizeof(javaMethods[0]));
if(val < 0)
{
qCWarning(AndroidInitLog) << "Error registering methods: " << val;
}
else
{
qCDebug(AndroidInitLog) << "Main Native Functions Registered";
}

cleanJavaException();

return JNI_OK;
}

//-----------------------------------------------------------------------------
jint JNI_OnLoad(JavaVM* vm, void* reserved)
{
Q_UNUSED(reserved);

qCDebug(AndroidInitLog) << Q_FUNC_INFO;

JNIEnv* env;
if(vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK)
{
return JNI_ERR;
}

if(jniSetNativeMethods() != JNI_OK)
{
return JNI_ERR;
}

#ifdef QGC_GST_STREAMING
// Tell the androidmedia plugin about the Java VM
gst_amc_jni_set_java_vm(vm);
#endif

#ifndef NO_SERIAL_LINK
QSerialPort::setNativeMethods();
#endif

JoystickAndroid::setNativeMethods();

return JNI_VERSION_1_6;
}
19 changes: 13 additions & 6 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -87,12 +87,19 @@ target_link_libraries(qgc
target_include_directories(qgc PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})

if(ANDROID)
target_sources(qgc
PRIVATE
${CMAKE_SOURCE_DIR}/android/src/AndroidInterface.cc
${CMAKE_SOURCE_DIR}/android/src/AndroidInterface.h
)
target_include_directories(qgc PUBLIC ${CMAKE_SOURCE_DIR}/android/src)
target_sources(qgc
PUBLIC
${CMAKE_SOURCE_DIR}/android/src/AndroidInit.cpp
${CMAKE_SOURCE_DIR}/android/src/AndroidInterface.cc
${CMAKE_SOURCE_DIR}/android/src/AndroidInterface.h
)

target_link_libraries(qgc
PUBLIC
qtandroidserialport
)

target_include_directories(qgc PUBLIC ${CMAKE_SOURCE_DIR}/android/src)
else()
target_sources(qgc
PRIVATE
Expand Down
124 changes: 9 additions & 115 deletions src/main.cc
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,18 @@
#include <iostream>

#ifndef __mobile__
#ifndef NO_SERIAL_LINK
#include <QSerialPort>
#endif
#include "QGCSerialPortInfo.h"
#include "RunGuard.h"
#ifndef NO_SERIAL_LINK
#include <QSerialPort>
#endif

#ifdef Q_OS_ANDROID
#include "AndroidInterface.h"
#ifndef NO_SERIAL_LINK
#include "qserialport.h"
#endif
#endif

#ifdef UNITTEST_BUILD
Expand Down Expand Up @@ -79,119 +86,6 @@ int WindowsCrtReportHook(int reportType, char* message, int* returnValue)

#endif

#if defined(Q_OS_ANDROID)
#include <jni.h>
#include "AndroidInterface.h"
#include "JoystickAndroid.h"
#if !defined(NO_SERIAL_LINK)
#include "qserialport.h"
#endif

static jobject _class_loader = nullptr;
static jobject _context = nullptr;

//-----------------------------------------------------------------------------
extern "C" {
void gst_amc_jni_set_java_vm(JavaVM *java_vm);

jobject gst_android_get_application_class_loader(void)
{
return _class_loader;
}
}

//-----------------------------------------------------------------------------
static void
gst_android_init(JNIEnv* env, jobject context)
{
jobject class_loader = nullptr;

jclass context_cls = env->GetObjectClass(context);
if (!context_cls) {
return;
}

jmethodID get_class_loader_id = env->GetMethodID(context_cls, "getClassLoader", "()Ljava/lang/ClassLoader;");
if (env->ExceptionCheck()) {
env->ExceptionDescribe();
env->ExceptionClear();
return;
}

class_loader = env->CallObjectMethod(context, get_class_loader_id);
if (env->ExceptionCheck()) {
env->ExceptionDescribe();
env->ExceptionClear();
return;
}

_context = env->NewGlobalRef(context);
_class_loader = env->NewGlobalRef (class_loader);
}

//-----------------------------------------------------------------------------
static const char kJniQGCActivityClassName[] {"org/mavlink/qgroundcontrol/QGCActivity"};

void setNativeMethods(void)
{
JNINativeMethod javaMethods[] {
{"nativeInit", "()V", reinterpret_cast<void *>(gst_android_init)}
};

QJniEnvironment jniEnv;
if (jniEnv->ExceptionCheck()) {
jniEnv->ExceptionDescribe();
jniEnv->ExceptionClear();
}

jclass objectClass = jniEnv->FindClass(kJniQGCActivityClassName);
if(!objectClass) {
qWarning() << "Couldn't find class:" << kJniQGCActivityClassName;
return;
}

jint val = jniEnv->RegisterNatives(objectClass, javaMethods, sizeof(javaMethods) / sizeof(javaMethods[0]));

if (val < 0) {
qWarning() << "Error registering methods: " << val;
} else {
qDebug() << "Main Native Functions Registered";
}

if (jniEnv->ExceptionCheck()) {
jniEnv->ExceptionDescribe();
jniEnv->ExceptionClear();
}
}

//-----------------------------------------------------------------------------
jint JNI_OnLoad(JavaVM* vm, void* reserved)
{
Q_UNUSED(reserved);

qDebug() << "JNI_OnLoa QGC called";
JNIEnv* env;
if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
return -1;
}

setNativeMethods();

#if defined(QGC_GST_STREAMING)
// Tell the androidmedia plugin about the Java VM
gst_amc_jni_set_java_vm(vm);
#endif

#if !defined(NO_SERIAL_LINK)
QSerialPort::setNativeMethods();
#endif

JoystickAndroid::setNativeMethods();

return JNI_VERSION_1_6;
}
#endif

// To shut down QGC on Ctrl+C on Linux
#ifdef Q_OS_LINUX
#include <csignal>
Expand Down

0 comments on commit 38eeeac

Please sign in to comment.