Forward Service.onBind notification to Qt

It is needed to implement Android Binder in Qt.

Change-Id: I8f6f8ef778f97a444a1b16d6f62e211e188b65cc
Reviewed-by: Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@qt.io>
This commit is contained in:
BogDan Vatra 2016-11-08 17:12:05 +02:00
parent cfbe03a6e0
commit 4f7507c523
5 changed files with 77 additions and 4 deletions

View File

@ -51,11 +51,12 @@ import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ActivityInfo;
import android.net.Uri;
import android.os.Build;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.content.ClipboardManager;
import android.content.ClipboardManager.OnPrimaryClipChangedListener;
import android.os.Build;
import android.util.Log;
import android.view.ContextMenu;
import android.view.KeyEvent;
@ -908,4 +909,9 @@ public class QtNative
private static native void setNativeActivity(Activity activity);
private static native void setNativeService(Service service);
// activity methods
// service methods
public static native IBinder onBind(Intent intent);
// service methods
}

View File

@ -53,6 +53,7 @@ import android.net.LocalSocket;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.ResultReceiver;
import android.text.method.MetaKeyKeyListener;
import android.util.Base64;
@ -187,4 +188,11 @@ public class QtServiceDelegate
{
QtNative.quitQtCoreApplication();
}
public IBinder onBind(Intent intent)
{
synchronized (this) {
return QtNative.onBind(intent);
}
}
}

View File

@ -75,6 +75,11 @@ static jmethodID g_hideSplashScreenMethodID = Q_NULLPTR;
Q_GLOBAL_STATIC(std::deque<QtAndroidPrivate::Runnable>, g_pendingRunnables);
static QBasicMutex g_pendingRunnablesMutex;
Q_GLOBAL_STATIC_WITH_ARGS(QtAndroidPrivate::OnBindListener*, g_onBindListener, (nullptr));
Q_GLOBAL_STATIC(QMutex, g_onBindListenerMutex);
Q_GLOBAL_STATIC(QSemaphore, g_waitForServiceSetupSemaphore);
Q_GLOBAL_STATIC(QAtomicInt, g_serviceSetupLockers);
class PermissionsResultClass : public QObject
{
Q_OBJECT
@ -511,7 +516,7 @@ void QtAndroidPrivate::requestPermissions(JNIEnv *env, const QStringList &permis
}, env);
}
QHash<QString, QtAndroidPrivate::PermissionsResult> QtAndroidPrivate::requestPermissionsSync(JNIEnv *env, const QStringList &permissions, int timeoutMs)
QtAndroidPrivate::PermissionsHash QtAndroidPrivate::requestPermissionsSync(JNIEnv *env, const QStringList &permissions, int timeoutMs)
{
QSharedPointer<QHash<QString, QtAndroidPrivate::PermissionsResult>> res(new QHash<QString, QtAndroidPrivate::PermissionsResult>());
QSharedPointer<QSemaphore> sem(new QSemaphore);
@ -572,6 +577,33 @@ void QtAndroidPrivate::hideSplashScreen(JNIEnv *env, int duration)
env->CallStaticVoidMethod(g_jNativeClass, g_hideSplashScreenMethodID, duration);
}
void QtAndroidPrivate::waitForServiceSetup()
{
g_waitForServiceSetupSemaphore->acquire();
}
int QtAndroidPrivate::acuqireServiceSetup(int flags)
{
g_serviceSetupLockers->ref();
return flags;
}
void QtAndroidPrivate::setOnBindListener(QtAndroidPrivate::OnBindListener *listener)
{
QMutexLocker lock(g_onBindListenerMutex);
*g_onBindListener = listener;
if (!(*g_serviceSetupLockers)--)
g_waitForServiceSetupSemaphore->release();
}
jobject QtAndroidPrivate::callOnBindListener(jobject intent)
{
QMutexLocker lock(g_onBindListenerMutex);
if (g_onBindListener)
return (*g_onBindListener)->onBind(intent);
return nullptr;
}
QT_END_NAMESPACE
#include "qjnihelpers.moc"

View File

@ -100,6 +100,13 @@ namespace QtAndroidPrivate
virtual bool handleKeyEvent(jobject event) = 0;
};
class Q_CORE_EXPORT OnBindListener
{
public:
virtual ~OnBindListener() {}
virtual jobject onBind(jobject intent) = 0;
};
enum class PermissionsResult {
Granted,
Denied
@ -143,6 +150,13 @@ namespace QtAndroidPrivate
Q_CORE_EXPORT void unregisterKeyEventListener(KeyEventListener *listener);
Q_CORE_EXPORT void hideSplashScreen(JNIEnv *env, int duration = 0);
Q_CORE_EXPORT void waitForServiceSetup();
Q_CORE_EXPORT int acuqireServiceSetup(int flags);
Q_CORE_EXPORT void setOnBindListener(OnBindListener *listener);
Q_CORE_EXPORT jobject callOnBindListener(jobject intent);
}
QT_END_NAMESPACE

View File

@ -542,7 +542,14 @@ static jboolean startQtApplication(JNIEnv *env, jobject /*object*/, jstring para
if (sem_init(&m_terminateSemaphore, 0, 0) == -1)
return false;
return pthread_create(&m_qtAppThread, nullptr, startMainMethod, nullptr) == 0;
jboolean res = pthread_create(&m_qtAppThread, nullptr, startMainMethod, nullptr) == 0;
// The service must wait until the QCoreApplication starts otherwise onBind will be
// called too early
if (m_serviceObject)
QtAndroidPrivate::waitForServiceSetup();
return res;
}
static void quitQtCoreApplication(JNIEnv *env, jclass /*clazz*/)
@ -742,6 +749,11 @@ static void onNewIntent(JNIEnv *env, jclass /*cls*/, jobject data)
QtAndroidPrivate::handleNewIntent(env, data);
}
static jobject onBind(JNIEnv */*env*/, jclass /*cls*/, jobject intent)
{
return QtAndroidPrivate::callOnBindListener(intent);
}
static JNINativeMethod methods[] = {
{"startQtAndroidPlugin", "()Z", (void *)startQtAndroidPlugin},
{"startQtApplication", "(Ljava/lang/String;Ljava/lang/String;)V", (void *)startQtApplication},
@ -754,7 +766,8 @@ static JNINativeMethod methods[] = {
{"updateApplicationState", "(I)V", (void *)updateApplicationState},
{"handleOrientationChanged", "(II)V", (void *)handleOrientationChanged},
{"onActivityResult", "(IILandroid/content/Intent;)V", (void *)onActivityResult},
{"onNewIntent", "(Landroid/content/Intent;)V", (void *)onNewIntent}
{"onNewIntent", "(Landroid/content/Intent;)V", (void *)onNewIntent},
{"onBind", "(Landroid/content/Intent;)Landroid/os/IBinder;", (void *)onBind}
};
#define FIND_AND_CHECK_CLASS(CLASS_NAME) \