QtAndroid (4): JNI calls Android system functions (1)
In the previous sections, we have explained the basic usage of the QtAndroid namespace. This time, we will use the methods and class libraries we mentioned earlier to demonstrate some simple small examples. In my book Qt on Android core programming, I mainly call some Android functions by inheriting QtActivity, implementing my own Activity and adding static methods. In this series of articles, we mainly use the methods in the QtAndroid namespace introduced in Qt 5.3 and the QAndroidJniObject class to demonstrate how to call JNI in Qt and rewrite QtActivity only when necessary.
Based on your needs, Qt on Android applications often call some functions provided by the Android system, such as determining network connections, obtaining external storage paths, or caching file directories. These are frequently asked by friends. In this series of articles, I will demonstrate the features frequently used in Qt on Android development. Hope to help you.
Example
The example is simple. It is displayed using Qt Widgets. Result:
As shown in, the interface is very simple. Click the Refresh button to obtain information about the Android system and the current application and put it in the QListWidget. Includes the following content:
After the Android version of the mobile phone's network status and network information, the mobile phone's data directory, the mobile phone's external storage directory, the mobile phone's photo, music, video, ringtones, and other Directory Application paths are installed, the files directory of the application where the APK is stored by the System
Source code analysis
The Code has no logic to explain ...... All in the following:
# Include widget. h # include
# Include
# Include
# Include
# Include
# Include
Using namespace QtAndroid; # define CHECK_EXCEPTION () if (env-> ExceptionCheck () {qDebug () <exception occured; env-> ExceptionClear ();} Widget :: widget (QWidget * parent): QWidget (parent) {QVBoxLayout * layout = new QVBoxLayout (this); m_refresh = new QPushButton (Refresh); connect (m_refresh, SIGNAL (clicked (), this, SLOT (onRefresh (); layout-> addWidget (m_refresh); m_list = new QListWidget (); layout-> ad DWidget (m_list, 1);} Widget ::~ Widget () {} void Widget: onRefresh () {m_list-> clear (); QAndroidJniEnvironment env; // get Android SDK version m_list-> addItem (QString (SDK version: % 1 ). arg (androidSdkVersion (); QAndroidJniObject activity = androidActivity (); // get network state QAndroidJniObject connectivity = QAndroidJniObject: getStaticObjectField (android/content/Context, CONNECTIVITY_SERVICE, ljava/lang/String;); if (connectivity. isValid () {qDebug () <connectivity id-<connectivity. toString (); CHECK_EXCEPTION () QAndroidJniObject connectivityService = activity. callObjectMethod (getSystemService, (Ljava/lang/String;) Ljava/lang/Object;, connectivity. object
(); CHECK_EXCEPTION () qDebug () <got connectivity service-<connectivityService. isValid (); if (connectivityService. isValid () {QAndroidJniObject networkInfo = connectivityService. callObjectMethod (getActiveNetworkInfo, () Landroid/net/NetworkInfo;); CHECK_EXCEPTION () qDebug () <got NetworkInfo-<networkInfo. isValid (); if (networkInfo. isValid () {m_list-> addItem (QString (Network Status: connected (% 1 )). arg (networkInfo. toString ();} else {m_list-> addItem (Network Status: Not connected); }}// get variable directories of Android System QAndroidJniObject externalStorageDir = QAndroidJniObject :: callStaticObjectMethod (android/OS/Environment, getExternalStorageDirectory, () Ljava/io/File;); CHECK_EXCEPTION () m_list-> addItem (QString (external storage directory: % 1 ). arg (externalStorageDir. toString (); QAndroidJniObject dataDir = QAndroidJniObject: callStaticObjectMethod (android/OS/Environment, getDataDirectory, () Ljava/io/File;); CHECK_EXCEPTION () m_list-> addItem (QString (Data Directory: % 1 ). arg (dataDir. toString (); QAndroidJniObject dcim = QAndroidJniObject: Runtime (android/OS/Environment, DIRECTORY_DCIM, Ljava/lang/String;); CHECK_EXCEPTION () QAndroidJniObject dcimDir = kernel :: callStaticObjectMethod (android/OS/Environment, getExternalStoragePublicDirectory, (Ljava/lang/String;) Ljava/io/File;, dcim. object
(); CHECK_EXCEPTION () m_list-> addItem (QString (photo directory: % 1 ). arg (dcimDir. toString (); QAndroidJniObject music = QAndroidJniObject: Runtime (android/OS/Environment, DIRECTORY_MUSIC, Ljava/lang/String;); CHECK_EXCEPTION () QAndroidJniObject musicDir = kernel :: callStaticObjectMethod (android/OS/Environment, getExternalStoragePublicDirectory, (Ljava/lang/String;) Ljava/io/File;, music. object
(); CHECK_EXCEPTION () m_list-> addItem (QString (music Directory: % 1 ). arg (musicDir. toString (); QAndroidJniObject movie = QAndroidJniObject: Runtime (android/OS/Environment, runtime, Ljava/lang/String;); CHECK_EXCEPTION () QAndroidJniObject movieDir = QAndroidJniObject :: callStaticObjectMethod (android/OS/Environment, getExternalStoragePublicDirectory, (Ljava/lang/String;) Ljava/io/File;, movie. object
(); CHECK_EXCEPTION () m_list-> addItem (QString (Video Directory: % 1 ). arg (movieDir. toString (); QAndroidJniObject ringtones = QAndroidJniObject: Runtime (android/OS/Environment, runtime, Ljava/lang/String;); CHECK_EXCEPTION () QAndroidJniObject ringtonesDir = kernel :: callStaticObjectMethod (android/OS/Environment, getExternalStoragePublicDirectory, (Ljava/lang/String;) Ljava/io/File;, ringtones. object
(); CHECK_EXCEPTION () m_list-> addItem (QString (Ringtone Directory: % 1 ). arg (ringtonesDir. toString (); // app's infomation QAndroidJniObject filesDir = activity. callObjectMethod (getFilesDir, () Ljava/io/File;); CHECK_EXCEPTION () m_list-> addItem (QString (application File directory: % 1 ). arg (filesDir. toString (); QAndroidJniObject packageName = activity. callObjectMethod
(GetPackageName); CHECK_EXCEPTION () m_list-> addItem (QString (application package name: % 1 ). arg (packageName. toString (); QAndroidJniObject appCacheDir = activity. callObjectMethod (getCacheDir, () Ljava/io/File;); CHECK_EXCEPTION () m_list-> addItem (QString (Application cache directory: % 1 ). arg (appCacheDir. toString (); QAndroidJniObject appInfo = activity. callObjectMethod (getApplicationInfo, () Landroid/content/pm/ApplicationInfo;); CHECK_EXCEPTION () QAndroidJniObject appClassName = appInfo. getObjectField
(ClassName); CHECK_EXCEPTION () m_list-> addItem (QString (Application Class Name: % 1 ). arg (appClassName. toString (); QAndroidJniObject appLocation = appInfo. getObjectField (sourceDir, Ljava/lang/String;); CHECK_EXCEPTION () m_list-> addItem (QString (APK location: % 1 ). arg (appLocation. toString ()));}
The most frightening thing is the onRefresh () slot, which contains nearly one hundred and fifty lines of code. This is not a good programming practice. Do not do this in actual development.
In fact, the key to calling Android functions through JNI in Qt is two points:
How to Use the APIS provided by Qt to use the Android class library?
The APIS provided by Qt are described in "QtAndroid details (1): QAndroidJniObject" and QtAndroid details (2): startActivity, its partners, and QtAndroid details (3 ): startActivity has been explained in detail in the three articles about the Android camera function.
In this regard, we may not be familiar with C ++ developers. But it doesn't matter. You can use the Android online SDK for learning. In addition, the Qt JNI code I provide here is all available for actual test. It demonstrates some functional code. If necessary, it can be used directly in the project.
Okay. Let's get started with it.
Obtain the Android version
This is very considerate. The QtAndroid namespace directly provides a method: androidSdkVersion (). It returns an integer indicating the Android SDK version number.
Network Status
In Android, there is a ConnectivityManager class that can query the network status of the system.
The getActiveNetworkInfo () method of the ConnectivityManager class can obtain the currently active network connection information, and it returns an instance of the NetworkInfo class. If the network is not connected, this method returns null.
ConnectivityManager exists as a service in the Android system and needs to be obtained through the getSystemService () method of Context. GetSystemService () accepts a string representing the service name as a parameter. For the network connection management service, the name is CONNECTIVITY_SERVICE, which is a static member variable of the Context class.
The Java code for getting the network connection management service is as follows:
Context.getSystemService(Context.CONNECTIVITY_SERVICE);
These are the background knowledge of Android Java. Now let's look at the Qt JNI code. One row has passed.
QAndroidJniObject connectivity = QAndroidJniObject::getStaticObjectField( android/content/Context, CONNECTIVITY_SERVICE, Ljava/lang/String;);
This line of code uses CONNECTIVITY_SERVICE, a static member of the Context class, to be stored in a connectivity object. We need it when getting ConnectivityManager.
QAndroidJniObject connectivityService = activity.callObjectMethod( getSystemService, (Ljava/lang/String;)Ljava/lang/Object;, connectivity.object
());
This line of code calls the getSystemService method of Context to obtain the ConnectivityManager instance. We need a Context instance, and the QtAndroid: androidActivity () method can return one to us.
When you get the ConnectivityManager instance, you should call its getActiveNetworkInfo () method to obtain the current active connection. The following code is used:
QAndroidJniObject networkInfo = connectivityService.callObjectMethod( getActiveNetworkInfo, ()Landroid/net/NetworkInfo;);
QAndroidJniObject has a method called isValid (). When it returns true, the JNI object in the table is normally available. false indicates that no JNI object is available, this is generally the null value in Java. Therefore, if networkInfo. isValid () is true, the network connection is normal.
The others are helper code. Check the source code at the beginning.
Various directories of the Android System
The various system-level directories in the example are obtained through the android. OS. Enviroment class.
Let's talk about images, videos, and ringtones. They are obtained using the getExternalStoragePublicDirectory (String) method. Android provides a string name for each public storage directory, which is defined as a static member variable of the Enviroment class. Therefore, the steps for obtaining these directories using Qt JNI are as follows:
Call getExternalStoragePublicDirectory to obtain the directory type name.
According to this logic, the code for obtaining the image directory is as follows:
QAndroidJniObject dcim = QAndroidJniObject::getStaticObjectField( android/os/Environment, DIRECTORY_DCIM, Ljava/lang/String; ); QAndroidJniObject dcimDir = QAndroidJniObject::callStaticObjectMethod( android/os/Environment, getExternalStoragePublicDirectory, (Ljava/lang/String;)Ljava/io/File;, dcim.object
() );
We use the QAndroidJniObject: getStaticObjectField () method to obtain the static member variable of the Java class Enviroment, and then use callStaticObjectMethod to call the getExternalStoragePublicDirectory method.
Current Application Information
Some information about the current application can be obtained through the Activity class in Android.
We need an Activity object. In the Qt on Android Application, the corresponding class is QtActivity. In the previous section "QtAndroid details (3 ): we have already introduced startActivity's actual Android photo taking feature. Not much.
The code for getting the files directory of the current application is as follows:
QAndroidJniObject filesDir = activity.callObjectMethod( getFilesDir, ()Ljava/io/File;);
The returned result is/data/an. qt. SystemInfo/files. In fact, the same result can be obtained using the QDir: currentPath () method of Qt.
--------
Okay, this time. Next time, we will show some more interesting practical functions, such as shaking the mobile phone, keeping the screen bright, and dynamically switching the portrait screen. In the future, we may also introduce how to adjust the volume, adjust the screen brightness, use the push, the notification bar, and select contacts. However, let's look at my time.