Russian Qt Forum

Qt => Qt Embedded => Тема начата: Гурман от Ноябрь 02, 2016, 19:57



Название: (РЕШЕНО) Просьба помочь с правильным оформлением JNI-кода
Отправлено: Гурман от Ноябрь 02, 2016, 19:57
Мне нужно вызвать из Qt-приложения функции AudioManager. В программировании на Java я полный плавающий 0.0 (можно интерпретировать и как смайлик). Поэтому прошу помощи в правильном оформлении подключаемого к проекту файла с интерфейсами для вызова функций Android AudioManager. Вроде понятно как к ним обратиться из C++ кода, и как это подключить к проекту. Пока нужна помощь толко по правильному оформлению Java кода. Изучать подробно Java сейчас некогда, надо сделать проект, он на 99.99% на Qt. На Java нужны только эти функции, поскольку их увы в Qt для Android нет. Вот написал такое глядя на различные примеры и обсуждения в Сети, пока без тел методов (там вроде тоже понятно какие методы AudioManager вызвать). Что здесь не правильно, чего не хватает, что лишнее? Буду невероятно признателен за исправление этого кода до состояния, когда он без сообщений об ошибках подключится к проекту и заработает.

Код:
// VolumeControl.java

package org.myfirm.myapp

import org.myfirm.myapp.QtApplication
import org.myfirm.myapp.QtActivity
import android.media.AudioManager

public class VolumeControl extends QtActivity
{
    public void Mute(){
    }

    public void VolumeUp(){
    }

    public void VolumeDn(){
    }
}


Название: Re: Просьба помочь с правильным оформлением JNI-кода
Отправлено: VPS от Ноябрь 02, 2016, 20:27
В андроиде не силён, но вот что заметил:
Строки с package и import должны заканчиваться ";"
Код
Java
package org.myfirm.myapp;
 
Также вызывает сомнение правильность полного имени импортируемых классов QtApplication (в заготовке он вроде не используется, поэтому может быть лишним) и QtActivity.
Возможно надо так:
Код
Java
package org.myfirm.myapp;
 
import org.qtproject.qt5.android.bindings.QtActivity;
import android.media.AudioManager;
 


Название: Re: Просьба помочь с правильным оформлением JNI-кода
Отправлено: Гурман от Ноябрь 02, 2016, 20:53
Ну, точка с запятой - это синтаксис... выругается при трансляции. Меня больше всё-таки интересуют правильные инклюды и оформление имени класса.  В фирменном примере Qt оно выглядит так:

Код:
public class NotificationClient extends org.qtproject.qt5.android.bindings.QtActivity

хотя в обсуждениях в форумах после extends обычно указано только QtActivity. Или просто Activity. Я не знаю, как правильно.


Название: Re: Просьба помочь с правильным оформлением JNI-кода
Отправлено: VPS от Ноябрь 02, 2016, 21:01
Код:
public class NotificationClient extends org.qtproject.qt5.android.bindings.QtActivity
Можно и так писать, тогда строка, импортирующая данный класс будет лишней и её можно опустить.

P/S: здесь  (https://gitlab.com/2gisqtandroid/2gisqt5android/blob/0d654cdee219bb004ab1c021bd164cb27fad0ece/qtbase/src/android/java/src/org/qtproject/qt5/android/bindings/QtActivity.java)видно, что класс QtActivity наследует класс android.app.Activity.


Название: Re: Просьба помочь с правильным оформлением JNI-кода
Отправлено: Гурман от Ноябрь 06, 2016, 19:32
up

Накрутил чего-то, приложение собирается, функции вроде должны вызываться, но управление громкостью не производится. Есть круговой слайдер, при его вращении вызываются два метода С++:

Код:
void volCtrl::volumeUp()
{
#ifdef __ANDROID__
    QAndroidJniObject::callStaticMethod<void>( "org/myfirm/myapp/PlayControl", "volumeUp" );
    qDebug()<<"volup";
#endif
}

void volCtrl::volumeDn()
{
#ifdef __ANDROID__
    QAndroidJniObject::callStaticMethod<void>( "org/myfirm/myapp/PlayControl", "volumeDn" );
    qDebug()<<"voldn";
#endif
}
Java код выглядит так

Код:
package org.myfirm.myapp;

import org.myfirm.myapp.QtActivity;
import android.media.AudioManager;

public class PlayControl extends QtActivity
{
    public static void VolumeUp(){
        AudioManager am = (AudioManager)context.getSystemService(Context.AUDIO_SERVICE);
        am.adjustVolume(ADJUST_RAISE, FLAG_SHOW_UI);
    }

    public static void VolumeDn(){
        AudioManager am = (AudioManager)context.getSystemService(Context.AUDIO_SERVICE);
        am.adjustVolume(ADJUST_LOWER, FLAG_SHOW_UI);
    }
}

при вращении слайдера выводится volup и voldn в консоль, но больше ничего не происходит

что не так, и что сделать, чтобы было так как надо?


Название: Re: Просьба помочь с правильным оформлением JNI-кода
Отправлено: Гурман от Ноябрь 06, 2016, 20:57
Cделал так

Код:
QAndroidJniObject r = QAndroidJniObject::callStaticObjectMethod<jstring>( "org/myfirm/myapp/PlayControl", "volumeDn");
if( !r.isValid() )
            qCritical()<<"Object not valid";

ну это и получил... Что может быть не так?

Да и QAndroidJniObject::isClassAvailable("org/myfirm/myapp/PlayControl") тоже возвращает false.


Название: Re: Просьба помочь с правильным оформлением JNI-кода
Отправлено: Гурман от Ноябрь 06, 2016, 23:04
Фух... кажется нашёл в чём проблема - посмотрел на пример Qt Notifier, и сделал всё как в нём. Наверно дело сдвинулось после того, как я создал маршрут src/org/myfirm/myapp в каталоге, который задан переменной ANDROID_PACKAGE_SOURCE_DIR проекта. До этого эта скотина просто молча не компилировала файл PlayControl.java, потому что не находила его. Молча... Теперь он стал компилироваться - вылезли сообщения об ошибках. И хоть бы кто-нибудь помог, уточнил, что исходник должен лежать в пути, который совпадает с package - я же специально о таких вещах спрашивал. Два дня коту под хвост из-за разбирательств с этой дебильной джавой. Это ж надо маразм какой - исходник нельзя где угодно положить и маршрут в проекте указать.

Java must die! Qt forewer! ;D


Название: Re: Просьба помочь с правильным оформлением JNI-кода
Отправлено: Гурман от Ноябрь 07, 2016, 13:19
Упёрся... Поддержка JNI в Qt позволяет вызывать только статические методы. Но для управления AudioManager-ом нужны не статические вызовы. То есть, нужен объект класса. Сделал так:

Код:
public class PlayControl extends org.qtproject.qt5.android.bindings.QtActivity
{
    public PlayControl(){}

    public void _VolumeUp(){
        AudioManager am = (AudioManager)this.getSystemService(Context.AUDIO_SERVICE);
        am.adjustVolume(AudioManager.ADJUST_RAISE, AudioManager.FLAG_SHOW_UI);
    }

    public static void VolumeUp(){
        new PlayControl()._VolumeUp();
    }
}
в С++ коде вызываю
Код:
void PlCtrlwidget::volumeUp()
{
#ifdef __ANDROID__
    QAndroidJniObject::callStaticMethod<void>( "org/myfirm/myapp/PlayControl", "volumeUp");
#endif
}
При первом вызове в консоль приложения вылетает одно сообщение о том, что исключение возникло при обработке исключения:
Цитировать
W/dalvikvm(28824): Exception thrown (Ljava/lang/RuntimeException;) while throwing internal exception (Ljava/lang/NoSuchMethodError;
И больше ничего не происходит, дальнейшие вызовы никак не отрабатываются, очевидно JNI-объект умер.

Делал просто пустую функцию на Java, в которой ничего нет - при вызове получаю это же сообщение. Всё, дальше не знаю, что с этим грёбаным (литературное выражение, встречается у Солженицына в "Один день Ивана Денисовича") JNI делать.


Название: Re: Просьба помочь с правильным оформлением JNI-кода
Отправлено: Igors от Ноябрь 07, 2016, 13:39
Всё, дальше не знаю, что с этим грёбанным (литературное выражение, встречается ..
Встречается или нет - но "н" там точно одно


Название: Re: Просьба помочь с правильным оформлением JNI-кода
Отправлено: Гурман от Ноябрь 07, 2016, 13:49
Всё, дальше не знаю, что с этим грёбанным (литературное выражение, встречается ..
Встречается или нет - но "н" там точно одно
Есть вариант, когда два н - "грёбанный в рот". Но ладно уж, пусть будет одно.


Название: Re: Просьба помочь с правильным оформлением JNI-кода
Отправлено: Гурман от Ноябрь 07, 2016, 14:49
Вызов работает

Код:
public static void VolumeUp(){
        return 101;
    }

Код:
void PlCtrlwidget::volumeUp()
{
#ifdef __ANDROID__
    qDebug()<<QAndroidJniObject::callStaticMethod<jint>( "org/myfirm/myapp/PlayControl", "volumeUp");
#endif
}

печатает 101. Валится при попытке вызвать статический метод из не статического.

Код:
public static int VolumeUp(){
        new PlayControl()._VolumeUp();
        return 101;
    }

Код:
void PlCtrlwidget::volumeUp()
{
#ifdef __ANDROID__
    qDebug()<<QAndroidJniObject::callStaticMethod<jint>( "org/myfirm/myapp/PlayControl", "volumeUp");
#endif
}

сначала напечатал случайное число и выдал то же сообщение об исключении, а при последующих вызовах выдаёт 0.

Код:
public static int PlayPauseDn(){
        PlayControl p = new PlayControl();
        p._PlayPauseDn();
        return 202;
    }

разумеется та же фигня.

Если создать объект в С++ коде

Код:
    public int _VolumeUp(){
        return 111;
    }
Код:
void PlCtrlwidget::VolumeUp()
{
#ifdef __ANDROID__
    QAndroidJniObject o("org/myfirm/myapp/PlayControl");
    qDebug()<<o.callMethod<jint>( "_VolumeUp" );
#endif
}

Исключение не вываливается, но и ничего не вызывается - печатает 0.

ЗНАТОКИ JAVA, КАК ВЫЗВАТЬ НЕ СТАТИЧЕСКИЙ МЕТОД КОРРЕКТНО?


Название: Re: Просьба помочь с правильным оформлением JNI-кода
Отправлено: Гурман от Ноябрь 07, 2016, 16:57
Трындец какой-то...

Код:
public int _VolumeUp(){
        return 101;
    }
Код:
void PlCtrlwidget::volumeUp()
{
#ifdef __ANDROID__
    QAndroidJniObject a = QtAndroid::androidActivity();
    qDebug()<<a.isValid()<<a.callMethod<jint>( "_volumeUp");
#endif
}

печатает true 0, исключения нет.

Тупик.


Название: Re: Просьба помочь с правильным оформлением JNI-кода
Отправлено: kambala от Ноябрь 07, 2016, 17:56
а это законно — возвращать что-либо из void метода?


Название: Re: Просьба помочь с правильным оформлением JNI-кода
Отправлено: Гурман от Ноябрь 07, 2016, 18:03
а это законно — возвращать что-либо из void метода?
там на самом деле int, другое объявление в форум скопировал

исправил


Название: Re: Просьба помочь с правильным оформлением JNI-кода
Отправлено: Гурман от Ноябрь 07, 2016, 22:44
В конце концов получилось вызывать AudioManager из статического метода и покрутить громкость Qt-шным кнобом на экране планшета. Полный код того, что у меня заработало. Может тут есть что-то лишнее, пусть знатоки покажут.

Код:
package org.myfirm.myapp;

import org.qtproject.qt5.android.bindings.QtApplication;
import org.qtproject.qt5.android.QtNative;
import android.media.AudioManager;
import android.content.Context;

public class PlayControl extends org.qtproject.qt5.android.bindings.QtActivity
{
    private static AudioManager a() {
        return (AudioManager) QtNative.activity().getApplicationContext().getSystemService(Context.AUDIO_SERVICE);
    }

    public static void VolumeUp(){
        a().adjustVolume(AudioManager.ADJUST_RAISE, AudioManager.FLAG_SHOW_UI);
    }

    public static void VolumeDn(){
        a().adjustVolume(AudioManager.ADJUST_LOWER, AudioManager.FLAG_SHOW_UI);
    }
}

Но обратиться к не статитческим методам JNI-класса - ни в какую. Если у кого-то получится работающий вариант, просьба в студию.


Название: Re: (РЕШЕНО) Просьба помочь с правильным оформлением JNI-кода
Отправлено: Гурман от Ноябрь 07, 2016, 22:56
Увы, с управлением воспроизведением треков пичалька. Метод dispatchMediaKeyEvent() появился у AudioManager только в 19-м API level, а я делаю для минимум 15-го.  :(