[SOLVED] Qt on Android : How to Vibrate the device ?



  • I'm looking a class to manage the vibrate on Android.

    When I developed in Symbian I used the following:

    @hapticfeedbackControl->vibrate(20,10)@

    where in .pro file I had:

    @LIBS += -lcone -leikcore -lavkon -lhwrmvibraclient@

    and the code was the following:

    @ hapticfeedbackControl = new HapticFeedback;
    hapticfeedbackControl->initHapticControl();
    hapticfeedbackControl->vibrate(20,10)@

    @#ifndef MAINWINDOW_H
    #define MAINWINDOW_H

    #include <QMainWindow>
    #include <hapticfeedback.h>

    namespace Ui {
    class MainWindow;
    }

    class MainWindow : public QMainWindow
    {
    Q_OBJECT

    public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();
    HapticFeedback *hapticfeedbackControl;

    private:
    Ui::MainWindow *ui;

    private slots:
    void on_bt_time_clicked();
    void on_pbLap4_clicked();
    void on_pbLap3_clicked();
    void on_pbLap2_clicked();
    void manageTimer();

    };

    #endif // MAINWINDOW_H@

    @/*************************

    • hapticfeedback.cpp
      *************************/

    #include "hapticfeedback.h"

    HapticFeedback::HapticFeedback()
    #ifdef Q_OS_SYMBIAN
    : iVibrate(NULL)
    #endif
    {
    }

    void HapticFeedback::initHapticControl()
    {
    #ifdef Q_OS_SYMBIAN
    if (iVibrate)
    return;
    iVibrate = CHWRMVibra::NewL();
    #endif
    }

    void HapticFeedback::destroyHapticControl()
    {
    #ifdef Q_OS_SYMBIAN
    if (iVibrate)
    {
    delete iVibrate;
    iVibrate = NULL;
    }
    #endif
    }

    void HapticFeedback::vibrate(int duration, int intensity)
    {
    #ifdef Q_OS_SYMBIAN
    if (iVibrate)
    {
    TRAPD(err, iVibrate->StartVibraL(duration, intensity));
    }
    #else
    #endif
    }@

    @/*************************

    • hapticfeedback.h
      *************************/

    #ifndef HAPTICFEEDBACK_H
    #define HAPTICFEEDBACK_H

    #include <QObject>

    #ifdef Q_OS_SYMBIAN
    #include <hwrmvibra.h>
    #endif

    class HapticFeedback
    {
    public:
    HapticFeedback();

    public:
    void initHapticControl();
    void destroyHapticControl();
    void vibrate(int duration, int intensity);

    #ifdef Q_OS_SYMBIAN
    CHWRMVibra* iVibrate;
    #endif

    };

    #endif // HAPTICFEEDBACK_H@

    but the main question is: how I have to do in Android ?



  • I guess you need to call an "android api":http://developer.android.com/reference/android/os/Vibrator.html to make it vibrate.
    "Here":http://qt-project.org/doc/qt-5/qtandroidextras-notification-example.html is an example on how to call android api from Qt



  • You are right and I have create the following java class:

    @package org.qtproject.example.Chronometer;

    import android.content.Context;
    import android.os.Vibrator;
    import android.app.Activity;

    public class Vibrate extends org.qtproject.qt5.android.bindings.QtActivity
    {

    private static Vibrate m_instance;

    public Vibrate()
    {
    m_instance = this;
    }

    public static void start(int x)
    {
    Vibrator v = (Vibrator) m_instance.getSystemService(Context.VIBRATOR_SERVICE);
    v.vibrate(x);

    }

    public static int add(int x)
    {
    return (x++);

    }

    }@

    I call the class from c++ in the following mode:

    @ QAndroidJniObject::callStaticMethod<void>("org/qtproject/example/Chronometer/Vibrate", "start", "(I)V;", 300);

    int value_in = 10;
    jint  value_out = QAndroidJniObject::callStaticMethod<jint>("org/qtproject/example/Chronometer/Vibrate", "add", "(I)I;",  value_in);
    
    qDebug() << "IN = "  << value_in << ", OUT = " << value_out;@
    

    The program is compiled without error, but when I click on the button
    I have no result, infact I was expecting the value 11 as the reply value in the second call. But nothing happens and the application output is the following:

    @D/Qt (18217): ..\chronometer\mainwindow.cpp:123 (void MainWindow::manageStartEnd()): IN = 10 , OUT = 0@

    Where am I doing wrong?



  • I did not work with Android yet. So it is just my guess.

    In the "doc":http://developer.android.com/reference/android/os/Vibrator.html#vibrate(long) it says "This method requires the caller to hold the permission VIBRATE."
    Did you get this permission for your app?

    In the add() function you use postfix increment, so you should get back 10 not 11.
    @
    public static int add(int x)
    {
    return (x++);
    }
    @

    You can add debug output to both functions to see what values are received.

    [EDIT] It maybe useful to "check":http://developer.android.com/reference/android/os/Vibrator.html#hasVibrator() whether the hardware has a vibrator.



  • bq. In the doc [developer.android.com]) it says “This method requires the caller to hold the permission VIBRATE.”
    Did you get this permission for your app?

    Yes. I have this permission in the AndroidManifest.xml file:

    @<uses-permission android:name="android.permission.VIBRATE"/>@

    I have change the following code

    @public static int add(int x)
    {
    return (x++);
    }@

    with the following:

    @ public static int add(int x)
    {
    return (++x);

    }@

    but the result don't change:

    @D/Qt ( 5509): ..\chronometer\mainwindow.cpp:123 (void MainWindow::manageStartEnd()): IN = 10 , OUT = 0@

    Also I have change the function in the following mode, but in anycase the function don't return any value:

    @ public static int add(int x)
    {
    return 53;

    }@

    infact:

    @D/Qt ( 6222): ..\chronometer\mainwindow.cpp:123 (void MainWindow::manageStartEnd()): IN = 10 , OUT = 0@

    I'd like to see the following:

    @D/Qt ( 6222): ..\chronometer\mainwindow.cpp:123 (void MainWindow::manageStartEnd()): IN = 10 , OUT = 53@

    bq. I'm going crazy .....



  • Don't know maybe it is not important but I don't see semicolon at the end of a signature in the "example":http://qt-project.org/doc/qt-5/qandroidjniobject.html#callStaticMethod-2
    @
    jint value_out = QAndroidJniObject::callStaticMethod<jint>("org/qtproject/example/Chronometer/Vibrate", "add", "(I)I;", /* <<<< at the end of this string */ value_in);
    @



  • I have try whitout semicolon in this way:

    @ QAndroidJniObject::callStaticMethod<void>("org/qtproject/example/Chronometer/Vibrate", "start", "(I)V", 300);

    int value_in = 10;
    jint  value_out = QAndroidJniObject::callStaticMethod<jint>("org/qtproject/example/Chronometer/Vibrate", "add", "(I)I",  value_in);
    
    qDebug() << "IN = "  << value_in << ", OUT = " << value_out;@
    

    but the result is the same:

    @D/Qt (20929): ..\chronometer\mainwindow.cpp:123 (void MainWindow::manageStartEnd()): IN = 10 , OUT = 0@

    I have a new error message when I quit for my application:

    @W/dalvikvm(24652): threadid=11: thread exiting with uncaught exception (group=0x416c92a0)
    E/AndroidRuntime(24652): FATAL EXCEPTION: QtThread-1516700272
    E/AndroidRuntime(24652): java.lang.NullPointerException
    E/AndroidRuntime(24652): at org.qtproject.example.Chronometer.Vibrate.start(Vibrate.java:21)
    E/AndroidRuntime(24652): at dalvik.system.NativeStart.run(Native Method)
    W/SurfaceView(24652): CHECK surface infomation creating=false formatChanged=false sizeChanged=false visible=false visibleChanged=true surfaceChanged=true realSizeChanged=false redrawNeeded=false left=false top=false@



  • I have found the solution and I have change the java class in this way:

    @
    import android.content.Context;
    import android.os.Vibrator;
    import android.app.Activity;

    public class Vibrate extends org.qtproject.qt5.android.bindings.QtActivity
    {

    public void start(int x)
    {
    Vibrator v;
    v = (Vibrator) this.getSystemService(Context.VIBRATOR_SERVICE);
    v.vibrate(x);
    }

    public static int add(int x)
    {
    return 53;

    }

    }@

    and now the result is the following (without error):

    @
    D/Qt (27146): ..\chronometer\mainwindow.cpp:123 (void MainWindow::manageStartEnd()): IN = 10 , OUT = 53@

    The problem is that I haven't the vibration in my device :-(



  • Try to declare the method start as static.
    Also if Vibrator::vibrate is async then you need to allocate v on a heap.



  • there is something I am not considering, and I begin to doubt the official example: "Here":http://qt-project.org/doc/qt-5/qtandroidextras-notification-example.html [qt-project.org].

    I have developed the new class java in this way:

    @package org.qtproject.example.Chronometer;

    import android.content.Context;
    import android.os.Vibrator;
    import android.app.Activity;

    public class Vibrate extends org.qtproject.qt5.android.bindings.QtActivity
    {

    public static Vibrator m_vibrator;
    public static Vibrate m_istance;

    public Vibrate()
    {
    System.out.println("Vibrate costrutor called");
    m_istance = this;
    }

    public static int start(int x)
    {
    System.out.println("start function called");
    if (m_vibrator == null)
    {
    if (m_istance != null)
    {
    m_vibrator = (Vibrator) m_istance.getSystemService(Context.VIBRATOR_SERVICE);
    m_vibrator.vibrate(x);
    return 1;
    }
    else
    {
    return 3;
    }
    }
    else
    {
    m_vibrator.vibrate(x);
    return 2;
    }
    }

    public static int add(int x)
    {
    System.out.println("Add function called");
    return 53;
    }

    }
    @

    and I call the class from c++ in this way:

    @jint value_out1 = QAndroidJniObject::callStaticMethod<jint>("org/qtproject/example/Chronometer/Vibrate", "start", "(I)I", 300);

    qDebug() << "OUT = " << value_out1;

    int value_in = 10;
    jint value_out = QAndroidJniObject::callStaticMethod<jint>("org/qtproject/example/Chronometer/Vibrate", "add", "(I)I", value_in);

    qDebug() << "IN = " << value_in << ", OUT = " << value_out;@

    the output is the following (and I still have the vibration of the device):

    @I/System.out(12301): start function called
    D/Qt (12301): ..\chronometer\mainwindow.cpp:120 (void MainWindow::manageStartEnd()): OUT = 3
    I/System.out(12301): Add function called
    D/Qt (12301): ..\chronometer\mainwindow.cpp:125 (void MainWindow::manageStartEnd()): IN = 10 , OUT = 53@

    As you can see the function "start" is called but the m_istance is null and the the function return the value 3:

    @D/Qt (12301): ..\chronometer\mainwindow.cpp:120 (void MainWindow::manageStartEnd()): OUT = 3@

    This means that the java class constructor is never called.

    In fact, in the log I do not see the inscription: "Vibrate costrutor called"



  • add this attribute to activity tag in AndroidMainifest.xml
    @android:name="org.qtproject.example.Chronometer.Vibrate"@



  • Wow !!!!! Now work. Thanks you very much.

    List below steps for all developers.

    1. change the .pro file in QT in this way:

    @QT += core gui androidextras@

    @ANDROID_PACKAGE_SOURCE_DIR = $$PWD/android@

    1. Add the permission in the AndroidMainifest.xml

    @<uses-permission android:name="android.permission.VIBRATE"/>@

    1. replace the attribute in the activity:

    from

    @android:name="org.qtproject.qt5.android.bindings.QtActivity"@

    to

    @android:name="org.qtproject.example.Chronometer.Vibrate"@

    Where Chronometer and Vibrate string can be changes.

    1. add the include following in the mainwindow.h

    @#include <QtAndroidExtras/QAndroidJniObject>@

    1. add the following Vibrate.java class in the following directory

    myprogget>android/src/org/qtproject/example/Chronometer/

    where Chronometer can be change:

    @//
    // Vibrate.java
    //
    package org.qtproject.example.Chronometer;

    import android.content.Context;
    import android.os.Vibrator;
    import android.app.Activity;
    import android.os.Bundle;

    public class Vibrate extends org.qtproject.qt5.android.bindings.QtActivity
    {

    public static Vibrator m_vibrator;
    public static Vibrate m_istance;

    public Vibrate()
    {
    m_istance = this;
    }

    public static void start(int x)
    {
    if (m_vibrator == null)
    {
    if (m_istance != null)
    {
    m_vibrator = (Vibrator) m_istance.getSystemService(Context.VIBRATOR_SERVICE);
    m_vibrator.vibrate(x);
    }

       }
       else m_vibrator.vibrate(x);
    

    }
    }@

    1. in your program call class in this way:

    @QAndroidJniObject::callStaticMethod<void>("org/qtproject/example/Chronometer/Vibrate", "start", "(I)V", 300);@



  • Thank you for putting it all together.

    Could you update the title and add [SOLVED] so other people will be able to find it.



  • Hi

    First of all thank you for sharing your solution.
    but when i replaced the attribute in the activity:
    from
    @android:name="org.qtproject.qt5.android.bindings.QtActivity"@
    to
    @android:name="org.qtproject.example.Chronometer.Vibrate"@

    i got this error msgs:
    @Warning: Dependency not found: C:/Qt/Qt5.3.0/5.3/android_armv7/plugins/platformthemes
    Warning: Dependency not found: C:/Qt/Qt5.3.0/5.3/android_armv7/plugins/platforminputcontexts
    Error while building/deploying project vibration (kit: Android for armeabi-v7a (GCC 4.7, Qt 5.3.0))
    When executing step 'Deploy to Android device'@

    What am i doing wrong?



  • It is not easy to understand, but it seems a problem of Dependency.

    Please can you check if you are following all steps indicate above ?

    You have put the file Vibrate.java under the following directory ?

    myprogget>android/src/org/qtproject/example/Chronometer/

    and add the file Vibrate.java into your qt projects (as exist file) ?

    If you share your .pro file perhaps I will understand better the problem.


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.