niedziela, 15 listopada 2015

Story of porting complex Qt application to Android - part I

1. Abstract

In this post (or posts) I'm going to describe process of porting Nootka to Android.
In a few chapters I will try to summarize steps of that process, write about some issues I had to faced with and possible solutions.
I hope it would help someone to avoid inventing a wheel once more time and to realize some questions that will appear during porting any Qt application to Android, also for myself, to better understand all of that.
Let me know if You think there is something wrong or You know some better way.


What Nootka is - read here
but from programming point of view there are some details about desktop versions:
  • C++ and QtWidgets are used but not QtQuick
  • Currently Qt 5.5 is on the board
  • For coding Kdevelop is used (under Arch Linux)
  • Code is quite big (more than 400 files, 60k lines)
  • Project is divided on three libraries and a few plugins
  • External libraries are used (fftw, soundtouch, ogg and RtAudio)
  • There is no any UI files, all layout is created in c++ code

2. Preparations

Before we start, it is recommended to read KDAB blogs about Qt under Android:
https://www.kdab.com/qt-on-android-episode-1/

3. The foundations - build environment

Qt Creator

In spite Qt Creator and entire Qt is easy available under any Linux distro, for Android purposes I'm using official Qt on-line installer. This way I have ready build environments for Android platforms (armv7 -real devices and x86 - emulator).

I'm still coding with Kdevelop but to easy deploying to Android device and debugging, I'm doing this from Qt Creator.
Also Qt Creator makes all Android related things automatically (generates manifest file and building final apk)

qmake

Desktop version is built with cmake but for Android I migrated to qmake.
Actually it is much easier to use cmake for Android projects than one or two years before (with Extra Cmake Modules) so in some future I will back to it.
Anyway, cmake requires more knowledge about how Android apk-s are built when qmake does it almost transparently.

Genymotion

To test the application I'm using Genymotion - Android emulator based on VirtualBox.
Unfortunately, my CPU is not so young (3 cores AMD Phenom 1) and to get Qt working on emulated Android x86 I had to recompile x86 Qt kit (due to lack of ssse3 extensions in that CPU).
To achieve that I cloned qt as is described here:
https://wiki.qt.io/Qt5ForAndroidBuilding
then configured the build with:
configure -xplatform android-g++ -no-sse3 -no-ssse3 -no-sse4.1 -no-sse4.2
 -android-arch x86 -nomake tests -nomake examples -android-ndk path_to_ndk
 -android-ndk-host linux-x86_64 -android-toolchain-version 4.8 -skip qttranslations
 -skip qtwebkit -skip qtserialport -skip qtwebkit-examples -no-warnings-are-errors
This hack is required to get QtMultimedia working in Qt 5.5 and above. QtWidgets are free from ssse3 dependencies.

4. Screen orientation, scaling and other issues

Orientation

As long as Nootka window size is well scalable on desktops - I decided to force landscape orientation on possible small phone screens. Guitar fingerboard requires it.
It is done by squeezing an entry
android:screenOrientation="landscape"
into Activity node in AndroidManifest.xml file.
This way I got rid of scaling issues occurring when phone or tablet changes its orientation.

Full screen and screen lock

To have whole screen for the app and stop screen going to sleep, there is a function using QAndroidExtras module that is invoked when the app is launching:


Also additional permission:

Has to be set to allow keeping screen on. Into AndroidManifest.xml file as well.

Of course, main window has to be set to full screen:


Dialog windows

Also any dialog window will be rather maximized:


5. Main window and layout issues

Probably, if I would be about to start again from scratch I might use QtQuick for GUI layout but porting to it - no, no it was to expensive.
Fortunately, some decisions about layout I was made long before any Android related thought come to my mind - saved many of efforts.
What was that?

To have a possibility of painting over main window, to display text boxes and to perform some fancy animations a central widget of QMainWindow is type of QGraphicsView.
auto innerWidget = new QGraphicsView(this);
innerWidget->setScene(new QGraphicsScene(innerWidget));
setCentralWidget(innerWidget);
Then to this innerWidget QGraphicsProxyWidget is added that wraps QWidget container with all staff.
auto container = new QWidget;
// add some widgets into it
QGraphicsProxyWidget *proxy = scene()->addWidget(container);
To keep those in proper size, resizeEvent() is re-implemented:
void MainWindow::resizeEvent(QResizeEvent*) {
  proxy->setGeometry(0, 0, width(), height());
  scene()->setSceneRect(0, 0, width(), height());
  container->resize(size());
}
Note: to have those sizes valid all layouts must to have content margins set to 0.
someLayout->setContentsMargins(0, 0, 0, 0);
But under small Android screens saving space is rather a good habit.

6. In good style

Since Qt 5.4 version Qt offers "android" style but after many attempts to adjust it for Nootka purposes I get rid, and re-implemented Fusion style.
I will keep eye, maybe in further Qt releases it will be more matured.
However, the following hacks may be usable also for applications where android style is suitable enough.



To force minimal height of any GUI element the following trick is used:
qApp->setGlobalStrut(QSize(qApp->globalStrut().width(), qMax(qApp->globalStrut().height(), fingerPixels())));
It improves touch interaction and layout look on smaller screens.

Example implementation of QProxyStyle subclass may look like:


This is still not all and a bit clumsy but with this directions it will become more pretty.

Part II is here:
http://nootka-app.blogspot.com/2015/11/story-of-porting-complex-qt-application_18.html

Brak komentarzy:

Prześlij komentarz