Android: Extract data for native style on startup

When Ministro is not in use, we need to extract style
information on startup in order for the native Android style
to work.

The code to extract data from the device is contributed from
the Ministro project.

[ChangeLog][Android] Enable using native style also when
Ministro deployment mechanism is not in use.

Task-number: QTBUG-36019
Change-Id: I2afef5219b4e8fbb2f3e387cbc5e570da1f41011
Reviewed-by: BogDan Vatra <bogdan@kde.org>
Reviewed-by: Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@digia.com>
bb10
BogDan Vatra 2014-05-21 12:23:31 +03:00 committed by The Qt Project
parent 00470662e3
commit 09ed9e3eae
7 changed files with 1625 additions and 4 deletions

117
src/3rdparty/android/extract.h vendored Normal file
View File

@ -0,0 +1,117 @@
/*
* Copyright (C) 2005 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef EXTRACT_H
#define EXTRACT_H
#include <cstdint>
#include <cstring>
// shamelessly stolen from ResourceTypes.h Android's sources
/**
* This chunk specifies how to split an image into segments for
* scaling.
*
* There are J horizontal and K vertical segments. These segments divide
* the image into J*K regions as follows (where J=4 and K=3):
*
* F0 S0 F1 S1
* +-----+----+------+-------+
* S2| 0 | 1 | 2 | 3 |
* +-----+----+------+-------+
* | | | | |
* | | | | |
* F2| 4 | 5 | 6 | 7 |
* | | | | |
* | | | | |
* +-----+----+------+-------+
* S3| 8 | 9 | 10 | 11 |
* +-----+----+------+-------+
*
* Each horizontal and vertical segment is considered to by either
* stretchable (marked by the Sx labels) or fixed (marked by the Fy
* labels), in the horizontal or vertical axis, respectively. In the
* above example, the first is horizontal segment (F0) is fixed, the
* next is stretchable and then they continue to alternate. Note that
* the segment list for each axis can begin or end with a stretchable
* or fixed segment.
*
* The relative sizes of the stretchy segments indicates the relative
* amount of stretchiness of the regions bordered by the segments. For
* example, regions 3, 7 and 11 above will take up more horizontal space
* than regions 1, 5 and 9 since the horizontal segment associated with
* the first set of regions is larger than the other set of regions. The
* ratios of the amount of horizontal (or vertical) space taken by any
* two stretchable slices is exactly the ratio of their corresponding
* segment lengths.
*
* xDivs and yDivs point to arrays of horizontal and vertical pixel
* indices. The first pair of Divs (in either array) indicate the
* starting and ending points of the first stretchable segment in that
* axis. The next pair specifies the next stretchable segment, etc. So
* in the above example xDiv[0] and xDiv[1] specify the horizontal
* coordinates for the regions labeled 1, 5 and 9. xDiv[2] and
* xDiv[3] specify the coordinates for regions 3, 7 and 11. Note that
* the leftmost slices always start at x=0 and the rightmost slices
* always end at the end of the image. So, for example, the regions 0,
* 4 and 8 (which are fixed along the X axis) start at x value 0 and
* go to xDiv[0] and slices 2, 6 and 10 start at xDiv[1] and end at
* xDiv[2].
*
* The array pointed to by the colors field lists contains hints for
* each of the regions. They are ordered according left-to-right and
* top-to-bottom as indicated above. For each segment that is a solid
* color the array entry will contain that color value; otherwise it
* will contain NO_COLOR. Segments that are completely transparent
* will always have the value TRANSPARENT_COLOR.
*
* The PNG chunk type is "npTc".
*/
struct Res_png_9patch
{
Res_png_9patch() : wasDeserialized(false), xDivs(NULL),
yDivs(NULL), colors(NULL) { }
int8_t wasDeserialized;
int8_t numXDivs;
int8_t numYDivs;
int8_t numColors;
// These tell where the next section of a patch starts.
// For example, the first patch includes the pixels from
// 0 to xDivs[0]-1 and the second patch includes the pixels
// from xDivs[0] to xDivs[1]-1.
// Note: allocation/free of these pointers is left to the caller.
int32_t* xDivs;
int32_t* yDivs;
int32_t paddingLeft, paddingRight;
int32_t paddingTop, paddingBottom;
enum {
// The 9 patch segment is not a solid color.
NO_COLOR = 0x00000001,
// The 9 patch segment is completely transparent.
TRANSPARENT_COLOR = 0x00000000
};
// Note: allocation/free of this pointer is left to the caller.
uint32_t* colors;
// Deserialize/Unmarshall the patch data
static Res_png_9patch* deserialize(const void* data);
};
#endif

View File

@ -12,7 +12,8 @@ JAVASOURCES += \
$$PATHPREFIX/QtMessageDialogHelper.java \
$$PATHPREFIX/QtNative.java \
$$PATHPREFIX/QtNativeLibrariesDir.java \
$$PATHPREFIX/QtSurface.java
$$PATHPREFIX/QtSurface.java \
$$PATHPREFIX/ExtractStyle.java
# install
target.path = $$[QT_INSTALL_PREFIX]/jar

File diff suppressed because it is too large Load Diff

View File

@ -99,6 +99,7 @@ public class QtActivityDelegate
private static final String APPLICATION_PARAMETERS_KEY = "application.parameters";
private static final String STATIC_INIT_CLASSES_KEY = "static.init.classes";
private static final String NECESSITAS_API_LEVEL_KEY = "necessitas.api.level";
private static final String EXTRACT_STYLE_KEY = "extract.android.style";
private static String m_environmentVariables = null;
private static String m_applicationParameters = null;
@ -426,6 +427,11 @@ public class QtActivityDelegate
if (null == m_mainLib && libraries.size() > 0)
m_mainLib = libraries.get(libraries.size() - 1);
if (loaderParams.containsKey(EXTRACT_STYLE_KEY)) {
String path = loaderParams.getString(EXTRACT_STYLE_KEY);
new ExtractStyle(m_activity, path);
}
try {
m_super_dispatchKeyEvent = m_activity.getClass().getMethod("super_dispatchKeyEvent", KeyEvent.class);
m_super_onRestoreInstanceState = m_activity.getClass().getMethod("super_onRestoreInstanceState", Bundle.class);

View File

@ -116,6 +116,7 @@ public class QtActivity extends Activity
private static final String MAIN_LIBRARY_KEY = "main.library";
private static final String STATIC_INIT_CLASSES_KEY = "static.init.classes";
private static final String NECESSITAS_API_LEVEL_KEY = "necessitas.api.level";
private static final String EXTRACT_STYLE_KEY = "extract.android.style";
/// Ministro server parameter keys
private static final String REQUIRED_MODULES_KEY = "required.modules";
@ -177,6 +178,7 @@ public class QtActivity extends Activity
// * unstable - unstable repository, DO NOT use this repository in production,
// this repository is used to push Qt snapshots.
private String[] m_qtLibs = null; // required qt libs
private int m_displayDensity = -1;
public QtActivity()
{
@ -629,6 +631,17 @@ public class QtActivity extends Activity
m_activityInfo.metaData.getString("android.app.static_init_classes").split(":"));
}
loaderParams.putStringArrayList(NATIVE_LIBRARIES_KEY, libraryList);
if (bundlingQtLibs) {
String themePath = pluginsPrefix + "android-style/";
String stylePath = themePath + m_displayDensity + "/";
if (!(new File(stylePath)).exists())
loaderParams.putString(EXTRACT_STYLE_KEY, stylePath);
ENVIRONMENT_VARIABLES += "\tMINISTRO_ANDROID_STYLE_PATH=" + stylePath
+ "\tQT_ANDROID_THEMES_ROOT_PATH=" + themePath;
}
loaderParams.putString(ENVIRONMENT_VARIABLES_KEY, ENVIRONMENT_VARIABLES
+ "\tQML2_IMPORT_PATH=" + pluginsPrefix + "/qml"
+ "\tQML_IMPORT_PATH=" + pluginsPrefix + "/imports"
@ -867,8 +880,10 @@ public class QtActivity extends Activity
return;
}
m_displayDensity = getResources().getDisplayMetrics().densityDpi;
ENVIRONMENT_VARIABLES += "\tQT_ANDROID_THEME=" + QT_ANDROID_DEFAULT_THEME
+ "/\tQT_ANDROID_THEME_DISPLAY_DPI=" + getResources().getDisplayMetrics().densityDpi + "\t";
+ "/\tQT_ANDROID_THEME_DISPLAY_DPI=" + m_displayDensity + "\t";
if (null == getLastNonConfigurationInstance()) {
// if splash screen is defined, then show it

View File

@ -21,7 +21,9 @@ CONFIG += qpa/genericunixfontdatabase
OTHER_FILES += $$PWD/android.json
INCLUDEPATH += $$PWD
INCLUDEPATH += \
$$PWD \
$$QT_SOURCE_TREE/src/3rdparty/android
SOURCES += $$PWD/androidplatformplugin.cpp \
$$PWD/androidjnimain.cpp \
@ -48,7 +50,8 @@ SOURCES += $$PWD/androidplatformplugin.cpp \
$$PWD/qandroidplatformrasterwindow.cpp \
$$PWD/qandroidplatformbackingstore.cpp \
$$PWD/qandroidplatformopenglcontext.cpp \
$$PWD/qandroidplatformforeignwindow.cpp
$$PWD/qandroidplatformforeignwindow.cpp \
$$PWD/extract.cpp
HEADERS += $$PWD/qandroidplatformintegration.h \
$$PWD/androidjnimain.h \

View File

@ -0,0 +1,135 @@
/****************************************************************************
**
** Copyright (C) 2014 BogDan Vatra <bogdan@kde.org>
** Contact: http://www.qt-project.org/legal
**
** This file is part of the plugins of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include <jni.h>
#include <android/log.h>
#include <extract.h>
#include <alloca.h>
#define LOG_TAG "extractSyleInfo"
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)
#define LOGF(...) __android_log_print(ANDROID_LOG_FATAL,LOG_TAG,__VA_ARGS__)
extern "C" JNIEXPORT jintArray JNICALL Java_org_qtproject_qt5_android_ExtractStyle_extractNativeChunkInfo(JNIEnv * env, jobject, Res_png_9patch* chunk)
{
Res_png_9patch::deserialize(chunk);
//printChunkInformation(chunk);
jintArray result;
size_t size = 3+chunk->numXDivs+chunk->numYDivs+chunk->numColors;
result = env->NewIntArray(size);
if (!result)
return 0;
jint *data = (jint*)malloc(sizeof(jint)*size);
size_t pos = 0;
data[pos++]=chunk->numXDivs;
data[pos++]=chunk->numYDivs;
data[pos++]=chunk->numColors;
for (int x = 0; x <chunk->numXDivs; x ++)
data[pos++]=chunk->xDivs[x];
for (int y = 0; y <chunk->numYDivs; y ++)
data[pos++]=chunk->yDivs[y];
for (int c = 0; c <chunk->numColors; c ++)
data[pos++]=chunk->colors[c];
env->SetIntArrayRegion(result, 0, size, data);
free(data);
return result;
}
extern "C" JNIEXPORT jintArray JNICALL Java_org_qtproject_qt5_android_ExtractStyle_extractChunkInfo(JNIEnv * env, jobject obj, jbyteArray chunkObj)
{
size_t chunkSize = env->GetArrayLength(chunkObj);
void* storage = alloca(chunkSize);
env->GetByteArrayRegion(chunkObj, 0, chunkSize,
reinterpret_cast<jbyte*>(storage));
if (!env->ExceptionCheck())
return Java_org_qtproject_qt5_android_ExtractStyle_extractNativeChunkInfo(env, obj, static_cast<Res_png_9patch*>(storage));
else
env->ExceptionClear();
return 0;
}
// The following part was shamelessly stolen from ResourceTypes.cpp from Android's sources
/*
* Copyright (C) 2005 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
static void deserializeInternal(const void* inData, Res_png_9patch* outData) {
char* patch = (char*) inData;
if (inData != outData) {
memmove(&outData->wasDeserialized, patch, 4); // copy wasDeserialized, numXDivs, numYDivs, numColors
memmove(&outData->paddingLeft, patch + 12, 4); // copy wasDeserialized, numXDivs, numYDivs, numColors
}
outData->wasDeserialized = true;
char* data = (char*)outData;
data += sizeof(Res_png_9patch);
outData->xDivs = (int32_t*) data;
data += outData->numXDivs * sizeof(int32_t);
outData->yDivs = (int32_t*) data;
data += outData->numYDivs * sizeof(int32_t);
outData->colors = (uint32_t*) data;
}
Res_png_9patch* Res_png_9patch::deserialize(const void* inData)
{
if (sizeof(void*) != sizeof(int32_t)) {
LOGE("Cannot deserialize on non 32-bit system\n");
return NULL;
}
deserializeInternal(inData, (Res_png_9patch*) inData);
return (Res_png_9patch*) inData;
}