androidc++qtqandroidjniobject

Can't make the phone play sound nor vibrate using Qt for Android


I'm deploying an Android application using QtCreator.

I'd like to play a sound and make the phone vibrate to notify the user that something bad happened. I use QAndroidJniObject to call SDK functions.

I could not make anyone work.

For "vibrate":

// java code:
// import android.os.Vibrator;
// Vibrator v = (Vibrator) this.context.getSystemService(Context.VIBRATOR_SERVICE);
// v.vibrate(500);
QAndroidJniObject activity = QAndroidJniObject::callStaticObjectMethod("org/qtproject/qt5/android/QtNative", "activity", "()Landroid/app/Activity;");
if ( activity.isValid() )
{
    QAndroidJniObject serviceName = QAndroidJniObject::getStaticObjectField<jstring>("android/content/Context","VIBRATOR_SERVICE");
    if ( serviceName.isValid() )
    {
        QAndroidJniObject vibrator = activity.callObjectMethod("getSystemService", "(Ljava/lang/String;)Ljava/lang/Object;",serviceName.object<jobject>());
        if ( vibrator.isValid() )
        {
            vibrator.callMethod<void>("vibrate", "(I)V", 1000);
        }
    }
}

vibrator.callMethod is reached (thanks to Michael help) but the phone does not vibrate (note that my application has android.permission.VIBRATE)

For "play sound", I tried both:

// java code:
// Uri notification = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
// Ringtone ring = RingtoneManager.getRingtone(getApplicationContext(), notification);
// ring.play();
QAndroidJniObject activity = QAndroidJniObject::callStaticObjectMethod("org/qtproject/qt5/android/QtNative", "activity", "()Landroid/app/Activity;");
if ( activity.isValid() )
{
    jint notifcationType = QAndroidJniObject::getStaticField<jint>("android/media/RingtoneManager", "TYPE_NOTIFICATION");
    {
        QAndroidJniObject notification = QAndroidJniObject::callStaticObjectMethod("android/media/RingtoneManager", "getDefaultUri", "(I)Landroid/net/Uri;", notifcationType);
        if ( notification.isValid() )
        {
            QAndroidJniObject ring = QAndroidJniObject::callStaticObjectMethod("android/media/RingtoneManager", "getRingtone", "(Landroid.content.Context;Landroid/net/Uri;)Landroid.media.Ringtone;",activity.object<jobject>(),notification.object<jobject>());
            if ( ring.isValid() )
            {
                ring.callMethod<void>("play", "()V");
            }
        }
    }
}

and

QAndroidJniObject activity = QAndroidJniObject::callStaticObjectMethod("org/qtproject/qt5/android/QtNative", "activity", "()Landroid/app/Activity;");
if ( activity.isValid() )
{
    jint notifcationType = QAndroidJniObject::getStaticField<jint>("android/media/RingtoneManager", "TYPE_NOTIFICATION");

    QAndroidJniObject notification = QAndroidJniObject::callStaticObjectMethod("android/media/RingtoneManager", "getDefaultUri", "(I)Landroid/net/Uri;", notifcationType);
    if ( notification.isValid() )
    {
        QAndroidJniObject player = QAndroidJniObject::callStaticObjectMethod("android/media/MediaPlayer", "create", "(Landroid.content.Context;Landroid/net/Uri;)Landroid.media.MediaPlayer;",activity.object<jobject>(),notification.object<jobject>());

        if ( player.isValid() )
        {
            player.callMethod<void>("start", "()V");
        }
    }
}

In both case, last function is not reached because objects are not valid (nor player, nor ring are valid).


Solution

    1. vibrate() takes long as an argument and not int.
    2. Always use slashes to separate package and class names in you jni calls.

    try:

    QAndroidJniObject activity = QAndroidJniObject::callStaticObjectMethod("org/qtproject/qt5/android/QtNative", "activity", "()Landroid/app/Activity;");
    //    QAndroidJniObject activity = QtAndroid::androidActivity(); // Req. Qt 5.3
    if ( activity.isValid() )
    {
        // This gets the string value of the VIBRATOR_SERVICE field.
        QAndroidJniObject serviceField = QAndroidJniObject::getStaticObjectField<jstring>("android/content/Context", "VIBRATOR_SERVICE");
        if ( serviceField.isValid() )
        {
            QAndroidJniObject vibrator = activity.callObjectMethod("getSystemService", "(Ljava/lang/String;)Ljava/lang/Object;",serviceField.object<jobject>());
            if ( vibrator.isValid() )
            {
                // Note that vibrate takes a long and not an int as argument.
                vibrator.callMethod<void>("vibrate", "(J)V", 500);
            }
        }
    }
    

    and

    QAndroidJniObject activity = QAndroidJniObject::callStaticObjectMethod("org/qtproject/qt5/android/QtNative", "activity", "()Landroid/app/Activity;");
    if ( activity.isValid() )
    {
        jint notifcationType = QAndroidJniObject::getStaticField<jint>("android/media/RingtoneManager", "TYPE_NOTIFICATION");
        QAndroidJniObject notification = QAndroidJniObject::callStaticObjectMethod("android/media/RingtoneManager", "getDefaultUri", "(I)Landroid/net/Uri;", notifcationType);
        if ( notification.isValid() )
        {
            // Note that package and class names needs to be separated with '/' and not '.'
            QAndroidJniObject ring = QAndroidJniObject::callStaticObjectMethod("android/media/RingtoneManager",
                                                                           "getRingtone",
                                                                           "(Landroid/content/Context;Landroid/net/Uri;)Landroid/media/Ringtone;",
                                                                           activity.object<jobject>(),
                                                                           notification.object<jobject>());
            if ( ring.isValid() )
            {
                ring.callMethod<void>("play", "()V");
            }
        }
    }