summaryrefslogtreecommitdiffstats
path: root/src/android
diff options
context:
space:
mode:
Diffstat (limited to 'src/android')
-rw-r--r--src/android/android.pro15
-rw-r--r--src/android/jar/AndroidManifest.xml4
-rw-r--r--src/android/jar/res/values/strings.xml4
-rw-r--r--src/android/jar/src/org/qtproject/qt5/android/QtActivityDelegate.java714
-rw-r--r--src/android/jar/src/org/qtproject/qt5/android/QtEditText.java97
-rw-r--r--src/android/jar/src/org/qtproject/qt5/android/QtInputConnection.java244
-rw-r--r--src/android/jar/src/org/qtproject/qt5/android/QtLayout.java201
-rw-r--r--src/android/jar/src/org/qtproject/qt5/android/QtNative.java611
-rw-r--r--src/android/jar/src/org/qtproject/qt5/android/QtNativeLibrariesDir.java61
-rw-r--r--src/android/jar/src/org/qtproject/qt5/android/QtSurface.java206
-rw-r--r--src/android/java/AndroidManifest.xml25
-rw-r--r--src/android/java/res/layout/splash.xml13
-rw-r--r--src/android/java/res/values-de/strings.xml6
-rw-r--r--src/android/java/res/values-el/strings.xml6
-rw-r--r--src/android/java/res/values-es/strings.xml6
-rw-r--r--src/android/java/res/values-et/strings.xml6
-rw-r--r--src/android/java/res/values-fa/strings.xml6
-rw-r--r--src/android/java/res/values-fr/strings.xml6
-rw-r--r--src/android/java/res/values-id/strings.xml6
-rw-r--r--src/android/java/res/values-it/strings.xml6
-rw-r--r--src/android/java/res/values-ja/strings.xml6
-rw-r--r--src/android/java/res/values-ms/strings.xml6
-rw-r--r--src/android/java/res/values-nb/strings.xml6
-rw-r--r--src/android/java/res/values-nl/strings.xml6
-rw-r--r--src/android/java/res/values-pl/strings.xml6
-rw-r--r--src/android/java/res/values-pt-rBR/strings.xml6
-rw-r--r--src/android/java/res/values-ro/strings.xml6
-rw-r--r--src/android/java/res/values-rs/strings.xml6
-rw-r--r--src/android/java/res/values-ru/strings.xml6
-rw-r--r--src/android/java/res/values-zh-rCN/strings.xml6
-rw-r--r--src/android/java/res/values-zh-rTW/strings.xml6
-rw-r--r--src/android/java/res/values/libs.xml8
-rw-r--r--src/android/java/res/values/strings.xml7
-rw-r--r--src/android/java/src/org/kde/necessitas/ministro/IMinistro.aidl49
-rw-r--r--src/android/java/src/org/kde/necessitas/ministro/IMinistroCallback.aidl53
-rw-r--r--src/android/java/src/org/qtproject/qt5/android/bindings/QtActivity.java1278
-rw-r--r--src/android/java/src/org/qtproject/qt5/android/bindings/QtApplication.java149
-rw-r--r--src/android/java/version.xml8
38 files changed, 3861 insertions, 0 deletions
diff --git a/src/android/android.pro b/src/android/android.pro
new file mode 100644
index 0000000000..049a51904c
--- /dev/null
+++ b/src/android/android.pro
@@ -0,0 +1,15 @@
+CONFIG += java
+TARGET = QtAndroid
+DESTDIR = $$[QT_INSTALL_PREFIX/get]/jar
+
+PATHPREFIX = $$PWD/jar/src/org/qtproject/qt5/android/
+
+JAVACLASSPATH += $$PWD/jar/src/
+JAVASOURCES += \
+ $$PATHPREFIX/QtActivityDelegate.java \
+ $$PATHPREFIX/QtEditText.java \
+ $$PATHPREFIX/QtInputConnection.java \
+ $$PATHPREFIX/QtLayout.java \
+ $$PATHPREFIX/QtNative.java \
+ $$PATHPREFIX/QtNativeLibrariesDir.java \
+ $$PATHPREFIX/QtSurface.java
diff --git a/src/android/jar/AndroidManifest.xml b/src/android/jar/AndroidManifest.xml
new file mode 100644
index 0000000000..ebc6fcfea7
--- /dev/null
+++ b/src/android/jar/AndroidManifest.xml
@@ -0,0 +1,4 @@
+<?xml version='1.0' encoding='utf-8'?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1" android:versionName="1.0" package="org.qtproject.qt5.android">
+ <supports-screens android:largeScreens="true" android:normalScreens="true" android:anyDensity="true" android:smallScreens="true"/>
+</manifest>
diff --git a/src/android/jar/res/values/strings.xml b/src/android/jar/res/values/strings.xml
new file mode 100644
index 0000000000..1021b5478a
--- /dev/null
+++ b/src/android/jar/res/values/strings.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="app_name">QtJar</string>
+</resources>
diff --git a/src/android/jar/src/org/qtproject/qt5/android/QtActivityDelegate.java b/src/android/jar/src/org/qtproject/qt5/android/QtActivityDelegate.java
new file mode 100644
index 0000000000..b6e6e3397e
--- /dev/null
+++ b/src/android/jar/src/org/qtproject/qt5/android/QtActivityDelegate.java
@@ -0,0 +1,714 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the Android port 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$
+**
+****************************************************************************/
+
+package org.qtproject.qt5.android;
+
+import java.io.File;
+import java.io.IOException;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Iterator;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.res.Configuration;
+import android.graphics.Rect;
+import android.os.Build;
+import android.os.Bundle;
+import android.text.method.MetaKeyKeyListener;
+import android.util.DisplayMetrics;
+import android.util.Log;
+import android.view.ContextMenu;
+import android.view.ContextMenu.ContextMenuInfo;
+import android.view.KeyCharacterMap;
+import android.view.KeyEvent;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+import android.view.inputmethod.InputMethodManager;
+
+public class QtActivityDelegate
+{
+ private Activity m_activity = null;
+ private Method m_super_dispatchKeyEvent = null;
+ private Method m_super_onRestoreInstanceState = null;
+ private Method m_super_onRetainNonConfigurationInstance = null;
+ private Method m_super_onSaveInstanceState = null;
+ private Method m_super_onKeyDown = null;
+ private Method m_super_onKeyUp = null;
+ private Method m_super_onConfigurationChanged = null;
+
+ private static final String NATIVE_LIBRARIES_KEY = "native.libraries";
+ private static final String BUNDLED_LIBRARIES_KEY = "bundled.libraries";
+ private static final String MAIN_LIBRARY_KEY = "main.library";
+ private static final String ENVIRONMENT_VARIABLES_KEY = "environment.variables";
+ 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 String m_environmentVariables = null;
+ private static String m_applicationParameters = null;
+
+ private int m_currentOrientation = Configuration.ORIENTATION_UNDEFINED;
+
+ private String m_mainLib;
+ private long m_metaState;
+ private int m_lastChar = 0;
+ private boolean m_fullScreen = false;
+ private boolean m_started = false;
+ private QtSurface m_surface = null;
+ private QtLayout m_layout = null;
+ private QtEditText m_editText = null;
+ private InputMethodManager m_imm = null;
+ private boolean m_quitApp = true;
+ private Process m_debuggerProcess = null; // debugger process
+
+ public boolean m_keyboardIsVisible = false;
+ public boolean m_keyboardIsHiding = false;
+
+ public QtLayout getQtLayout()
+ {
+ return m_layout;
+ }
+
+ public QtSurface getQtSurface()
+ {
+ return m_surface;
+ }
+
+ public void redrawWindow(int left, int top, int right, int bottom)
+ {
+ m_surface.drawBitmap(new Rect(left, top, right, bottom));
+ }
+
+ public void setFullScreen(boolean enterFullScreen)
+ {
+ if (m_fullScreen == enterFullScreen)
+ return;
+
+ if (m_fullScreen = enterFullScreen) {
+ m_activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
+ m_activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
+ } else {
+ m_activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
+ m_activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
+ }
+ }
+
+ // case status
+ private final int ImhNoAutoUppercase = 0x2;
+ private final int ImhPreferUppercase = 0x8;
+ @SuppressWarnings("unused")
+ private final int ImhPreferLowercase = 0x10;
+ private final int ImhUppercaseOnly = 0x40000;
+ private final int ImhLowercaseOnly = 0x80000;
+
+ // options
+ private final int ImhNoPredictiveText = 0x20;
+
+ // layout
+ private final int ImhHiddenText = 0x1;
+ private final int ImhPreferNumbers = 0x4;
+ private final int ImhMultiLine = 0x400;
+ private final int ImhDigitsOnly = 0x10000;
+ private final int ImhFormattedNumbersOnly = 0x20000;
+ private final int ImhDialableCharactersOnly = 0x100000;
+ private final int ImhEmailCharactersOnly = 0x200000;
+ private final int ImhUrlCharactersOnly = 0x400000;
+
+ public void resetSoftwareKeyboard()
+ {
+ if (m_imm == null)
+ return;
+ m_editText.postDelayed(new Runnable() {
+ @Override
+ public void run() {
+ m_imm.restartInput(m_editText);
+ }
+ }, 5);
+ }
+
+ public void showSoftwareKeyboard(int x, int y, int width, int height, int inputHints)
+ {
+ if (m_imm == null)
+ return;
+ if (height > m_surface.getHeight()*2/3)
+ m_activity.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_UNCHANGED | WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
+ else
+ m_activity.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_UNCHANGED | WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN);
+
+ int initialCapsMode = 0;
+ int imeOptions = android.view.inputmethod.EditorInfo.IME_ACTION_DONE;
+ int inputType = android.text.InputType.TYPE_CLASS_TEXT;
+
+ if ((inputHints & ImhMultiLine) != 0) {
+ inputType = android.text.InputType.TYPE_CLASS_TEXT | android.text.InputType.TYPE_TEXT_FLAG_MULTI_LINE;
+ imeOptions = android.view.inputmethod.EditorInfo.IME_FLAG_NO_ENTER_ACTION;
+ }
+
+ if (((inputHints & ImhNoAutoUppercase) != 0 || (inputHints & ImhPreferUppercase) != 0)
+ && (inputHints & ImhLowercaseOnly) == 0) {
+ initialCapsMode = android.text.TextUtils.CAP_MODE_SENTENCES;
+ }
+
+ if ((inputHints & ImhUppercaseOnly) != 0)
+ initialCapsMode = android.text.TextUtils.CAP_MODE_CHARACTERS;
+
+ if ((inputHints & ImhHiddenText) != 0)
+ inputType = android.text.InputType.TYPE_TEXT_VARIATION_PASSWORD;
+
+ if ((inputHints & ImhPreferNumbers) != 0)
+ inputType = android.text.InputType.TYPE_CLASS_NUMBER;
+
+ if ((inputHints & ImhDigitsOnly) != 0)
+ inputType = android.text.InputType.TYPE_CLASS_NUMBER;
+
+ if ((inputHints & ImhFormattedNumbersOnly) != 0) {
+ inputType = android.text.InputType.TYPE_CLASS_NUMBER
+ | android.text.InputType.TYPE_NUMBER_FLAG_DECIMAL
+ | android.text.InputType.TYPE_NUMBER_FLAG_SIGNED;
+ }
+
+ if ((inputHints & ImhDialableCharactersOnly) != 0)
+ inputType = android.text.InputType.TYPE_CLASS_PHONE;
+
+ if ((inputHints & ImhEmailCharactersOnly) != 0)
+ inputType = android.text.InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS;
+
+ if ((inputHints & ImhUrlCharactersOnly) != 0) {
+ inputType = android.text.InputType.TYPE_TEXT_VARIATION_URI;
+ imeOptions = android.view.inputmethod.EditorInfo.IME_ACTION_GO;
+ }
+
+ if ((inputHints & ImhNoPredictiveText) != 0) {
+ //android.text.InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS | android.text.InputType.TYPE_CLASS_TEXT;
+ inputType = android.text.InputType.TYPE_CLASS_TEXT | android.text.InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD;
+ }
+
+ m_editText.setInitialCapsMode(initialCapsMode);
+ m_editText.setImeOptions(imeOptions);
+ m_editText.setInputType(inputType);
+
+ m_layout.removeView(m_editText);
+ m_layout.addView(m_editText, new QtLayout.LayoutParams(width, height, x, y));
+ m_editText.bringToFront();
+ m_editText.requestFocus();
+ m_editText.postDelayed(new Runnable() {
+ @Override
+ public void run() {
+ m_imm.showSoftInput(m_editText, 0);
+ m_keyboardIsVisible = true;
+ m_keyboardIsHiding = false;
+ m_editText.postDelayed(new Runnable() {
+ @Override
+ public void run() {
+ m_imm.restartInput(m_editText);
+ }
+ }, 25);
+ }
+ }, 15);
+ }
+
+ public void hideSoftwareKeyboard()
+ {
+ if (m_imm == null)
+ return;
+ m_imm.hideSoftInputFromWindow(m_editText.getWindowToken(), 0);
+ m_keyboardIsVisible = false;
+ m_keyboardIsHiding = false;
+ }
+
+ public boolean isSoftwareKeyboardVisible()
+ {
+ return m_keyboardIsVisible;
+ }
+
+ String getAppIconSize(Activity a)
+ {
+ int size = a.getResources().getDimensionPixelSize(android.R.dimen.app_icon_size);
+ if (size < 36 || size > 512) { // check size sanity
+ DisplayMetrics metrics = new DisplayMetrics();
+ a.getWindowManager().getDefaultDisplay().getMetrics(metrics);
+ size = metrics.densityDpi/10*3;
+ if (size < 36)
+ size = 36;
+
+ if (size > 512)
+ size = 512;
+ }
+ return "\tQT_ANDROID_APP_ICON_SIZE=" + size;
+ }
+
+ public void updateSelection(int selStart, int selEnd, int candidatesStart, int candidatesEnd)
+ {
+ if (m_imm == null)
+ return;
+
+ m_imm.updateSelection(m_editText, selStart, selEnd, candidatesStart, candidatesEnd);
+ }
+
+ public boolean loadApplication(Activity activity, ClassLoader classLoader, Bundle loaderParams)
+ {
+ /// check parameters integrity
+ if (!loaderParams.containsKey(NATIVE_LIBRARIES_KEY)
+ || !loaderParams.containsKey(BUNDLED_LIBRARIES_KEY)
+ || !loaderParams.containsKey(ENVIRONMENT_VARIABLES_KEY)) {
+ return false;
+ }
+
+ m_activity = activity;
+ QtNative.setActivity(m_activity, this);
+ QtNative.setClassLoader(classLoader);
+ if (loaderParams.containsKey(STATIC_INIT_CLASSES_KEY)) {
+ for (String className: loaderParams.getStringArray(STATIC_INIT_CLASSES_KEY)) {
+ if (className.length() == 0)
+ continue;
+
+ try {
+ @SuppressWarnings("rawtypes")
+ Class initClass = classLoader.loadClass(className);
+ Object staticInitDataObject = initClass.newInstance(); // create an instance
+ Method m = initClass.getMethod("setActivity", Activity.class, Object.class);
+ m.invoke(staticInitDataObject, m_activity, this);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ QtNative.loadQtLibraries(loaderParams.getStringArrayList(NATIVE_LIBRARIES_KEY));
+ ArrayList<String> libraries = loaderParams.getStringArrayList(BUNDLED_LIBRARIES_KEY);
+ QtNative.loadBundledLibraries(libraries, QtNativeLibrariesDir.nativeLibrariesDir(m_activity));
+ m_mainLib = loaderParams.getString(MAIN_LIBRARY_KEY);
+ // older apps provide the main library as the last bundled library; look for this if the main library isn't provided
+ if (null == m_mainLib && libraries.size() > 0)
+ m_mainLib = libraries.get(libraries.size() - 1);
+
+ try {
+ m_super_dispatchKeyEvent = m_activity.getClass().getMethod("super_dispatchKeyEvent", KeyEvent.class);
+ m_super_onRestoreInstanceState = m_activity.getClass().getMethod("super_onRestoreInstanceState", Bundle.class);
+ m_super_onRetainNonConfigurationInstance = m_activity.getClass().getMethod("super_onRetainNonConfigurationInstance");
+ m_super_onSaveInstanceState = m_activity.getClass().getMethod("super_onSaveInstanceState", Bundle.class);
+ m_super_onKeyDown = m_activity.getClass().getMethod("super_onKeyDown", Integer.TYPE, KeyEvent.class);
+ m_super_onKeyUp = m_activity.getClass().getMethod("super_onKeyUp", Integer.TYPE, KeyEvent.class);
+ m_super_onConfigurationChanged = m_activity.getClass().getMethod("super_onConfigurationChanged", Configuration.class);
+ } catch (Exception e) {
+ e.printStackTrace();
+ return false;
+ }
+
+ int necessitasApiLevel = 1;
+ if (loaderParams.containsKey(NECESSITAS_API_LEVEL_KEY))
+ necessitasApiLevel = loaderParams.getInt(NECESSITAS_API_LEVEL_KEY);
+
+ m_environmentVariables = loaderParams.getString(ENVIRONMENT_VARIABLES_KEY);
+ String additionalEnvironmentVariables = "QT_ANDROID_FONTS_MONOSPACE=Droid Sans Mono;Droid Sans;Droid Sans Fallback"
+ + "\tNECESSITAS_API_LEVEL=" + necessitasApiLevel
+ + "\tHOME=" + m_activity.getFilesDir().getAbsolutePath()
+ + "\tTMPDIR=" + m_activity.getFilesDir().getAbsolutePath();
+ if (android.os.Build.VERSION.SDK_INT < 14)
+ additionalEnvironmentVariables += "\tQT_ANDROID_FONTS=Droid Sans;Droid Sans Fallback";
+ else
+ additionalEnvironmentVariables += "\tQT_ANDROID_FONTS=Roboto;Droid Sans;Droid Sans Fallback";
+
+ additionalEnvironmentVariables += getAppIconSize(activity);
+
+ if (m_environmentVariables != null && m_environmentVariables.length() > 0)
+ m_environmentVariables = additionalEnvironmentVariables + "\t" + m_environmentVariables;
+ else
+ m_environmentVariables = additionalEnvironmentVariables;
+
+ if (loaderParams.containsKey(APPLICATION_PARAMETERS_KEY))
+ m_applicationParameters = loaderParams.getString(APPLICATION_PARAMETERS_KEY);
+ else
+ m_applicationParameters = "";
+
+ return true;
+ }
+
+ public boolean startApplication()
+ {
+ // start application
+ try {
+ // FIXME turn on debuggable check
+ // if the applications is debuggable and it has a native debug request
+ Bundle extras = m_activity.getIntent().getExtras();
+ if ( /*(ai.flags&ApplicationInfo.FLAG_DEBUGGABLE) != 0
+ &&*/ extras != null
+ && extras.containsKey("native_debug")
+ && extras.getString("native_debug").equals("true")) {
+ try {
+ String packagePath =
+ m_activity.getPackageManager().getApplicationInfo(m_activity.getPackageName(),
+ PackageManager.GET_CONFIGURATIONS).dataDir + "/";
+ String gdbserverPath =
+ extras.containsKey("gdbserver_path")
+ ? extras.getString("gdbserver_path")
+ : packagePath+"lib/gdbserver ";
+
+ String socket =
+ extras.containsKey("gdbserver_socket")
+ ? extras.getString("gdbserver_socket")
+ : "+debug-socket";
+
+ // start debugger
+ m_debuggerProcess = Runtime.getRuntime().exec(gdbserverPath
+ + socket
+ + " --attach "
+ + android.os.Process.myPid(),
+ null,
+ new File(packagePath));
+ } catch (IOException ioe) {
+ Log.e(QtNative.QtTAG,"Can't start debugger" + ioe.getMessage());
+ } catch (SecurityException se) {
+ Log.e(QtNative.QtTAG,"Can't start debugger" + se.getMessage());
+ } catch (NameNotFoundException e) {
+ Log.e(QtNative.QtTAG,"Can't start debugger" + e.getMessage());
+ }
+ }
+
+
+ if ( /*(ai.flags&ApplicationInfo.FLAG_DEBUGGABLE) != 0
+ &&*/ extras != null
+ && extras.containsKey("debug_ping")
+ && extras.getString("debug_ping").equals("true")) {
+ String packagePath =
+ m_activity.getPackageManager().getApplicationInfo(m_activity.getPackageName(),
+ PackageManager.GET_CONFIGURATIONS).dataDir + "/";
+ String debugPing = packagePath + "debug_ping";
+ int i = 0;
+ while (true) {
+ ++i;
+ Log.i(QtNative.QtTAG, "DEBUGGER: WAITING FOR PING AT " + debugPing + ", ATTEMPT " + i);
+ File file = new File(debugPing);
+ if (file.exists()) {
+ file.delete();
+ break;
+ }
+ Thread.sleep(1000);
+ }
+
+ Log.i(QtNative.QtTAG, "DEBUGGER: GOT PING " + debugPing);
+ }
+
+
+ if (/*(ai.flags&ApplicationInfo.FLAG_DEBUGGABLE) != 0
+ &&*/ extras != null
+ && extras.containsKey("qml_debug")
+ && extras.getString("qml_debug").equals("true")) {
+ String qmljsdebugger;
+ if (extras.containsKey("qmljsdebugger")) {
+ qmljsdebugger = extras.getString("qmljsdebugger");
+ qmljsdebugger.replaceAll("\\s", ""); // remove whitespace for security
+ } else {
+ qmljsdebugger = "port:3768";
+ }
+ m_applicationParameters += "\t-qmljsdebugger=" + qmljsdebugger;
+ }
+
+ if (null == m_surface)
+ onCreate(null);
+ String nativeLibraryDir = QtNativeLibrariesDir.nativeLibrariesDir(m_activity);
+ m_surface.applicationStarted( QtNative.startApplication(m_applicationParameters,
+ m_environmentVariables,
+ m_mainLib,
+ nativeLibraryDir));
+ m_started = true;
+ return true;
+ } catch (Exception e) {
+ e.printStackTrace();
+ return false;
+ }
+ }
+
+ public void onTerminate()
+ {
+ QtNative.terminateQt();
+ }
+
+ public void onCreate(Bundle savedInstanceState)
+ {
+ m_quitApp = true;
+ if (null == savedInstanceState) {
+ DisplayMetrics metrics = new DisplayMetrics();
+ m_activity.getWindowManager().getDefaultDisplay().getMetrics(metrics);
+ QtNative.setApplicationDisplayMetrics(metrics.widthPixels, metrics.heightPixels,
+ metrics.widthPixels, metrics.heightPixels,
+ metrics.xdpi, metrics.ydpi);
+ }
+ m_layout = new QtLayout(m_activity);
+ m_surface = new QtSurface(m_activity, 0);
+ m_editText = new QtEditText(m_activity);
+ m_imm = (InputMethodManager)m_activity.getSystemService(Context.INPUT_METHOD_SERVICE);
+ m_layout.addView(m_surface,0);
+ m_activity.setContentView(m_layout,
+ new ViewGroup.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT,
+ ViewGroup.LayoutParams.FILL_PARENT));
+ m_layout.bringChildToFront(m_surface);
+ m_activity.registerForContextMenu(m_layout);
+
+ m_currentOrientation = m_activity.getResources().getConfiguration().orientation;
+ }
+
+ public void onConfigurationChanged(Configuration configuration)
+ {
+ try {
+ m_super_onConfigurationChanged.invoke(m_activity, configuration);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ if (configuration.orientation != m_currentOrientation
+ && m_currentOrientation != Configuration.ORIENTATION_UNDEFINED) {
+ QtNative.handleOrientationChanged(configuration.orientation);
+ }
+
+ m_currentOrientation = configuration.orientation;
+ }
+
+ public void onDestroy()
+ {
+ if (m_quitApp) {
+ if (m_debuggerProcess != null)
+ m_debuggerProcess.destroy();
+ System.exit(0);// FIXME remove it or find a better way
+ }
+ }
+
+ public void onRestoreInstanceState(Bundle savedInstanceState)
+ {
+ try {
+ m_super_onRestoreInstanceState.invoke(m_activity, savedInstanceState);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+// setFullScreen(savedInstanceState.getBoolean("FullScreen"));
+ m_started = savedInstanceState.getBoolean("Started");
+ if (m_started)
+ m_surface.applicationStarted(true);
+ }
+
+ public void onResume()
+ {
+ // fire all lostActions
+ synchronized (QtNative.m_mainActivityMutex)
+ {
+ Iterator<Runnable> itr = QtNative.getLostActions().iterator();
+ while (itr.hasNext())
+ m_activity.runOnUiThread(itr.next());
+
+ if (m_started) {
+ QtNative.clearLostActions();
+ QtNative.updateWindow();
+ }
+ }
+ }
+
+ public Object onRetainNonConfigurationInstance()
+ {
+ try {
+ m_super_onRetainNonConfigurationInstance.invoke(m_activity);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ m_quitApp = false;
+ return true;
+ }
+
+ public void onSaveInstanceState(Bundle outState) {
+ try {
+ m_super_onSaveInstanceState.invoke(m_activity, outState);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ outState.putBoolean("FullScreen", m_fullScreen);
+ outState.putBoolean("Started", m_started);
+ }
+
+ public boolean onKeyDown(int keyCode, KeyEvent event)
+ {
+ if (!m_started)
+ return false;
+
+ if (keyCode == KeyEvent.KEYCODE_MENU) {
+ try {
+ return (Boolean)m_super_onKeyDown.invoke(m_activity, keyCode, event);
+ } catch (Exception e) {
+ e.printStackTrace();
+ return false;
+ }
+ }
+
+ m_metaState = MetaKeyKeyListener.handleKeyDown(m_metaState, keyCode, event);
+ int c = event.getUnicodeChar(MetaKeyKeyListener.getMetaState(m_metaState));
+ int lc = c;
+ m_metaState = MetaKeyKeyListener.adjustMetaAfterKeypress(m_metaState);
+
+ if ((c & KeyCharacterMap.COMBINING_ACCENT) != 0) {
+ c = c & KeyCharacterMap.COMBINING_ACCENT_MASK;
+ int composed = KeyEvent.getDeadChar(m_lastChar, c);
+ c = composed;
+ }
+
+ m_lastChar = lc;
+ if (keyCode != KeyEvent.KEYCODE_BACK)
+ QtNative.keyDown(keyCode, c, event.getMetaState());
+
+ return true;
+ }
+
+ public boolean onKeyUp(int keyCode, KeyEvent event)
+ {
+ if (!m_started)
+ return false;
+
+ if (keyCode == KeyEvent.KEYCODE_MENU) {
+ try {
+ return (Boolean)m_super_onKeyUp.invoke(m_activity, keyCode, event);
+ } catch (Exception e) {
+ e.printStackTrace();
+ return false;
+ }
+ }
+
+ if (keyCode == KeyEvent.KEYCODE_BACK && m_keyboardIsVisible)
+ {
+ if (!m_keyboardIsHiding)
+ hideSoftwareKeyboard();
+ return true;
+ }
+
+ m_metaState = MetaKeyKeyListener.handleKeyUp(m_metaState, keyCode, event);
+ QtNative.keyUp(keyCode, event.getUnicodeChar(), event.getMetaState());
+ return true;
+ }
+
+ public boolean dispatchKeyEvent(KeyEvent event)
+ {
+ if (m_started
+ && event.getAction() == KeyEvent.ACTION_MULTIPLE
+ && event.getCharacters() != null
+ && event.getCharacters().length() == 1
+ && event.getKeyCode() == 0) {
+ QtNative.keyDown(0, event.getCharacters().charAt(0), event.getMetaState());
+ QtNative.keyUp(0, event.getCharacters().charAt(0), event.getMetaState());
+ }
+
+ try {
+ return (Boolean) m_super_dispatchKeyEvent.invoke(m_activity, event);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return false;
+ }
+
+ private boolean m_opionsMenuIsVisible = false;
+ public boolean onCreateOptionsMenu(Menu menu)
+ {
+ menu.clear();
+ return true;
+ }
+ public boolean onPrepareOptionsMenu(Menu menu)
+ {
+ m_opionsMenuIsVisible = true;
+ return QtNative.onPrepareOptionsMenu(menu);
+ }
+
+ public boolean onOptionsItemSelected(MenuItem item)
+ {
+ return QtNative.onOptionsItemSelected(item.getItemId(), item.isChecked());
+ }
+
+ public void onOptionsMenuClosed(Menu menu)
+ {
+ m_opionsMenuIsVisible = false;
+ QtNative.onOptionsMenuClosed(menu);
+ }
+
+ public void resetOptionsMenu()
+ {
+ if (m_opionsMenuIsVisible)
+ m_activity.closeOptionsMenu();
+ }
+ private boolean m_contextMenuVisible = false;
+ public void onCreateContextMenu(ContextMenu menu,
+ View v,
+ ContextMenuInfo menuInfo)
+ {
+ menu.clearHeader();
+ QtNative.onCreateContextMenu(menu);
+ m_contextMenuVisible = true;
+ }
+
+ public void onContextMenuClosed(Menu menu)
+ {
+ if (!m_contextMenuVisible) {
+ Log.e(QtNative.QtTAG, "invalid onContextMenuClosed call");
+ return;
+ }
+ m_contextMenuVisible = false;
+ QtNative.onContextMenuClosed(menu);
+ }
+
+ public boolean onContextItemSelected(MenuItem item)
+ {
+ return QtNative.onContextItemSelected(item.getItemId(), item.isChecked());
+ }
+
+ public void openContextMenu()
+ {
+ m_layout.postDelayed(new Runnable() {
+ @Override
+ public void run() {
+ m_activity.openContextMenu(m_layout);
+ }
+ }, 10);
+ }
+
+ public void closeContextMenu()
+ {
+ m_activity.closeContextMenu();
+ }
+}
diff --git a/src/android/jar/src/org/qtproject/qt5/android/QtEditText.java b/src/android/jar/src/org/qtproject/qt5/android/QtEditText.java
new file mode 100644
index 0000000000..b95e0c070c
--- /dev/null
+++ b/src/android/jar/src/org/qtproject/qt5/android/QtEditText.java
@@ -0,0 +1,97 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the Android port 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$
+**
+****************************************************************************/
+
+package org.qtproject.qt5.android;
+
+import android.content.Context;
+import android.text.InputType;
+import android.view.View;
+import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.InputConnection;
+
+public class QtEditText extends View
+{
+ QtInputConnection m_inputConnection;
+ int m_initialCapsMode = 0;
+ int m_imeOptions = 0;
+ int m_inputType = InputType.TYPE_CLASS_TEXT;
+
+ public void setImeOptions(int m_imeOptions)
+ {
+ this.m_imeOptions = m_imeOptions;
+ }
+
+ public void setInitialCapsMode(int m_initialCapsMode)
+ {
+ this.m_initialCapsMode = m_initialCapsMode;
+ }
+
+
+ public void setInputType(int m_inputType)
+ {
+ this.m_inputType = m_inputType;
+ }
+
+ public QtEditText(Context context)
+ {
+ super(context);
+ setFocusable(true);
+ setFocusableInTouchMode(true);
+ m_inputConnection = new QtInputConnection(this);
+ }
+
+ @Override
+ public InputConnection onCreateInputConnection(EditorInfo outAttrs)
+ {
+ outAttrs.inputType = m_inputType;
+ outAttrs.imeOptions = m_imeOptions;
+ outAttrs.initialCapsMode = m_initialCapsMode;
+ outAttrs.imeOptions |= EditorInfo.IME_FLAG_NO_EXTRACT_UI;
+ return m_inputConnection;
+ }
+// // DEBUG CODE
+// @Override
+// protected void onDraw(Canvas canvas) {
+// canvas.drawARGB(127, 255, 0, 255);
+// super.onDraw(canvas);
+// }
+}
diff --git a/src/android/jar/src/org/qtproject/qt5/android/QtInputConnection.java b/src/android/jar/src/org/qtproject/qt5/android/QtInputConnection.java
new file mode 100644
index 0000000000..3bcec030b5
--- /dev/null
+++ b/src/android/jar/src/org/qtproject/qt5/android/QtInputConnection.java
@@ -0,0 +1,244 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the Android port 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$
+**
+****************************************************************************/
+
+package org.qtproject.qt5.android;
+
+import android.content.Context;
+import android.os.Build;
+import android.view.View;
+import android.view.inputmethod.BaseInputConnection;
+import android.view.inputmethod.CompletionInfo;
+import android.view.inputmethod.ExtractedText;
+import android.view.inputmethod.ExtractedTextRequest;
+import android.view.inputmethod.InputMethodManager;
+
+class QtExtractedText
+{
+ public int partialEndOffset;
+ public int partialStartOffset;
+ public int selectionEnd;
+ public int selectionStart;
+ public int startOffset;
+ public String text;
+}
+
+class QtNativeInputConnection
+{
+ static native boolean commitText(String text, int newCursorPosition);
+ static native boolean commitCompletion(String text, int position);
+ static native boolean deleteSurroundingText(int leftLength, int rightLength);
+ static native boolean finishComposingText();
+ static native int getCursorCapsMode(int reqModes);
+ static native QtExtractedText getExtractedText(int hintMaxChars, int hintMaxLines, int flags);
+ static native String getSelectedText(int flags);
+ static native String getTextAfterCursor(int length, int flags);
+ static native String getTextBeforeCursor(int length, int flags);
+ static native boolean setComposingText(String text, int newCursorPosition);
+ static native boolean setSelection(int start, int end);
+ static native boolean selectAll();
+ static native boolean cut();
+ static native boolean copy();
+ static native boolean copyURL();
+ static native boolean paste();
+}
+
+public class QtInputConnection extends BaseInputConnection
+{
+ private static final int ID_SELECT_ALL = android.R.id.selectAll;
+ private static final int ID_CUT = android.R.id.cut;
+ private static final int ID_COPY = android.R.id.copy;
+ private static final int ID_PASTE = android.R.id.paste;
+ private static final int ID_COPY_URL = android.R.id.copyUrl;
+ private static final int ID_SWITCH_INPUT_METHOD = android.R.id.switchInputMethod;
+ private static final int ID_ADD_TO_DICTIONARY = android.R.id.addToDictionary;
+
+ View m_view;
+ boolean m_closing;
+ public QtInputConnection(View targetView)
+ {
+ super(targetView, true);
+ m_view = targetView;
+ m_closing = false;
+ }
+
+ @Override
+ public boolean beginBatchEdit()
+ {
+ m_closing = false;
+ return true;
+ }
+
+ @Override
+ public boolean endBatchEdit()
+ {
+ m_closing = false;
+ return true;
+ }
+
+ @Override
+ public boolean commitCompletion(CompletionInfo text)
+ {
+ m_closing = false;
+ return QtNativeInputConnection.commitCompletion(text.getText().toString(), text.getPosition());
+ }
+
+ @Override
+ public boolean commitText(CharSequence text, int newCursorPosition)
+ {
+ m_closing = false;
+ return QtNativeInputConnection.commitText(text.toString(), newCursorPosition);
+ }
+
+ @Override
+ public boolean deleteSurroundingText(int leftLength, int rightLength)
+ {
+ m_closing = false;
+ return QtNativeInputConnection.deleteSurroundingText(leftLength, rightLength);
+ }
+
+ @Override
+ public boolean finishComposingText()
+ {
+ if (m_closing) {
+ QtNative.activityDelegate().m_keyboardIsHiding = true;
+ m_view.postDelayed(new Runnable() {
+ @Override
+ public void run() {
+ if (QtNative.activityDelegate().m_keyboardIsHiding)
+ QtNative.activityDelegate().m_keyboardIsVisible=false;
+ }
+ }, 5000); // it seems finishComposingText comes musch faster than onKeyUp event,
+ // so we must delay hide notification
+ m_closing = false;
+ } else {
+ m_closing = true;
+ }
+ return QtNativeInputConnection.finishComposingText();
+ }
+
+ @Override
+ public int getCursorCapsMode(int reqModes)
+ {
+ return QtNativeInputConnection.getCursorCapsMode(reqModes);
+ }
+
+ @Override
+ public ExtractedText getExtractedText(ExtractedTextRequest request, int flags)
+ {
+ QtExtractedText qExtractedText = QtNativeInputConnection.getExtractedText(request.hintMaxChars,
+ request.hintMaxLines,
+ flags);
+ ExtractedText extractedText = new ExtractedText();
+ extractedText.partialEndOffset = qExtractedText.partialEndOffset;
+ extractedText.partialStartOffset = qExtractedText.partialStartOffset;
+ extractedText.selectionEnd = qExtractedText.selectionEnd;
+ extractedText.selectionStart = qExtractedText.selectionStart;
+ extractedText.startOffset = qExtractedText.startOffset;
+ extractedText.text = qExtractedText.text;
+ return extractedText;
+ }
+
+ public CharSequence getSelectedText(int flags)
+ {
+ return QtNativeInputConnection.getSelectedText(flags);
+ }
+
+ @Override
+ public CharSequence getTextAfterCursor(int length, int flags)
+ {
+ return QtNativeInputConnection.getTextAfterCursor(length, flags);
+ }
+
+ @Override
+ public CharSequence getTextBeforeCursor(int length, int flags)
+ {
+ return QtNativeInputConnection.getTextBeforeCursor(length, flags);
+ }
+
+ @Override
+ public boolean performContextMenuAction(int id)
+ {
+ switch (id) {
+ case ID_SELECT_ALL:
+ return QtNativeInputConnection.selectAll();
+ case ID_COPY:
+ return QtNativeInputConnection.copy();
+ case ID_COPY_URL:
+ return QtNativeInputConnection.copyURL();
+ case ID_CUT:
+ return QtNativeInputConnection.cut();
+ case ID_PASTE:
+ return QtNativeInputConnection.paste();
+
+ case ID_SWITCH_INPUT_METHOD:
+ InputMethodManager imm = (InputMethodManager)m_view.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
+ if (imm != null)
+ imm.showInputMethodPicker();
+
+ return true;
+
+ case ID_ADD_TO_DICTIONARY:
+// TODO
+// String word = m_editable.subSequence(0, m_editable.length()).toString();
+// if (word != null) {
+// Intent i = new Intent("com.android.settings.USER_DICTIONARY_INSERT");
+// i.putExtra("word", word);
+// i.setFlags(i.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);
+// m_view.getContext().startActivity(i);
+// }
+ return true;
+ }
+ return super.performContextMenuAction(id);
+ }
+
+ @Override
+ public boolean setComposingText(CharSequence text, int newCursorPosition)
+ {
+ return QtNativeInputConnection.setComposingText(text.toString(), newCursorPosition);
+ }
+
+ @Override
+ public boolean setSelection(int start, int end)
+ {
+ return QtNativeInputConnection.setSelection(start, end);
+ }
+}
diff --git a/src/android/jar/src/org/qtproject/qt5/android/QtLayout.java b/src/android/jar/src/org/qtproject/qt5/android/QtLayout.java
new file mode 100644
index 0000000000..043dab5ce8
--- /dev/null
+++ b/src/android/jar/src/org/qtproject/qt5/android/QtLayout.java
@@ -0,0 +1,201 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the Android port 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$
+**
+****************************************************************************/
+
+package org.qtproject.qt5.android;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.ViewGroup;
+
+public class QtLayout extends ViewGroup
+{
+ public QtLayout(Context context)
+ {
+ super(context);
+ }
+
+ public QtLayout(Context context, AttributeSet attrs)
+ {
+ super(context, attrs);
+ }
+
+ public QtLayout(Context context, AttributeSet attrs, int defStyle)
+ {
+ super(context, attrs, defStyle);
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
+ {
+ int count = getChildCount();
+
+ int maxHeight = 0;
+ int maxWidth = 0;
+
+ // Find out how big everyone wants to be
+ measureChildren(widthMeasureSpec, heightMeasureSpec);
+
+ // Find rightmost and bottom-most child
+ for (int i = 0; i < count; i++) {
+ View child = getChildAt(i);
+ if (child.getVisibility() != GONE) {
+ int childRight;
+ int childBottom;
+
+ QtLayout.LayoutParams lp
+ = (QtLayout.LayoutParams) child.getLayoutParams();
+
+ childRight = lp.x + child.getMeasuredWidth();
+ childBottom = lp.y + child.getMeasuredHeight();
+
+ maxWidth = Math.max(maxWidth, childRight);
+ maxHeight = Math.max(maxHeight, childBottom);
+ }
+ }
+
+ // Check against minimum height and width
+ maxHeight = Math.max(maxHeight, getSuggestedMinimumHeight());
+ maxWidth = Math.max(maxWidth, getSuggestedMinimumWidth());
+
+ setMeasuredDimension(resolveSize(maxWidth, widthMeasureSpec),
+ resolveSize(maxHeight, heightMeasureSpec));
+ }
+
+ /**
+ * Returns a set of layout parameters with a width of
+ * {@link android.view.ViewGroup.LayoutParams#WRAP_CONTENT},
+ * a height of {@link android.view.ViewGroup.LayoutParams#WRAP_CONTENT}
+ * and with the coordinates (0, 0).
+ */
+ @Override
+ protected ViewGroup.LayoutParams generateDefaultLayoutParams()
+ {
+ return new LayoutParams(android.view.ViewGroup.LayoutParams.WRAP_CONTENT,
+ android.view.ViewGroup.LayoutParams.WRAP_CONTENT,
+ 0,
+ 0);
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int l, int t, int r, int b)
+ {
+ int count = getChildCount();
+
+ for (int i = 0; i < count; i++) {
+ View child = getChildAt(i);
+ if (child.getVisibility() != GONE) {
+ QtLayout.LayoutParams lp =
+ (QtLayout.LayoutParams) child.getLayoutParams();
+
+ int childLeft = lp.x;
+ int childTop = lp.y;
+ child.layout(childLeft, childTop,
+ childLeft + child.getMeasuredWidth(),
+ childTop + child.getMeasuredHeight());
+
+ }
+ }
+ }
+
+ // Override to allow type-checking of LayoutParams.
+ @Override
+ protected boolean checkLayoutParams(ViewGroup.LayoutParams p)
+ {
+ return p instanceof QtLayout.LayoutParams;
+ }
+
+ @Override
+ protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p)
+ {
+ return new LayoutParams(p);
+ }
+
+ /**
+ * Per-child layout information associated with AbsoluteLayout.
+ * See
+ * {@link android.R.styleable#AbsoluteLayout_Layout Absolute Layout Attributes}
+ * for a list of all child view attributes that this class supports.
+ */
+ public static class LayoutParams extends ViewGroup.LayoutParams
+ {
+ /**
+ * The horizontal, or X, location of the child within the view group.
+ */
+ public int x;
+ /**
+ * The vertical, or Y, location of the child within the view group.
+ */
+ public int y;
+
+ /**
+ * Creates a new set of layout parameters with the specified width,
+ * height and location.
+ *
+ * @param width the width, either {@link #FILL_PARENT},
+ {@link #WRAP_CONTENT} or a fixed size in pixels
+ * @param height the height, either {@link #FILL_PARENT},
+ {@link #WRAP_CONTENT} or a fixed size in pixels
+ * @param x the X location of the child
+ * @param y the Y location of the child
+ */
+ public LayoutParams(int width, int height, int x, int y)
+ {
+ super(width, height);
+ this.x = x;
+ this.y = y;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public LayoutParams(ViewGroup.LayoutParams source)
+ {
+ super(source);
+ }
+ }
+
+ public void bringChildFront(int child)
+ {
+ bringChildToFront(getChildAt(child));
+ }
+}
diff --git a/src/android/jar/src/org/qtproject/qt5/android/QtNative.java b/src/android/jar/src/org/qtproject/qt5/android/QtNative.java
new file mode 100644
index 0000000000..346bc1221a
--- /dev/null
+++ b/src/android/jar/src/org/qtproject/qt5/android/QtNative.java
@@ -0,0 +1,611 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the Android port 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$
+**
+****************************************************************************/
+
+package org.qtproject.qt5.android;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.concurrent.Semaphore;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Build;
+import android.text.ClipboardManager;
+import android.util.Log;
+import android.view.ContextMenu;
+import android.view.Menu;
+import android.view.MotionEvent;
+
+public class QtNative
+{
+ private static Activity m_activity = null;
+ private static QtActivityDelegate m_activityDelegate = null;
+ public static Object m_mainActivityMutex = new Object(); // mutex used to synchronize runnable operations
+
+ public static final String QtTAG = "Qt JAVA"; // string used for Log.x
+ private static ArrayList<Runnable> m_lostActions = new ArrayList<Runnable>(); // a list containing all actions which could not be performed (e.g. the main activity is destroyed, etc.)
+ private static boolean m_started = false;
+ private static int m_displayMetricsScreenWidthPixels = 0;
+ private static int m_displayMetricsScreenHeightPixels = 0;
+ private static int m_displayMetricsDesktopWidthPixels = 0;
+ private static int m_displayMetricsDesktopHeightPixels = 0;
+ private static double m_displayMetricsXDpi = .0;
+ private static double m_displayMetricsYDpi = .0;
+ private static int m_oldx, m_oldy;
+ private static final int m_moveThreshold = 0;
+ private static ClipboardManager m_clipboardManager = null;
+
+ private static ClassLoader m_classLoader = null;
+ public static ClassLoader classLoader()
+ {
+ return m_classLoader;
+ }
+
+ public static void setClassLoader(ClassLoader classLoader)
+ {
+ m_classLoader = classLoader;
+ }
+
+ public static Activity activity()
+ {
+ synchronized (m_mainActivityMutex) {
+ return m_activity;
+ }
+ }
+
+ public static QtActivityDelegate activityDelegate()
+ {
+ synchronized (m_mainActivityMutex) {
+ return m_activityDelegate;
+ }
+ }
+
+ public static void openURL(String url)
+ {
+ Uri uri = Uri.parse(url);
+ Intent intent = new Intent(Intent.ACTION_VIEW, uri);
+ activity().startActivity(intent);
+ }
+
+ // this method loads full path libs
+ public static void loadQtLibraries(ArrayList<String> libraries)
+ {
+ if (libraries == null)
+ return;
+
+ for (String libName : libraries) {
+ try {
+ File f = new File(libName);
+ if (f.exists())
+ System.load(libName);
+ } catch (SecurityException e) {
+ Log.i(QtTAG, "Can't load '" + libName + "'", e);
+ } catch (Exception e) {
+ Log.i(QtTAG, "Can't load '" + libName + "'", e);
+ }
+ }
+ }
+
+ // this method loads bundled libs by name.
+ public static void loadBundledLibraries(ArrayList<String> libraries, String nativeLibraryDir)
+ {
+ if (libraries == null)
+ return;
+
+ for (String libName : libraries) {
+ try {
+ File f = new File(nativeLibraryDir+"lib"+libName+".so");
+ if (f.exists())
+ System.load(f.getAbsolutePath());
+ else
+ Log.i(QtTAG, "Can't find '" + f.getAbsolutePath());
+ } catch (Exception e) {
+ Log.i(QtTAG, "Can't load '" + libName + "'", e);
+ }
+ }
+ }
+
+ public static void setActivity(Activity qtMainActivity, QtActivityDelegate qtActivityDelegate)
+ {
+ synchronized (m_mainActivityMutex) {
+ m_activity = qtMainActivity;
+ m_activityDelegate = qtActivityDelegate;
+ }
+ }
+
+ static public ArrayList<Runnable> getLostActions()
+ {
+ return m_lostActions;
+ }
+
+ static public void clearLostActions()
+ {
+ m_lostActions.clear();
+ }
+
+ private static boolean runAction(Runnable action)
+ {
+ synchronized (m_mainActivityMutex) {
+ if (m_activity == null)
+ m_lostActions.add(action);
+ else
+ m_activity.runOnUiThread(action);
+ return m_activity != null;
+ }
+ }
+
+ public static boolean startApplication(String params,
+ String environment,
+ String mainLibrary,
+ String nativeLibraryDir) throws Exception
+ {
+ File f = new File(nativeLibraryDir + "lib" + mainLibrary + ".so");
+ if (!f.exists())
+ throw new Exception("Can't find main library '" + mainLibrary + "'");
+
+ if (params == null)
+ params = "-platform\tandroid";
+
+ boolean res = false;
+ synchronized (m_mainActivityMutex) {
+ res = startQtAndroidPlugin();
+ setDisplayMetrics(m_displayMetricsScreenWidthPixels,
+ m_displayMetricsScreenHeightPixels,
+ m_displayMetricsDesktopWidthPixels,
+ m_displayMetricsDesktopHeightPixels,
+ m_displayMetricsXDpi,
+ m_displayMetricsYDpi);
+ if (params.length() > 0)
+ params = "\t" + params;
+ startQtApplication(f.getAbsolutePath() + "\t" + params, environment);
+ m_started = true;
+ }
+ return res;
+ }
+
+ public static void setApplicationDisplayMetrics(int screenWidthPixels,
+ int screenHeightPixels,
+ int desktopWidthPixels,
+ int desktopHeightPixels,
+ double XDpi,
+ double YDpi)
+ {
+ /* Fix buggy dpi report */
+ if (XDpi < android.util.DisplayMetrics.DENSITY_LOW)
+ XDpi = android.util.DisplayMetrics.DENSITY_LOW;
+ if (YDpi < android.util.DisplayMetrics.DENSITY_LOW)
+ YDpi = android.util.DisplayMetrics.DENSITY_LOW;
+
+ synchronized (m_mainActivityMutex) {
+ if (m_started) {
+ setDisplayMetrics(screenWidthPixels,
+ screenHeightPixels,
+ desktopWidthPixels,
+ desktopHeightPixels,
+ XDpi,
+ YDpi);
+ } else {
+ m_displayMetricsScreenWidthPixels = screenWidthPixels;
+ m_displayMetricsScreenHeightPixels = screenHeightPixels;
+ m_displayMetricsDesktopWidthPixels = desktopWidthPixels;
+ m_displayMetricsDesktopHeightPixels = desktopHeightPixels;
+ m_displayMetricsXDpi = XDpi;
+ m_displayMetricsYDpi = YDpi;
+ }
+ }
+ }
+
+ public static void pauseApplication()
+ {
+ synchronized (m_mainActivityMutex) {
+ if (m_started)
+ pauseQtApp();
+ }
+ }
+
+ public static void resumeApplication()
+ {
+ synchronized (m_mainActivityMutex) {
+ if (m_started) {
+ resumeQtApp();
+ updateWindow();
+ }
+ }
+ }
+
+ // application methods
+ public static native void startQtApplication(String params, String env);
+ public static native void startQtApp(String params, String env);
+ public static native void pauseQtApp();
+ public static native void resumeQtApp();
+ public static native boolean startQtAndroidPlugin();
+ public static native void quitQtAndroidPlugin();
+ public static native void terminateQt();
+ // application methods
+
+ private static void quitApp()
+ {
+ m_activity.finish();
+ }
+
+ private static void redrawSurface(final int left, final int top, final int right, final int bottom )
+ {
+ runAction(new Runnable() {
+ @Override
+ public void run() {
+ m_activityDelegate.redrawWindow(left, top, right, bottom);
+ }
+ });
+ }
+
+ //@ANDROID-5
+ static private int getAction(int index, MotionEvent event)
+ {
+ int action = event.getAction();
+ if (action == MotionEvent.ACTION_MOVE) {
+ int hsz = event.getHistorySize();
+ if (hsz > 0) {
+ if (Math.abs(event.getX(index) - event.getHistoricalX(index, hsz-1)) > 1
+ || Math.abs(event.getY(index) - event.getHistoricalY(index, hsz-1)) > 1) {
+ return 1;
+ } else {
+ return 2;
+ }
+ }
+ return 1;
+ }
+
+ switch (index) {
+ case 0:
+ if (action == MotionEvent.ACTION_DOWN
+ || action == MotionEvent.ACTION_POINTER_1_DOWN) {
+ return 0;
+ }
+
+ if (action == MotionEvent.ACTION_UP
+ || action == MotionEvent.ACTION_POINTER_1_UP) {
+ return 3;
+ }
+ break;
+
+ case 1:
+ if (action == MotionEvent.ACTION_POINTER_2_DOWN
+ || action == MotionEvent.ACTION_POINTER_DOWN) {
+ return 0;
+ }
+
+ if (action == MotionEvent.ACTION_POINTER_2_UP
+ || action == MotionEvent.ACTION_POINTER_UP) {
+ return 3;
+ }
+ break;
+
+ case 2:
+ if (action == MotionEvent.ACTION_POINTER_3_DOWN
+ || action == MotionEvent.ACTION_POINTER_DOWN) {
+ return 0;
+ }
+
+ if (action == MotionEvent.ACTION_POINTER_3_UP
+ || action == MotionEvent.ACTION_POINTER_UP) {
+ return 3;
+ }
+
+ break;
+ }
+ return 2;
+ }
+ //@ANDROID-5
+
+ static public void sendTouchEvent(MotionEvent event, int id)
+ {
+ //@ANDROID-5
+ touchBegin(id);
+ for (int i=0;i<event.getPointerCount();i++) {
+ touchAdd(id,
+ event.getPointerId(i),
+ getAction(i, event),
+ i == 0,
+ (int)event.getX(i),
+ (int)event.getY(i),
+ event.getSize(i),
+ event.getPressure(i));
+ }
+
+ switch (event.getAction()) {
+ case MotionEvent.ACTION_DOWN:
+ touchEnd(id,0);
+ break;
+
+ case MotionEvent.ACTION_UP:
+ touchEnd(id,2);
+ break;
+
+ default:
+ touchEnd(id,1);
+ }
+ //@ANDROID-5
+
+ switch (event.getAction()) {
+ case MotionEvent.ACTION_UP:
+ mouseUp(id,(int) event.getX(), (int) event.getY());
+ break;
+
+ case MotionEvent.ACTION_DOWN:
+ mouseDown(id,(int) event.getX(), (int) event.getY());
+ m_oldx = (int) event.getX();
+ m_oldy = (int) event.getY();
+ break;
+
+ case MotionEvent.ACTION_MOVE:
+ int dx = (int) (event.getX() - m_oldx);
+ int dy = (int) (event.getY() - m_oldy);
+ if (Math.abs(dx) > m_moveThreshold || Math.abs(dy) > m_moveThreshold) {
+ mouseMove(id, (int) event.getX(), (int) event.getY());
+ m_oldx = (int) event.getX();
+ m_oldy = (int) event.getY();
+ }
+ break;
+ }
+ }
+
+ static public void sendTrackballEvent(MotionEvent event, int id)
+ {
+ switch (event.getAction()) {
+ case MotionEvent.ACTION_UP:
+ mouseUp(id, (int) event.getX(), (int) event.getY());
+ break;
+
+ case MotionEvent.ACTION_DOWN:
+ mouseDown(id, (int) event.getX(), (int) event.getY());
+ m_oldx = (int) event.getX();
+ m_oldy = (int) event.getY();
+ break;
+
+ case MotionEvent.ACTION_MOVE:
+ int dx = (int) (event.getX() - m_oldx);
+ int dy = (int) (event.getY() - m_oldy);
+ if (Math.abs(dx) > 5 || Math.abs(dy) > 5) {
+ mouseMove(id, (int) event.getX(), (int) event.getY());
+ m_oldx = (int) event.getX();
+ m_oldy = (int) event.getY();
+ }
+ break;
+ }
+ }
+
+ private static void updateSelection(final int selStart,
+ final int selEnd,
+ final int candidatesStart,
+ final int candidatesEnd)
+ {
+ runAction(new Runnable() {
+ @Override
+ public void run() {
+ m_activityDelegate.updateSelection(selStart, selEnd, candidatesStart, candidatesEnd);
+ }
+ });
+ }
+
+ private static void showSoftwareKeyboard(final int x,
+ final int y,
+ final int width,
+ final int height,
+ final int inputHints )
+ {
+ runAction(new Runnable() {
+ @Override
+ public void run() {
+ m_activityDelegate.showSoftwareKeyboard(x, y, width, height, inputHints);
+ }
+ });
+ }
+
+ private static void resetSoftwareKeyboard()
+ {
+ runAction(new Runnable() {
+ @Override
+ public void run() {
+ m_activityDelegate.resetSoftwareKeyboard();
+ }
+ });
+ }
+
+ private static void hideSoftwareKeyboard()
+ {
+ runAction(new Runnable() {
+ @Override
+ public void run() {
+ m_activityDelegate.hideSoftwareKeyboard();
+ }
+ });
+ }
+
+ private static boolean isSoftwareKeyboardVisible()
+ {
+ Semaphore semaphore = new Semaphore(1);
+ Boolean ret = false;
+ class RunnableRes implements Runnable {
+ @SuppressWarnings("unused")
+ Boolean returnValue = null;
+ Semaphore semaphore = null;
+ RunnableRes(Boolean ret, Semaphore sem) {
+ semaphore = sem;
+ returnValue = ret;
+ }
+ @Override
+ public void run() {
+ returnValue = m_activityDelegate.isSoftwareKeyboardVisible();
+ semaphore.release();
+ }
+ }
+
+ runAction(new RunnableRes(ret, semaphore));
+ try {
+ semaphore.acquire();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return ret;
+ }
+
+ private static void setFullScreen(final boolean fullScreen)
+ {
+ runAction(new Runnable() {
+ @Override
+ public void run() {
+ m_activityDelegate.setFullScreen(fullScreen);
+ updateWindow();
+ }
+ });
+ }
+
+ private static void registerClipboardManager()
+ {
+ final Semaphore semaphore = new Semaphore(1);
+ runAction(new Runnable() {
+ @Override
+ public void run() {
+ m_clipboardManager = (android.text.ClipboardManager) m_activity.getSystemService(Context.CLIPBOARD_SERVICE);
+ semaphore.release();
+ }
+ });
+ try {
+ semaphore.acquire();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ private static void setClipboardText(String text)
+ {
+ m_clipboardManager.setText(text);
+ }
+
+ private static boolean hasClipboardText()
+ {
+ return m_clipboardManager.hasText();
+ }
+
+ private static String getClipboardText()
+ {
+ return m_clipboardManager.getText().toString();
+ }
+
+ private static void openContextMenu()
+ {
+ runAction(new Runnable() {
+ @Override
+ public void run() {
+ m_activityDelegate.openContextMenu();
+ }
+ });
+ }
+
+ private static void closeContextMenu()
+ {
+ runAction(new Runnable() {
+ @Override
+ public void run() {
+ m_activityDelegate.closeContextMenu();
+ }
+ });
+ }
+
+ private static void resetOptionsMenu()
+ {
+ runAction(new Runnable() {
+ @Override
+ public void run() {
+ m_activityDelegate.resetOptionsMenu();
+ }
+ });
+ }
+
+ // screen methods
+ public static native void setDisplayMetrics(int screenWidthPixels,
+ int screenHeightPixels,
+ int desktopWidthPixels,
+ int desktopHeightPixels,
+ double XDpi,
+ double YDpi);
+ public static native void handleOrientationChanged(int newOrientation);
+ // screen methods
+
+ // pointer methods
+ public static native void mouseDown(int winId, int x, int y);
+ public static native void mouseUp(int winId, int x, int y);
+ public static native void mouseMove(int winId, int x, int y);
+ public static native void touchBegin(int winId);
+ public static native void touchAdd(int winId, int pointerId, int action, boolean primary, int x, int y, float size, float pressure);
+ public static native void touchEnd(int winId, int action);
+ public static native void longPress(int winId, int x, int y);
+ // pointer methods
+
+ // keyboard methods
+ public static native void keyDown(int key, int unicode, int modifier);
+ public static native void keyUp(int key, int unicode, int modifier);
+ // keyboard methods
+
+ // surface methods
+ public static native void destroySurface();
+ public static native void setSurface(Object surface);
+ public static native void lockSurface();
+ public static native void unlockSurface();
+ // surface methods
+
+ // window methods
+ public static native void updateWindow();
+ // window methods
+
+ // menu methods
+ public static native boolean onPrepareOptionsMenu(Menu menu);
+ public static native boolean onOptionsItemSelected(int itemId, boolean checked);
+ public static native void onOptionsMenuClosed(Menu menu);
+
+ public static native void onCreateContextMenu(ContextMenu menu);
+ public static native boolean onContextItemSelected(int itemId, boolean checked);
+ public static native void onContextMenuClosed(Menu menu);
+ // menu methods
+}
diff --git a/src/android/jar/src/org/qtproject/qt5/android/QtNativeLibrariesDir.java b/src/android/jar/src/org/qtproject/qt5/android/QtNativeLibrariesDir.java
new file mode 100644
index 0000000000..219ea13f1a
--- /dev/null
+++ b/src/android/jar/src/org/qtproject/qt5/android/QtNativeLibrariesDir.java
@@ -0,0 +1,61 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the Android port 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$
+**
+****************************************************************************/
+
+package org.qtproject.qt5.android;
+
+import android.app.Activity;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager.NameNotFoundException;
+
+public class QtNativeLibrariesDir {
+ public static String nativeLibrariesDir(Activity activity)
+ {
+ String m_nativeLibraryDir = null;
+ try {
+ ApplicationInfo ai = activity.getPackageManager().getApplicationInfo(activity.getPackageName(), 0);
+ m_nativeLibraryDir = ai.nativeLibraryDir+"/";
+ } catch (NameNotFoundException e) {
+ e.printStackTrace();
+ }
+ return m_nativeLibraryDir;
+ }
+}
diff --git a/src/android/jar/src/org/qtproject/qt5/android/QtSurface.java b/src/android/jar/src/org/qtproject/qt5/android/QtSurface.java
new file mode 100644
index 0000000000..77126ec1c8
--- /dev/null
+++ b/src/android/jar/src/org/qtproject/qt5/android/QtSurface.java
@@ -0,0 +1,206 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the Android port 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$
+**
+****************************************************************************/
+
+package org.qtproject.qt5.android;
+
+import android.app.Activity;
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Rect;
+import android.graphics.PixelFormat;
+import android.util.DisplayMetrics;
+import android.util.Log;
+import android.view.GestureDetector;
+import android.view.MotionEvent;
+import android.view.SurfaceHolder;
+import android.view.SurfaceView;
+
+public class QtSurface extends SurfaceView implements SurfaceHolder.Callback
+{
+ private Bitmap m_bitmap = null;
+ private boolean m_started = false;
+ private boolean m_usesGL = false;
+ private GestureDetector m_gestureDetector;
+
+ public QtSurface(Context context, int id)
+ {
+ super(context);
+ setFocusable(true);
+ getHolder().addCallback(this);
+ getHolder().setType(SurfaceHolder.SURFACE_TYPE_GPU);
+ setId(id);
+ m_gestureDetector =
+ new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() {
+ public void onLongPress(MotionEvent event) {
+ if (!m_started)
+ return;
+ QtNative.longPress(getId(), (int) event.getX(), (int) event.getY());
+ }
+ });
+ m_gestureDetector.setIsLongpressEnabled(true);
+ }
+
+ public void applicationStarted(boolean usesGL)
+ {
+ m_started = true;
+ m_usesGL = usesGL;
+ if (getWidth() < 1 || getHeight() < 1)
+ return;
+ if (m_usesGL) {
+ QtNative.setSurface(getHolder().getSurface());
+ } else {
+ QtNative.lockSurface();
+ QtNative.setSurface(null);
+ m_bitmap = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.RGB_565);
+ QtNative.setSurface(m_bitmap);
+ QtNative.unlockSurface();
+ }
+ }
+
+ @Override
+ public void surfaceCreated(SurfaceHolder holder)
+ {
+ DisplayMetrics metrics = new DisplayMetrics();
+ ((Activity) getContext()).getWindowManager().getDefaultDisplay().getMetrics(metrics);
+ QtNative.setApplicationDisplayMetrics(metrics.widthPixels,
+ metrics.heightPixels, getWidth(), getHeight(), metrics.xdpi, metrics.ydpi);
+
+ if (m_usesGL)
+ holder.setFormat(PixelFormat.RGBA_8888);
+
+// if (!m_started)
+// return;
+//
+// if (m_usesGL)
+// QtApplication.setSurface(holder.getSurface());
+// else
+// {
+// QtApplication.lockSurface();
+// QtApplication.setSurface(null);
+// m_bitmap=Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.RGB_565);
+// QtApplication.setSurface(m_bitmap);
+// QtApplication.unlockSurface();
+// }
+ }
+
+ @Override
+ public void surfaceChanged(SurfaceHolder holder, int format, int width, int height)
+ {
+ if (width<1 || height<1)
+ return;
+
+ DisplayMetrics metrics = new DisplayMetrics();
+ ((Activity) getContext()).getWindowManager().getDefaultDisplay().getMetrics(metrics);
+ QtNative.setApplicationDisplayMetrics(metrics.widthPixels,
+ metrics.heightPixels,
+ width,
+ height,
+ metrics.xdpi,
+ metrics.ydpi);
+
+ if (!m_started)
+ return;
+
+ if (m_usesGL) {
+ QtNative.setSurface(holder.getSurface());
+ } else {
+ QtNative.lockSurface();
+ QtNative.setSurface(null);
+ m_bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);
+ QtNative.setSurface(m_bitmap);
+ QtNative.unlockSurface();
+ QtNative.updateWindow();
+ }
+ }
+
+ @Override
+ public void surfaceDestroyed(SurfaceHolder holder)
+ {
+ if (m_usesGL) {
+ QtNative.destroySurface();
+ } else {
+ if (!m_started)
+ return;
+
+ QtNative.lockSurface();
+ QtNative.setSurface(null);
+ QtNative.unlockSurface();
+ }
+ }
+
+ public void drawBitmap(Rect rect)
+ {
+ if (!m_started)
+ return;
+ QtNative.lockSurface();
+ if (null != m_bitmap) {
+ try {
+ Canvas cv = getHolder().lockCanvas(rect);
+ cv.drawBitmap(m_bitmap, rect, rect, null);
+ getHolder().unlockCanvasAndPost(cv);
+ } catch (Exception e) {
+ Log.e(QtNative.QtTAG, "Can't create main activity", e);
+ }
+ }
+ QtNative.unlockSurface();
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent event)
+ {
+ if (!m_started)
+ return false;
+ QtNative.sendTouchEvent(event, getId());
+ m_gestureDetector.onTouchEvent(event);
+ return true;
+ }
+
+ @Override
+ public boolean onTrackballEvent(MotionEvent event)
+ {
+ if (!m_started)
+ return false;
+ QtNative.sendTrackballEvent(event, getId());
+ return true;
+ }
+}
diff --git a/src/android/java/AndroidManifest.xml b/src/android/java/AndroidManifest.xml
new file mode 100644
index 0000000000..7a77d6fd83
--- /dev/null
+++ b/src/android/java/AndroidManifest.xml
@@ -0,0 +1,25 @@
+<?xml version='1.0' encoding='utf-8'?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1" android:versionName="1.0" package="org.kde.necessitas.example">
+ <application android:name="org.qtproject.qt5.android.bindings.QtApplication" android:label="@string/app_name">
+ <activity android:name="org.qtproject.qt5.android.bindings.QtActivity" android:label="@string/app_name" android:configChanges="orientation|locale|fontScale|keyboard|keyboardHidden" >
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
+ </intent-filter>
+ <meta-data android:name="android.app.qt_libs_resource_id" android:resource="@array/qt_libs"/>
+ <meta-data android:name="android.app.bundled_libs_resource_id" android:resource="@array/bundled_libs"/>
+ <meta-data android:name="android.app.lib_name" android:value=""/>
+ <!-- Messages maps -->
+ <meta-data android:name="android.app.ministro_not_found_msg" android:value="@string/ministro_not_found_msg"/>
+ <meta-data android:name="android.app.ministro_needed_msg" android:value="@string/ministro_needed_msg"/>
+ <meta-data android:name="android.app.fatal_error_msg" android:value="@string/fatal_error_msg"/>
+ <!-- Messages maps -->
+ <!-- Splash screen -->
+ <meta-data android:name="android.app.splash_screen" android:resource="@layout/splash"/>
+ <!-- Splash screen -->
+ </activity>
+ </application>
+ <supports-screens android:largeScreens="true" android:normalScreens="true" android:anyDensity="true" android:smallScreens="true"/>
+ <uses-permission android:name="android.permission.INTERNET"/>
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
+</manifest>
diff --git a/src/android/java/res/layout/splash.xml b/src/android/java/res/layout/splash.xml
new file mode 100644
index 0000000000..6b0d492dd5
--- /dev/null
+++ b/src/android/java/res/layout/splash.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:layout_gravity="center"
+ >
+ <ImageView
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:scaleType="fitXY"
+ />
+</LinearLayout>
diff --git a/src/android/java/res/values-de/strings.xml b/src/android/java/res/values-de/strings.xml
new file mode 100644
index 0000000000..320d9ec33f
--- /dev/null
+++ b/src/android/java/res/values-de/strings.xml
@@ -0,0 +1,6 @@
+<?xml version='1.0' encoding='utf-8'?>
+<resources>
+ <string name="ministro_not_found_msg">Ministro-Dienst wurde nicht gefunden.\nAnwendung kann nicht gestartet werden</string>
+ <string name="ministro_needed_msg">Diese Anwendung benötigt den Ministro-Dienst. Möchten Sie ihn installieren?</string>
+ <string name="fatal_error_msg">In Ihrer Anwendung ist ein schwerwiegender Fehler aufgetreten, sie kann nicht fortgesetzt werden</string>
+</resources>
diff --git a/src/android/java/res/values-el/strings.xml b/src/android/java/res/values-el/strings.xml
new file mode 100644
index 0000000000..3cab212f2b
--- /dev/null
+++ b/src/android/java/res/values-el/strings.xml
@@ -0,0 +1,6 @@
+<?xml version='1.0' encoding='utf-8'?>
+<resources>
+ <string name="ministro_not_found_msg">Δεν ήταν δυνατή η εύρεση της υπηρεσίας Ministro. Δεν είναι δυνατή η εκκίνηση της εφαρμογής.</string>
+ <string name="ministro_needed_msg">Η εφαρμογή απαιτεί την υπηρεσία Ministro. Να εγκατασταθεί η υπηρεσία?</string>
+ <string name="fatal_error_msg">Παρουσιάστηκε ένα κρίσιμο σφάλμα και η εφαρμογή δεν μπορεί να συνεχίσει.</string>
+</resources>
diff --git a/src/android/java/res/values-es/strings.xml b/src/android/java/res/values-es/strings.xml
new file mode 100644
index 0000000000..cf0b54d0b0
--- /dev/null
+++ b/src/android/java/res/values-es/strings.xml
@@ -0,0 +1,6 @@
+<?xml version='1.0' encoding='utf-8'?>
+<resources>
+ <string name="ministro_not_found_msg">Servicio Ministro inesistente. Imposible ejecutar la aplicación.</string>
+ <string name="ministro_needed_msg">Esta aplicación requiere el servicio Ministro. Instalarlo?</string>
+ <string name="fatal_error_msg">La aplicación ha causado un error grave y no es posible continuar.</string>
+</resources>
diff --git a/src/android/java/res/values-et/strings.xml b/src/android/java/res/values-et/strings.xml
new file mode 100644
index 0000000000..d55a3c1471
--- /dev/null
+++ b/src/android/java/res/values-et/strings.xml
@@ -0,0 +1,6 @@
+<?xml version='1.0' encoding='utf-8'?>
+<resources>
+ <string name="ministro_not_found_msg">Ei suuda leida Ministro teenust.\nProgrammi ei saa käivitada.</string>
+ <string name="ministro_needed_msg">See programm vajab Ministro teenust.\nKas soovite paigaldada?</string>
+ <string name="fatal_error_msg">Programmiga juhtus fataalne viga.\nKahjuks ei saa jätkata.</string>
+</resources>
diff --git a/src/android/java/res/values-fa/strings.xml b/src/android/java/res/values-fa/strings.xml
new file mode 100644
index 0000000000..a8d1b87444
--- /dev/null
+++ b/src/android/java/res/values-fa/strings.xml
@@ -0,0 +1,6 @@
+<?xml version='1.0' encoding='utf-8'?>
+<resources>
+ <string name="ministro_not_found_msg">سرویس Ministro را پیدا نمی‌کند. برنامه نمی‌تواند آغاز شود.</string>
+ <string name="ministro_needed_msg">این نرم‌افزار به سرویس Ministro احتیاج دارد. آیا دوست دارید آن را نصب کنید؟</string>
+ <string name="fatal_error_msg">خطایی اساسی در برنامه‌تان رخ داد و اجرای برنامه نمی‌تواند ادامه یابد.</string>
+</resources>
diff --git a/src/android/java/res/values-fr/strings.xml b/src/android/java/res/values-fr/strings.xml
new file mode 100644
index 0000000000..efc0fb6e1e
--- /dev/null
+++ b/src/android/java/res/values-fr/strings.xml
@@ -0,0 +1,6 @@
+<?xml version='1.0' encoding='utf-8'?>
+<resources>
+ <string name="ministro_not_found_msg">Le service Ministro est introuvable.\nL\'application ne peut pas démarrer.</string>
+ <string name="ministro_needed_msg">Cette application requiert le service Ministro. Voulez-vous l\'installer?</string>
+ <string name="fatal_error_msg">Votre application a rencontré une erreur fatale et ne peut pas continuer.</string>
+</resources>
diff --git a/src/android/java/res/values-id/strings.xml b/src/android/java/res/values-id/strings.xml
new file mode 100644
index 0000000000..aaa5bda0de
--- /dev/null
+++ b/src/android/java/res/values-id/strings.xml
@@ -0,0 +1,6 @@
+<?xml version='1.0' encoding='utf-8'?>
+<resources>
+ <string name="ministro_not_found_msg">Layanan Ministro tidak bisa ditemukan.\nAplikasi tidak bisa dimulai.</string>
+ <string name="ministro_needed_msg">Aplikasi ini membutuhkan layanan Ministro. Apakah Anda ingin menginstalnya?</string>
+ <string name="fatal_error_msg">Aplikasi Anda mengalami kesalahan fatal dan tidak dapat melanjutkan.</string>
+</resources>
diff --git a/src/android/java/res/values-it/strings.xml b/src/android/java/res/values-it/strings.xml
new file mode 100644
index 0000000000..4773419c44
--- /dev/null
+++ b/src/android/java/res/values-it/strings.xml
@@ -0,0 +1,6 @@
+<?xml version='1.0' encoding='utf-8'?>
+<resources>
+ <string name="ministro_not_found_msg">Servizio Ministro inesistente. Impossibile eseguire \nl\'applicazione.</string>
+ <string name="ministro_needed_msg">Questa applicazione richiede il servizio Ministro.Installarlo?</string>
+ <string name="fatal_error_msg">L\'applicazione ha provocato un errore grave e non puo\' continuare.</string>
+</resources>
diff --git a/src/android/java/res/values-ja/strings.xml b/src/android/java/res/values-ja/strings.xml
new file mode 100644
index 0000000000..ba1cfda9ec
--- /dev/null
+++ b/src/android/java/res/values-ja/strings.xml
@@ -0,0 +1,6 @@
+<?xml version='1.0' encoding='utf-8'?>
+<resources>
+ <string name="ministro_not_found_msg">Ministroサービスが見つかりません。\nアプリケーションが起動できません。</string>
+ <string name="ministro_needed_msg">このアプリケーションにはMinistroサービスが必要です。 インストールしてもよろしいですか?</string>
+ <string name="fatal_error_msg">アプリケーションで致命的なエラーが発生したため続行できません。</string>
+</resources>
diff --git a/src/android/java/res/values-ms/strings.xml b/src/android/java/res/values-ms/strings.xml
new file mode 100644
index 0000000000..6e3952eaec
--- /dev/null
+++ b/src/android/java/res/values-ms/strings.xml
@@ -0,0 +1,6 @@
+<?xml version='1.0' encoding='utf-8'?>
+<resources>
+ <string name="ministro_not_found_msg">Tidak jumpa servis Ministro.\nAplikasi tidak boleh dimulakan.</string>
+ <string name="ministro_needed_msg">Aplikasi ini memerlukan servis Ministro. Adakah anda ingin pasang servis itu?</string>
+ <string name="fatal_error_msg">Aplikasi anda menemui ralat muat dan tidak boleh diteruskan.</string>
+</resources>
diff --git a/src/android/java/res/values-nb/strings.xml b/src/android/java/res/values-nb/strings.xml
new file mode 100644
index 0000000000..8a550e99a2
--- /dev/null
+++ b/src/android/java/res/values-nb/strings.xml
@@ -0,0 +1,6 @@
+<?xml version='1.0' encoding='utf-8'?>
+<resources>
+ <string name="ministro_not_found_msg">Kan ikke finne tjenesten Ministro. Applikasjonen kan ikke starte.</string>
+ <string name="ministro_needed_msg">Denne applikasjonen krever tjenesten Ministro. Vil du installere denne?</string>
+ <string name="fatal_error_msg">Applikasjonen fikk en kritisk feil og kan ikke fortsette</string>
+</resources>
diff --git a/src/android/java/res/values-nl/strings.xml b/src/android/java/res/values-nl/strings.xml
new file mode 100644
index 0000000000..8a45a724ff
--- /dev/null
+++ b/src/android/java/res/values-nl/strings.xml
@@ -0,0 +1,6 @@
+<?xml version='1.0' encoding='utf-8'?>
+<resources>
+ <string name="ministro_not_found_msg">De Ministro service is niet gevonden.\nDe applicatie kan niet starten.</string>
+ <string name="ministro_needed_msg">Deze applicatie maakt gebruik van de Ministro service. Wilt u deze installeren?</string>
+ <string name="fatal_error_msg">Er is een fatale fout in de applicatie opgetreden. De applicatie kan niet verder gaan.</string>
+</resources>
diff --git a/src/android/java/res/values-pl/strings.xml b/src/android/java/res/values-pl/strings.xml
new file mode 100644
index 0000000000..9fefc92dcd
--- /dev/null
+++ b/src/android/java/res/values-pl/strings.xml
@@ -0,0 +1,6 @@
+<?xml version='1.0' encoding='utf-8'?>
+<resources>
+ <string name="ministro_not_found_msg">Usługa Ministro nie została znaleziona.\nAplikacja nie może zostać uruchomiona.</string>
+ <string name="ministro_needed_msg">Aplikacja wymaga usługi Ministro. Czy chcesz ją zainstalować?</string>
+ <string name="fatal_error_msg">Wystąpił błąd krytyczny. Aplikacja zostanie zamknięta.</string>
+</resources>
diff --git a/src/android/java/res/values-pt-rBR/strings.xml b/src/android/java/res/values-pt-rBR/strings.xml
new file mode 100644
index 0000000000..67ac3f9f98
--- /dev/null
+++ b/src/android/java/res/values-pt-rBR/strings.xml
@@ -0,0 +1,6 @@
+<?xml version='1.0' encoding='utf-8'?>
+<resources>
+ <string name="ministro_not_found_msg">Não foi possível encontrar o serviço Ministro.\nA aplicação não pode iniciar.</string>
+ <string name="ministro_needed_msg">Essa aplicação requer o serviço Ministro. Gostaria de instalá-lo?</string>
+ <string name="fatal_error_msg">Sua aplicação encontrou um erro fatal e não pode continuar.</string>
+</resources>
diff --git a/src/android/java/res/values-ro/strings.xml b/src/android/java/res/values-ro/strings.xml
new file mode 100644
index 0000000000..f88a442b35
--- /dev/null
+++ b/src/android/java/res/values-ro/strings.xml
@@ -0,0 +1,6 @@
+<?xml version='1.0' encoding='utf-8'?>
+<resources>
+ <string name="ministro_not_found_msg">Serviciul Ministro nu poate fi găsit.\nAplicaţia nu poate porni.</string>
+ <string name="ministro_needed_msg">Această aplicaţie necesită serviciul Ministro.\nDoriţi să-l instalaţi?</string>
+ <string name="fatal_error_msg">Aplicaţia dumneavoastră a întâmpinat o eroare fatală şi nu poate continua.</string>
+</resources>
diff --git a/src/android/java/res/values-rs/strings.xml b/src/android/java/res/values-rs/strings.xml
new file mode 100644
index 0000000000..3194ce9022
--- /dev/null
+++ b/src/android/java/res/values-rs/strings.xml
@@ -0,0 +1,6 @@
+<?xml version='1.0' encoding='utf-8'?>
+<resources>
+ <string name="ministro_not_found_msg">Ministro servise nije pronađen. Aplikacija ne može biti pokrenuta.</string>
+ <string name="ministro_needed_msg">Ova aplikacija zahteva Ministro servis. Želite li da ga instalirate?</string>
+ <string name="fatal_error_msg">Vaša aplikacija je naišla na fatalnu grešku i ne može nastaviti sa radom.</string>
+</resources>
diff --git a/src/android/java/res/values-ru/strings.xml b/src/android/java/res/values-ru/strings.xml
new file mode 100644
index 0000000000..d3cee80f9d
--- /dev/null
+++ b/src/android/java/res/values-ru/strings.xml
@@ -0,0 +1,6 @@
+<?xml version='1.0' encoding='utf-8'?>
+<resources>
+ <string name="ministro_not_found_msg">Сервис Ministro не найден.\nПриложение нельзя запустить.</string>
+ <string name="ministro_needed_msg">Этому приложению необходим сервис Ministro. Вы хотите его установить?</string>
+ <string name="fatal_error_msg">Ваше приложение столкнулось с фатальной ошибкой и не может более работать.</string>
+</resources>
diff --git a/src/android/java/res/values-zh-rCN/strings.xml b/src/android/java/res/values-zh-rCN/strings.xml
new file mode 100644
index 0000000000..2eb1269880
--- /dev/null
+++ b/src/android/java/res/values-zh-rCN/strings.xml
@@ -0,0 +1,6 @@
+<?xml version='1.0' encoding='utf-8'?>
+<resources>
+ <string name="ministro_not_found_msg">无法找到Ministro服务。\n应用程序无法启动。</string>
+ <string name="ministro_needed_msg">此应用程序需要Ministro服务。您想安装它吗?</string>
+ <string name="fatal_error_msg">您的应用程序遇到一个致命错误导致它无法继续。</string>
+</resources>
diff --git a/src/android/java/res/values-zh-rTW/strings.xml b/src/android/java/res/values-zh-rTW/strings.xml
new file mode 100644
index 0000000000..f6e68efa52
--- /dev/null
+++ b/src/android/java/res/values-zh-rTW/strings.xml
@@ -0,0 +1,6 @@
+<?xml version='1.0' encoding='utf-8'?>
+<resources>
+ <string name="ministro_not_found_msg">無法找到Ministro服務。\n應用程序無法啟動。</string>
+ <string name="ministro_needed_msg">此應用程序需要Ministro服務。您想安裝它嗎?</string>
+ <string name="fatal_error_msg">您的應用程序遇到一個致命錯誤導致它無法繼續。</string>
+</resources>
diff --git a/src/android/java/res/values/libs.xml b/src/android/java/res/values/libs.xml
new file mode 100644
index 0000000000..92ce09b7c0
--- /dev/null
+++ b/src/android/java/res/values/libs.xml
@@ -0,0 +1,8 @@
+<?xml version='1.0' encoding='utf-8'?>
+<resources>
+ <array name="qt_libs">
+ <item>QtCore</item>
+ <item>QtGui</item>
+ </array>
+ <array name="bundled_libs"/>
+</resources>
diff --git a/src/android/java/res/values/strings.xml b/src/android/java/res/values/strings.xml
new file mode 100644
index 0000000000..bd6928fe59
--- /dev/null
+++ b/src/android/java/res/values/strings.xml
@@ -0,0 +1,7 @@
+<?xml version='1.0' encoding='utf-8'?>
+<resources>
+ <string name="app_name"></string>
+ <string name="ministro_not_found_msg">Can\'t find Ministro service.\nThe application can\'t start.</string>
+ <string name="ministro_needed_msg">This application requires Ministro service. Would you like to install it?</string>
+ <string name="fatal_error_msg">Your application encountered a fatal error and cannot continue.</string>
+</resources>
diff --git a/src/android/java/src/org/kde/necessitas/ministro/IMinistro.aidl b/src/android/java/src/org/kde/necessitas/ministro/IMinistro.aidl
new file mode 100644
index 0000000000..1c33a77fdb
--- /dev/null
+++ b/src/android/java/src/org/kde/necessitas/ministro/IMinistro.aidl
@@ -0,0 +1,49 @@
+/*
+ Copyright (c) 2012, BogDan Vatra <bogdan@kde.org>
+ Contact: http://www.qt-project.org/legal
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+package org.kde.necessitas.ministro;
+
+import org.kde.necessitas.ministro.IMinistroCallback;
+
+interface IMinistro
+{
+/**
+* Check/download required libs to run the application
+*
+* param callback - interface used by Minsitro service to notify the client when the loader is ready
+* param parameters
+* parameters fields:
+* * Key Name Key type Explanations
+* "required.modules" StringArray Required modules by your application
+* "application.title" String Application name, used to show more informations to user
+* "qt.provider" String Qt libs provider, currently only "necessitas" is supported.
+* "minimum.ministro.api" Integer Minimum Ministro API level, used to check if Ministro service compatible with your application. Current API Level is 1 !
+* "minimum.qt.version" Integer Minimim Qt version (e.g. 0x040800, which means Qt 4.8.0, check http://doc.trolltech.com/4.8/qtglobal.html#QT_VERSION)!
+* "3rd.party.repositories" StringArray 3rd party repositories, which should be downloaded by ministro, needs minimum.ministro.api >= 2
+* Check http://community.kde.org/Necessitas/Ministro for more details.
+*/
+ void requestLoader(in IMinistroCallback callback, in Bundle parameters);
+}
diff --git a/src/android/java/src/org/kde/necessitas/ministro/IMinistroCallback.aidl b/src/android/java/src/org/kde/necessitas/ministro/IMinistroCallback.aidl
new file mode 100644
index 0000000000..eec270aec1
--- /dev/null
+++ b/src/android/java/src/org/kde/necessitas/ministro/IMinistroCallback.aidl
@@ -0,0 +1,53 @@
+/*
+ Copyright (c) 2012, BogDan Vatra <bogdan@kde.org>
+ Contact: http://www.qt-project.org/legal
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+package org.kde.necessitas.ministro;
+
+oneway interface IMinistroCallback {
+/**
+* This method is called by the Ministro service back into the application which
+* implements this interface.
+*
+* param in - loaderParams
+* loaderParams fields:
+* * Key Name Key type Explanations
+* * "error.code" Integer See below
+* * "error.message" String Missing if no error, otherwise will contain the error message translated into phone language where available.
+* * "dex.path" String The list of jar/apk files containing classes and resources, needed to be passed to application DexClassLoader
+* * "lib.path" String The list of directories containing native libraries; may be missing, needed to be passed to application DexClassLoader
+* * "loader.class.name" String Loader class name.
+*
+* "error.code" field possible errors:
+* - 0 no error.
+* - 1 incompatible Ministro version. Ministro needs to be upgraded.
+* - 2 not all modules could be satisfy.
+* - 3 invalid parameters
+*
+* This parameter will contain additional fields which are used by the loader to start your application, so it must be passed to loader.
+*/
+
+ void loaderReady(in Bundle loaderParams);
+}
diff --git a/src/android/java/src/org/qtproject/qt5/android/bindings/QtActivity.java b/src/android/java/src/org/qtproject/qt5/android/bindings/QtActivity.java
new file mode 100644
index 0000000000..c3d82bca8d
--- /dev/null
+++ b/src/android/java/src/org/qtproject/qt5/android/bindings/QtActivity.java
@@ -0,0 +1,1278 @@
+/*
+ Copyright (c) 2012, BogDan Vatra <bogdan@kde.org>
+ Contact: http://www.qt-project.org/legal
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+package org.qtproject.qt5.android.bindings;
+
+import java.io.File;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Arrays;
+
+import org.kde.necessitas.ministro.IMinistro;
+import org.kde.necessitas.ministro.IMinistroCallback;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.content.pm.ActivityInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.res.Configuration;
+import android.content.res.Resources.Theme;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.ContextMenu;
+import android.view.ContextMenu.ContextMenuInfo;
+import android.view.KeyEvent;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.Window;
+import android.view.WindowManager.LayoutParams;
+import android.view.accessibility.AccessibilityEvent;
+import dalvik.system.DexClassLoader;
+
+//@ANDROID-11
+import android.app.Fragment;
+import android.view.ActionMode;
+import android.view.ActionMode.Callback;
+//@ANDROID-11
+
+public class QtActivity extends Activity
+{
+ private final static int MINISTRO_INSTALL_REQUEST_CODE = 0xf3ee; // request code used to know when Ministro instalation is finished
+ private static final int MINISTRO_API_LEVEL = 2; // Ministro api level (check IMinistro.aidl file)
+ private static final int NECESSITAS_API_LEVEL = 2; // Necessitas api level used by platform plugin
+ private static final String QT_PROVIDER = "necessitas";
+ private static final int QT_VERSION = 0x050100; // This app requires at least Qt version 5.1.0
+
+ private static final String ERROR_CODE_KEY = "error.code";
+ private static final String ERROR_MESSAGE_KEY = "error.message";
+ private static final String DEX_PATH_KEY = "dex.path";
+ private static final String LIB_PATH_KEY = "lib.path";
+ private static final String LOADER_CLASS_NAME_KEY = "loader.class.name";
+ private static final String NATIVE_LIBRARIES_KEY = "native.libraries";
+ private static final String ENVIRONMENT_VARIABLES_KEY = "environment.variables";
+ private static final String APPLICATION_PARAMETERS_KEY = "application.parameters";
+ private static final String BUNDLED_LIBRARIES_KEY = "bundled.libraries";
+ 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";
+
+ /// Ministro server parameter keys
+ private static final String REQUIRED_MODULES_KEY = "required.modules";
+ private static final String APPLICATION_TITLE_KEY = "application.title";
+ private static final String QT_PROVIDER_KEY = "qt.provider";
+ private static final String MINIMUM_MINISTRO_API_KEY = "minimum.ministro.api";
+ private static final String MINIMUM_QT_VERSION_KEY = "minimum.qt.version";
+// private static final String REPOSITORIES="3rd.party.repositories"; // needs MINISTRO_API_LEVEL >=2 !!!
+ // Use this key to specify any 3rd party repositories urls
+ // Ministro will download these repositories into thier
+ // own folders, check http://community.kde.org/Necessitas/Ministro
+ // for more details.
+
+ private static final String APPLICATION_PARAMETERS = null; // use this variable to pass any parameters to your application,
+ // the parameters must not contain any white spaces
+ // and must be separated with "\t"
+ // e.g "-param1\t-param2=value2\t-param3\tvalue3"
+
+ private static final String ENVIRONMENT_VARIABLES = "QT_USE_ANDROID_NATIVE_STYLE=1\t";
+ // use this variable to add any environment variables to your application.
+ // the env vars must be separated with "\t"
+ // e.g. "ENV_VAR1=1\tENV_VAR2=2\t"
+ // Currently the following vars are used by the android plugin:
+ // * QT_USE_ANDROID_NATIVE_STYLE - 0 if you don't want to use android style plugin, it will save a few ms at startup.
+
+ private static final int INCOMPATIBLE_MINISTRO_VERSION = 1; // Incompatible Ministro version. Ministro needs to be upgraded.
+ private ActivityInfo m_activityInfo = null; // activity info object, used to access the libs and the strings
+ private DexClassLoader m_classLoader = null; // loader object
+ private String[] m_qtLibs = null; // required qt libs
+
+ // this function is used to load and start the loader
+ private void loadApplication(Bundle loaderParams)
+ {
+ try {
+ final int errorCode = loaderParams.getInt(ERROR_CODE_KEY);
+ if (errorCode != 0) {
+ if (errorCode == INCOMPATIBLE_MINISTRO_VERSION) {
+ downloadUpgradeMinistro(loaderParams.getString(ERROR_MESSAGE_KEY));
+ return;
+ }
+
+ // fatal error, show the error and quit
+ AlertDialog errorDialog = new AlertDialog.Builder(QtActivity.this).create();
+ errorDialog.setMessage(loaderParams.getString(ERROR_MESSAGE_KEY));
+ errorDialog.setButton(getResources().getString(android.R.string.ok), new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ finish();
+ }
+ });
+ errorDialog.show();
+ return;
+ }
+
+ // add all bundled Qt libs to loader params
+ ArrayList<String> libs = new ArrayList<String>();
+ if ( m_activityInfo.metaData.containsKey("android.app.bundled_libs_resource_id") )
+ libs.addAll(Arrays.asList(getResources().getStringArray(m_activityInfo.metaData.getInt("android.app.bundled_libs_resource_id"))));
+
+ String libName = null;
+ if ( m_activityInfo.metaData.containsKey("android.app.lib_name") ) {
+ libName = m_activityInfo.metaData.getString("android.app.lib_name");
+ loaderParams.putString(MAIN_LIBRARY_KEY, libName); //main library contains main() function
+ }
+
+ loaderParams.putStringArrayList(BUNDLED_LIBRARIES_KEY, libs);
+ loaderParams.putInt(NECESSITAS_API_LEVEL_KEY, NECESSITAS_API_LEVEL);
+
+ // load and start QtLoader class
+ m_classLoader = new DexClassLoader(loaderParams.getString(DEX_PATH_KEY), // .jar/.apk files
+ getDir("outdex", Context.MODE_PRIVATE).getAbsolutePath(), // directory where optimized DEX files should be written.
+ loaderParams.containsKey(LIB_PATH_KEY) ? loaderParams.getString(LIB_PATH_KEY) : null, // libs folder (if exists)
+ getClassLoader()); // parent loader
+
+ @SuppressWarnings("rawtypes")
+ Class loaderClass = m_classLoader.loadClass(loaderParams.getString(LOADER_CLASS_NAME_KEY)); // load QtLoader class
+ Object qtLoader = loaderClass.newInstance(); // create an instance
+ Method perpareAppMethod = qtLoader.getClass().getMethod("loadApplication",
+ Activity.class,
+ ClassLoader.class,
+ Bundle.class);
+ if (!(Boolean)perpareAppMethod.invoke(qtLoader, this, m_classLoader, loaderParams))
+ throw new Exception("");
+
+ QtApplication.setQtActivityDelegate(qtLoader);
+
+ // now load the application library so it's accessible from this class loader
+ if (libName != null)
+ System.loadLibrary(libName);
+
+ Method startAppMethod=qtLoader.getClass().getMethod("startApplication");
+ if (!(Boolean)startAppMethod.invoke(qtLoader))
+ throw new Exception("");
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ AlertDialog errorDialog = new AlertDialog.Builder(QtActivity.this).create();
+ if (m_activityInfo != null && m_activityInfo.metaData.containsKey("android.app.fatal_error_msg"))
+ errorDialog.setMessage(m_activityInfo.metaData.getString("android.app.fatal_error_msg"));
+ else
+ errorDialog.setMessage("Fatal error, your application can't be started.");
+
+ errorDialog.setButton(getResources().getString(android.R.string.ok), new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ finish();
+ }
+ });
+ errorDialog.show();
+ }
+ }
+
+ private ServiceConnection m_ministroConnection=new ServiceConnection() {
+ private IMinistro m_service = null;
+ @Override
+ public void onServiceConnected(ComponentName name, IBinder service)
+ {
+ m_service = IMinistro.Stub.asInterface(service);
+ try {
+ if (m_service!=null) {
+ Bundle parameters= new Bundle();
+ parameters.putStringArray(REQUIRED_MODULES_KEY, m_qtLibs);
+ parameters.putString(APPLICATION_TITLE_KEY, (String)QtActivity.this.getTitle());
+ parameters.putInt(MINIMUM_MINISTRO_API_KEY, MINISTRO_API_LEVEL);
+ parameters.putString(QT_PROVIDER_KEY, QT_PROVIDER);
+ parameters.putInt(MINIMUM_QT_VERSION_KEY, QT_VERSION);
+ parameters.putString(ENVIRONMENT_VARIABLES_KEY, ENVIRONMENT_VARIABLES);
+ if (null!=APPLICATION_PARAMETERS)
+ parameters.putString(APPLICATION_PARAMETERS_KEY, APPLICATION_PARAMETERS);
+ // parameters.putStringArray(REPOSITORIES, null);
+ m_service.requestLoader(m_ministroCallback, parameters);
+ }
+ } catch (RemoteException e) {
+ e.printStackTrace();
+ }
+ }
+
+ private IMinistroCallback m_ministroCallback = new IMinistroCallback.Stub() {
+ // this function is called back by Ministro.
+ @Override
+ public void loaderReady(final Bundle loaderParams) throws RemoteException {
+ runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ unbindService(m_ministroConnection);
+ loadApplication(loaderParams);
+ }
+ });
+ }
+ };
+
+ @Override
+ public void onServiceDisconnected(ComponentName name) {
+ m_service = null;
+ }
+ };
+
+ private void downloadUpgradeMinistro(String msg)
+ {
+ AlertDialog.Builder downloadDialog = new AlertDialog.Builder(this);
+ downloadDialog.setMessage(msg);
+ downloadDialog.setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialogInterface, int i) {
+ try {
+ Uri uri = Uri.parse("market://search?q=pname:org.kde.necessitas.ministro");
+ Intent intent = new Intent(Intent.ACTION_VIEW, uri);
+ startActivityForResult(intent, MINISTRO_INSTALL_REQUEST_CODE);
+ } catch (Exception e) {
+ e.printStackTrace();
+ ministroNotFound();
+ }
+ }
+ });
+
+ downloadDialog.setNegativeButton(android.R.string.no, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialogInterface, int i) {
+ QtActivity.this.finish();
+ }
+ });
+ downloadDialog.show();
+ }
+
+ private void ministroNotFound()
+ {
+ AlertDialog errorDialog = new AlertDialog.Builder(QtActivity.this).create();
+
+ if (m_activityInfo != null && m_activityInfo.metaData.containsKey("android.app.ministro_not_found_msg"))
+ errorDialog.setMessage(m_activityInfo.metaData.getString("android.app.ministro_not_found_msg"));
+ else
+ errorDialog.setMessage("Can't find Ministro service.\nThe application can't start.");
+
+ errorDialog.setButton(getResources().getString(android.R.string.ok), new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ finish();
+ }
+ });
+ errorDialog.show();
+ }
+
+ private void startApp(final boolean firstStart)
+ {
+ try {
+ ActivityInfo ai=getPackageManager().getActivityInfo(getComponentName(), PackageManager.GET_META_DATA);
+ if (ai.metaData.containsKey("android.app.qt_libs_resource_id")) {
+ int resourceId = ai.metaData.getInt("android.app.qt_libs_resource_id");
+ m_qtLibs = getResources().getStringArray(resourceId);
+ }
+
+ if (getIntent().getExtras()!= null
+ && getIntent().getExtras().containsKey("use_local_qt_libs")
+ && getIntent().getExtras().getString("use_local_qt_libs").equals("true")) {
+ ArrayList<String> libraryList= new ArrayList<String>();
+
+ String localPrefix="/data/local/tmp/qt/";
+ if (getIntent().getExtras().containsKey("libs_prefix"))
+ localPrefix=getIntent().getExtras().getString("libs_prefix");
+
+ if (m_qtLibs != null) {
+ for (int i=0;i<m_qtLibs.length;i++)
+ libraryList.add(localPrefix+"lib/lib"+m_qtLibs[i]+".so");
+ }
+
+ if (getIntent().getExtras().containsKey("load_local_libs")) {
+ String[] extraLibs=getIntent().getExtras().getString("load_local_libs").split(":");
+ for (String lib:extraLibs) {
+ if (lib.length() > 0)
+ libraryList.add(localPrefix + lib);
+ }
+ }
+
+ String dexPaths = new String();
+ String pathSeparator = System.getProperty("path.separator", ":");
+ if (getIntent().getExtras().containsKey("load_local_jars")) {
+ String[] jarFiles = getIntent().getExtras().getString("load_local_jars").split(":");
+ for (String jar:jarFiles) {
+ if (jar.length() > 0) {
+ if (dexPaths.length() > 0)
+ dexPaths += pathSeparator;
+ dexPaths += localPrefix + jar;
+ }
+ }
+ }
+
+ Bundle loaderParams = new Bundle();
+ loaderParams.putInt(ERROR_CODE_KEY, 0);
+ loaderParams.putString(DEX_PATH_KEY, dexPaths);
+ loaderParams.putString(LOADER_CLASS_NAME_KEY, getIntent().getExtras().containsKey("loader_class_name")
+ ? getIntent().getExtras().getString("loader_class_name")
+ : "org.qtproject.qt5.android.QtActivityDelegate");
+ if (getIntent().getExtras().containsKey("static_init_classes")) {
+ loaderParams.putStringArray(STATIC_INIT_CLASSES_KEY,
+ getIntent().getExtras().getString("static_init_classes").split(":"));
+ }
+ loaderParams.putStringArrayList(NATIVE_LIBRARIES_KEY, libraryList);
+ loaderParams.putString(ENVIRONMENT_VARIABLES_KEY, ENVIRONMENT_VARIABLES
+ + "QT_QPA_EGLFS_HIDECURSOR=1"
+ + "\tQML2_IMPORT_PATH=" + localPrefix + "/qml"
+ + "\tQML_IMPORT_PATH=" + localPrefix + "/imports"
+ + "\tQT_PLUGIN_PATH=" + localPrefix + "/plugins");
+ loadApplication(loaderParams);
+ return;
+ }
+
+ try {
+ if (!bindService(new Intent(org.kde.necessitas.ministro.IMinistro.class.getCanonicalName()),
+ m_ministroConnection,
+ Context.BIND_AUTO_CREATE)) {
+ throw new SecurityException("");
+ }
+ } catch (Exception e) {
+ if (firstStart) {
+ String msg = "This application requires Ministro service. Would you like to install it?";
+ if (m_activityInfo != null && m_activityInfo.metaData.containsKey("android.app.ministro_needed_msg"))
+ msg = m_activityInfo.metaData.getString("android.app.ministro_needed_msg");
+ downloadUpgradeMinistro(msg);
+ } else {
+ ministroNotFound();
+ }
+ }
+ } catch (Exception e) {
+ Log.e(QtApplication.QtTAG, "Can't create main activity", e);
+ }
+ }
+
+
+
+ /////////////////////////// forward all notifications ////////////////////////////
+ /////////////////////////// Super class calls ////////////////////////////////////
+ /////////////// PLEASE DO NOT CHANGE THE FOLLOWING CODE //////////////////////////
+ //////////////////////////////////////////////////////////////////////////////////
+
+ @Override
+ public boolean dispatchKeyEvent(KeyEvent event)
+ {
+ if (QtApplication.m_delegateObject != null && QtApplication.dispatchKeyEvent != null)
+ return (Boolean) QtApplication.invokeDelegateMethod(QtApplication.dispatchKeyEvent, event);
+ else
+ return super.dispatchKeyEvent(event);
+ }
+ public boolean super_dispatchKeyEvent(KeyEvent event)
+ {
+ return super.dispatchKeyEvent(event);
+ }
+ //---------------------------------------------------------------------------
+
+ @Override
+ public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event)
+ {
+ if (QtApplication.m_delegateObject != null && QtApplication.dispatchPopulateAccessibilityEvent != null)
+ return (Boolean) QtApplication.invokeDelegateMethod(QtApplication.dispatchPopulateAccessibilityEvent, event);
+ else
+ return super.dispatchPopulateAccessibilityEvent(event);
+ }
+ public boolean super_dispatchPopulateAccessibilityEvent(AccessibilityEvent event)
+ {
+ return super_dispatchPopulateAccessibilityEvent(event);
+ }
+ //---------------------------------------------------------------------------
+
+ @Override
+ public boolean dispatchTouchEvent(MotionEvent ev)
+ {
+ if (QtApplication.m_delegateObject != null && QtApplication.dispatchTouchEvent != null)
+ return (Boolean) QtApplication.invokeDelegateMethod(QtApplication.dispatchTouchEvent, ev);
+ else
+ return super.dispatchTouchEvent(ev);
+ }
+ public boolean super_dispatchTouchEvent(MotionEvent event)
+ {
+ return super.dispatchTouchEvent(event);
+ }
+ //---------------------------------------------------------------------------
+
+ @Override
+ public boolean dispatchTrackballEvent(MotionEvent ev)
+ {
+ if (QtApplication.m_delegateObject != null && QtApplication.dispatchTrackballEvent != null)
+ return (Boolean) QtApplication.invokeDelegateMethod(QtApplication.dispatchTrackballEvent, ev);
+ else
+ return super.dispatchTrackballEvent(ev);
+ }
+ public boolean super_dispatchTrackballEvent(MotionEvent event)
+ {
+ return super.dispatchTrackballEvent(event);
+ }
+ //---------------------------------------------------------------------------
+
+ @Override
+ protected void onActivityResult(int requestCode, int resultCode, Intent data)
+ {
+
+ if (QtApplication.m_delegateObject != null && QtApplication.onActivityResult != null) {
+ QtApplication.invokeDelegateMethod(QtApplication.onActivityResult, requestCode, resultCode, data);
+ return;
+ }
+ if (requestCode == MINISTRO_INSTALL_REQUEST_CODE)
+ startApp(false);
+ super.onActivityResult(requestCode, resultCode, data);
+ }
+ public void super_onActivityResult(int requestCode, int resultCode, Intent data)
+ {
+ super.onActivityResult(requestCode, resultCode, data);
+ }
+ //---------------------------------------------------------------------------
+
+ @Override
+ protected void onApplyThemeResource(Theme theme, int resid, boolean first)
+ {
+ if (!QtApplication.invokeDelegate(theme, resid, first).invoked)
+ super.onApplyThemeResource(theme, resid, first);
+ }
+ public void super_onApplyThemeResource(Theme theme, int resid, boolean first)
+ {
+ super.onApplyThemeResource(theme, resid, first);
+ }
+ //---------------------------------------------------------------------------
+
+
+ @Override
+ protected void onChildTitleChanged(Activity childActivity, CharSequence title)
+ {
+ if (!QtApplication.invokeDelegate(childActivity, title).invoked)
+ super.onChildTitleChanged(childActivity, title);
+ }
+ public void super_onChildTitleChanged(Activity childActivity, CharSequence title)
+ {
+ super.onChildTitleChanged(childActivity, title);
+ }
+ //---------------------------------------------------------------------------
+
+ @Override
+ public void onConfigurationChanged(Configuration newConfig)
+ {
+ if (!QtApplication.invokeDelegate(newConfig).invoked)
+ super.onConfigurationChanged(newConfig);
+ }
+ public void super_onConfigurationChanged(Configuration newConfig)
+ {
+ super.onConfigurationChanged(newConfig);
+ }
+ //---------------------------------------------------------------------------
+
+ @Override
+ public void onContentChanged()
+ {
+ if (!QtApplication.invokeDelegate().invoked)
+ super.onContentChanged();
+ }
+ public void super_onContentChanged()
+ {
+ super.onContentChanged();
+ }
+ //---------------------------------------------------------------------------
+
+ @Override
+ public boolean onContextItemSelected(MenuItem item)
+ {
+ QtApplication.InvokeResult res = QtApplication.invokeDelegate(item);
+ if (res.invoked)
+ return (Boolean)res.methodReturns;
+ else
+ return super.onContextItemSelected(item);
+ }
+ public boolean super_onContextItemSelected(MenuItem item)
+ {
+ return super.onContextItemSelected(item);
+ }
+ //---------------------------------------------------------------------------
+
+ @Override
+ public void onContextMenuClosed(Menu menu)
+ {
+ if (!QtApplication.invokeDelegate(menu).invoked)
+ super.onContextMenuClosed(menu);
+ }
+ public void super_onContextMenuClosed(Menu menu)
+ {
+ super.onContextMenuClosed(menu);
+ }
+ //---------------------------------------------------------------------------
+
+ @Override
+ public void onCreate(Bundle savedInstanceState)
+ {
+ super.onCreate(savedInstanceState);
+ if (QtApplication.m_delegateObject != null && QtApplication.onCreate != null) {
+ QtApplication.invokeDelegateMethod(QtApplication.onCreate, savedInstanceState);
+ return;
+ }
+
+ requestWindowFeature(Window.FEATURE_NO_TITLE);
+ try {
+ m_activityInfo = getPackageManager().getActivityInfo(getComponentName(), PackageManager.GET_META_DATA);
+ } catch (NameNotFoundException e) {
+ e.printStackTrace();
+ finish();
+ return;
+ }
+
+ if (null == getLastNonConfigurationInstance()) {
+ // if splash screen is defined, then show it
+ if (m_activityInfo.metaData.containsKey("android.app.splash_screen") )
+ setContentView(m_activityInfo.metaData.getInt("android.app.splash_screen"));
+ startApp(true);
+ }
+ }
+ //---------------------------------------------------------------------------
+
+ @Override
+ public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo)
+ {
+ if (!QtApplication.invokeDelegate(menu, v, menuInfo).invoked)
+ super.onCreateContextMenu(menu, v, menuInfo);
+ }
+ public void super_onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo)
+ {
+ super.onCreateContextMenu(menu, v, menuInfo);
+ }
+ //---------------------------------------------------------------------------
+
+ @Override
+ public CharSequence onCreateDescription()
+ {
+ QtApplication.InvokeResult res = QtApplication.invokeDelegate();
+ if (res.invoked)
+ return (CharSequence)res.methodReturns;
+ else
+ return super.onCreateDescription();
+ }
+ public CharSequence super_onCreateDescription()
+ {
+ return super.onCreateDescription();
+ }
+ //---------------------------------------------------------------------------
+
+ @Override
+ protected Dialog onCreateDialog(int id)
+ {
+ QtApplication.InvokeResult res = QtApplication.invokeDelegate(id);
+ if (res.invoked)
+ return (Dialog)res.methodReturns;
+ else
+ return super.onCreateDialog(id);
+ }
+ public Dialog super_onCreateDialog(int id)
+ {
+ return super.onCreateDialog(id);
+ }
+ //---------------------------------------------------------------------------
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu)
+ {
+ QtApplication.InvokeResult res = QtApplication.invokeDelegate(menu);
+ if (res.invoked)
+ return (Boolean)res.methodReturns;
+ else
+ return super.onCreateOptionsMenu(menu);
+ }
+ public boolean super_onCreateOptionsMenu(Menu menu)
+ {
+ return super.onCreateOptionsMenu(menu);
+ }
+ //---------------------------------------------------------------------------
+
+ @Override
+ public boolean onCreatePanelMenu(int featureId, Menu menu)
+ {
+ QtApplication.InvokeResult res = QtApplication.invokeDelegate(featureId, menu);
+ if (res.invoked)
+ return (Boolean)res.methodReturns;
+ else
+ return super.onCreatePanelMenu(featureId, menu);
+ }
+ public boolean super_onCreatePanelMenu(int featureId, Menu menu)
+ {
+ return super.onCreatePanelMenu(featureId, menu);
+ }
+ //---------------------------------------------------------------------------
+
+
+ @Override
+ public View onCreatePanelView(int featureId)
+ {
+ QtApplication.InvokeResult res = QtApplication.invokeDelegate(featureId);
+ if (res.invoked)
+ return (View)res.methodReturns;
+ else
+ return super.onCreatePanelView(featureId);
+ }
+ public View super_onCreatePanelView(int featureId)
+ {
+ return super.onCreatePanelView(featureId);
+ }
+ //---------------------------------------------------------------------------
+
+ @Override
+ public boolean onCreateThumbnail(Bitmap outBitmap, Canvas canvas)
+ {
+ QtApplication.InvokeResult res = QtApplication.invokeDelegate(outBitmap, canvas);
+ if (res.invoked)
+ return (Boolean)res.methodReturns;
+ else
+ return super.onCreateThumbnail(outBitmap, canvas);
+ }
+ public boolean super_onCreateThumbnail(Bitmap outBitmap, Canvas canvas)
+ {
+ return super.onCreateThumbnail(outBitmap, canvas);
+ }
+ //---------------------------------------------------------------------------
+
+ @Override
+ public View onCreateView(String name, Context context, AttributeSet attrs)
+ {
+ QtApplication.InvokeResult res = QtApplication.invokeDelegate(name, context, attrs);
+ if (res.invoked)
+ return (View)res.methodReturns;
+ else
+ return super.onCreateView(name, context, attrs);
+ }
+ public View super_onCreateView(String name, Context context, AttributeSet attrs)
+ {
+ return super.onCreateView(name, context, attrs);
+ }
+ //---------------------------------------------------------------------------
+
+ @Override
+ protected void onDestroy()
+ {
+ super.onDestroy();
+ QtApplication.invokeDelegate();
+ }
+ //---------------------------------------------------------------------------
+
+
+ @Override
+ public boolean onKeyDown(int keyCode, KeyEvent event)
+ {
+ if (QtApplication.m_delegateObject != null && QtApplication.onKeyDown != null)
+ return (Boolean) QtApplication.invokeDelegateMethod(QtApplication.onKeyDown, keyCode, event);
+ else
+ return super.onKeyDown(keyCode, event);
+ }
+ public boolean super_onKeyDown(int keyCode, KeyEvent event)
+ {
+ return super.onKeyDown(keyCode, event);
+ }
+ //---------------------------------------------------------------------------
+
+
+ @Override
+ public boolean onKeyMultiple(int keyCode, int repeatCount, KeyEvent event)
+ {
+ if (QtApplication.m_delegateObject != null && QtApplication.onKeyMultiple != null)
+ return (Boolean) QtApplication.invokeDelegateMethod(QtApplication.onKeyMultiple, keyCode, repeatCount, event);
+ else
+ return super.onKeyMultiple(keyCode, repeatCount, event);
+ }
+ public boolean super_onKeyMultiple(int keyCode, int repeatCount, KeyEvent event)
+ {
+ return super.onKeyMultiple(keyCode, repeatCount, event);
+ }
+ //---------------------------------------------------------------------------
+
+ @Override
+ public boolean onKeyUp(int keyCode, KeyEvent event)
+ {
+ if (QtApplication.m_delegateObject != null && QtApplication.onKeyDown != null)
+ return (Boolean) QtApplication.invokeDelegateMethod(QtApplication.onKeyUp, keyCode, event);
+ else
+ return super.onKeyUp(keyCode, event);
+ }
+ public boolean super_onKeyUp(int keyCode, KeyEvent event)
+ {
+ return super.onKeyUp(keyCode, event);
+ }
+ //---------------------------------------------------------------------------
+
+ @Override
+ public void onLowMemory()
+ {
+ if (!QtApplication.invokeDelegate().invoked)
+ super.onLowMemory();
+ }
+ //---------------------------------------------------------------------------
+
+ @Override
+ public boolean onMenuItemSelected(int featureId, MenuItem item)
+ {
+ QtApplication.InvokeResult res = QtApplication.invokeDelegate(featureId, item);
+ if (res.invoked)
+ return (Boolean)res.methodReturns;
+ else
+ return super.onMenuItemSelected(featureId, item);
+ }
+ public boolean super_onMenuItemSelected(int featureId, MenuItem item)
+ {
+ return super.onMenuItemSelected(featureId, item);
+ }
+ //---------------------------------------------------------------------------
+
+ @Override
+ public boolean onMenuOpened(int featureId, Menu menu)
+ {
+ QtApplication.InvokeResult res = QtApplication.invokeDelegate(featureId, menu);
+ if (res.invoked)
+ return (Boolean)res.methodReturns;
+ else
+ return super.onMenuOpened(featureId, menu);
+ }
+ public boolean super_onMenuOpened(int featureId, Menu menu)
+ {
+ return super.onMenuOpened(featureId, menu);
+ }
+ //---------------------------------------------------------------------------
+
+ @Override
+ protected void onNewIntent(Intent intent)
+ {
+ if (!QtApplication.invokeDelegate(intent).invoked)
+ super.onNewIntent(intent);
+ }
+ public void super_onNewIntent(Intent intent)
+ {
+ super.onNewIntent(intent);
+ }
+ //---------------------------------------------------------------------------
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item)
+ {
+ QtApplication.InvokeResult res = QtApplication.invokeDelegate(item);
+ if (res.invoked)
+ return (Boolean)res.methodReturns;
+ else
+ return super.onOptionsItemSelected(item);
+ }
+ public boolean super_onOptionsItemSelected(MenuItem item)
+ {
+ return super.onOptionsItemSelected(item);
+ }
+ //---------------------------------------------------------------------------
+
+ @Override
+ public void onOptionsMenuClosed(Menu menu)
+ {
+ if (!QtApplication.invokeDelegate(menu).invoked)
+ super.onOptionsMenuClosed(menu);
+ }
+ public void super_onOptionsMenuClosed(Menu menu)
+ {
+ super.onOptionsMenuClosed(menu);
+ }
+ //---------------------------------------------------------------------------
+
+ @Override
+ public void onPanelClosed(int featureId, Menu menu)
+ {
+ if (!QtApplication.invokeDelegate(featureId, menu).invoked)
+ super.onPanelClosed(featureId, menu);
+ }
+ public void super_onPanelClosed(int featureId, Menu menu)
+ {
+ super.onPanelClosed(featureId, menu);
+ }
+ //---------------------------------------------------------------------------
+
+ @Override
+ protected void onPause()
+ {
+ super.onPause();
+ QtApplication.invokeDelegate();
+ }
+ //---------------------------------------------------------------------------
+
+ @Override
+ protected void onPostCreate(Bundle savedInstanceState)
+ {
+ super.onPostCreate(savedInstanceState);
+ QtApplication.invokeDelegate(savedInstanceState);
+ }
+ //---------------------------------------------------------------------------
+
+ @Override
+ protected void onPostResume()
+ {
+ super.onPostResume();
+ QtApplication.invokeDelegate();
+ }
+ //---------------------------------------------------------------------------
+
+ @Override
+ protected void onPrepareDialog(int id, Dialog dialog)
+ {
+ if (!QtApplication.invokeDelegate(id, dialog).invoked)
+ super.onPrepareDialog(id, dialog);
+ }
+ public void super_onPrepareDialog(int id, Dialog dialog)
+ {
+ super.onPrepareDialog(id, dialog);
+ }
+ //---------------------------------------------------------------------------
+
+ @Override
+ public boolean onPrepareOptionsMenu(Menu menu)
+ {
+ QtApplication.InvokeResult res = QtApplication.invokeDelegate(menu);
+ if (res.invoked)
+ return (Boolean)res.methodReturns;
+ else
+ return super.onPrepareOptionsMenu(menu);
+ }
+ public boolean super_onPrepareOptionsMenu(Menu menu)
+ {
+ return super.onPrepareOptionsMenu(menu);
+ }
+ //---------------------------------------------------------------------------
+
+ @Override
+ public boolean onPreparePanel(int featureId, View view, Menu menu)
+ {
+ QtApplication.InvokeResult res = QtApplication.invokeDelegate(featureId, view, menu);
+ if (res.invoked)
+ return (Boolean)res.methodReturns;
+ else
+ return super.onPreparePanel(featureId, view, menu);
+ }
+ public boolean super_onPreparePanel(int featureId, View view, Menu menu)
+ {
+ return super.onPreparePanel(featureId, view, menu);
+ }
+ //---------------------------------------------------------------------------
+
+ @Override
+ protected void onRestart()
+ {
+ super.onRestart();
+ QtApplication.invokeDelegate();
+ }
+ //---------------------------------------------------------------------------
+
+ @Override
+ protected void onRestoreInstanceState(Bundle savedInstanceState)
+ {
+ if (!QtApplication.invokeDelegate(savedInstanceState).invoked)
+ super.onRestoreInstanceState(savedInstanceState);
+ }
+ public void super_onRestoreInstanceState(Bundle savedInstanceState)
+ {
+ super.onRestoreInstanceState(savedInstanceState);
+ }
+ //---------------------------------------------------------------------------
+
+ @Override
+ protected void onResume()
+ {
+ super.onResume();
+ QtApplication.invokeDelegate();
+ }
+ //---------------------------------------------------------------------------
+
+ @Override
+ public Object onRetainNonConfigurationInstance()
+ {
+ QtApplication.InvokeResult res = QtApplication.invokeDelegate();
+ if (res.invoked)
+ return res.methodReturns;
+ else
+ return super.onRetainNonConfigurationInstance();
+ }
+ public Object super_onRetainNonConfigurationInstance()
+ {
+ return super.onRetainNonConfigurationInstance();
+ }
+ //---------------------------------------------------------------------------
+
+ @Override
+ protected void onSaveInstanceState(Bundle outState)
+ {
+ if (!QtApplication.invokeDelegate(outState).invoked)
+ super.onSaveInstanceState(outState);
+ }
+ public void super_onSaveInstanceState(Bundle outState)
+ {
+ super.onSaveInstanceState(outState);
+
+ }
+ //---------------------------------------------------------------------------
+
+ @Override
+ public boolean onSearchRequested()
+ {
+ QtApplication.InvokeResult res = QtApplication.invokeDelegate();
+ if (res.invoked)
+ return (Boolean)res.methodReturns;
+ else
+ return super.onSearchRequested();
+ }
+ public boolean super_onSearchRequested()
+ {
+ return super.onSearchRequested();
+ }
+ //---------------------------------------------------------------------------
+
+ @Override
+ protected void onStart()
+ {
+ super.onStart();
+ QtApplication.invokeDelegate();
+ }
+ //---------------------------------------------------------------------------
+
+ @Override
+ protected void onStop()
+ {
+ super.onStop();
+ QtApplication.invokeDelegate();
+ }
+ //---------------------------------------------------------------------------
+
+ @Override
+ protected void onTitleChanged(CharSequence title, int color)
+ {
+ if (!QtApplication.invokeDelegate(title, color).invoked)
+ super.onTitleChanged(title, color);
+ }
+ public void super_onTitleChanged(CharSequence title, int color)
+ {
+ super.onTitleChanged(title, color);
+ }
+ //---------------------------------------------------------------------------
+
+ @Override
+ public boolean onTouchEvent(MotionEvent event)
+ {
+ if (QtApplication.m_delegateObject != null && QtApplication.onTouchEvent != null)
+ return (Boolean) QtApplication.invokeDelegateMethod(QtApplication.onTouchEvent, event);
+ else
+ return super.onTouchEvent(event);
+ }
+ public boolean super_onTouchEvent(MotionEvent event)
+ {
+ return super.onTouchEvent(event);
+ }
+ //---------------------------------------------------------------------------
+
+ @Override
+ public boolean onTrackballEvent(MotionEvent event)
+ {
+ if (QtApplication.m_delegateObject != null && QtApplication.onTrackballEvent != null)
+ return (Boolean) QtApplication.invokeDelegateMethod(QtApplication.onTrackballEvent, event);
+ else
+ return super.onTrackballEvent(event);
+ }
+ public boolean super_onTrackballEvent(MotionEvent event)
+ {
+ return super.onTrackballEvent(event);
+ }
+ //---------------------------------------------------------------------------
+
+ @Override
+ public void onUserInteraction()
+ {
+ if (!QtApplication.invokeDelegate().invoked)
+ super.onUserInteraction();
+ }
+ public void super_onUserInteraction()
+ {
+ super.onUserInteraction();
+ }
+ //---------------------------------------------------------------------------
+
+ @Override
+ protected void onUserLeaveHint()
+ {
+ if (!QtApplication.invokeDelegate().invoked)
+ super.onUserLeaveHint();
+ }
+ public void super_onUserLeaveHint()
+ {
+ super.onUserLeaveHint();
+ }
+ //---------------------------------------------------------------------------
+
+ @Override
+ public void onWindowAttributesChanged(LayoutParams params)
+ {
+ if (!QtApplication.invokeDelegate(params).invoked)
+ super.onWindowAttributesChanged(params);
+ }
+ public void super_onWindowAttributesChanged(LayoutParams params)
+ {
+ super.onWindowAttributesChanged(params);
+ }
+ //---------------------------------------------------------------------------
+
+ @Override
+ public void onWindowFocusChanged(boolean hasFocus)
+ {
+ if (!QtApplication.invokeDelegate(hasFocus).invoked)
+ super.onWindowFocusChanged(hasFocus);
+ }
+ public void super_onWindowFocusChanged(boolean hasFocus)
+ {
+ super.onWindowFocusChanged(hasFocus);
+ }
+ //---------------------------------------------------------------------------
+
+ //////////////// Activity API 5 /////////////
+//@ANDROID-5
+ @Override
+ public void onAttachedToWindow()
+ {
+ if (!QtApplication.invokeDelegate().invoked)
+ super.onAttachedToWindow();
+ }
+ public void super_onAttachedToWindow()
+ {
+ super.onAttachedToWindow();
+ }
+ //---------------------------------------------------------------------------
+
+ @Override
+ public void onBackPressed()
+ {
+ if (!QtApplication.invokeDelegate().invoked)
+ super.onBackPressed();
+ }
+ public void super_onBackPressed()
+ {
+ super.onBackPressed();
+ }
+ //---------------------------------------------------------------------------
+
+ @Override
+ public void onDetachedFromWindow()
+ {
+ if (!QtApplication.invokeDelegate().invoked)
+ super.onDetachedFromWindow();
+ }
+ public void super_onDetachedFromWindow()
+ {
+ super.onDetachedFromWindow();
+ }
+ //---------------------------------------------------------------------------
+
+ @Override
+ public boolean onKeyLongPress(int keyCode, KeyEvent event)
+ {
+ if (QtApplication.m_delegateObject != null && QtApplication.onKeyLongPress != null)
+ return (Boolean) QtApplication.invokeDelegateMethod(QtApplication.onKeyLongPress, keyCode, event);
+ else
+ return super.onKeyLongPress(keyCode, event);
+ }
+ public boolean super_onKeyLongPress(int keyCode, KeyEvent event)
+ {
+ return super.onKeyLongPress(keyCode, event);
+ }
+ //---------------------------------------------------------------------------
+//@ANDROID-5
+
+//////////////// Activity API 8 /////////////
+//@ANDROID-8
+@Override
+ protected Dialog onCreateDialog(int id, Bundle args)
+ {
+ QtApplication.InvokeResult res = QtApplication.invokeDelegate(id, args);
+ if (res.invoked)
+ return (Dialog)res.methodReturns;
+ else
+ return super.onCreateDialog(id, args);
+ }
+ public Dialog super_onCreateDialog(int id, Bundle args)
+ {
+ return super.onCreateDialog(id, args);
+ }
+ //---------------------------------------------------------------------------
+
+ @Override
+ protected void onPrepareDialog(int id, Dialog dialog, Bundle args)
+ {
+ if (!QtApplication.invokeDelegate(id, dialog, args).invoked)
+ super.onPrepareDialog(id, dialog, args);
+ }
+ public void super_onPrepareDialog(int id, Dialog dialog, Bundle args)
+ {
+ super.onPrepareDialog(id, dialog, args);
+ }
+ //---------------------------------------------------------------------------
+//@ANDROID-8
+ //////////////// Activity API 11 /////////////
+
+//@ANDROID-11
+ @Override
+ public boolean dispatchKeyShortcutEvent(KeyEvent event)
+ {
+ if (QtApplication.m_delegateObject != null && QtApplication.dispatchKeyShortcutEvent != null)
+ return (Boolean) QtApplication.invokeDelegateMethod(QtApplication.dispatchKeyShortcutEvent, event);
+ else
+ return super.dispatchKeyShortcutEvent(event);
+ }
+ public boolean super_dispatchKeyShortcutEvent(KeyEvent event)
+ {
+ return super.dispatchKeyShortcutEvent(event);
+ }
+ //---------------------------------------------------------------------------
+
+ @Override
+ public void onActionModeFinished(ActionMode mode)
+ {
+ if (!QtApplication.invokeDelegate(mode).invoked)
+ super.onActionModeFinished(mode);
+ }
+ public void super_onActionModeFinished(ActionMode mode)
+ {
+ super.onActionModeFinished(mode);
+ }
+ //---------------------------------------------------------------------------
+
+ @Override
+ public void onActionModeStarted(ActionMode mode)
+ {
+ if (!QtApplication.invokeDelegate(mode).invoked)
+ super.onActionModeStarted(mode);
+ }
+ public void super_onActionModeStarted(ActionMode mode)
+ {
+ super.onActionModeStarted(mode);
+ }
+ //---------------------------------------------------------------------------
+
+ @Override
+ public void onAttachFragment(Fragment fragment)
+ {
+ if (!QtApplication.invokeDelegate(fragment).invoked)
+ super.onAttachFragment(fragment);
+ }
+ public void super_onAttachFragment(Fragment fragment)
+ {
+ super.onAttachFragment(fragment);
+ }
+ //---------------------------------------------------------------------------
+
+ @Override
+ public View onCreateView(View parent, String name, Context context, AttributeSet attrs)
+ {
+ QtApplication.InvokeResult res = QtApplication.invokeDelegate(parent, name, context, attrs);
+ if (res.invoked)
+ return (View)res.methodReturns;
+ else
+ return super.onCreateView(parent, name, context, attrs);
+ }
+ public View super_onCreateView(View parent, String name, Context context,
+ AttributeSet attrs) {
+ return super.onCreateView(parent, name, context, attrs);
+ }
+ //---------------------------------------------------------------------------
+
+ @Override
+ public boolean onKeyShortcut(int keyCode, KeyEvent event)
+ {
+ if (QtApplication.m_delegateObject != null && QtApplication.onKeyShortcut != null)
+ return (Boolean) QtApplication.invokeDelegateMethod(QtApplication.onKeyShortcut, keyCode,event);
+ else
+ return super.onKeyShortcut(keyCode, event);
+ }
+ public boolean super_onKeyShortcut(int keyCode, KeyEvent event)
+ {
+ return super.onKeyShortcut(keyCode, event);
+ }
+ //---------------------------------------------------------------------------
+
+ @Override
+ public ActionMode onWindowStartingActionMode(Callback callback)
+ {
+ QtApplication.InvokeResult res = QtApplication.invokeDelegate(callback);
+ if (res.invoked)
+ return (ActionMode)res.methodReturns;
+ else
+ return super.onWindowStartingActionMode(callback);
+ }
+ public ActionMode super_onWindowStartingActionMode(Callback callback)
+ {
+ return super.onWindowStartingActionMode(callback);
+ }
+ //---------------------------------------------------------------------------
+//@ANDROID-11
+ //////////////// Activity API 12 /////////////
+
+//@ANDROID-12
+ @Override
+ public boolean dispatchGenericMotionEvent(MotionEvent ev)
+ {
+ if (QtApplication.m_delegateObject != null && QtApplication.dispatchGenericMotionEvent != null)
+ return (Boolean) QtApplication.invokeDelegateMethod(QtApplication.dispatchGenericMotionEvent, ev);
+ else
+ return super.dispatchGenericMotionEvent(ev);
+ }
+ public boolean super_dispatchGenericMotionEvent(MotionEvent event)
+ {
+ return super.dispatchGenericMotionEvent(event);
+ }
+ //---------------------------------------------------------------------------
+
+ @Override
+ public boolean onGenericMotionEvent(MotionEvent event)
+ {
+ if (QtApplication.m_delegateObject != null && QtApplication.onGenericMotionEvent != null)
+ return (Boolean) QtApplication.invokeDelegateMethod(QtApplication.onGenericMotionEvent, event);
+ else
+ return super.onGenericMotionEvent(event);
+ }
+ public boolean super_onGenericMotionEvent(MotionEvent event)
+ {
+ return super.onGenericMotionEvent(event);
+ }
+ //---------------------------------------------------------------------------
+//@ANDROID-12
+
+}
diff --git a/src/android/java/src/org/qtproject/qt5/android/bindings/QtApplication.java b/src/android/java/src/org/qtproject/qt5/android/bindings/QtApplication.java
new file mode 100644
index 0000000000..a23c3afb4d
--- /dev/null
+++ b/src/android/java/src/org/qtproject/qt5/android/bindings/QtApplication.java
@@ -0,0 +1,149 @@
+/*
+ Copyright (c) 2012, BogDan Vatra <bogdan@kde.org>
+ Contact: http://www.qt-project.org/legal
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+package org.qtproject.qt5.android.bindings;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.HashMap;
+
+import android.app.Application;
+
+public class QtApplication extends Application
+{
+ public final static String QtTAG = "Qt";
+ public static Object m_delegateObject = null;
+ public static HashMap<String, ArrayList<Method>> m_delegateMethods= new HashMap<String, ArrayList<Method>>();
+ public static Method dispatchKeyEvent = null;
+ public static Method dispatchPopulateAccessibilityEvent = null;
+ public static Method dispatchTouchEvent = null;
+ public static Method dispatchTrackballEvent = null;
+ public static Method onKeyDown = null;
+ public static Method onKeyMultiple = null;
+ public static Method onKeyUp = null;
+ public static Method onTouchEvent = null;
+ public static Method onTrackballEvent = null;
+ public static Method onActivityResult = null;
+ public static Method onCreate = null;
+ public static Method onKeyLongPress = null;
+ public static Method dispatchKeyShortcutEvent = null;
+ public static Method onKeyShortcut = null;
+ public static Method dispatchGenericMotionEvent = null;
+ public static Method onGenericMotionEvent = null;
+
+ public static void setQtActivityDelegate(Object listener)
+ {
+ QtApplication.m_delegateObject = listener;
+
+ ArrayList<Method> delegateMethods = new ArrayList<Method>();
+ for (Method m : listener.getClass().getMethods()) {
+ if (m.getDeclaringClass().getName().startsWith("org.qtproject.qt5.android"))
+ delegateMethods.add(m);
+ }
+
+ ArrayList<Field> applicationFields = new ArrayList<Field>();
+ for (Field f : QtApplication.class.getFields()) {
+ if (f.getDeclaringClass().getName().equals(QtApplication.class.getName()))
+ applicationFields.add(f);
+ }
+
+ for (Method delegateMethod : delegateMethods) {
+ try {
+ QtActivity.class.getDeclaredMethod(delegateMethod.getName(), delegateMethod.getParameterTypes());
+ if (QtApplication.m_delegateMethods.containsKey(delegateMethod.getName())) {
+ QtApplication.m_delegateMethods.get(delegateMethod.getName()).add(delegateMethod);
+ } else {
+ ArrayList<Method> delegateSet = new ArrayList<Method>();
+ delegateSet.add(delegateMethod);
+ QtApplication.m_delegateMethods.put(delegateMethod.getName(), delegateSet);
+ }
+ for (Field applicationField:applicationFields) {
+ if (applicationField.getName().equals(delegateMethod.getName())) {
+ try {
+ applicationField.set(null, delegateMethod);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ } catch (Exception e) {
+ }
+ }
+ }
+
+ @Override
+ public void onTerminate() {
+ if (m_delegateObject != null && m_delegateMethods.containsKey("onTerminate"))
+ invokeDelegateMethod(m_delegateMethods.get("onTerminate").get(0));
+ super.onTerminate();
+ }
+
+ public static class InvokeResult
+ {
+ public boolean invoked = false;
+ public Object methodReturns = null;
+ }
+
+ private static int stackDeep=-1;
+ public static InvokeResult invokeDelegate(Object... args)
+ {
+ InvokeResult result = new InvokeResult();
+ if (m_delegateObject == null)
+ return result;
+ StackTraceElement[] elements = Thread.currentThread().getStackTrace();
+ if (-1 == stackDeep) {
+ String activityClassName = QtActivity.class.getCanonicalName();
+ for (int it=0;it<elements.length;it++)
+ if (elements[it].getClassName().equals(activityClassName)) {
+ stackDeep = it;
+ break;
+ }
+ }
+ final String methodName=elements[stackDeep].getMethodName();
+ if (-1 == stackDeep || !m_delegateMethods.containsKey(methodName))
+ return result;
+
+ for (Method m : m_delegateMethods.get(methodName)) {
+ if (m.getParameterTypes().length == args.length) {
+ result.methodReturns = invokeDelegateMethod(m, args);
+ result.invoked = true;
+ return result;
+ }
+ }
+ return result;
+ }
+
+ public static Object invokeDelegateMethod(Method m, Object... args)
+ {
+ try {
+ return m.invoke(m_delegateObject, args);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+}
diff --git a/src/android/java/version.xml b/src/android/java/version.xml
new file mode 100644
index 0000000000..1cd8eb31fe
--- /dev/null
+++ b/src/android/java/version.xml
@@ -0,0 +1,8 @@
+<version value="3">
+ <ignore>
+ <file>AndroidManifest.xml</file>
+ <file>libs.xml</file>
+ <file>logo.png</file>
+ <file>icon.png</file>
+ </ignore>
+</version>