Unverified Commit b5dc7ed1 authored by Gus Grubba's avatar Gus Grubba Committed by GitHub

Merge pull request #7148 from MatejFranceskin/pr-android-joystick2

PR android joystick improvement v2
parents 647dc7fb 2801f206
......@@ -7,6 +7,8 @@
<category android:name="android.intent.category.LAUNCHER"/>
<action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"/>
<action android:name="android.hardware.usb.action.USB_DEVICE_DETACHED"/>
<action android:name="android.bluetooth.device.action.ACL_CONNECTED" />
<action android:name="android.bluetooth.device.action.ACL_DISCONNECTED" />
<action android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED"/>
</intent-filter>
......
......@@ -55,6 +55,8 @@ import android.os.PowerManager;
import android.os.Bundle;
import android.app.PendingIntent;
import android.view.WindowManager;
import android.os.Bundle;
import android.bluetooth.BluetoothDevice;
import com.hoho.android.usbserial.driver.*;
import org.qtproject.qt5.android.bindings.QtActivity;
......@@ -162,6 +164,12 @@ public class QGCActivity extends QtActivity
}
}
}
try {
nativeUpdateAvailableJoysticks();
} catch(Exception e) {
Log.e(TAG, "Exception nativeUpdateAvailableJoysticks()");
}
}
};
......@@ -169,6 +177,7 @@ public class QGCActivity extends QtActivity
private static native void nativeDeviceHasDisconnected(int userData);
private static native void nativeDeviceException(int userData, String messageA);
private static native void nativeDeviceNewData(int userData, byte[] dataA);
private static native void nativeUpdateAvailableJoysticks();
// Native C++ functions called to log output
public static native void qgcLogDebug(String message);
......@@ -200,8 +209,11 @@ public class QGCActivity extends QtActivity
// Register for USB Detach and USB Permission intent
IntentFilter filter = new IntentFilter();
filter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);
filter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED);
filter.addAction(ACTION_USB_PERMISSION);
filter.addAction(BluetoothDevice.ACTION_ACL_CONNECTED);
filter.addAction(BluetoothDevice.ACTION_ACL_DISCONNECTED);
_instance.registerReceiver(_instance._usbReceiver, filter);
// Create intent for usb permission request
......
......@@ -73,11 +73,8 @@ JoystickAndroid::~JoystickAndroid() {
QMap<QString, Joystick*> JoystickAndroid::discover(MultiVehicleManager* _multiVehicleManager) {
bool joystickFound = false;
static QMap<QString, Joystick*> ret;
_initStatic(); //it's enough to run it once, should be in a static constructor
QMutexLocker lock(&m_mutex);
QAndroidJniEnvironment env;
......@@ -89,27 +86,29 @@ QMap<QString, Joystick*> JoystickAndroid::discover(MultiVehicleManager* _multiVe
int SOURCE_GAMEPAD = QAndroidJniObject::getStaticField<jint>("android/view/InputDevice", "SOURCE_GAMEPAD");
int SOURCE_JOYSTICK = QAndroidJniObject::getStaticField<jint>("android/view/InputDevice", "SOURCE_JOYSTICK");
QList<QString> names;
for (int i = 0; i < sz; ++i) {
QAndroidJniObject inputDevice = QAndroidJniObject::callStaticObjectMethod("android/view/InputDevice", "getDevice", "(I)Landroid/view/InputDevice;", buff[i]);
int sources = inputDevice.callMethod<jint>("getSources", "()I");
if (((sources & SOURCE_GAMEPAD) != SOURCE_GAMEPAD) //check if the input device is interesting to us
&& ((sources & SOURCE_JOYSTICK) != SOURCE_JOYSTICK)) continue;
//get id and name
// get id and name
QString id = inputDevice.callObjectMethod("getDescriptor", "()Ljava/lang/String;").toString();
QString name = inputDevice.callObjectMethod("getName", "()Ljava/lang/String;").toString();
names.push_back(name);
if (joystickFound) { //skipping {
qWarning() << "Skipping joystick:" << name;
if (ret.contains(name)) {
continue;
}
//get number of axis
// get number of axis
QAndroidJniObject rangeListNative = inputDevice.callObjectMethod("getMotionRanges", "()Ljava/util/List;");
int axisCount = rangeListNative.callMethod<jint>("size");
//get number of buttons
// get number of buttons
jintArray a = env->NewIntArray(_androidBtnListCount);
env->SetIntArrayRegion(a,0,_androidBtnListCount,_androidBtnList);
QAndroidJniObject btns = inputDevice.callObjectMethod("hasKeys", "([I)[Z", a);
......@@ -123,11 +122,17 @@ QMap<QString, Joystick*> JoystickAndroid::discover(MultiVehicleManager* _multiVe
qCDebug(JoystickLog) << "\t" << name << "id:" << buff[i] << "axes:" << axisCount << "buttons:" << buttonCount;
ret[name] = new JoystickAndroid(name, axisCount, buttonCount, buff[i], _multiVehicleManager);
joystickFound = true;
}
env->ReleaseIntArrayElements(jarr, buff, 0);
for (auto i = ret.begin(); i != ret.end();) {
if (!names.contains(i.key())) {
i = ret.erase(i);
} else {
i++;
}
}
env->ReleaseIntArrayElements(jarr, buff, 0);
return ret;
}
......@@ -165,7 +170,6 @@ bool JoystickAndroid::handleGenericMotionEvent(jobject event) {
return true;
}
bool JoystickAndroid::_open(void) {
return true;
}
......@@ -193,8 +197,14 @@ uint8_t JoystickAndroid::_getHat(int hat,int i) {
return 0;
}
static JoystickManager *_manager = nullptr;
//helper method
void JoystickAndroid::_initStatic() {
bool JoystickAndroid::init(JoystickManager *manager) {
if (_manager == nullptr) {
setNativeMethods(manager);
}
//this gets list of all possible buttons - this is needed to check how many buttons our gamepad supports
//instead of the whole logic below we could have just a simple array of hardcoded int values as these 'should' not change
......@@ -229,5 +239,56 @@ void JoystickAndroid::_initStatic() {
ACTION_DOWN = QAndroidJniObject::getStaticField<jint>("android/view/KeyEvent", "ACTION_DOWN");
ACTION_UP = QAndroidJniObject::getStaticField<jint>("android/view/KeyEvent", "ACTION_UP");
return true;
}
static const char kJniClassName[] {"org/mavlink/qgroundcontrol/QGCActivity"};
static void jniUpdateAvailableJoysticks(JNIEnv *envA, jobject thizA)
{
Q_UNUSED(envA);
Q_UNUSED(thizA);
if (_manager != nullptr) {
qCDebug(JoystickLog) << "jniUpdateAvailableJoysticks triggered";
emit _manager->updateAvailableJoysticksSignal();
}
}
void JoystickAndroid::setNativeMethods(JoystickManager *manager)
{
qCDebug(JoystickLog) << "Registering Native Functions";
_manager = manager;
// REGISTER THE C++ FUNCTION WITH JNI
JNINativeMethod javaMethods[] {
{"nativeUpdateAvailableJoysticks", "()V", reinterpret_cast<void *>(jniUpdateAvailableJoysticks)}
};
QAndroidJniEnvironment jniEnv;
if (jniEnv->ExceptionCheck()) {
jniEnv->ExceptionDescribe();
jniEnv->ExceptionClear();
}
jclass objectClass = jniEnv->FindClass(kJniClassName);
if(!objectClass) {
qWarning() << "Couldn't find class:" << kJniClassName;
return;
}
jint val = jniEnv->RegisterNatives(objectClass, javaMethods, sizeof(javaMethods) / sizeof(javaMethods[0]));
if (val < 0) {
qWarning() << "Error registering methods: " << val;
} else {
qCDebug(JoystickLog) << "Native Functions Registered";
}
if (jniEnv->ExceptionCheck()) {
jniEnv->ExceptionDescribe();
jniEnv->ExceptionClear();
}
}
......@@ -16,14 +16,19 @@ class JoystickAndroid : public Joystick, public QtAndroidPrivate::GenericMotionE
{
public:
JoystickAndroid(const QString& name, int axisCount, int buttonCount, int id, MultiVehicleManager* multiVehicleManager);
~JoystickAndroid();
static QMap<QString, Joystick*> discover(MultiVehicleManager* _multiVehicleManager);
static bool init(JoystickManager *manager);
static QMap<QString, Joystick*> discover(MultiVehicleManager* _multiVehicleManager);
private:
bool handleKeyEvent(jobject event);
bool handleGenericMotionEvent(jobject event);
static void setNativeMethods(JoystickManager *manager);
virtual bool _open();
virtual void _close();
virtual bool _update();
......@@ -37,7 +42,6 @@ private:
bool *btnValue;
int *axisValue;
static void _initStatic();
static int * _androidBtnList; //list of all possible android buttons
static int _androidBtnListCount;
......
/****************************************************************************
*
* (c) 2009-2016 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
* (c) 2009-2019 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
*
* QGroundControl is licensed according to the terms in the file
* COPYING.md in the root of the source code directory.
......@@ -29,8 +29,8 @@ const char * JoystickManager::_settingsKeyActiveJoystick = "ActiveJoystick";
JoystickManager::JoystickManager(QGCApplication* app, QGCToolbox* toolbox)
: QGCTool(app, toolbox)
, _activeJoystick(NULL)
, _multiVehicleManager(NULL)
, _activeJoystick(nullptr)
, _multiVehicleManager(nullptr)
{
}
......@@ -54,15 +54,19 @@ void JoystickManager::setToolbox(QGCToolbox *toolbox)
void JoystickManager::init() {
#ifdef __sdljoystick__
if (JoystickSDL::init()) {
_setActiveJoystickFromSettings();
connect(&_joystickCheckTimer, &QTimer::timeout, this, &JoystickManager::_updateAvailableJoysticks);
_joystickCheckTimer.start(250);
if (!JoystickSDL::init()) {
return;
}
#elif defined(__android__)
_setActiveJoystickFromSettings();
//TODO: Investigate Android events for Joystick hot plugging & run _joystickCheckTimer if possible
#elif defined(__android__)
if (!JoystickAndroid::init(this)) {
return;
}
connect(this, &JoystickManager::updateAvailableJoysticksSignal, this, &JoystickManager::restartJoystickCheckTimer);
#endif
connect(&_joystickCheckTimer, &QTimer::timeout, this, &JoystickManager::_updateAvailableJoysticks);
_joystickCheckTimerCounter = 5;
_joystickCheckTimer.start(1000);
}
void JoystickManager::_setActiveJoystickFromSettings(void)
......@@ -78,7 +82,7 @@ void JoystickManager::_setActiveJoystickFromSettings(void)
if (_activeJoystick && !newMap.contains(_activeJoystick->name())) {
qCDebug(JoystickManagerLog) << "Active joystick removed";
setActiveJoystick(NULL);
setActiveJoystick(nullptr);
}
// Check to see if our current mapping contains any joysticks that are not in the new mapping
......@@ -97,7 +101,7 @@ void JoystickManager::_setActiveJoystickFromSettings(void)
emit availableJoysticksChanged();
if (!_name2JoystickMap.count()) {
setActiveJoystick(NULL);
setActiveJoystick(nullptr);
return;
}
......@@ -123,7 +127,7 @@ void JoystickManager::setActiveJoystick(Joystick* joystick)
{
QSettings settings;
if (joystick != NULL && !_name2JoystickMap.contains(joystick->name())) {
if (joystick != nullptr && !_name2JoystickMap.contains(joystick->name())) {
qCWarning(JoystickManagerLog) << "Set active not in map" << joystick->name();
return;
}
......@@ -138,7 +142,7 @@ void JoystickManager::setActiveJoystick(Joystick* joystick)
_activeJoystick = joystick;
if (_activeJoystick != NULL) {
if (_activeJoystick != nullptr) {
qCDebug(JoystickManagerLog) << "Set active:" << _activeJoystick->name();
settings.beginGroup(_settingsGroup);
......@@ -183,7 +187,7 @@ void JoystickManager::setActiveJoystickName(const QString& name)
/*
* TODO: move this to the right place: JoystickSDL.cc and JoystickAndroid.cc respectively and call through Joystick.cc
*/
void JoystickManager::_updateAvailableJoysticks(void)
void JoystickManager::_updateAvailableJoysticks()
{
#ifdef __sdljoystick__
SDL_Event event;
......@@ -205,8 +209,16 @@ void JoystickManager::_updateAvailableJoysticks(void)
}
}
#elif defined(__android__)
/*
* TODO: Investigate Android events for Joystick hot plugging
*/
_joystickCheckTimerCounter--;
_setActiveJoystickFromSettings();
if (_joystickCheckTimerCounter <= 0) {
_joystickCheckTimer.stop();
}
#endif
}
void JoystickManager::restartJoystickCheckTimer()
{
_joystickCheckTimerCounter = 5;
_joystickCheckTimer.start(1000);
}
......@@ -45,6 +45,8 @@ public:
QString activeJoystickName(void);
void setActiveJoystickName(const QString& name);
void restartJoystickCheckTimer(void);
// Override from QGCTool
virtual void setToolbox(QGCToolbox *toolbox);
......@@ -55,6 +57,7 @@ signals:
void activeJoystickChanged(Joystick* joystick);
void activeJoystickNameChanged(const QString& name);
void availableJoysticksChanged(void);
void updateAvailableJoysticksSignal();
private slots:
void _updateAvailableJoysticks(void);
......@@ -70,6 +73,7 @@ private:
static const char * _settingsGroup;
static const char * _settingsKeyActiveJoystick;
int _joystickCheckTimerCounter;
QTimer _joystickCheckTimer;
};
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment