QtAndroid详解(5):JNI调用Android系统功能(2)

在“QtAndroid详解(4):JNI调用Android系统功能(1)”中我们给出了一些简单的示例,演示了如何使用 Qt JNI 类库访问网络状态、系统资源目录、当前应用信息等等,这次呢,我们提供一些新的示例,这些示例可能更具实际意义。本文的示例包括:

示例介绍

图1

我们按照界面上的顺序,一个一个来看这些功能如何实现。

源码分析

构建界面的代码在 Widget 类的构造函数里,不说了。这次我们换个搞法,不列所有代码了,一个功能一个功能分开说代码,这样文章看起来短一些。

震动

当你点击图1中的“Vibrate”按钮,onVibrate() 槽会被调用,它的代码如下:

void Widget::onVibrate(){QAndroidJniEnvironment env;QAndroidJniObject activity = androidActivity();QAndroidJniObject name = QAndroidJniObject::getStaticObjectField("android/content/Context","VIBRATOR_SERVICE","Ljava/lang/String;");CHECK_EXCEPTION();QAndroidJniObject vibrateService = activity.callObjectMethod("getSystemService","(Ljava/lang/String;)Ljava/lang/Object;",name.object<jstring>());CHECK_EXCEPTION();jlong duration = 200;vibrateService.callMethod<void>("vibrate", "(J)V", duration);CHECK_EXCEPTION();} 看着是不是很熟悉呢?其实使用 QAndroidJniObject 来调用 Java 类库,写出来的代码看起来都差不多……你翻翻“QtAndroid详解(3):startActivity实战Android拍照功能”和“QtAndroid详解(4):JNI调用Android系统功能(1)”里面的代码就会更确认这一点。其实这里面体现的是QAndroidJniObject的一般用法。

Android 里的很多系统服务都有一个名字,以静态成员变量的形式定义在 Context 类中。之前也见识过了。震动器的名字是 Context.VIBRATOR_SERVICE ,对应的类为android.os.Vibrator。Vibrator 的方法 “void vibrate(long ms)” ,可以产生震动,参数单位是毫秒。

我们 C++ 代码,先使用 QAndroidJniObject::getStaticObjectField() 方法从 android.content.Context 类获取服务的名字;然后调用 Activity 的 getSystemService方法获取 Vibrator 实例;最后调用 Vibrator 的 vibrate(long) 方法来产生震动。

改变应用在屏幕上的显示方向

Qt Creator给我们生成的针对 Android 的应用,默认没有设置 Activity 的 screenOrientation ,如果你手机旋转,应用也可能变成横屏或竖屏显示。当我们需要应用固定以某个方向显示时,需要修改 AndroidManifest.xml 中 <activity> 标签的 “android:screenOrientation” 属性。那其实,, android.app.Activity 类也提供了 “voidsetRequestedOrientation(int requestedOrientation)” 方法,允许我们通过代码来调整一个 Activity 的显示方向。

再简单的说一下:Android的一个应用,可能有多个Activity,每个Activity都可以有自己的屏幕显示方向,即,屏幕显示方向,是Activity的特性。

当你点击图1中的“ScreenOrientation”按钮,就会调用到槽 onScreenOrientation() ,代码如下:

void Widget::onScreenOrientation(){QAndroidJniEnvironment env;QAndroidJniObject activity = androidActivity();jint orient = activity.callMethod<jint>("getRequestedOrientation");CHECK_EXCEPTION();if(orient == 1){orient = 0;}else{orient = 1;}activity.callMethod<void>("setRequestedOrientation","(I)V", orient);CHECK_EXCEPTION();} QtAndroid名字空间里的 androidActivity() 方法可以返回Qt应用使用的 Activity 对象,然后直接调用setRequestOrientation() 方法来改变当前Activity的屏幕方向。铃声模式

手机来电铃声,一般有普通(响铃)、静音、震动三种模式,对应在代码里呢,是通过android.media.AudioManager 类的“voidsetRingerMode(int ringerMode)”来设置铃声模式。 AudioManager 的名字是AUDIO_SERVICE 。

setRingerMode的整形参数,有三个值:RINGER_MODE_NORMAL 、RINGER_MODE_SILENT 、RINGER_MODE_VIBRATE 。这些以静态成员变量的形式定义在android.media.AudioManager 类中,我们在 C++ 代码中可以通过 QAndroidJniObject::getStaticField 方法来获取,不过我在代码里偷了个懒,直接用数字了。关于铃声模式对应的宏:

#define RINGER_MODE_NORMAL 2#define RINGER_MODE_SILENT 0#define RINGER_MODE_VIBRATE 1 如图1所示,铃声模式是通过一组单选按钮(QRadioButton)来选择的。我在代码里使用 QButtonGroup 来管理三个单选按钮,同时将每个按钮的 id 设置为它代表的铃声模式。这样当 QButtonGroup 的“buttonClicked(int id)”触发时,我们的槽“void Widget::onRingerModeClicked(int mode)”被调用,参数直接就是响铃模式了,很方便。

那先看看这组铃声模式单选按钮初始化的代码:

void Widget::initRingerMode(QVBoxLayout *layout){QAndroidJniEnvironment env;QAndroidJniObject activity = androidActivity();QAndroidJniObject name = QAndroidJniObject::getStaticObjectField("android/content/Context","AUDIO_SERVICE","Ljava/lang/String;");CHECK_EXCEPTION();QAndroidJniObject audioService = activity.callObjectMethod("getSystemService","(Ljava/lang/String;)Ljava/lang/Object;",name.object<jstring>());CHECK_EXCEPTION();int mode = audioService.callMethod<jint>("getRingerMode","()I");CHECK_EXCEPTION();layout->addWidget(new QLabel("Ringer Mode:"));QHBoxLayout *rowLayout = new QHBoxLayout();layout->addLayout(rowLayout);rowLayout->addSpacing(30);m_ringerModeGroup = new QButtonGroup(this);QRadioButton *normal = new QRadioButton("Normal");m_ringerModeGroup->addButton(normal, RINGER_MODE_NORMAL);rowLayout->addWidget(normal);QRadioButton *silent = new QRadioButton("Silent");m_ringerModeGroup->addButton(silent, RINGER_MODE_SILENT);rowLayout->addWidget(silent);QRadioButton *vibrate = new QRadioButton("Vibrate");m_ringerModeGroup->addButton(vibrate, RINGER_MODE_VIBRATE);rowLayout->addWidget(vibrate);switch(mode){case RINGER_MODE_NORMAL:normal->setChecked(true);break;case RINGER_MODE_SILENT:silent->setChecked(true);break;case RINGER_MODE_VIBRATE:vibrate->setChecked(true);break;}connect(m_ringerModeGroup, SIGNAL(buttonClicked(int)),this, SLOT(onRingerModeClicked(int)));} 在上面的代码里,我还调用 android.media.AudioManager 的 “int getRingerMode()” 方法获取了系统当前的铃声模式,然后选中对应的单选按钮。既有美妙的风景,也会有称不上景只有风的地方。

QtAndroid详解(5):JNI调用Android系统功能(2)

相关文章:

你感兴趣的文章:

标签云: