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 @@ ...@@ -7,6 +7,8 @@
<category android:name="android.intent.category.LAUNCHER"/> <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_ATTACHED"/>
<action android:name="android.hardware.usb.action.USB_DEVICE_DETACHED"/> <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"/> <action android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED"/>
</intent-filter> </intent-filter>
......
...@@ -55,6 +55,8 @@ import android.os.PowerManager; ...@@ -55,6 +55,8 @@ import android.os.PowerManager;
import android.os.Bundle; import android.os.Bundle;
import android.app.PendingIntent; import android.app.PendingIntent;
import android.view.WindowManager; import android.view.WindowManager;
import android.os.Bundle;
import android.bluetooth.BluetoothDevice;
import com.hoho.android.usbserial.driver.*; import com.hoho.android.usbserial.driver.*;
import org.qtproject.qt5.android.bindings.QtActivity; import org.qtproject.qt5.android.bindings.QtActivity;
...@@ -162,6 +164,12 @@ public class QGCActivity extends 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 ...@@ -169,6 +177,7 @@ public class QGCActivity extends QtActivity
private static native void nativeDeviceHasDisconnected(int userData); private static native void nativeDeviceHasDisconnected(int userData);
private static native void nativeDeviceException(int userData, String messageA); private static native void nativeDeviceException(int userData, String messageA);
private static native void nativeDeviceNewData(int userData, byte[] dataA); private static native void nativeDeviceNewData(int userData, byte[] dataA);
private static native void nativeUpdateAvailableJoysticks();
// Native C++ functions called to log output // Native C++ functions called to log output
public static native void qgcLogDebug(String message); public static native void qgcLogDebug(String message);
...@@ -200,8 +209,11 @@ public class QGCActivity extends QtActivity ...@@ -200,8 +209,11 @@ public class QGCActivity extends QtActivity
// Register for USB Detach and USB Permission intent // Register for USB Detach and USB Permission intent
IntentFilter filter = new IntentFilter(); IntentFilter filter = new IntentFilter();
filter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);
filter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED); filter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED);
filter.addAction(ACTION_USB_PERMISSION); filter.addAction(ACTION_USB_PERMISSION);
filter.addAction(BluetoothDevice.ACTION_ACL_CONNECTED);
filter.addAction(BluetoothDevice.ACTION_ACL_DISCONNECTED);
_instance.registerReceiver(_instance._usbReceiver, filter); _instance.registerReceiver(_instance._usbReceiver, filter);
// Create intent for usb permission request // Create intent for usb permission request
......
...@@ -73,11 +73,8 @@ JoystickAndroid::~JoystickAndroid() { ...@@ -73,11 +73,8 @@ JoystickAndroid::~JoystickAndroid() {
QMap<QString, Joystick*> JoystickAndroid::discover(MultiVehicleManager* _multiVehicleManager) { QMap<QString, Joystick*> JoystickAndroid::discover(MultiVehicleManager* _multiVehicleManager) {
bool joystickFound = false;
static QMap<QString, Joystick*> ret; static QMap<QString, Joystick*> ret;
_initStatic(); //it's enough to run it once, should be in a static constructor
QMutexLocker lock(&m_mutex); QMutexLocker lock(&m_mutex);
QAndroidJniEnvironment env; QAndroidJniEnvironment env;
...@@ -89,27 +86,29 @@ QMap<QString, Joystick*> JoystickAndroid::discover(MultiVehicleManager* _multiVe ...@@ -89,27 +86,29 @@ QMap<QString, Joystick*> JoystickAndroid::discover(MultiVehicleManager* _multiVe
int SOURCE_GAMEPAD = QAndroidJniObject::getStaticField<jint>("android/view/InputDevice", "SOURCE_GAMEPAD"); int SOURCE_GAMEPAD = QAndroidJniObject::getStaticField<jint>("android/view/InputDevice", "SOURCE_GAMEPAD");
int SOURCE_JOYSTICK = QAndroidJniObject::getStaticField<jint>("android/view/InputDevice", "SOURCE_JOYSTICK"); int SOURCE_JOYSTICK = QAndroidJniObject::getStaticField<jint>("android/view/InputDevice", "SOURCE_JOYSTICK");
QList<QString> names;
for (int i = 0; i < sz; ++i) { for (int i = 0; i < sz; ++i) {
QAndroidJniObject inputDevice = QAndroidJniObject::callStaticObjectMethod("android/view/InputDevice", "getDevice", "(I)Landroid/view/InputDevice;", buff[i]); QAndroidJniObject inputDevice = QAndroidJniObject::callStaticObjectMethod("android/view/InputDevice", "getDevice", "(I)Landroid/view/InputDevice;", buff[i]);
int sources = inputDevice.callMethod<jint>("getSources", "()I"); int sources = inputDevice.callMethod<jint>("getSources", "()I");
if (((sources & SOURCE_GAMEPAD) != SOURCE_GAMEPAD) //check if the input device is interesting to us if (((sources & SOURCE_GAMEPAD) != SOURCE_GAMEPAD) //check if the input device is interesting to us
&& ((sources & SOURCE_JOYSTICK) != SOURCE_JOYSTICK)) continue; && ((sources & SOURCE_JOYSTICK) != SOURCE_JOYSTICK)) continue;
//get id and name // get id and name
QString id = inputDevice.callObjectMethod("getDescriptor", "()Ljava/lang/String;").toString(); QString id = inputDevice.callObjectMethod("getDescriptor", "()Ljava/lang/String;").toString();
QString name = inputDevice.callObjectMethod("getName", "()Ljava/lang/String;").toString(); QString name = inputDevice.callObjectMethod("getName", "()Ljava/lang/String;").toString();
names.push_back(name);
if (joystickFound) { //skipping { if (ret.contains(name)) {
qWarning() << "Skipping joystick:" << name;
continue; continue;
} }
//get number of axis // get number of axis
QAndroidJniObject rangeListNative = inputDevice.callObjectMethod("getMotionRanges", "()Ljava/util/List;"); QAndroidJniObject rangeListNative = inputDevice.callObjectMethod("getMotionRanges", "()Ljava/util/List;");
int axisCount = rangeListNative.callMethod<jint>("size"); int axisCount = rangeListNative.callMethod<jint>("size");
//get number of buttons // get number of buttons
jintArray a = env->NewIntArray(_androidBtnListCount); jintArray a = env->NewIntArray(_androidBtnListCount);
env->SetIntArrayRegion(a,0,_androidBtnListCount,_androidBtnList); env->SetIntArrayRegion(a,0,_androidBtnListCount,_androidBtnList);
QAndroidJniObject btns = inputDevice.callObjectMethod("hasKeys", "([I)[Z", a); QAndroidJniObject btns = inputDevice.callObjectMethod("hasKeys", "([I)[Z", a);
...@@ -123,11 +122,17 @@ QMap<QString, Joystick*> JoystickAndroid::discover(MultiVehicleManager* _multiVe ...@@ -123,11 +122,17 @@ QMap<QString, Joystick*> JoystickAndroid::discover(MultiVehicleManager* _multiVe
qCDebug(JoystickLog) << "\t" << name << "id:" << buff[i] << "axes:" << axisCount << "buttons:" << buttonCount; qCDebug(JoystickLog) << "\t" << name << "id:" << buff[i] << "axes:" << axisCount << "buttons:" << buttonCount;
ret[name] = new JoystickAndroid(name, axisCount, buttonCount, buff[i], _multiVehicleManager); 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; return ret;
} }
...@@ -165,7 +170,6 @@ bool JoystickAndroid::handleGenericMotionEvent(jobject event) { ...@@ -165,7 +170,6 @@ bool JoystickAndroid::handleGenericMotionEvent(jobject event) {
return true; return true;
} }
bool JoystickAndroid::_open(void) { bool JoystickAndroid::_open(void) {
return true; return true;
} }
...@@ -193,8 +197,14 @@ uint8_t JoystickAndroid::_getHat(int hat,int i) { ...@@ -193,8 +197,14 @@ uint8_t JoystickAndroid::_getHat(int hat,int i) {
return 0; return 0;
} }
static JoystickManager *_manager = nullptr;
//helper method //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 //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 //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() { ...@@ -229,5 +239,56 @@ void JoystickAndroid::_initStatic() {
ACTION_DOWN = QAndroidJniObject::getStaticField<jint>("android/view/KeyEvent", "ACTION_DOWN"); ACTION_DOWN = QAndroidJniObject::getStaticField<jint>("android/view/KeyEvent", "ACTION_DOWN");
ACTION_UP = QAndroidJniObject::getStaticField<jint>("android/view/KeyEvent", "ACTION_UP"); 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 ...@@ -16,14 +16,19 @@ class JoystickAndroid : public Joystick, public QtAndroidPrivate::GenericMotionE
{ {
public: public:
JoystickAndroid(const QString& name, int axisCount, int buttonCount, int id, MultiVehicleManager* multiVehicleManager); JoystickAndroid(const QString& name, int axisCount, int buttonCount, int id, MultiVehicleManager* multiVehicleManager);
~JoystickAndroid(); ~JoystickAndroid();
static QMap<QString, Joystick*> discover(MultiVehicleManager* _multiVehicleManager); static bool init(JoystickManager *manager);
static QMap<QString, Joystick*> discover(MultiVehicleManager* _multiVehicleManager);
private: private:
bool handleKeyEvent(jobject event); bool handleKeyEvent(jobject event);
bool handleGenericMotionEvent(jobject event); bool handleGenericMotionEvent(jobject event);
static void setNativeMethods(JoystickManager *manager);
virtual bool _open(); virtual bool _open();
virtual void _close(); virtual void _close();
virtual bool _update(); virtual bool _update();
...@@ -37,7 +42,6 @@ private: ...@@ -37,7 +42,6 @@ private:
bool *btnValue; bool *btnValue;
int *axisValue; int *axisValue;
static void _initStatic();
static int * _androidBtnList; //list of all possible android buttons static int * _androidBtnList; //list of all possible android buttons
static int _androidBtnListCount; 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 * QGroundControl is licensed according to the terms in the file
* COPYING.md in the root of the source code directory. * COPYING.md in the root of the source code directory.
...@@ -29,8 +29,8 @@ const char * JoystickManager::_settingsKeyActiveJoystick = "ActiveJoystick"; ...@@ -29,8 +29,8 @@ const char * JoystickManager::_settingsKeyActiveJoystick = "ActiveJoystick";
JoystickManager::JoystickManager(QGCApplication* app, QGCToolbox* toolbox) JoystickManager::JoystickManager(QGCApplication* app, QGCToolbox* toolbox)
: QGCTool(app, toolbox) : QGCTool(app, toolbox)
, _activeJoystick(NULL) , _activeJoystick(nullptr)
, _multiVehicleManager(NULL) , _multiVehicleManager(nullptr)
{ {
} }
...@@ -54,15 +54,19 @@ void JoystickManager::setToolbox(QGCToolbox *toolbox) ...@@ -54,15 +54,19 @@ void JoystickManager::setToolbox(QGCToolbox *toolbox)
void JoystickManager::init() { void JoystickManager::init() {
#ifdef __sdljoystick__ #ifdef __sdljoystick__
if (JoystickSDL::init()) { if (!JoystickSDL::init()) {
_setActiveJoystickFromSettings(); return;
connect(&_joystickCheckTimer, &QTimer::timeout, this, &JoystickManager::_updateAvailableJoysticks);
_joystickCheckTimer.start(250);
} }
#elif defined(__android__)
_setActiveJoystickFromSettings(); _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 #endif
connect(&_joystickCheckTimer, &QTimer::timeout, this, &JoystickManager::_updateAvailableJoysticks);
_joystickCheckTimerCounter = 5;
_joystickCheckTimer.start(1000);
} }
void JoystickManager::_setActiveJoystickFromSettings(void) void JoystickManager::_setActiveJoystickFromSettings(void)
...@@ -78,7 +82,7 @@ void JoystickManager::_setActiveJoystickFromSettings(void) ...@@ -78,7 +82,7 @@ void JoystickManager::_setActiveJoystickFromSettings(void)
if (_activeJoystick && !newMap.contains(_activeJoystick->name())) { if (_activeJoystick && !newMap.contains(_activeJoystick->name())) {
qCDebug(JoystickManagerLog) << "Active joystick removed"; 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 // 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) ...@@ -97,7 +101,7 @@ void JoystickManager::_setActiveJoystickFromSettings(void)
emit availableJoysticksChanged(); emit availableJoysticksChanged();
if (!_name2JoystickMap.count()) { if (!_name2JoystickMap.count()) {
setActiveJoystick(NULL); setActiveJoystick(nullptr);
return; return;
} }
...@@ -123,7 +127,7 @@ void JoystickManager::setActiveJoystick(Joystick* joystick) ...@@ -123,7 +127,7 @@ void JoystickManager::setActiveJoystick(Joystick* joystick)
{ {
QSettings settings; 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(); qCWarning(JoystickManagerLog) << "Set active not in map" << joystick->name();
return; return;
} }
...@@ -138,7 +142,7 @@ void JoystickManager::setActiveJoystick(Joystick* joystick) ...@@ -138,7 +142,7 @@ void JoystickManager::setActiveJoystick(Joystick* joystick)
_activeJoystick = joystick; _activeJoystick = joystick;
if (_activeJoystick != NULL) { if (_activeJoystick != nullptr) {
qCDebug(JoystickManagerLog) << "Set active:" << _activeJoystick->name(); qCDebug(JoystickManagerLog) << "Set active:" << _activeJoystick->name();
settings.beginGroup(_settingsGroup); settings.beginGroup(_settingsGroup);
...@@ -183,7 +187,7 @@ void JoystickManager::setActiveJoystickName(const QString& name) ...@@ -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 * 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__ #ifdef __sdljoystick__
SDL_Event event; SDL_Event event;
...@@ -205,8 +209,16 @@ void JoystickManager::_updateAvailableJoysticks(void) ...@@ -205,8 +209,16 @@ void JoystickManager::_updateAvailableJoysticks(void)
} }
} }
#elif defined(__android__) #elif defined(__android__)
/* _joystickCheckTimerCounter--;
* TODO: Investigate Android events for Joystick hot plugging _setActiveJoystickFromSettings();
*/ if (_joystickCheckTimerCounter <= 0) {
_joystickCheckTimer.stop();
}
#endif #endif
} }
void JoystickManager::restartJoystickCheckTimer()
{
_joystickCheckTimerCounter = 5;
_joystickCheckTimer.start(1000);
}
...@@ -45,6 +45,8 @@ public: ...@@ -45,6 +45,8 @@ public:
QString activeJoystickName(void); QString activeJoystickName(void);
void setActiveJoystickName(const QString& name); void setActiveJoystickName(const QString& name);
void restartJoystickCheckTimer(void);
// Override from QGCTool // Override from QGCTool
virtual void setToolbox(QGCToolbox *toolbox); virtual void setToolbox(QGCToolbox *toolbox);
...@@ -55,6 +57,7 @@ signals: ...@@ -55,6 +57,7 @@ signals:
void activeJoystickChanged(Joystick* joystick); void activeJoystickChanged(Joystick* joystick);
void activeJoystickNameChanged(const QString& name); void activeJoystickNameChanged(const QString& name);
void availableJoysticksChanged(void); void availableJoysticksChanged(void);
void updateAvailableJoysticksSignal();
private slots: private slots:
void _updateAvailableJoysticks(void); void _updateAvailableJoysticks(void);
...@@ -70,6 +73,7 @@ private: ...@@ -70,6 +73,7 @@ private:
static const char * _settingsGroup; static const char * _settingsGroup;
static const char * _settingsKeyActiveJoystick; static const char * _settingsKeyActiveJoystick;
int _joystickCheckTimerCounter;
QTimer _joystickCheckTimer; 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