├── AndroidNativeCallsSender.cpp ├── AndroidNativeCallsSender.h ├── AndroidNativeWebViewExample.pro ├── QtCustomAndroidWebView.cpp ├── QtCustomAndroidWebView.h ├── android ├── .classpath ├── .project ├── AndroidManifest.xml ├── build.xml ├── gen │ └── org │ │ ├── kde │ │ └── necessitas │ │ │ └── ministro │ │ │ ├── IMinistro.java │ │ │ └── IMinistroCallback.java │ │ └── qtproject │ │ └── example │ │ └── AndroidNativeWebViewExample │ │ ├── BuildConfig.java │ │ └── R.java ├── local.properties ├── proguard-project.txt ├── project.properties ├── res │ ├── layout │ │ └── splash.xml │ ├── values-de │ │ └── strings.xml │ ├── values-el │ │ └── strings.xml │ ├── values-es │ │ └── strings.xml │ ├── values-et │ │ └── strings.xml │ ├── values-fa │ │ └── strings.xml │ ├── values-fr │ │ └── strings.xml │ ├── values-id │ │ └── strings.xml │ ├── values-it │ │ └── strings.xml │ ├── values-ja │ │ └── strings.xml │ ├── values-ms │ │ └── strings.xml │ ├── values-nb │ │ └── strings.xml │ ├── values-nl │ │ └── strings.xml │ ├── values-pl │ │ └── strings.xml │ ├── values-pt-rBR │ │ └── strings.xml │ ├── values-ro │ │ └── strings.xml │ ├── values-rs │ │ └── strings.xml │ ├── values-ru │ │ └── strings.xml │ ├── values-zh-rCN │ │ └── strings.xml │ ├── values-zh-rTW │ │ └── strings.xml │ └── values │ │ ├── libs.xml │ │ └── strings.xml ├── src │ └── org │ │ ├── kde │ │ └── necessitas │ │ │ └── ministro │ │ │ ├── IMinistro.aidl │ │ │ └── IMinistroCallback.aidl │ │ └── qtproject │ │ └── qt5 │ │ └── android │ │ └── bindings │ │ ├── NativeCalls.java │ │ ├── QtActivity.java │ │ └── QtApplication.java └── version.xml ├── main.cpp ├── mainwindow.cpp ├── mainwindow.h └── mainwindow.ui /AndroidNativeCallsSender.cpp: -------------------------------------------------------------------------------- 1 | #include "AndroidNativeCallsSender.h" 2 | 3 | //----------------------------------------------------------------------------- 4 | CAndroidNativeCallsSender::CAndroidNativeCallsSender() 5 | { 6 | QAndroidJniEnvironment jniEnv; 7 | QAndroidJniObject qObjAct = QAndroidJniObject::callStaticObjectMethod( "org/qtproject/qt5/android/QtNative", 8 | "activity", 9 | "()Landroid/app/Activity;" ); 10 | jobject objAct = qObjAct.object(); 11 | m_objectRef = jniEnv->NewGlobalRef( objAct ); 12 | jclass cls = jniEnv->GetObjectClass( objAct ); 13 | if( cls ) 14 | { 15 | m_createNewWebViewMID = jniEnv->GetMethodID( cls, "createNewWebView", "(I)V" ); 16 | m_removeWebViewMID = jniEnv->GetMethodID( cls, "removeWebView", "(I)V" ); 17 | m_attachWebViewToMainLayoutMID = jniEnv->GetMethodID( cls, "attachWebViewToMainLayout", "(I)V" ); 18 | m_moveWebViewMID = jniEnv->GetMethodID( cls, "moveWebView", "(III)V" ); 19 | m_resizeWebViewMID = jniEnv->GetMethodID( cls, "resizeWebView", "(III)V" ); 20 | m_loadUrlAtWebViewMID = jniEnv->GetMethodID( cls, "loadUrlAtWebView", "(ILjava/lang/String;)V" ); 21 | m_loadHtmlAtWebViewMID = jniEnv->GetMethodID( cls, "loadHtmlAtWebView", "(ILjava/lang/String;)V" ); 22 | } 23 | } 24 | 25 | //----------------------------------------------------------------------------- 26 | CAndroidNativeCallsSender::~CAndroidNativeCallsSender() 27 | { 28 | if( m_objectRef != NULL ) 29 | { 30 | QAndroidJniEnvironment jniEnv; 31 | jniEnv->DeleteGlobalRef( m_objectRef ); 32 | } 33 | } 34 | 35 | //----------------------------------------------------------------------------- 36 | void CAndroidNativeCallsSender::createNewWebView( int id ) const 37 | { 38 | if( m_createNewWebViewMID ) 39 | { 40 | QAndroidJniEnvironment jniEnv; 41 | jniEnv->CallVoidMethod( m_objectRef, m_createNewWebViewMID, id ); 42 | } 43 | } 44 | 45 | //----------------------------------------------------------------------------- 46 | void CAndroidNativeCallsSender::removeWebView( int id ) const 47 | { 48 | if( m_removeWebViewMID ) 49 | { 50 | QAndroidJniEnvironment jniEnv; 51 | jniEnv->CallVoidMethod( m_objectRef, m_removeWebViewMID, id ); 52 | } 53 | } 54 | 55 | //----------------------------------------------------------------------------- 56 | void CAndroidNativeCallsSender::attachWebViewToMainLayout( int id ) const 57 | { 58 | if( m_attachWebViewToMainLayoutMID ) 59 | { 60 | QAndroidJniEnvironment jniEnv; 61 | jniEnv->CallVoidMethod( m_objectRef, m_attachWebViewToMainLayoutMID, id ); 62 | } 63 | } 64 | 65 | //----------------------------------------------------------------------------- 66 | void CAndroidNativeCallsSender::moveWebView( int id, int x, int y ) const 67 | { 68 | if( m_moveWebViewMID ) 69 | { 70 | QAndroidJniEnvironment jniEnv; 71 | jniEnv->CallVoidMethod( m_objectRef, m_moveWebViewMID, id, x, y ); 72 | } 73 | } 74 | 75 | //----------------------------------------------------------------------------- 76 | void CAndroidNativeCallsSender::resizeWebView( int id, int w, int h ) const 77 | { 78 | if( m_resizeWebViewMID ) 79 | { 80 | QAndroidJniEnvironment jniEnv; 81 | jniEnv->CallVoidMethod( m_objectRef, m_resizeWebViewMID, id, w, h ); 82 | } 83 | } 84 | 85 | //----------------------------------------------------------------------------- 86 | void CAndroidNativeCallsSender::loadUrlAtWebView( int id, QString const& url ) const 87 | { 88 | if( m_loadUrlAtWebViewMID ) 89 | { 90 | QAndroidJniEnvironment jniEnv; 91 | jstring jurl = jniEnv->NewStringUTF( url.toUtf8().constData() ); 92 | jniEnv->CallVoidMethod( m_objectRef, 93 | m_loadUrlAtWebViewMID, 94 | id, 95 | jurl ); 96 | jniEnv->DeleteLocalRef( jurl ); 97 | } 98 | } 99 | 100 | //----------------------------------------------------------------------------- 101 | void CAndroidNativeCallsSender::loadHtmlAtWebView( int id, QString const& html ) const 102 | { 103 | if( m_loadUrlAtWebViewMID ) 104 | { 105 | QAndroidJniEnvironment jniEnv; 106 | jstring jhtml = jniEnv->NewStringUTF( html.toUtf8().constData() ); 107 | jniEnv->CallVoidMethod( m_objectRef, 108 | m_loadHtmlAtWebViewMID, 109 | id, 110 | jhtml ); 111 | jniEnv->DeleteLocalRef( jhtml ); 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /AndroidNativeCallsSender.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | class CAndroidNativeCallsSender 8 | { 9 | public: 10 | CAndroidNativeCallsSender(); 11 | ~CAndroidNativeCallsSender(); 12 | 13 | void createNewWebView( int id ) const; 14 | void removeWebView( int id ) const; 15 | void attachWebViewToMainLayout( int id ) const; 16 | void moveWebView( int id, int x, int y ) const; 17 | void resizeWebView( int id, int w, int h ) const; 18 | void loadUrlAtWebView( int id, QString const& url ) const; 19 | void loadHtmlAtWebView( int id, QString const& html ) const; 20 | 21 | protected: 22 | jmethodID m_createNewWebViewMID; 23 | jmethodID m_removeWebViewMID; 24 | jmethodID m_attachWebViewToMainLayoutMID; 25 | jmethodID m_moveWebViewMID; 26 | jmethodID m_resizeWebViewMID; 27 | jmethodID m_loadUrlAtWebViewMID; 28 | jmethodID m_loadHtmlAtWebViewMID; 29 | 30 | jobject m_objectRef; 31 | }; 32 | -------------------------------------------------------------------------------- /AndroidNativeWebViewExample.pro: -------------------------------------------------------------------------------- 1 | #------------------------------------------------- 2 | # 3 | # Project created by QtCreator 2014-06-03T10:17:17 4 | # 5 | #------------------------------------------------- 6 | 7 | QT += core gui 8 | 9 | greaterThan(QT_MAJOR_VERSION, 4): QT += widgets 10 | 11 | android: QT += androidextras 12 | 13 | android: ANDROID_PACKAGE_SOURCE_DIR = $$PWD/android 14 | 15 | TARGET = AndroidNativeWebViewExample 16 | TEMPLATE = app 17 | 18 | 19 | SOURCES += main.cpp\ 20 | mainwindow.cpp \ 21 | QtCustomAndroidWebView.cpp \ 22 | AndroidNativeCallsSender.cpp 23 | 24 | HEADERS += mainwindow.h \ 25 | QtCustomAndroidWebView.h \ 26 | AndroidNativeCallsSender.h 27 | 28 | FORMS += mainwindow.ui 29 | 30 | CONFIG += mobility 31 | MOBILITY = 32 | 33 | OTHER_FILES += \ 34 | android/AndroidManifest.xml 35 | 36 | -------------------------------------------------------------------------------- /QtCustomAndroidWebView.cpp: -------------------------------------------------------------------------------- 1 | #include "QtCustomAndroidWebView.h" 2 | 3 | //#include 4 | 5 | //----------------------------------------------------------------------------- 6 | int QtCustomAndroidWebView::sm_tag = 0; 7 | 8 | //----------------------------------------------------------------------------- 9 | QtCustomAndroidWebView::QtCustomAndroidWebView( QWidget *parent ) 10 | : QWidget( parent ) 11 | , m_androidID( generateNewTag() ) 12 | { 13 | // if( parent && parent->layout() ) 14 | // parent->layout()->addWidget( this ); 15 | 16 | m_nativeSender.createNewWebView( androidID() ); 17 | m_nativeSender.attachWebViewToMainLayout( androidID() ); 18 | } 19 | 20 | //----------------------------------------------------------------------------- 21 | QtCustomAndroidWebView::~QtCustomAndroidWebView() 22 | { 23 | m_nativeSender.removeWebView( androidID() ); 24 | } 25 | 26 | //----------------------------------------------------------------------------- 27 | void QtCustomAndroidWebView::loadURL( QString const& url ) const 28 | { 29 | m_nativeSender.loadUrlAtWebView( androidID(), url ); 30 | } 31 | 32 | //----------------------------------------------------------------------------- 33 | void QtCustomAndroidWebView::loadHtmlData( QString const& data ) const 34 | { 35 | m_nativeSender.loadHtmlAtWebView( androidID(), data ); 36 | } 37 | 38 | //----------------------------------------------------------------------------- 39 | void QtCustomAndroidWebView::move( int x, int y ) 40 | { 41 | QWidget::move( x, y ); 42 | m_nativeSender.moveWebView( androidID(), x, y ); 43 | } 44 | 45 | //----------------------------------------------------------------------------- 46 | void QtCustomAndroidWebView::move( QPoint const& p ) 47 | { 48 | QtCustomAndroidWebView::move( p.x(), p.y() ); 49 | } 50 | 51 | //----------------------------------------------------------------------------- 52 | void QtCustomAndroidWebView::resize( int w, int h ) 53 | { 54 | QWidget::resize( w, h ); 55 | m_nativeSender.resizeWebView( androidID(), w, h ); 56 | } 57 | 58 | //----------------------------------------------------------------------------- 59 | int QtCustomAndroidWebView::generateNewTag() 60 | { 61 | sm_tag++; 62 | return sm_tag; 63 | } 64 | -------------------------------------------------------------------------------- /QtCustomAndroidWebView.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include "AndroidNativeCallsSender.h" 7 | 8 | class QtCustomAndroidWebView : public QWidget 9 | { 10 | Q_OBJECT 11 | public: 12 | explicit QtCustomAndroidWebView( QWidget *parent = 0 ); 13 | ~QtCustomAndroidWebView(); 14 | 15 | void loadURL( QString const& url ) const; 16 | void loadHtmlData( QString const& data ) const; 17 | 18 | void move( int x, int y ); 19 | void move( QPoint const& p ); 20 | void resize( int w, int h ); 21 | 22 | int androidID() const { return m_androidID; } 23 | 24 | protected: 25 | static int sm_tag; 26 | int m_androidID; 27 | CAndroidNativeCallsSender m_nativeSender; 28 | 29 | int generateNewTag(); 30 | 31 | signals: 32 | 33 | public slots: 34 | }; 35 | -------------------------------------------------------------------------------- /android/.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /android/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | QtActivity 4 | 5 | 6 | 7 | 8 | 9 | com.android.ide.eclipse.adt.ResourceManagerBuilder 10 | 11 | 12 | 13 | 14 | com.android.ide.eclipse.adt.PreCompilerBuilder 15 | 16 | 17 | 18 | 19 | org.eclipse.jdt.core.javabuilder 20 | 21 | 22 | 23 | 24 | com.android.ide.eclipse.adt.ApkBuilder 25 | 26 | 27 | 28 | 29 | 30 | com.android.ide.eclipse.adt.AndroidNature 31 | org.eclipse.jdt.core.javanature 32 | 33 | 34 | -------------------------------------------------------------------------------- /android/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 42 | 43 | 44 | 45 | 46 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /android/build.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 9 | 29 | 30 | 31 | 35 | 36 | 37 | 38 | 39 | 40 | 49 | 50 | 51 | 52 | 56 | 57 | 69 | 70 | 71 | 89 | 90 | 91 | 92 | 93 | -------------------------------------------------------------------------------- /android/gen/org/kde/necessitas/ministro/IMinistro.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is auto-generated. DO NOT MODIFY. 3 | * Original file: C:\\projects\\AndroidNativeWebViewExample\\android\\src\\org\\kde\\necessitas\\ministro\\IMinistro.aidl 4 | */ 5 | package org.kde.necessitas.ministro; 6 | public interface IMinistro extends android.os.IInterface 7 | { 8 | /** Local-side IPC implementation stub class. */ 9 | public static abstract class Stub extends android.os.Binder implements org.kde.necessitas.ministro.IMinistro 10 | { 11 | private static final java.lang.String DESCRIPTOR = "org.kde.necessitas.ministro.IMinistro"; 12 | /** Construct the stub at attach it to the interface. */ 13 | public Stub() 14 | { 15 | this.attachInterface(this, DESCRIPTOR); 16 | } 17 | /** 18 | * Cast an IBinder object into an org.kde.necessitas.ministro.IMinistro interface, 19 | * generating a proxy if needed. 20 | */ 21 | public static org.kde.necessitas.ministro.IMinistro asInterface(android.os.IBinder obj) 22 | { 23 | if ((obj==null)) { 24 | return null; 25 | } 26 | android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR); 27 | if (((iin!=null)&&(iin instanceof org.kde.necessitas.ministro.IMinistro))) { 28 | return ((org.kde.necessitas.ministro.IMinistro)iin); 29 | } 30 | return new org.kde.necessitas.ministro.IMinistro.Stub.Proxy(obj); 31 | } 32 | @Override public android.os.IBinder asBinder() 33 | { 34 | return this; 35 | } 36 | @Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException 37 | { 38 | switch (code) 39 | { 40 | case INTERFACE_TRANSACTION: 41 | { 42 | reply.writeString(DESCRIPTOR); 43 | return true; 44 | } 45 | case TRANSACTION_requestLoader: 46 | { 47 | data.enforceInterface(DESCRIPTOR); 48 | org.kde.necessitas.ministro.IMinistroCallback _arg0; 49 | _arg0 = org.kde.necessitas.ministro.IMinistroCallback.Stub.asInterface(data.readStrongBinder()); 50 | android.os.Bundle _arg1; 51 | if ((0!=data.readInt())) { 52 | _arg1 = android.os.Bundle.CREATOR.createFromParcel(data); 53 | } 54 | else { 55 | _arg1 = null; 56 | } 57 | this.requestLoader(_arg0, _arg1); 58 | reply.writeNoException(); 59 | return true; 60 | } 61 | } 62 | return super.onTransact(code, data, reply, flags); 63 | } 64 | private static class Proxy implements org.kde.necessitas.ministro.IMinistro 65 | { 66 | private android.os.IBinder mRemote; 67 | Proxy(android.os.IBinder remote) 68 | { 69 | mRemote = remote; 70 | } 71 | @Override public android.os.IBinder asBinder() 72 | { 73 | return mRemote; 74 | } 75 | public java.lang.String getInterfaceDescriptor() 76 | { 77 | return DESCRIPTOR; 78 | } 79 | /** 80 | * Check/download required libs to run the application 81 | * 82 | * param callback - interface used by Minsitro service to notify the client when the loader is ready 83 | * param parameters 84 | * parameters fields: 85 | * * Key Name Key type Explanations 86 | * "sources" StringArray Sources list from where Ministro will download the libs. Make sure you are using ONLY secure locations. 87 | * "repository" String Overwrites the default Ministro repository. Possible values: default, stable, testing and unstable 88 | * "required.modules" StringArray Required modules by your application 89 | * "application.title" String Application name, used to show more informations to user 90 | * "qt.provider" String Qt libs provider, currently only "necessitas" is supported. 91 | * "minimum.ministro.api" Integer Minimum Ministro API level, used to check if Ministro service compatible with your application. Current API Level is 3 ! 92 | * "minimum.qt.version" Integer Minimim Qt version (e.g. 0x040800, which means Qt 4.8.0, check http://qt-project.org/doc/qt-4.8/qtglobal.html#QT_VERSION)! 93 | */ 94 | @Override public void requestLoader(org.kde.necessitas.ministro.IMinistroCallback callback, android.os.Bundle parameters) throws android.os.RemoteException 95 | { 96 | android.os.Parcel _data = android.os.Parcel.obtain(); 97 | android.os.Parcel _reply = android.os.Parcel.obtain(); 98 | try { 99 | _data.writeInterfaceToken(DESCRIPTOR); 100 | _data.writeStrongBinder((((callback!=null))?(callback.asBinder()):(null))); 101 | if ((parameters!=null)) { 102 | _data.writeInt(1); 103 | parameters.writeToParcel(_data, 0); 104 | } 105 | else { 106 | _data.writeInt(0); 107 | } 108 | mRemote.transact(Stub.TRANSACTION_requestLoader, _data, _reply, 0); 109 | _reply.readException(); 110 | } 111 | finally { 112 | _reply.recycle(); 113 | _data.recycle(); 114 | } 115 | } 116 | } 117 | static final int TRANSACTION_requestLoader = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0); 118 | } 119 | /** 120 | * Check/download required libs to run the application 121 | * 122 | * param callback - interface used by Minsitro service to notify the client when the loader is ready 123 | * param parameters 124 | * parameters fields: 125 | * * Key Name Key type Explanations 126 | * "sources" StringArray Sources list from where Ministro will download the libs. Make sure you are using ONLY secure locations. 127 | * "repository" String Overwrites the default Ministro repository. Possible values: default, stable, testing and unstable 128 | * "required.modules" StringArray Required modules by your application 129 | * "application.title" String Application name, used to show more informations to user 130 | * "qt.provider" String Qt libs provider, currently only "necessitas" is supported. 131 | * "minimum.ministro.api" Integer Minimum Ministro API level, used to check if Ministro service compatible with your application. Current API Level is 3 ! 132 | * "minimum.qt.version" Integer Minimim Qt version (e.g. 0x040800, which means Qt 4.8.0, check http://qt-project.org/doc/qt-4.8/qtglobal.html#QT_VERSION)! 133 | */ 134 | public void requestLoader(org.kde.necessitas.ministro.IMinistroCallback callback, android.os.Bundle parameters) throws android.os.RemoteException; 135 | } 136 | -------------------------------------------------------------------------------- /android/gen/org/kde/necessitas/ministro/IMinistroCallback.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is auto-generated. DO NOT MODIFY. 3 | * Original file: C:\\projects\\AndroidNativeWebViewExample\\android\\src\\org\\kde\\necessitas\\ministro\\IMinistroCallback.aidl 4 | */ 5 | package org.kde.necessitas.ministro; 6 | public interface IMinistroCallback extends android.os.IInterface 7 | { 8 | /** Local-side IPC implementation stub class. */ 9 | public static abstract class Stub extends android.os.Binder implements org.kde.necessitas.ministro.IMinistroCallback 10 | { 11 | private static final java.lang.String DESCRIPTOR = "org.kde.necessitas.ministro.IMinistroCallback"; 12 | /** Construct the stub at attach it to the interface. */ 13 | public Stub() 14 | { 15 | this.attachInterface(this, DESCRIPTOR); 16 | } 17 | /** 18 | * Cast an IBinder object into an org.kde.necessitas.ministro.IMinistroCallback interface, 19 | * generating a proxy if needed. 20 | */ 21 | public static org.kde.necessitas.ministro.IMinistroCallback asInterface(android.os.IBinder obj) 22 | { 23 | if ((obj==null)) { 24 | return null; 25 | } 26 | android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR); 27 | if (((iin!=null)&&(iin instanceof org.kde.necessitas.ministro.IMinistroCallback))) { 28 | return ((org.kde.necessitas.ministro.IMinistroCallback)iin); 29 | } 30 | return new org.kde.necessitas.ministro.IMinistroCallback.Stub.Proxy(obj); 31 | } 32 | @Override public android.os.IBinder asBinder() 33 | { 34 | return this; 35 | } 36 | @Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException 37 | { 38 | switch (code) 39 | { 40 | case INTERFACE_TRANSACTION: 41 | { 42 | reply.writeString(DESCRIPTOR); 43 | return true; 44 | } 45 | case TRANSACTION_loaderReady: 46 | { 47 | data.enforceInterface(DESCRIPTOR); 48 | android.os.Bundle _arg0; 49 | if ((0!=data.readInt())) { 50 | _arg0 = android.os.Bundle.CREATOR.createFromParcel(data); 51 | } 52 | else { 53 | _arg0 = null; 54 | } 55 | this.loaderReady(_arg0); 56 | return true; 57 | } 58 | } 59 | return super.onTransact(code, data, reply, flags); 60 | } 61 | private static class Proxy implements org.kde.necessitas.ministro.IMinistroCallback 62 | { 63 | private android.os.IBinder mRemote; 64 | Proxy(android.os.IBinder remote) 65 | { 66 | mRemote = remote; 67 | } 68 | @Override public android.os.IBinder asBinder() 69 | { 70 | return mRemote; 71 | } 72 | public java.lang.String getInterfaceDescriptor() 73 | { 74 | return DESCRIPTOR; 75 | } 76 | /** 77 | * This method is called by the Ministro service back into the application which 78 | * implements this interface. 79 | * 80 | * param in - loaderParams 81 | * loaderParams fields: 82 | * * Key Name Key type Explanations 83 | * * "error.code" Integer See below 84 | * * "error.message" String Missing if no error, otherwise will contain the error message translated into phone language where available. 85 | * * "dex.path" String The list of jar/apk files containing classes and resources, needed to be passed to application DexClassLoader 86 | * * "lib.path" String The list of directories containing native libraries; may be missing, needed to be passed to application DexClassLoader 87 | * * "loader.class.name" String Loader class name. 88 | * 89 | * "error.code" field possible errors: 90 | * - 0 no error. 91 | * - 1 incompatible Ministro version. Ministro needs to be upgraded. 92 | * - 2 not all modules could be satisfy. 93 | * - 3 invalid parameters 94 | * - 4 invalid qt version 95 | * - 5 download canceled 96 | * 97 | * The parameter contains additional fields which are used by the loader to start your application, so it must be passed to the loader. 98 | */ 99 | @Override public void loaderReady(android.os.Bundle loaderParams) throws android.os.RemoteException 100 | { 101 | android.os.Parcel _data = android.os.Parcel.obtain(); 102 | try { 103 | _data.writeInterfaceToken(DESCRIPTOR); 104 | if ((loaderParams!=null)) { 105 | _data.writeInt(1); 106 | loaderParams.writeToParcel(_data, 0); 107 | } 108 | else { 109 | _data.writeInt(0); 110 | } 111 | mRemote.transact(Stub.TRANSACTION_loaderReady, _data, null, android.os.IBinder.FLAG_ONEWAY); 112 | } 113 | finally { 114 | _data.recycle(); 115 | } 116 | } 117 | } 118 | static final int TRANSACTION_loaderReady = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0); 119 | } 120 | /** 121 | * This method is called by the Ministro service back into the application which 122 | * implements this interface. 123 | * 124 | * param in - loaderParams 125 | * loaderParams fields: 126 | * * Key Name Key type Explanations 127 | * * "error.code" Integer See below 128 | * * "error.message" String Missing if no error, otherwise will contain the error message translated into phone language where available. 129 | * * "dex.path" String The list of jar/apk files containing classes and resources, needed to be passed to application DexClassLoader 130 | * * "lib.path" String The list of directories containing native libraries; may be missing, needed to be passed to application DexClassLoader 131 | * * "loader.class.name" String Loader class name. 132 | * 133 | * "error.code" field possible errors: 134 | * - 0 no error. 135 | * - 1 incompatible Ministro version. Ministro needs to be upgraded. 136 | * - 2 not all modules could be satisfy. 137 | * - 3 invalid parameters 138 | * - 4 invalid qt version 139 | * - 5 download canceled 140 | * 141 | * The parameter contains additional fields which are used by the loader to start your application, so it must be passed to the loader. 142 | */ 143 | public void loaderReady(android.os.Bundle loaderParams) throws android.os.RemoteException; 144 | } 145 | -------------------------------------------------------------------------------- /android/gen/org/qtproject/example/AndroidNativeWebViewExample/BuildConfig.java: -------------------------------------------------------------------------------- 1 | /** Automatically generated file. DO NOT MODIFY */ 2 | package org.qtproject.example.AndroidNativeWebViewExample; 3 | 4 | public final class BuildConfig { 5 | public final static boolean DEBUG = true; 6 | } -------------------------------------------------------------------------------- /android/gen/org/qtproject/example/AndroidNativeWebViewExample/R.java: -------------------------------------------------------------------------------- 1 | /* AUTO-GENERATED FILE. DO NOT MODIFY. 2 | * 3 | * This class was automatically generated by the 4 | * aapt tool from the resource data it found. It 5 | * should not be modified by hand. 6 | */ 7 | 8 | package org.qtproject.example.AndroidNativeWebViewExample; 9 | 10 | public final class R { 11 | public static final class array { 12 | public static final int bundled_in_assets=0x7f030004; 13 | public static final int bundled_in_lib=0x7f030003; 14 | /** The following is handled automatically by the deployment tool. It should 15 | not be edited manually. 16 | */ 17 | public static final int bundled_libs=0x7f030001; 18 | public static final int qt_libs=0x7f030002; 19 | public static final int qt_sources=0x7f030000; 20 | } 21 | public static final class attr { 22 | } 23 | public static final class layout { 24 | public static final int splash=0x7f020000; 25 | } 26 | public static final class string { 27 | public static final int app_name=0x7f040000; 28 | public static final int fatal_error_msg=0x7f040003; 29 | public static final int ministro_needed_msg=0x7f040002; 30 | public static final int ministro_not_found_msg=0x7f040001; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /android/local.properties: -------------------------------------------------------------------------------- 1 | # This file is automatically generated by Android Tools. 2 | # Do not modify this file -- YOUR CHANGES WILL BE ERASED! 3 | # 4 | # This file must *NOT* be checked into Version Control Systems, 5 | # as it contains information specific to your local configuration. 6 | 7 | # location of the SDK. This is only used by Ant 8 | # For customization when using a Version Control System, please read the 9 | # header note. 10 | sdk.dir=C:\\Android\\adt-bundle-windows-x86_64-20140321\\sdk 11 | -------------------------------------------------------------------------------- /android/proguard-project.txt: -------------------------------------------------------------------------------- 1 | # To enable ProGuard in your project, edit project.properties 2 | # to define the proguard.config property as described in that file. 3 | # 4 | # Add project specific ProGuard rules here. 5 | # By default, the flags in this file are appended to flags specified 6 | # in ${sdk.dir}/tools/proguard/proguard-android.txt 7 | # You can edit the include path and order by changing the ProGuard 8 | # include property in project.properties. 9 | # 10 | # For more details, see 11 | # http://developer.android.com/guide/developing/tools/proguard.html 12 | 13 | # Add any project specific keep options here: 14 | 15 | # If your project uses WebView with JS, uncomment the following 16 | # and specify the fully qualified class name to the JavaScript interface 17 | # class: 18 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 19 | # public *; 20 | #} 21 | -------------------------------------------------------------------------------- /android/project.properties: -------------------------------------------------------------------------------- 1 | # This file is automatically generated by Android Tools. 2 | # Do not modify this file -- YOUR CHANGES WILL BE ERASED! 3 | # 4 | # This file must be checked in Version Control Systems. 5 | # 6 | # To customize properties used by the Ant build system edit 7 | # "ant.properties", and override values to adapt the script to your 8 | # project structure. 9 | # 10 | # To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home): 11 | #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt 12 | 13 | # Project target. 14 | target=android-19 15 | -------------------------------------------------------------------------------- /android/res/layout/splash.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /android/res/values-de/strings.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | Ministro-Dienst wurde nicht gefunden.\nAnwendung kann nicht gestartet werden 4 | Diese Anwendung benötigt den Ministro-Dienst. Möchten Sie ihn installieren? 5 | In Ihrer Anwendung ist ein schwerwiegender Fehler aufgetreten, sie kann nicht fortgesetzt werden 6 | 7 | -------------------------------------------------------------------------------- /android/res/values-el/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Δεν ήταν δυνατή η εύρεση της υπηρεσίας Ministro. Δεν είναι δυνατή η εκκίνηση της εφαρμογής. 4 | Η εφαρμογή απαιτεί την υπηρεσία Ministro. Να εγκατασταθεί η υπηρεσία? 5 | Παρουσιάστηκε ένα κρίσιμο σφάλμα και η εφαρμογή δεν μπορεί να συνεχίσει. 6 | 7 | -------------------------------------------------------------------------------- /android/res/values-es/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Servicio Ministro inesistente. Imposible ejecutar la aplicación. 4 | Esta aplicación requiere el servicio Ministro. Instalarlo? 5 | La aplicación ha causado un error grave y no es posible continuar. 6 | 7 | -------------------------------------------------------------------------------- /android/res/values-et/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Ei suuda leida Ministro teenust.\nProgrammi ei saa käivitada. 4 | See programm vajab Ministro teenust.\nKas soovite paigaldada? 5 | Programmiga juhtus fataalne viga.\nKahjuks ei saa jätkata. 6 | 7 | -------------------------------------------------------------------------------- /android/res/values-fa/strings.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | سرویس Ministro را پیدا نمی‌کند. برنامه نمی‌تواند آغاز شود. 4 | این نرم‌افزار به سرویس Ministro احتیاج دارد. آیا دوست دارید آن را نصب کنید؟ 5 | خطایی اساسی در برنامه‌تان رخ داد و اجرای برنامه نمی‌تواند ادامه یابد. 6 | 7 | -------------------------------------------------------------------------------- /android/res/values-fr/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Le service Ministro est introuvable.\nL\'application ne peut pas démarrer. 4 | Cette application requiert le service Ministro. Voulez-vous l\'installer? 5 | Votre application a rencontré une erreur fatale et ne peut pas continuer. 6 | 7 | -------------------------------------------------------------------------------- /android/res/values-id/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Layanan Ministro tidak bisa ditemukan.\nAplikasi tidak bisa dimulai. 4 | Aplikasi ini membutuhkan layanan Ministro. Apakah Anda ingin menginstalnya? 5 | Aplikasi Anda mengalami kesalahan fatal dan tidak dapat melanjutkan. 6 | 7 | -------------------------------------------------------------------------------- /android/res/values-it/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Servizio Ministro inesistente. Impossibile eseguire \nl\'applicazione. 4 | Questa applicazione richiede il servizio Ministro.Installarlo? 5 | L\'applicazione ha provocato un errore grave e non puo\' continuare. 6 | 7 | -------------------------------------------------------------------------------- /android/res/values-ja/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Ministroサービスが見つかりません。\nアプリケーションが起動できません。 4 | このアプリケーションにはMinistroサービスが必要です。 インストールしてもよろしいですか? 5 | アプリケーションで致命的なエラーが発生したため続行できません。 6 | 7 | -------------------------------------------------------------------------------- /android/res/values-ms/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Tidak jumpa servis Ministro.\nAplikasi tidak boleh dimulakan. 4 | Aplikasi ini memerlukan servis Ministro. Adakah anda ingin pasang servis itu? 5 | Aplikasi anda menemui ralat muat dan tidak boleh diteruskan. 6 | 7 | -------------------------------------------------------------------------------- /android/res/values-nb/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Kan ikke finne tjenesten Ministro. Applikasjonen kan ikke starte. 4 | Denne applikasjonen krever tjenesten Ministro. Vil du installere denne? 5 | Applikasjonen fikk en kritisk feil og kan ikke fortsette 6 | 7 | -------------------------------------------------------------------------------- /android/res/values-nl/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | De Ministro service is niet gevonden.\nDe applicatie kan niet starten. 4 | Deze applicatie maakt gebruik van de Ministro service. Wilt u deze installeren? 5 | Er is een fatale fout in de applicatie opgetreden. De applicatie kan niet verder gaan. 6 | 7 | -------------------------------------------------------------------------------- /android/res/values-pl/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Usługa Ministro nie została znaleziona.\nAplikacja nie może zostać uruchomiona. 4 | Aplikacja wymaga usługi Ministro. Czy chcesz ją zainstalować? 5 | Wystąpił błąd krytyczny. Aplikacja zostanie zamknięta. 6 | 7 | -------------------------------------------------------------------------------- /android/res/values-pt-rBR/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Não foi possível encontrar o serviço Ministro.\nA aplicação não pode iniciar. 4 | Essa aplicação requer o serviço Ministro. Gostaria de instalá-lo? 5 | Sua aplicação encontrou um erro fatal e não pode continuar. 6 | 7 | -------------------------------------------------------------------------------- /android/res/values-ro/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Serviciul Ministro nu poate fi găsit.\nAplicaţia nu poate porni. 4 | Această aplicaţie necesită serviciul Ministro.\nDoriţi să-l instalaţi? 5 | Aplicaţia dumneavoastră a întâmpinat o eroare fatală şi nu poate continua. 6 | 7 | -------------------------------------------------------------------------------- /android/res/values-rs/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Ministro servise nije pronađen. Aplikacija ne može biti pokrenuta. 4 | Ova aplikacija zahteva Ministro servis. Želite li da ga instalirate? 5 | Vaša aplikacija je naišla na fatalnu grešku i ne može nastaviti sa radom. 6 | 7 | -------------------------------------------------------------------------------- /android/res/values-ru/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Сервис Ministro не найден.\nПриложение нельзя запустить. 4 | Этому приложению необходим сервис Ministro. Вы хотите его установить? 5 | Ваше приложение столкнулось с фатальной ошибкой и не может более работать. 6 | 7 | -------------------------------------------------------------------------------- /android/res/values-zh-rCN/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 无法找到Ministro服务。\n应用程序无法启动。 4 | 此应用程序需要Ministro服务。您想安装它吗? 5 | 您的应用程序遇到一个致命错误导致它无法继续。 6 | 7 | -------------------------------------------------------------------------------- /android/res/values-zh-rTW/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 無法找到Ministro服務。\n應用程序無法啟動。 4 | 此應用程序需要Ministro服務。您想安裝它嗎? 5 | 您的應用程序遇到一個致命錯誤導致它無法繼續。 6 | 7 | -------------------------------------------------------------------------------- /android/res/values/libs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | https://download.qt-project.org/ministro/android/qt5/qt-5.3 5 | 6 | 7 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | gnustl_shared 16 | Qt5Core 17 | Qt5Gui 18 | Qt5Widgets 19 | Qt5AndroidExtras 20 | 21 | 22 | 23 | 24 | libplugins_platforms_android_libqtforandroid.so:plugins/platforms/android/libqtforandroid.so 25 | libplugins_platforms_libqminimal.so:plugins/platforms/libqminimal.so 26 | libplugins_platforms_libqoffscreen.so:plugins/platforms/libqoffscreen.so 27 | libplugins_generic_libqevdevkeyboardplugin.so:plugins/generic/libqevdevkeyboardplugin.so 28 | libplugins_generic_libqevdevmouseplugin.so:plugins/generic/libqevdevmouseplugin.so 29 | libplugins_generic_libqevdevtabletplugin.so:plugins/generic/libqevdevtabletplugin.so 30 | libplugins_generic_libqevdevtouchplugin.so:plugins/generic/libqevdevtouchplugin.so 31 | libplugins_imageformats_libqdds.so:plugins/imageformats/libqdds.so 32 | libplugins_imageformats_libqgif.so:plugins/imageformats/libqgif.so 33 | libplugins_imageformats_libqicns.so:plugins/imageformats/libqicns.so 34 | libplugins_imageformats_libqico.so:plugins/imageformats/libqico.so 35 | libplugins_imageformats_libqjp2.so:plugins/imageformats/libqjp2.so 36 | libplugins_imageformats_libqjpeg.so:plugins/imageformats/libqjpeg.so 37 | libplugins_imageformats_libqmng.so:plugins/imageformats/libqmng.so 38 | libplugins_imageformats_libqtga.so:plugins/imageformats/libqtga.so 39 | libplugins_imageformats_libqtiff.so:plugins/imageformats/libqtiff.so 40 | libplugins_imageformats_libqwbmp.so:plugins/imageformats/libqwbmp.so 41 | libplugins_accessible_libqtaccessiblewidgets.so:plugins/accessible/libqtaccessiblewidgets.so 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /android/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | AndroidNativeWebViewExample 4 | 5 | Can\'t find Ministro service.\nThe application can\'t start. 6 | This application requires Ministro service. Would you like to install it? 7 | Your application encountered a fatal error and cannot continue. 8 | 9 | -------------------------------------------------------------------------------- /android/src/org/kde/necessitas/ministro/IMinistro.aidl: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2011-2013, BogDan Vatra 3 | Contact: http://www.qt-project.org/legal 4 | 5 | Commercial License Usage 6 | Licensees holding valid commercial Qt licenses may use this file in 7 | accordance with the commercial license agreement provided with the 8 | Software or, alternatively, in accordance with the terms contained in 9 | a written agreement between you and Digia. For licensing terms and 10 | conditions see http://qt.digia.com/licensing. For further information 11 | use the contact form at http://qt.digia.com/contact-us. 12 | 13 | BSD License Usage 14 | Alternatively, this file may be used under the BSD license as follows: 15 | Redistribution and use in source and binary forms, with or without 16 | modification, are permitted provided that the following conditions 17 | are met: 18 | 19 | 1. Redistributions of source code must retain the above copyright 20 | notice, this list of conditions and the following disclaimer. 21 | 2. Redistributions in binary form must reproduce the above copyright 22 | notice, this list of conditions and the following disclaimer in the 23 | documentation and/or other materials provided with the distribution. 24 | 25 | THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 26 | IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 27 | OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 28 | IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 29 | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 30 | NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 31 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 32 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 33 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 34 | THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 35 | */ 36 | 37 | 38 | package org.kde.necessitas.ministro; 39 | 40 | import org.kde.necessitas.ministro.IMinistroCallback; 41 | 42 | interface IMinistro 43 | { 44 | /** 45 | * Check/download required libs to run the application 46 | * 47 | * param callback - interface used by Minsitro service to notify the client when the loader is ready 48 | * param parameters 49 | * parameters fields: 50 | * * Key Name Key type Explanations 51 | * "sources" StringArray Sources list from where Ministro will download the libs. Make sure you are using ONLY secure locations. 52 | * "repository" String Overwrites the default Ministro repository. Possible values: default, stable, testing and unstable 53 | * "required.modules" StringArray Required modules by your application 54 | * "application.title" String Application name, used to show more informations to user 55 | * "qt.provider" String Qt libs provider, currently only "necessitas" is supported. 56 | * "minimum.ministro.api" Integer Minimum Ministro API level, used to check if Ministro service compatible with your application. Current API Level is 3 ! 57 | * "minimum.qt.version" Integer Minimim Qt version (e.g. 0x040800, which means Qt 4.8.0, check http://qt-project.org/doc/qt-4.8/qtglobal.html#QT_VERSION)! 58 | */ 59 | void requestLoader(in IMinistroCallback callback, in Bundle parameters); 60 | } 61 | -------------------------------------------------------------------------------- /android/src/org/kde/necessitas/ministro/IMinistroCallback.aidl: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2011-2013, BogDan Vatra 3 | Contact: http://www.qt-project.org/legal 4 | 5 | Commercial License Usage 6 | Licensees holding valid commercial Qt licenses may use this file in 7 | accordance with the commercial license agreement provided with the 8 | Software or, alternatively, in accordance with the terms contained in 9 | a written agreement between you and Digia. For licensing terms and 10 | conditions see http://qt.digia.com/licensing. For further information 11 | use the contact form at http://qt.digia.com/contact-us. 12 | 13 | BSD License Usage 14 | Alternatively, this file may be used under the BSD license as follows: 15 | Redistribution and use in source and binary forms, with or without 16 | modification, are permitted provided that the following conditions 17 | are met: 18 | 19 | 1. Redistributions of source code must retain the above copyright 20 | notice, this list of conditions and the following disclaimer. 21 | 2. Redistributions in binary form must reproduce the above copyright 22 | notice, this list of conditions and the following disclaimer in the 23 | documentation and/or other materials provided with the distribution. 24 | 25 | THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 26 | IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 27 | OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 28 | IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 29 | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 30 | NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 31 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 32 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 33 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 34 | THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 35 | */ 36 | 37 | package org.kde.necessitas.ministro; 38 | 39 | oneway interface IMinistroCallback { 40 | /** 41 | * This method is called by the Ministro service back into the application which 42 | * implements this interface. 43 | * 44 | * param in - loaderParams 45 | * loaderParams fields: 46 | * * Key Name Key type Explanations 47 | * * "error.code" Integer See below 48 | * * "error.message" String Missing if no error, otherwise will contain the error message translated into phone language where available. 49 | * * "dex.path" String The list of jar/apk files containing classes and resources, needed to be passed to application DexClassLoader 50 | * * "lib.path" String The list of directories containing native libraries; may be missing, needed to be passed to application DexClassLoader 51 | * * "loader.class.name" String Loader class name. 52 | * 53 | * "error.code" field possible errors: 54 | * - 0 no error. 55 | * - 1 incompatible Ministro version. Ministro needs to be upgraded. 56 | * - 2 not all modules could be satisfy. 57 | * - 3 invalid parameters 58 | * - 4 invalid qt version 59 | * - 5 download canceled 60 | * 61 | * The parameter contains additional fields which are used by the loader to start your application, so it must be passed to the loader. 62 | */ 63 | 64 | void loaderReady(in Bundle loaderParams); 65 | } 66 | -------------------------------------------------------------------------------- /android/src/org/qtproject/qt5/android/bindings/NativeCalls.java: -------------------------------------------------------------------------------- 1 | package org.qtproject.qt5.android.bindings; 2 | 3 | public interface NativeCalls { 4 | public void createNewWebView(int tag); 5 | public void removeWebView(int tag); 6 | public void moveWebView(int tag, int x, int y); 7 | public void resizeWebView(int tag, int w, int h); 8 | public void attachWebViewToMainLayout(int tag); 9 | public void loadUrlAtWebView(int tag, String url); 10 | public void loadHtmlAtWebView(int tag, String html); 11 | } 12 | -------------------------------------------------------------------------------- /android/src/org/qtproject/qt5/android/bindings/QtActivity.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2012-2013, BogDan Vatra 3 | Contact: http://www.qt-project.org/legal 4 | 5 | Commercial License Usage 6 | Licensees holding valid commercial Qt licenses may use this file in 7 | accordance with the commercial license agreement provided with the 8 | Software or, alternatively, in accordance with the terms contained in 9 | a written agreement between you and Digia. For licensing terms and 10 | conditions see http://qt.digia.com/licensing. For further information 11 | use the contact form at http://qt.digia.com/contact-us. 12 | 13 | BSD License Usage 14 | Alternatively, this file may be used under the BSD license as follows: 15 | Redistribution and use in source and binary forms, with or without 16 | modification, are permitted provided that the following conditions 17 | are met: 18 | 19 | 1. Redistributions of source code must retain the above copyright 20 | notice, this list of conditions and the following disclaimer. 21 | 2. Redistributions in binary form must reproduce the above copyright 22 | notice, this list of conditions and the following disclaimer in the 23 | documentation and/or other materials provided with the distribution. 24 | 25 | THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 26 | IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 27 | OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 28 | IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 29 | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 30 | NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 31 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 32 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 33 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 34 | THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 35 | */ 36 | 37 | package org.qtproject.qt5.android.bindings; 38 | 39 | import java.io.File; 40 | import java.io.IOException; 41 | import java.io.OutputStream; 42 | import java.io.InputStream; 43 | import java.io.FileOutputStream; 44 | import java.io.FileInputStream; 45 | import java.io.DataOutputStream; 46 | import java.io.DataInputStream; 47 | import java.lang.reflect.Field; 48 | import java.lang.reflect.Method; 49 | import java.util.ArrayList; 50 | import java.util.Arrays; 51 | 52 | import org.kde.necessitas.ministro.IMinistro; 53 | import org.kde.necessitas.ministro.IMinistroCallback; 54 | 55 | import android.R; 56 | import android.annotation.SuppressLint; 57 | import android.app.Activity; 58 | import android.app.AlertDialog; 59 | import android.app.Dialog; 60 | import android.content.ComponentName; 61 | import android.content.Context; 62 | import android.content.DialogInterface; 63 | import android.content.Intent; 64 | import android.content.ServiceConnection; 65 | import android.content.pm.ActivityInfo; 66 | import android.content.pm.PackageManager; 67 | import android.content.pm.PackageManager.NameNotFoundException; 68 | import android.content.pm.PackageInfo; 69 | import android.content.res.Configuration; 70 | import android.content.res.Resources.Theme; 71 | import android.content.res.AssetManager; 72 | import android.graphics.Bitmap; 73 | import android.graphics.Canvas; 74 | import android.graphics.Color; 75 | import android.net.Uri; 76 | import android.os.Build; 77 | import android.os.Bundle; 78 | import android.os.Handler; 79 | import android.os.IBinder; 80 | import android.os.Message; 81 | import android.os.RemoteException; 82 | import android.util.AttributeSet; 83 | import android.util.Log; 84 | import android.view.ContextMenu; 85 | import android.view.ContextMenu.ContextMenuInfo; 86 | import android.view.KeyEvent; 87 | import android.view.Menu; 88 | import android.view.MenuItem; 89 | import android.view.MotionEvent; 90 | import android.view.View; 91 | import android.view.Window; 92 | import android.view.WindowManager.LayoutParams; 93 | import android.view.accessibility.AccessibilityEvent; 94 | import android.webkit.WebChromeClient; 95 | import android.webkit.WebView; 96 | import android.webkit.WebViewClient; 97 | import android.widget.FrameLayout; 98 | import dalvik.system.DexClassLoader; 99 | 100 | 101 | 102 | public class QtActivity extends Activity implements NativeCalls 103 | { 104 | private final static int MINISTRO_INSTALL_REQUEST_CODE = 0xf3ee; // request code used to know when Ministro instalation is finished 105 | private static final int MINISTRO_API_LEVEL = 4; // Ministro api level (check IMinistro.aidl file) 106 | private static final int NECESSITAS_API_LEVEL = 2; // Necessitas api level used by platform plugin 107 | private static final int QT_VERSION = 0x050100; // This app requires at least Qt version 5.1.0 108 | 109 | private static final String ERROR_CODE_KEY = "error.code"; 110 | private static final String ERROR_MESSAGE_KEY = "error.message"; 111 | private static final String DEX_PATH_KEY = "dex.path"; 112 | private static final String LIB_PATH_KEY = "lib.path"; 113 | private static final String LOADER_CLASS_NAME_KEY = "loader.class.name"; 114 | private static final String NATIVE_LIBRARIES_KEY = "native.libraries"; 115 | private static final String ENVIRONMENT_VARIABLES_KEY = "environment.variables"; 116 | private static final String APPLICATION_PARAMETERS_KEY = "application.parameters"; 117 | private static final String BUNDLED_LIBRARIES_KEY = "bundled.libraries"; 118 | private static final String BUNDLED_IN_LIB_RESOURCE_ID_KEY = "android.app.bundled_in_lib_resource_id"; 119 | private static final String BUNDLED_IN_ASSETS_RESOURCE_ID_KEY = "android.app.bundled_in_assets_resource_id"; 120 | private static final String MAIN_LIBRARY_KEY = "main.library"; 121 | private static final String STATIC_INIT_CLASSES_KEY = "static.init.classes"; 122 | private static final String NECESSITAS_API_LEVEL_KEY = "necessitas.api.level"; 123 | 124 | /// Ministro server parameter keys 125 | private static final String REQUIRED_MODULES_KEY = "required.modules"; 126 | private static final String APPLICATION_TITLE_KEY = "application.title"; 127 | private static final String MINIMUM_MINISTRO_API_KEY = "minimum.ministro.api"; 128 | private static final String MINIMUM_QT_VERSION_KEY = "minimum.qt.version"; 129 | private static final String SOURCES_KEY = "sources"; // needs MINISTRO_API_LEVEL >=3 !!! 130 | // Use this key to specify any 3rd party sources urls 131 | // Ministro will download these repositories into their 132 | // own folders, check http://community.kde.org/Necessitas/Ministro 133 | // for more details. 134 | 135 | private static final String REPOSITORY_KEY = "repository"; // use this key to overwrite the default ministro repsitory 136 | private static final String ANDROID_THEMES_KEY = "android.themes"; // themes that your application uses 137 | 138 | 139 | public String APPLICATION_PARAMETERS = null; // use this variable to pass any parameters to your application, 140 | // the parameters must not contain any white spaces 141 | // and must be separated with "\t" 142 | // e.g "-param1\t-param2=value2\t-param3\tvalue3" 143 | 144 | public String ENVIRONMENT_VARIABLES = "QT_USE_ANDROID_NATIVE_STYLE=1\tQT_USE_ANDROID_NATIVE_DIALOGS=1\t"; 145 | // use this variable to add any environment variables to your application. 146 | // the env vars must be separated with "\t" 147 | // e.g. "ENV_VAR1=1\tENV_VAR2=2\t" 148 | // Currently the following vars are used by the android plugin: 149 | // * QT_USE_ANDROID_NATIVE_STYLE - 1 to use the android widget style if available. 150 | // * QT_USE_ANDROID_NATIVE_DIALOGS -1 to use the android native dialogs. 151 | 152 | public String[] QT_ANDROID_THEMES = null; // A list with all themes that your application want to use. 153 | // The name of the theme must be the same with any theme from 154 | // http://developer.android.com/reference/android/R.style.html 155 | // The most used themes are: 156 | // * "Theme" - (fallback) check http://developer.android.com/reference/android/R.style.html#Theme 157 | // * "Theme_Black" - check http://developer.android.com/reference/android/R.style.html#Theme_Black 158 | // * "Theme_Light" - (default for API <=10) check http://developer.android.com/reference/android/R.style.html#Theme_Light 159 | // * "Theme_Holo" - check http://developer.android.com/reference/android/R.style.html#Theme_Holo 160 | // * "Theme_Holo_Light" - (default for API 11-13) check http://developer.android.com/reference/android/R.style.html#Theme_Holo_Light 161 | // * "Theme_DeviceDefault" - check http://developer.android.com/reference/android/R.style.html#Theme_DeviceDefault 162 | // * "Theme_DeviceDefault_Light" - (default for API 14+) check http://developer.android.com/reference/android/R.style.html#Theme_DeviceDefault_Light 163 | 164 | public String QT_ANDROID_DEFAULT_THEME = null; // sets the default theme. 165 | 166 | private static final int INCOMPATIBLE_MINISTRO_VERSION = 1; // Incompatible Ministro version. Ministro needs to be upgraded. 167 | private static final int BUFFER_SIZE = 1024; 168 | 169 | private ActivityInfo m_activityInfo = null; // activity info object, used to access the libs and the strings 170 | private DexClassLoader m_classLoader = null; // loader object 171 | private String[] m_sources = {"https://download.qt-project.org/ministro/android/qt5/qt-5.2"}; // Make sure you are using ONLY secure locations 172 | private String m_repository = "default"; // Overwrites the default Ministro repository 173 | // Possible values: 174 | // * default - Ministro default repository set with "Ministro configuration tool". 175 | // By default the stable version is used. Only this or stable repositories should 176 | // be used in production. 177 | // * stable - stable repository, only this and default repositories should be used 178 | // in production. 179 | // * testing - testing repository, DO NOT use this repository in production, 180 | // this repository is used to push a new release, and should be used to test your application. 181 | // * unstable - unstable repository, DO NOT use this repository in production, 182 | // this repository is used to push Qt snapshots. 183 | private String[] m_qtLibs = null; // required qt libs 184 | 185 | //-------------WEBVIEW---------------- 186 | protected ArrayList webViewsList = new ArrayList(); 187 | 188 | //----------------------------------------------------------------------------- 189 | protected WebView findWebViewByTag(int tag) { 190 | WebView webViewRes = null; 191 | for (int i = 0; i < webViewsList.size(); i++) { 192 | WebView wv = (WebView) webViewsList.get(i); 193 | if (((Integer)wv.getTag()).intValue() == tag) { 194 | webViewRes = wv; 195 | break; 196 | } 197 | } 198 | 199 | return webViewRes; 200 | } 201 | 202 | //----------------------------------------------------------------------------- 203 | @Override 204 | public void createNewWebView(int tag) { 205 | Message msg = new Message(); 206 | msg.what = tag; 207 | 208 | createNewWebViewHandler.sendMessage(msg); 209 | } 210 | 211 | protected Handler createNewWebViewHandler = new Handler() { 212 | @SuppressLint("SetJavaScriptEnabled") 213 | @Override 214 | public void handleMessage(Message msg) { 215 | WebView webView = new WebView(QtActivity.this); 216 | webView.setTag(msg.what); 217 | webView.getSettings().setJavaScriptEnabled(true); 218 | webView.setWebViewClient(new WebViewClient()); 219 | webView.setBackgroundColor(Color.BLACK); 220 | webViewsList.add(webView); 221 | } 222 | }; 223 | 224 | //----------------------------------------------------------------------------- 225 | @Override 226 | public void removeWebView(int tag) { 227 | Message msg = new Message(); 228 | msg.what = tag; 229 | 230 | removeWebViewHandler.sendMessage(msg); 231 | } 232 | 233 | protected Handler removeWebViewHandler = new Handler() { 234 | @Override 235 | public void handleMessage(Message msg) { 236 | WebView webView = findWebViewByTag(msg.what); 237 | if (webView != null) { 238 | webViewsList.remove(webView); 239 | FrameLayout mainLayout = (FrameLayout) findViewById(R.id.content); 240 | mainLayout.removeView(webView); 241 | } 242 | } 243 | }; 244 | 245 | //----------------------------------------------------------------------------- 246 | @Override 247 | public void moveWebView(int tag, int x, int y) { 248 | Message msg = new Message(); 249 | msg.what = tag; 250 | msg.arg1 = x; 251 | msg.arg2 = y; 252 | 253 | moveWebViewHandler.sendMessage(msg); 254 | } 255 | 256 | protected Handler moveWebViewHandler = new Handler() { 257 | @Override 258 | public void handleMessage(Message msg) { 259 | View viewToMove = null; 260 | viewToMove = findWebViewByTag(msg.what); 261 | 262 | if (viewToMove != null) { 263 | FrameLayout.LayoutParams params = (android.widget.FrameLayout.LayoutParams) viewToMove 264 | .getLayoutParams(); 265 | params.leftMargin = msg.arg1; 266 | params.topMargin = msg.arg2; 267 | viewToMove.setLayoutParams(params); 268 | } 269 | } 270 | }; 271 | 272 | //----------------------------------------------------------------------------- 273 | @Override 274 | public void resizeWebView(int tag, int w, int h) { 275 | Message msg = new Message(); 276 | msg.what = tag; 277 | msg.arg1 = w; 278 | msg.arg2 = h; 279 | 280 | resizeWebViewHandler.sendMessage(msg); 281 | } 282 | 283 | protected Handler resizeWebViewHandler = new Handler() { 284 | @Override 285 | public void handleMessage(Message msg) { 286 | View viewToResize = null; 287 | viewToResize = findWebViewByTag(msg.what); 288 | 289 | if (viewToResize != null) { 290 | FrameLayout.LayoutParams params = (android.widget.FrameLayout.LayoutParams) viewToResize 291 | .getLayoutParams(); 292 | params.width = msg.arg1; 293 | params.height = msg.arg2; 294 | viewToResize.setLayoutParams(params); 295 | } 296 | } 297 | }; 298 | 299 | //----------------------------------------------------------------------------- 300 | @Override 301 | public void attachWebViewToMainLayout(int tag) { 302 | Message msg = new Message(); 303 | msg.what = tag; 304 | 305 | attachWebViewToMainLayoutHandler.sendMessage(msg); 306 | } 307 | 308 | protected Handler attachWebViewToMainLayoutHandler = new Handler() { 309 | @Override 310 | public void handleMessage(Message msg) { 311 | View viewToAttach = null; 312 | viewToAttach = findWebViewByTag(msg.what); 313 | 314 | if (viewToAttach != null) { 315 | FrameLayout mainLayout = (FrameLayout) findViewById(R.id.content); 316 | FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(100, 100); 317 | params.leftMargin = 0; 318 | params.topMargin = 0; 319 | 320 | mainLayout.addView(viewToAttach, params); 321 | } 322 | } 323 | }; 324 | 325 | //----------------------------------------------------------------------------- 326 | @Override 327 | public void loadUrlAtWebView(int tag, String url) { 328 | Message msg = new Message(); 329 | msg.what = tag; 330 | msg.obj = url; 331 | 332 | loadUrlAtWebViewHandler.sendMessage(msg); 333 | } 334 | 335 | protected Handler loadUrlAtWebViewHandler = new Handler() { 336 | @Override 337 | public void handleMessage(Message msg) { 338 | WebView webView = findWebViewByTag(msg.what); 339 | if (webView != null) { 340 | webView.loadUrl(msg.obj.toString()); 341 | Log.i("url", msg.obj.toString()); 342 | } 343 | } 344 | }; 345 | 346 | //----------------------------------------------------------------------------- 347 | @Override 348 | public void loadHtmlAtWebView(int tag, String html) { 349 | Message msg = new Message(); 350 | msg.what = tag; 351 | msg.obj = html; 352 | 353 | loadHtmlAtWebViewHandler.sendMessage(msg); 354 | } 355 | 356 | protected Handler loadHtmlAtWebViewHandler = new Handler() { 357 | @Override 358 | public void handleMessage(Message msg) { 359 | WebView webView = findWebViewByTag(msg.what); 360 | if (webView != null) { 361 | webView.loadData(msg.obj.toString(), "text/html; charset=UTF-8", "UTF-8"); 362 | } 363 | } 364 | }; 365 | //-------------END-WEBVIEW------------ 366 | 367 | public QtActivity() 368 | { 369 | if (Build.VERSION.SDK_INT <= 10) { 370 | QT_ANDROID_THEMES = new String[] {"Theme_Light"}; 371 | QT_ANDROID_DEFAULT_THEME = "Theme_Light"; 372 | } 373 | else if (Build.VERSION.SDK_INT >= 11 && Build.VERSION.SDK_INT <= 13) { 374 | QT_ANDROID_THEMES = new String[] {"Theme_Holo_Light"}; 375 | QT_ANDROID_DEFAULT_THEME = "Theme_Holo_Light"; 376 | } else { 377 | QT_ANDROID_THEMES = new String[] {"Theme_DeviceDefault_Light"}; 378 | QT_ANDROID_DEFAULT_THEME = "Theme_DeviceDefault_Light"; 379 | } 380 | } 381 | 382 | // this function is used to load and start the loader 383 | private void loadApplication(Bundle loaderParams) 384 | { 385 | try { 386 | final int errorCode = loaderParams.getInt(ERROR_CODE_KEY); 387 | if (errorCode != 0) { 388 | if (errorCode == INCOMPATIBLE_MINISTRO_VERSION) { 389 | downloadUpgradeMinistro(loaderParams.getString(ERROR_MESSAGE_KEY)); 390 | return; 391 | } 392 | 393 | // fatal error, show the error and quit 394 | AlertDialog errorDialog = new AlertDialog.Builder(QtActivity.this).create(); 395 | errorDialog.setMessage(loaderParams.getString(ERROR_MESSAGE_KEY)); 396 | errorDialog.setButton(getResources().getString(android.R.string.ok), new DialogInterface.OnClickListener() { 397 | @Override 398 | public void onClick(DialogInterface dialog, int which) { 399 | finish(); 400 | } 401 | }); 402 | errorDialog.show(); 403 | return; 404 | } 405 | 406 | // add all bundled Qt libs to loader params 407 | ArrayList libs = new ArrayList(); 408 | if ( m_activityInfo.metaData.containsKey("android.app.bundled_libs_resource_id") ) 409 | libs.addAll(Arrays.asList(getResources().getStringArray(m_activityInfo.metaData.getInt("android.app.bundled_libs_resource_id")))); 410 | 411 | String libName = null; 412 | if ( m_activityInfo.metaData.containsKey("android.app.lib_name") ) { 413 | libName = m_activityInfo.metaData.getString("android.app.lib_name"); 414 | loaderParams.putString(MAIN_LIBRARY_KEY, libName); //main library contains main() function 415 | } 416 | 417 | loaderParams.putStringArrayList(BUNDLED_LIBRARIES_KEY, libs); 418 | loaderParams.putInt(NECESSITAS_API_LEVEL_KEY, NECESSITAS_API_LEVEL); 419 | 420 | // load and start QtLoader class 421 | m_classLoader = new DexClassLoader(loaderParams.getString(DEX_PATH_KEY), // .jar/.apk files 422 | getDir("outdex", Context.MODE_PRIVATE).getAbsolutePath(), // directory where optimized DEX files should be written. 423 | loaderParams.containsKey(LIB_PATH_KEY) ? loaderParams.getString(LIB_PATH_KEY) : null, // libs folder (if exists) 424 | getClassLoader()); // parent loader 425 | 426 | @SuppressWarnings("rawtypes") 427 | Class loaderClass = m_classLoader.loadClass(loaderParams.getString(LOADER_CLASS_NAME_KEY)); // load QtLoader class 428 | Object qtLoader = loaderClass.newInstance(); // create an instance 429 | Method perpareAppMethod = qtLoader.getClass().getMethod("loadApplication", 430 | Activity.class, 431 | ClassLoader.class, 432 | Bundle.class); 433 | if (!(Boolean)perpareAppMethod.invoke(qtLoader, this, m_classLoader, loaderParams)) 434 | throw new Exception(""); 435 | 436 | QtApplication.setQtActivityDelegate(qtLoader); 437 | 438 | // now load the application library so it's accessible from this class loader 439 | if (libName != null) 440 | System.loadLibrary(libName); 441 | 442 | Method startAppMethod=qtLoader.getClass().getMethod("startApplication"); 443 | if (!(Boolean)startAppMethod.invoke(qtLoader)) 444 | throw new Exception(""); 445 | 446 | } catch (Exception e) { 447 | e.printStackTrace(); 448 | AlertDialog errorDialog = new AlertDialog.Builder(QtActivity.this).create(); 449 | if (m_activityInfo.metaData.containsKey("android.app.fatal_error_msg")) 450 | errorDialog.setMessage(m_activityInfo.metaData.getString("android.app.fatal_error_msg")); 451 | else 452 | errorDialog.setMessage("Fatal error, your application can't be started."); 453 | 454 | errorDialog.setButton(getResources().getString(android.R.string.ok), new DialogInterface.OnClickListener() { 455 | @Override 456 | public void onClick(DialogInterface dialog, int which) { 457 | finish(); 458 | } 459 | }); 460 | errorDialog.show(); 461 | } 462 | } 463 | 464 | private ServiceConnection m_ministroConnection=new ServiceConnection() { 465 | private IMinistro m_service = null; 466 | @Override 467 | public void onServiceConnected(ComponentName name, IBinder service) 468 | { 469 | m_service = IMinistro.Stub.asInterface(service); 470 | try { 471 | if (m_service != null) { 472 | Bundle parameters = new Bundle(); 473 | parameters.putStringArray(REQUIRED_MODULES_KEY, m_qtLibs); 474 | parameters.putString(APPLICATION_TITLE_KEY, (String)QtActivity.this.getTitle()); 475 | parameters.putInt(MINIMUM_MINISTRO_API_KEY, MINISTRO_API_LEVEL); 476 | parameters.putInt(MINIMUM_QT_VERSION_KEY, QT_VERSION); 477 | parameters.putString(ENVIRONMENT_VARIABLES_KEY, ENVIRONMENT_VARIABLES); 478 | if (APPLICATION_PARAMETERS != null) 479 | parameters.putString(APPLICATION_PARAMETERS_KEY, APPLICATION_PARAMETERS); 480 | parameters.putStringArray(SOURCES_KEY, m_sources); 481 | parameters.putString(REPOSITORY_KEY, m_repository); 482 | if (QT_ANDROID_THEMES != null) 483 | parameters.putStringArray(ANDROID_THEMES_KEY, QT_ANDROID_THEMES); 484 | m_service.requestLoader(m_ministroCallback, parameters); 485 | } 486 | } catch (RemoteException e) { 487 | e.printStackTrace(); 488 | } 489 | } 490 | 491 | private IMinistroCallback m_ministroCallback = new IMinistroCallback.Stub() { 492 | // this function is called back by Ministro. 493 | @Override 494 | public void loaderReady(final Bundle loaderParams) throws RemoteException { 495 | runOnUiThread(new Runnable() { 496 | @Override 497 | public void run() { 498 | unbindService(m_ministroConnection); 499 | loadApplication(loaderParams); 500 | } 501 | }); 502 | } 503 | }; 504 | 505 | @Override 506 | public void onServiceDisconnected(ComponentName name) { 507 | m_service = null; 508 | } 509 | }; 510 | 511 | private void downloadUpgradeMinistro(String msg) 512 | { 513 | AlertDialog.Builder downloadDialog = new AlertDialog.Builder(this); 514 | downloadDialog.setMessage(msg); 515 | downloadDialog.setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() { 516 | @Override 517 | public void onClick(DialogInterface dialogInterface, int i) { 518 | try { 519 | Uri uri = Uri.parse("market://search?q=pname:org.kde.necessitas.ministro"); 520 | Intent intent = new Intent(Intent.ACTION_VIEW, uri); 521 | startActivityForResult(intent, MINISTRO_INSTALL_REQUEST_CODE); 522 | } catch (Exception e) { 523 | e.printStackTrace(); 524 | ministroNotFound(); 525 | } 526 | } 527 | }); 528 | 529 | downloadDialog.setNegativeButton(android.R.string.no, new DialogInterface.OnClickListener() { 530 | @Override 531 | public void onClick(DialogInterface dialogInterface, int i) { 532 | QtActivity.this.finish(); 533 | } 534 | }); 535 | downloadDialog.show(); 536 | } 537 | 538 | private void ministroNotFound() 539 | { 540 | AlertDialog errorDialog = new AlertDialog.Builder(QtActivity.this).create(); 541 | 542 | if (m_activityInfo.metaData.containsKey("android.app.ministro_not_found_msg")) 543 | errorDialog.setMessage(m_activityInfo.metaData.getString("android.app.ministro_not_found_msg")); 544 | else 545 | errorDialog.setMessage("Can't find Ministro service.\nThe application can't start."); 546 | 547 | errorDialog.setButton(getResources().getString(android.R.string.ok), new DialogInterface.OnClickListener() { 548 | @Override 549 | public void onClick(DialogInterface dialog, int which) { 550 | finish(); 551 | } 552 | }); 553 | errorDialog.show(); 554 | } 555 | 556 | static private void copyFile(InputStream inputStream, OutputStream outputStream) 557 | throws IOException 558 | { 559 | byte[] buffer = new byte[BUFFER_SIZE]; 560 | 561 | int count; 562 | while ((count = inputStream.read(buffer)) > 0) 563 | outputStream.write(buffer, 0, count); 564 | } 565 | 566 | 567 | private void copyAsset(String source, String destination) 568 | throws IOException 569 | { 570 | // Already exists, we don't have to do anything 571 | File destinationFile = new File(destination); 572 | if (destinationFile.exists()) 573 | return; 574 | 575 | File parentDirectory = destinationFile.getParentFile(); 576 | if (!parentDirectory.exists()) 577 | parentDirectory.mkdirs(); 578 | 579 | destinationFile.createNewFile(); 580 | 581 | AssetManager assetsManager = getAssets(); 582 | InputStream inputStream = assetsManager.open(source); 583 | OutputStream outputStream = new FileOutputStream(destinationFile); 584 | copyFile(inputStream, outputStream); 585 | 586 | inputStream.close(); 587 | outputStream.close(); 588 | } 589 | 590 | private static void createBundledBinary(String source, String destination) 591 | throws IOException 592 | { 593 | // Already exists, we don't have to do anything 594 | File destinationFile = new File(destination); 595 | if (destinationFile.exists()) 596 | return; 597 | 598 | File parentDirectory = destinationFile.getParentFile(); 599 | if (!parentDirectory.exists()) 600 | parentDirectory.mkdirs(); 601 | 602 | destinationFile.createNewFile(); 603 | 604 | InputStream inputStream = new FileInputStream(source); 605 | OutputStream outputStream = new FileOutputStream(destinationFile); 606 | copyFile(inputStream, outputStream); 607 | 608 | inputStream.close(); 609 | outputStream.close(); 610 | } 611 | 612 | private boolean cleanCacheIfNecessary(String pluginsPrefix, long packageVersion) 613 | { 614 | File versionFile = new File(pluginsPrefix + "cache.version"); 615 | 616 | long cacheVersion = 0; 617 | if (versionFile.exists() && versionFile.canRead()) { 618 | try { 619 | DataInputStream inputStream = new DataInputStream(new FileInputStream(versionFile)); 620 | cacheVersion = inputStream.readLong(); 621 | inputStream.close(); 622 | } catch (Exception e) { 623 | e.printStackTrace(); 624 | } 625 | } 626 | 627 | if (cacheVersion != packageVersion) { 628 | deleteRecursively(new File(pluginsPrefix)); 629 | return true; 630 | } else { 631 | return false; 632 | } 633 | } 634 | 635 | private void extractBundledPluginsAndImports(String pluginsPrefix) 636 | throws IOException 637 | { 638 | ArrayList libs = new ArrayList(); 639 | 640 | String dataDir = getApplicationInfo().dataDir + "/"; 641 | 642 | long packageVersion = -1; 643 | try { 644 | PackageInfo packageInfo = getPackageManager().getPackageInfo(getPackageName(), 0); 645 | packageVersion = packageInfo.lastUpdateTime; 646 | } catch (Exception e) { 647 | e.printStackTrace(); 648 | } 649 | 650 | if (!cleanCacheIfNecessary(pluginsPrefix, packageVersion)) 651 | return; 652 | 653 | { 654 | File versionFile = new File(pluginsPrefix + "cache.version"); 655 | 656 | File parentDirectory = versionFile.getParentFile(); 657 | if (!parentDirectory.exists()) 658 | parentDirectory.mkdirs(); 659 | 660 | versionFile.createNewFile(); 661 | 662 | DataOutputStream outputStream = new DataOutputStream(new FileOutputStream(versionFile)); 663 | outputStream.writeLong(packageVersion); 664 | outputStream.close(); 665 | } 666 | 667 | { 668 | String key = BUNDLED_IN_LIB_RESOURCE_ID_KEY; 669 | java.util.Set keys = m_activityInfo.metaData.keySet(); 670 | if (m_activityInfo.metaData.containsKey(key)) { 671 | String[] list = getResources().getStringArray(m_activityInfo.metaData.getInt(key)); 672 | 673 | for (String bundledImportBinary : list) { 674 | String[] split = bundledImportBinary.split(":"); 675 | String sourceFileName = dataDir + "lib/" + split[0]; 676 | String destinationFileName = pluginsPrefix + split[1]; 677 | createBundledBinary(sourceFileName, destinationFileName); 678 | } 679 | } 680 | } 681 | 682 | { 683 | String key = BUNDLED_IN_ASSETS_RESOURCE_ID_KEY; 684 | if (m_activityInfo.metaData.containsKey(key)) { 685 | String[] list = getResources().getStringArray(m_activityInfo.metaData.getInt(key)); 686 | 687 | for (String fileName : list) { 688 | String[] split = fileName.split(":"); 689 | String sourceFileName = split[0]; 690 | String destinationFileName = pluginsPrefix + split[1]; 691 | copyAsset(sourceFileName, destinationFileName); 692 | } 693 | } 694 | 695 | } 696 | } 697 | 698 | private void deleteRecursively(File directory) 699 | { 700 | File[] files = directory.listFiles(); 701 | if (files != null) { 702 | for (File file : files) { 703 | if (file.isDirectory()) 704 | deleteRecursively(file); 705 | else 706 | file.delete(); 707 | } 708 | 709 | directory.delete(); 710 | } 711 | } 712 | 713 | private void cleanOldCacheIfNecessary(String oldLocalPrefix, String localPrefix) 714 | { 715 | File newCache = new File(localPrefix); 716 | if (!newCache.exists()) { 717 | { 718 | File oldPluginsCache = new File(oldLocalPrefix + "plugins/"); 719 | if (oldPluginsCache.exists() && oldPluginsCache.isDirectory()) 720 | deleteRecursively(oldPluginsCache); 721 | } 722 | 723 | { 724 | File oldImportsCache = new File(oldLocalPrefix + "imports/"); 725 | if (oldImportsCache.exists() && oldImportsCache.isDirectory()) 726 | deleteRecursively(oldImportsCache); 727 | } 728 | 729 | { 730 | File oldQmlCache = new File(oldLocalPrefix + "qml/"); 731 | if (oldQmlCache.exists() && oldQmlCache.isDirectory()) 732 | deleteRecursively(oldQmlCache); 733 | } 734 | } 735 | } 736 | 737 | private void startApp(final boolean firstStart) 738 | { 739 | try { 740 | if (m_activityInfo.metaData.containsKey("android.app.qt_sources_resource_id")) { 741 | int resourceId = m_activityInfo.metaData.getInt("android.app.qt_sources_resource_id"); 742 | m_sources = getResources().getStringArray(resourceId); 743 | } 744 | 745 | if (m_activityInfo.metaData.containsKey("android.app.repository")) 746 | m_repository = m_activityInfo.metaData.getString("android.app.repository"); 747 | 748 | if (m_activityInfo.metaData.containsKey("android.app.qt_libs_resource_id")) { 749 | int resourceId = m_activityInfo.metaData.getInt("android.app.qt_libs_resource_id"); 750 | m_qtLibs = getResources().getStringArray(resourceId); 751 | } 752 | 753 | if (m_activityInfo.metaData.containsKey("android.app.use_local_qt_libs") 754 | && m_activityInfo.metaData.getInt("android.app.use_local_qt_libs") == 1) { 755 | ArrayList libraryList = new ArrayList(); 756 | 757 | 758 | String localPrefix = "/data/local/tmp/qt/"; 759 | if (m_activityInfo.metaData.containsKey("android.app.libs_prefix")) 760 | localPrefix = m_activityInfo.metaData.getString("android.app.libs_prefix"); 761 | 762 | String pluginsPrefix = localPrefix; 763 | 764 | boolean bundlingQtLibs = false; 765 | if (m_activityInfo.metaData.containsKey("android.app.bundle_local_qt_libs") 766 | && m_activityInfo.metaData.getInt("android.app.bundle_local_qt_libs") == 1) { 767 | localPrefix = getApplicationInfo().dataDir + "/"; 768 | pluginsPrefix = localPrefix + "qt-reserved-files/"; 769 | cleanOldCacheIfNecessary(localPrefix, pluginsPrefix); 770 | extractBundledPluginsAndImports(pluginsPrefix); 771 | bundlingQtLibs = true; 772 | } 773 | 774 | if (m_qtLibs != null) { 775 | for (int i=0;i 0) { 787 | if (lib.startsWith("lib/")) 788 | libraryList.add(localPrefix + lib); 789 | else 790 | libraryList.add(pluginsPrefix + lib); 791 | } 792 | } 793 | } 794 | 795 | 796 | String dexPaths = new String(); 797 | String pathSeparator = System.getProperty("path.separator", ":"); 798 | if (!bundlingQtLibs && m_activityInfo.metaData.containsKey("android.app.load_local_jars")) { 799 | String[] jarFiles = m_activityInfo.metaData.getString("android.app.load_local_jars").split(":"); 800 | for (String jar:jarFiles) { 801 | if (jar.length() > 0) { 802 | if (dexPaths.length() > 0) 803 | dexPaths += pathSeparator; 804 | dexPaths += localPrefix + jar; 805 | } 806 | } 807 | } 808 | 809 | Bundle loaderParams = new Bundle(); 810 | loaderParams.putInt(ERROR_CODE_KEY, 0); 811 | loaderParams.putString(DEX_PATH_KEY, dexPaths); 812 | loaderParams.putString(LOADER_CLASS_NAME_KEY, "org.qtproject.qt5.android.QtActivityDelegate"); 813 | if (m_activityInfo.metaData.containsKey("android.app.static_init_classes")) { 814 | loaderParams.putStringArray(STATIC_INIT_CLASSES_KEY, 815 | m_activityInfo.metaData.getString("android.app.static_init_classes").split(":")); 816 | } 817 | loaderParams.putStringArrayList(NATIVE_LIBRARIES_KEY, libraryList); 818 | loaderParams.putString(ENVIRONMENT_VARIABLES_KEY, ENVIRONMENT_VARIABLES 819 | + "\tQML2_IMPORT_PATH=" + pluginsPrefix + "/qml" 820 | + "\tQML_IMPORT_PATH=" + pluginsPrefix + "/imports" 821 | + "\tQT_PLUGIN_PATH=" + pluginsPrefix + "/plugins"); 822 | 823 | if (APPLICATION_PARAMETERS != null) { 824 | loaderParams.putString(APPLICATION_PARAMETERS_KEY, APPLICATION_PARAMETERS); 825 | } else { 826 | Intent intent = getIntent(); 827 | if (intent != null) { 828 | String parameters = intent.getStringExtra("applicationArguments"); 829 | if (parameters != null) 830 | loaderParams.putString(APPLICATION_PARAMETERS_KEY, parameters.replace(' ', '\t')); 831 | } 832 | } 833 | 834 | loadApplication(loaderParams); 835 | return; 836 | } 837 | 838 | try { 839 | if (!bindService(new Intent(org.kde.necessitas.ministro.IMinistro.class.getCanonicalName()), 840 | m_ministroConnection, 841 | Context.BIND_AUTO_CREATE)) { 842 | throw new SecurityException(""); 843 | } 844 | } catch (Exception e) { 845 | if (firstStart) { 846 | String msg = "This application requires Ministro service. Would you like to install it?"; 847 | if (m_activityInfo.metaData.containsKey("android.app.ministro_needed_msg")) 848 | msg = m_activityInfo.metaData.getString("android.app.ministro_needed_msg"); 849 | downloadUpgradeMinistro(msg); 850 | } else { 851 | ministroNotFound(); 852 | } 853 | } 854 | } catch (Exception e) { 855 | Log.e(QtApplication.QtTAG, "Can't create main activity", e); 856 | } 857 | } 858 | 859 | 860 | 861 | /////////////////////////// forward all notifications //////////////////////////// 862 | /////////////////////////// Super class calls //////////////////////////////////// 863 | /////////////// PLEASE DO NOT CHANGE THE FOLLOWING CODE ////////////////////////// 864 | ////////////////////////////////////////////////////////////////////////////////// 865 | 866 | @Override 867 | public boolean dispatchKeyEvent(KeyEvent event) 868 | { 869 | if (QtApplication.m_delegateObject != null && QtApplication.dispatchKeyEvent != null) 870 | return (Boolean) QtApplication.invokeDelegateMethod(QtApplication.dispatchKeyEvent, event); 871 | else 872 | return super.dispatchKeyEvent(event); 873 | } 874 | public boolean super_dispatchKeyEvent(KeyEvent event) 875 | { 876 | return super.dispatchKeyEvent(event); 877 | } 878 | //--------------------------------------------------------------------------- 879 | 880 | @Override 881 | public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) 882 | { 883 | if (QtApplication.m_delegateObject != null && QtApplication.dispatchPopulateAccessibilityEvent != null) 884 | return (Boolean) QtApplication.invokeDelegateMethod(QtApplication.dispatchPopulateAccessibilityEvent, event); 885 | else 886 | return super.dispatchPopulateAccessibilityEvent(event); 887 | } 888 | public boolean super_dispatchPopulateAccessibilityEvent(AccessibilityEvent event) 889 | { 890 | return super_dispatchPopulateAccessibilityEvent(event); 891 | } 892 | //--------------------------------------------------------------------------- 893 | 894 | @Override 895 | public boolean dispatchTouchEvent(MotionEvent ev) 896 | { 897 | if (QtApplication.m_delegateObject != null && QtApplication.dispatchTouchEvent != null) 898 | return (Boolean) QtApplication.invokeDelegateMethod(QtApplication.dispatchTouchEvent, ev); 899 | else 900 | return super.dispatchTouchEvent(ev); 901 | } 902 | public boolean super_dispatchTouchEvent(MotionEvent event) 903 | { 904 | return super.dispatchTouchEvent(event); 905 | } 906 | //--------------------------------------------------------------------------- 907 | 908 | @Override 909 | public boolean dispatchTrackballEvent(MotionEvent ev) 910 | { 911 | if (QtApplication.m_delegateObject != null && QtApplication.dispatchTrackballEvent != null) 912 | return (Boolean) QtApplication.invokeDelegateMethod(QtApplication.dispatchTrackballEvent, ev); 913 | else 914 | return super.dispatchTrackballEvent(ev); 915 | } 916 | public boolean super_dispatchTrackballEvent(MotionEvent event) 917 | { 918 | return super.dispatchTrackballEvent(event); 919 | } 920 | //--------------------------------------------------------------------------- 921 | 922 | @Override 923 | protected void onActivityResult(int requestCode, int resultCode, Intent data) 924 | { 925 | 926 | if (QtApplication.m_delegateObject != null && QtApplication.onActivityResult != null) { 927 | QtApplication.invokeDelegateMethod(QtApplication.onActivityResult, requestCode, resultCode, data); 928 | return; 929 | } 930 | if (requestCode == MINISTRO_INSTALL_REQUEST_CODE) 931 | startApp(false); 932 | super.onActivityResult(requestCode, resultCode, data); 933 | } 934 | public void super_onActivityResult(int requestCode, int resultCode, Intent data) 935 | { 936 | super.onActivityResult(requestCode, resultCode, data); 937 | } 938 | //--------------------------------------------------------------------------- 939 | 940 | @Override 941 | protected void onApplyThemeResource(Theme theme, int resid, boolean first) 942 | { 943 | if (!QtApplication.invokeDelegate(theme, resid, first).invoked) 944 | super.onApplyThemeResource(theme, resid, first); 945 | } 946 | public void super_onApplyThemeResource(Theme theme, int resid, boolean first) 947 | { 948 | super.onApplyThemeResource(theme, resid, first); 949 | } 950 | //--------------------------------------------------------------------------- 951 | 952 | 953 | @Override 954 | protected void onChildTitleChanged(Activity childActivity, CharSequence title) 955 | { 956 | if (!QtApplication.invokeDelegate(childActivity, title).invoked) 957 | super.onChildTitleChanged(childActivity, title); 958 | } 959 | public void super_onChildTitleChanged(Activity childActivity, CharSequence title) 960 | { 961 | super.onChildTitleChanged(childActivity, title); 962 | } 963 | //--------------------------------------------------------------------------- 964 | 965 | @Override 966 | public void onConfigurationChanged(Configuration newConfig) 967 | { 968 | if (!QtApplication.invokeDelegate(newConfig).invoked) 969 | super.onConfigurationChanged(newConfig); 970 | } 971 | public void super_onConfigurationChanged(Configuration newConfig) 972 | { 973 | super.onConfigurationChanged(newConfig); 974 | } 975 | //--------------------------------------------------------------------------- 976 | 977 | @Override 978 | public void onContentChanged() 979 | { 980 | if (!QtApplication.invokeDelegate().invoked) 981 | super.onContentChanged(); 982 | } 983 | public void super_onContentChanged() 984 | { 985 | super.onContentChanged(); 986 | } 987 | //--------------------------------------------------------------------------- 988 | 989 | @Override 990 | public boolean onContextItemSelected(MenuItem item) 991 | { 992 | QtApplication.InvokeResult res = QtApplication.invokeDelegate(item); 993 | if (res.invoked) 994 | return (Boolean)res.methodReturns; 995 | else 996 | return super.onContextItemSelected(item); 997 | } 998 | public boolean super_onContextItemSelected(MenuItem item) 999 | { 1000 | return super.onContextItemSelected(item); 1001 | } 1002 | //--------------------------------------------------------------------------- 1003 | 1004 | @Override 1005 | public void onContextMenuClosed(Menu menu) 1006 | { 1007 | if (!QtApplication.invokeDelegate(menu).invoked) 1008 | super.onContextMenuClosed(menu); 1009 | } 1010 | public void super_onContextMenuClosed(Menu menu) 1011 | { 1012 | super.onContextMenuClosed(menu); 1013 | } 1014 | //--------------------------------------------------------------------------- 1015 | 1016 | @Override 1017 | public void onCreate(Bundle savedInstanceState) 1018 | { 1019 | super.onCreate(savedInstanceState); 1020 | 1021 | try { 1022 | m_activityInfo = getPackageManager().getActivityInfo(getComponentName(), PackageManager.GET_META_DATA); 1023 | for (Field f : Class.forName("android.R$style").getDeclaredFields()) { 1024 | if (f.getInt(null) == m_activityInfo.getThemeResource()) { 1025 | QT_ANDROID_THEMES = new String[] {f.getName()}; 1026 | QT_ANDROID_DEFAULT_THEME = f.getName(); 1027 | } 1028 | } 1029 | } catch (Exception e) { 1030 | e.printStackTrace(); 1031 | finish(); 1032 | return; 1033 | } 1034 | 1035 | try { 1036 | setTheme(Class.forName("android.R$style").getDeclaredField(QT_ANDROID_DEFAULT_THEME).getInt(null)); 1037 | } catch (Exception e) { 1038 | e.printStackTrace(); 1039 | } 1040 | 1041 | if (Build.VERSION.SDK_INT > 10) { 1042 | try { 1043 | requestWindowFeature(Window.class.getField("FEATURE_ACTION_BAR").getInt(null)); 1044 | } catch (Exception e) { 1045 | e.printStackTrace(); 1046 | } 1047 | } else { 1048 | requestWindowFeature(Window.FEATURE_NO_TITLE); 1049 | } 1050 | 1051 | if (QtApplication.m_delegateObject != null && QtApplication.onCreate != null) { 1052 | QtApplication.invokeDelegateMethod(QtApplication.onCreate, savedInstanceState); 1053 | return; 1054 | } 1055 | 1056 | ENVIRONMENT_VARIABLES += "\tQT_ANDROID_THEME=" + QT_ANDROID_DEFAULT_THEME 1057 | + "/\tQT_ANDROID_THEME_DISPLAY_DPI=" + getResources().getDisplayMetrics().densityDpi + "\t"; 1058 | 1059 | if (null == getLastNonConfigurationInstance()) { 1060 | // if splash screen is defined, then show it 1061 | if (m_activityInfo.metaData.containsKey("android.app.splash_screen_drawable")) 1062 | getWindow().setBackgroundDrawableResource(m_activityInfo.metaData.getInt("android.app.splash_screen_drawable")); 1063 | startApp(true); 1064 | } 1065 | } 1066 | //--------------------------------------------------------------------------- 1067 | 1068 | @Override 1069 | public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) 1070 | { 1071 | if (!QtApplication.invokeDelegate(menu, v, menuInfo).invoked) 1072 | super.onCreateContextMenu(menu, v, menuInfo); 1073 | } 1074 | public void super_onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) 1075 | { 1076 | super.onCreateContextMenu(menu, v, menuInfo); 1077 | } 1078 | //--------------------------------------------------------------------------- 1079 | 1080 | @Override 1081 | public CharSequence onCreateDescription() 1082 | { 1083 | QtApplication.InvokeResult res = QtApplication.invokeDelegate(); 1084 | if (res.invoked) 1085 | return (CharSequence)res.methodReturns; 1086 | else 1087 | return super.onCreateDescription(); 1088 | } 1089 | public CharSequence super_onCreateDescription() 1090 | { 1091 | return super.onCreateDescription(); 1092 | } 1093 | //--------------------------------------------------------------------------- 1094 | 1095 | @Override 1096 | protected Dialog onCreateDialog(int id) 1097 | { 1098 | QtApplication.InvokeResult res = QtApplication.invokeDelegate(id); 1099 | if (res.invoked) 1100 | return (Dialog)res.methodReturns; 1101 | else 1102 | return super.onCreateDialog(id); 1103 | } 1104 | public Dialog super_onCreateDialog(int id) 1105 | { 1106 | return super.onCreateDialog(id); 1107 | } 1108 | //--------------------------------------------------------------------------- 1109 | 1110 | @Override 1111 | public boolean onCreateOptionsMenu(Menu menu) 1112 | { 1113 | QtApplication.InvokeResult res = QtApplication.invokeDelegate(menu); 1114 | if (res.invoked) 1115 | return (Boolean)res.methodReturns; 1116 | else 1117 | return super.onCreateOptionsMenu(menu); 1118 | } 1119 | public boolean super_onCreateOptionsMenu(Menu menu) 1120 | { 1121 | return super.onCreateOptionsMenu(menu); 1122 | } 1123 | //--------------------------------------------------------------------------- 1124 | 1125 | @Override 1126 | public boolean onCreatePanelMenu(int featureId, Menu menu) 1127 | { 1128 | QtApplication.InvokeResult res = QtApplication.invokeDelegate(featureId, menu); 1129 | if (res.invoked) 1130 | return (Boolean)res.methodReturns; 1131 | else 1132 | return super.onCreatePanelMenu(featureId, menu); 1133 | } 1134 | public boolean super_onCreatePanelMenu(int featureId, Menu menu) 1135 | { 1136 | return super.onCreatePanelMenu(featureId, menu); 1137 | } 1138 | //--------------------------------------------------------------------------- 1139 | 1140 | 1141 | @Override 1142 | public View onCreatePanelView(int featureId) 1143 | { 1144 | QtApplication.InvokeResult res = QtApplication.invokeDelegate(featureId); 1145 | if (res.invoked) 1146 | return (View)res.methodReturns; 1147 | else 1148 | return super.onCreatePanelView(featureId); 1149 | } 1150 | public View super_onCreatePanelView(int featureId) 1151 | { 1152 | return super.onCreatePanelView(featureId); 1153 | } 1154 | //--------------------------------------------------------------------------- 1155 | 1156 | @Override 1157 | public boolean onCreateThumbnail(Bitmap outBitmap, Canvas canvas) 1158 | { 1159 | QtApplication.InvokeResult res = QtApplication.invokeDelegate(outBitmap, canvas); 1160 | if (res.invoked) 1161 | return (Boolean)res.methodReturns; 1162 | else 1163 | return super.onCreateThumbnail(outBitmap, canvas); 1164 | } 1165 | public boolean super_onCreateThumbnail(Bitmap outBitmap, Canvas canvas) 1166 | { 1167 | return super.onCreateThumbnail(outBitmap, canvas); 1168 | } 1169 | //--------------------------------------------------------------------------- 1170 | 1171 | @Override 1172 | public View onCreateView(String name, Context context, AttributeSet attrs) 1173 | { 1174 | QtApplication.InvokeResult res = QtApplication.invokeDelegate(name, context, attrs); 1175 | if (res.invoked) 1176 | return (View)res.methodReturns; 1177 | else 1178 | return super.onCreateView(name, context, attrs); 1179 | } 1180 | public View super_onCreateView(String name, Context context, AttributeSet attrs) 1181 | { 1182 | return super.onCreateView(name, context, attrs); 1183 | } 1184 | //--------------------------------------------------------------------------- 1185 | 1186 | @Override 1187 | protected void onDestroy() 1188 | { 1189 | super.onDestroy(); 1190 | QtApplication.invokeDelegate(); 1191 | } 1192 | //--------------------------------------------------------------------------- 1193 | 1194 | 1195 | @Override 1196 | public boolean onKeyDown(int keyCode, KeyEvent event) 1197 | { 1198 | if (QtApplication.m_delegateObject != null && QtApplication.onKeyDown != null) 1199 | return (Boolean) QtApplication.invokeDelegateMethod(QtApplication.onKeyDown, keyCode, event); 1200 | else 1201 | return super.onKeyDown(keyCode, event); 1202 | } 1203 | public boolean super_onKeyDown(int keyCode, KeyEvent event) 1204 | { 1205 | return super.onKeyDown(keyCode, event); 1206 | } 1207 | //--------------------------------------------------------------------------- 1208 | 1209 | 1210 | @Override 1211 | public boolean onKeyMultiple(int keyCode, int repeatCount, KeyEvent event) 1212 | { 1213 | if (QtApplication.m_delegateObject != null && QtApplication.onKeyMultiple != null) 1214 | return (Boolean) QtApplication.invokeDelegateMethod(QtApplication.onKeyMultiple, keyCode, repeatCount, event); 1215 | else 1216 | return super.onKeyMultiple(keyCode, repeatCount, event); 1217 | } 1218 | public boolean super_onKeyMultiple(int keyCode, int repeatCount, KeyEvent event) 1219 | { 1220 | return super.onKeyMultiple(keyCode, repeatCount, event); 1221 | } 1222 | //--------------------------------------------------------------------------- 1223 | 1224 | @Override 1225 | public boolean onKeyUp(int keyCode, KeyEvent event) 1226 | { 1227 | if (QtApplication.m_delegateObject != null && QtApplication.onKeyDown != null) 1228 | return (Boolean) QtApplication.invokeDelegateMethod(QtApplication.onKeyUp, keyCode, event); 1229 | else 1230 | return super.onKeyUp(keyCode, event); 1231 | } 1232 | public boolean super_onKeyUp(int keyCode, KeyEvent event) 1233 | { 1234 | return super.onKeyUp(keyCode, event); 1235 | } 1236 | //--------------------------------------------------------------------------- 1237 | 1238 | @Override 1239 | public void onLowMemory() 1240 | { 1241 | if (!QtApplication.invokeDelegate().invoked) 1242 | super.onLowMemory(); 1243 | } 1244 | //--------------------------------------------------------------------------- 1245 | 1246 | @Override 1247 | public boolean onMenuItemSelected(int featureId, MenuItem item) 1248 | { 1249 | QtApplication.InvokeResult res = QtApplication.invokeDelegate(featureId, item); 1250 | if (res.invoked) 1251 | return (Boolean)res.methodReturns; 1252 | else 1253 | return super.onMenuItemSelected(featureId, item); 1254 | } 1255 | public boolean super_onMenuItemSelected(int featureId, MenuItem item) 1256 | { 1257 | return super.onMenuItemSelected(featureId, item); 1258 | } 1259 | //--------------------------------------------------------------------------- 1260 | 1261 | @Override 1262 | public boolean onMenuOpened(int featureId, Menu menu) 1263 | { 1264 | QtApplication.InvokeResult res = QtApplication.invokeDelegate(featureId, menu); 1265 | if (res.invoked) 1266 | return (Boolean)res.methodReturns; 1267 | else 1268 | return super.onMenuOpened(featureId, menu); 1269 | } 1270 | public boolean super_onMenuOpened(int featureId, Menu menu) 1271 | { 1272 | return super.onMenuOpened(featureId, menu); 1273 | } 1274 | //--------------------------------------------------------------------------- 1275 | 1276 | @Override 1277 | protected void onNewIntent(Intent intent) 1278 | { 1279 | if (!QtApplication.invokeDelegate(intent).invoked) 1280 | super.onNewIntent(intent); 1281 | } 1282 | public void super_onNewIntent(Intent intent) 1283 | { 1284 | super.onNewIntent(intent); 1285 | } 1286 | //--------------------------------------------------------------------------- 1287 | 1288 | @Override 1289 | public boolean onOptionsItemSelected(MenuItem item) 1290 | { 1291 | QtApplication.InvokeResult res = QtApplication.invokeDelegate(item); 1292 | if (res.invoked) 1293 | return (Boolean)res.methodReturns; 1294 | else 1295 | return super.onOptionsItemSelected(item); 1296 | } 1297 | public boolean super_onOptionsItemSelected(MenuItem item) 1298 | { 1299 | return super.onOptionsItemSelected(item); 1300 | } 1301 | //--------------------------------------------------------------------------- 1302 | 1303 | @Override 1304 | public void onOptionsMenuClosed(Menu menu) 1305 | { 1306 | if (!QtApplication.invokeDelegate(menu).invoked) 1307 | super.onOptionsMenuClosed(menu); 1308 | } 1309 | public void super_onOptionsMenuClosed(Menu menu) 1310 | { 1311 | super.onOptionsMenuClosed(menu); 1312 | } 1313 | //--------------------------------------------------------------------------- 1314 | 1315 | @Override 1316 | public void onPanelClosed(int featureId, Menu menu) 1317 | { 1318 | if (!QtApplication.invokeDelegate(featureId, menu).invoked) 1319 | super.onPanelClosed(featureId, menu); 1320 | } 1321 | public void super_onPanelClosed(int featureId, Menu menu) 1322 | { 1323 | super.onPanelClosed(featureId, menu); 1324 | } 1325 | //--------------------------------------------------------------------------- 1326 | 1327 | @Override 1328 | protected void onPause() 1329 | { 1330 | super.onPause(); 1331 | QtApplication.invokeDelegate(); 1332 | } 1333 | //--------------------------------------------------------------------------- 1334 | 1335 | @Override 1336 | protected void onPostCreate(Bundle savedInstanceState) 1337 | { 1338 | super.onPostCreate(savedInstanceState); 1339 | QtApplication.invokeDelegate(savedInstanceState); 1340 | } 1341 | //--------------------------------------------------------------------------- 1342 | 1343 | @Override 1344 | protected void onPostResume() 1345 | { 1346 | super.onPostResume(); 1347 | QtApplication.invokeDelegate(); 1348 | } 1349 | //--------------------------------------------------------------------------- 1350 | 1351 | @Override 1352 | protected void onPrepareDialog(int id, Dialog dialog) 1353 | { 1354 | if (!QtApplication.invokeDelegate(id, dialog).invoked) 1355 | super.onPrepareDialog(id, dialog); 1356 | } 1357 | public void super_onPrepareDialog(int id, Dialog dialog) 1358 | { 1359 | super.onPrepareDialog(id, dialog); 1360 | } 1361 | //--------------------------------------------------------------------------- 1362 | 1363 | @Override 1364 | public boolean onPrepareOptionsMenu(Menu menu) 1365 | { 1366 | QtApplication.InvokeResult res = QtApplication.invokeDelegate(menu); 1367 | if (res.invoked) 1368 | return (Boolean)res.methodReturns; 1369 | else 1370 | return super.onPrepareOptionsMenu(menu); 1371 | } 1372 | public boolean super_onPrepareOptionsMenu(Menu menu) 1373 | { 1374 | return super.onPrepareOptionsMenu(menu); 1375 | } 1376 | //--------------------------------------------------------------------------- 1377 | 1378 | @Override 1379 | public boolean onPreparePanel(int featureId, View view, Menu menu) 1380 | { 1381 | QtApplication.InvokeResult res = QtApplication.invokeDelegate(featureId, view, menu); 1382 | if (res.invoked) 1383 | return (Boolean)res.methodReturns; 1384 | else 1385 | return super.onPreparePanel(featureId, view, menu); 1386 | } 1387 | public boolean super_onPreparePanel(int featureId, View view, Menu menu) 1388 | { 1389 | return super.onPreparePanel(featureId, view, menu); 1390 | } 1391 | //--------------------------------------------------------------------------- 1392 | 1393 | @Override 1394 | protected void onRestart() 1395 | { 1396 | super.onRestart(); 1397 | QtApplication.invokeDelegate(); 1398 | } 1399 | //--------------------------------------------------------------------------- 1400 | 1401 | @Override 1402 | protected void onRestoreInstanceState(Bundle savedInstanceState) 1403 | { 1404 | if (!QtApplication.invokeDelegate(savedInstanceState).invoked) 1405 | super.onRestoreInstanceState(savedInstanceState); 1406 | } 1407 | public void super_onRestoreInstanceState(Bundle savedInstanceState) 1408 | { 1409 | super.onRestoreInstanceState(savedInstanceState); 1410 | } 1411 | //--------------------------------------------------------------------------- 1412 | 1413 | @Override 1414 | protected void onResume() 1415 | { 1416 | super.onResume(); 1417 | QtApplication.invokeDelegate(); 1418 | } 1419 | //--------------------------------------------------------------------------- 1420 | 1421 | @Override 1422 | public Object onRetainNonConfigurationInstance() 1423 | { 1424 | QtApplication.InvokeResult res = QtApplication.invokeDelegate(); 1425 | if (res.invoked) 1426 | return res.methodReturns; 1427 | else 1428 | return super.onRetainNonConfigurationInstance(); 1429 | } 1430 | public Object super_onRetainNonConfigurationInstance() 1431 | { 1432 | return super.onRetainNonConfigurationInstance(); 1433 | } 1434 | //--------------------------------------------------------------------------- 1435 | 1436 | @Override 1437 | protected void onSaveInstanceState(Bundle outState) 1438 | { 1439 | if (!QtApplication.invokeDelegate(outState).invoked) 1440 | super.onSaveInstanceState(outState); 1441 | } 1442 | public void super_onSaveInstanceState(Bundle outState) 1443 | { 1444 | super.onSaveInstanceState(outState); 1445 | 1446 | } 1447 | //--------------------------------------------------------------------------- 1448 | 1449 | @Override 1450 | public boolean onSearchRequested() 1451 | { 1452 | QtApplication.InvokeResult res = QtApplication.invokeDelegate(); 1453 | if (res.invoked) 1454 | return (Boolean)res.methodReturns; 1455 | else 1456 | return super.onSearchRequested(); 1457 | } 1458 | public boolean super_onSearchRequested() 1459 | { 1460 | return super.onSearchRequested(); 1461 | } 1462 | //--------------------------------------------------------------------------- 1463 | 1464 | @Override 1465 | protected void onStart() 1466 | { 1467 | super.onStart(); 1468 | QtApplication.invokeDelegate(); 1469 | } 1470 | //--------------------------------------------------------------------------- 1471 | 1472 | @Override 1473 | protected void onStop() 1474 | { 1475 | super.onStop(); 1476 | QtApplication.invokeDelegate(); 1477 | } 1478 | //--------------------------------------------------------------------------- 1479 | 1480 | @Override 1481 | protected void onTitleChanged(CharSequence title, int color) 1482 | { 1483 | if (!QtApplication.invokeDelegate(title, color).invoked) 1484 | super.onTitleChanged(title, color); 1485 | } 1486 | public void super_onTitleChanged(CharSequence title, int color) 1487 | { 1488 | super.onTitleChanged(title, color); 1489 | } 1490 | //--------------------------------------------------------------------------- 1491 | 1492 | @Override 1493 | public boolean onTouchEvent(MotionEvent event) 1494 | { 1495 | if (QtApplication.m_delegateObject != null && QtApplication.onTouchEvent != null) 1496 | return (Boolean) QtApplication.invokeDelegateMethod(QtApplication.onTouchEvent, event); 1497 | else 1498 | return super.onTouchEvent(event); 1499 | } 1500 | public boolean super_onTouchEvent(MotionEvent event) 1501 | { 1502 | return super.onTouchEvent(event); 1503 | } 1504 | //--------------------------------------------------------------------------- 1505 | 1506 | @Override 1507 | public boolean onTrackballEvent(MotionEvent event) 1508 | { 1509 | if (QtApplication.m_delegateObject != null && QtApplication.onTrackballEvent != null) 1510 | return (Boolean) QtApplication.invokeDelegateMethod(QtApplication.onTrackballEvent, event); 1511 | else 1512 | return super.onTrackballEvent(event); 1513 | } 1514 | public boolean super_onTrackballEvent(MotionEvent event) 1515 | { 1516 | return super.onTrackballEvent(event); 1517 | } 1518 | //--------------------------------------------------------------------------- 1519 | 1520 | @Override 1521 | public void onUserInteraction() 1522 | { 1523 | if (!QtApplication.invokeDelegate().invoked) 1524 | super.onUserInteraction(); 1525 | } 1526 | public void super_onUserInteraction() 1527 | { 1528 | super.onUserInteraction(); 1529 | } 1530 | //--------------------------------------------------------------------------- 1531 | 1532 | @Override 1533 | protected void onUserLeaveHint() 1534 | { 1535 | if (!QtApplication.invokeDelegate().invoked) 1536 | super.onUserLeaveHint(); 1537 | } 1538 | public void super_onUserLeaveHint() 1539 | { 1540 | super.onUserLeaveHint(); 1541 | } 1542 | //--------------------------------------------------------------------------- 1543 | 1544 | @Override 1545 | public void onWindowAttributesChanged(LayoutParams params) 1546 | { 1547 | if (!QtApplication.invokeDelegate(params).invoked) 1548 | super.onWindowAttributesChanged(params); 1549 | } 1550 | public void super_onWindowAttributesChanged(LayoutParams params) 1551 | { 1552 | super.onWindowAttributesChanged(params); 1553 | } 1554 | //--------------------------------------------------------------------------- 1555 | 1556 | @Override 1557 | public void onWindowFocusChanged(boolean hasFocus) 1558 | { 1559 | if (!QtApplication.invokeDelegate(hasFocus).invoked) 1560 | super.onWindowFocusChanged(hasFocus); 1561 | } 1562 | public void super_onWindowFocusChanged(boolean hasFocus) 1563 | { 1564 | super.onWindowFocusChanged(hasFocus); 1565 | } 1566 | //--------------------------------------------------------------------------- 1567 | 1568 | //////////////// Activity API 5 ///////////// 1569 | //@ANDROID-5 1570 | @Override 1571 | public void onAttachedToWindow() 1572 | { 1573 | if (!QtApplication.invokeDelegate().invoked) 1574 | super.onAttachedToWindow(); 1575 | } 1576 | public void super_onAttachedToWindow() 1577 | { 1578 | super.onAttachedToWindow(); 1579 | } 1580 | //--------------------------------------------------------------------------- 1581 | 1582 | @Override 1583 | public void onBackPressed() 1584 | { 1585 | if (!QtApplication.invokeDelegate().invoked) 1586 | super.onBackPressed(); 1587 | } 1588 | public void super_onBackPressed() 1589 | { 1590 | super.onBackPressed(); 1591 | } 1592 | //--------------------------------------------------------------------------- 1593 | 1594 | @Override 1595 | public void onDetachedFromWindow() 1596 | { 1597 | if (!QtApplication.invokeDelegate().invoked) 1598 | super.onDetachedFromWindow(); 1599 | } 1600 | public void super_onDetachedFromWindow() 1601 | { 1602 | super.onDetachedFromWindow(); 1603 | } 1604 | //--------------------------------------------------------------------------- 1605 | 1606 | @Override 1607 | public boolean onKeyLongPress(int keyCode, KeyEvent event) 1608 | { 1609 | if (QtApplication.m_delegateObject != null && QtApplication.onKeyLongPress != null) 1610 | return (Boolean) QtApplication.invokeDelegateMethod(QtApplication.onKeyLongPress, keyCode, event); 1611 | else 1612 | return super.onKeyLongPress(keyCode, event); 1613 | } 1614 | public boolean super_onKeyLongPress(int keyCode, KeyEvent event) 1615 | { 1616 | return super.onKeyLongPress(keyCode, event); 1617 | } 1618 | //--------------------------------------------------------------------------- 1619 | //@ANDROID-5 1620 | 1621 | //////////////// Activity API 8 ///////////// 1622 | //@ANDROID-8 1623 | @Override 1624 | protected Dialog onCreateDialog(int id, Bundle args) 1625 | { 1626 | QtApplication.InvokeResult res = QtApplication.invokeDelegate(id, args); 1627 | if (res.invoked) 1628 | return (Dialog)res.methodReturns; 1629 | else 1630 | return super.onCreateDialog(id, args); 1631 | } 1632 | public Dialog super_onCreateDialog(int id, Bundle args) 1633 | { 1634 | return super.onCreateDialog(id, args); 1635 | } 1636 | //--------------------------------------------------------------------------- 1637 | 1638 | @Override 1639 | protected void onPrepareDialog(int id, Dialog dialog, Bundle args) 1640 | { 1641 | if (!QtApplication.invokeDelegate(id, dialog, args).invoked) 1642 | super.onPrepareDialog(id, dialog, args); 1643 | } 1644 | public void super_onPrepareDialog(int id, Dialog dialog, Bundle args) 1645 | { 1646 | super.onPrepareDialog(id, dialog, args); 1647 | } 1648 | //--------------------------------------------------------------------------- 1649 | //@ANDROID-8 1650 | //////////////// Activity API 11 ///////////// 1651 | 1652 | //////////////// Activity API 12 ///////////// 1653 | 1654 | 1655 | } 1656 | -------------------------------------------------------------------------------- /android/src/org/qtproject/qt5/android/bindings/QtApplication.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2012-2013, BogDan Vatra 3 | Contact: http://www.qt-project.org/legal 4 | 5 | Commercial License Usage 6 | Licensees holding valid commercial Qt licenses may use this file in 7 | accordance with the commercial license agreement provided with the 8 | Software or, alternatively, in accordance with the terms contained in 9 | a written agreement between you and Digia. For licensing terms and 10 | conditions see http://qt.digia.com/licensing. For further information 11 | use the contact form at http://qt.digia.com/contact-us. 12 | 13 | BSD License Usage 14 | Alternatively, this file may be used under the BSD license as follows: 15 | Redistribution and use in source and binary forms, with or without 16 | modification, are permitted provided that the following conditions 17 | are met: 18 | 19 | 1. Redistributions of source code must retain the above copyright 20 | notice, this list of conditions and the following disclaimer. 21 | 2. Redistributions in binary form must reproduce the above copyright 22 | notice, this list of conditions and the following disclaimer in the 23 | documentation and/or other materials provided with the distribution. 24 | 25 | THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 26 | IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 27 | OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 28 | IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 29 | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 30 | NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 31 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 32 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 33 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 34 | THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 35 | */ 36 | 37 | package org.qtproject.qt5.android.bindings; 38 | 39 | import java.lang.reflect.Field; 40 | import java.lang.reflect.Method; 41 | import java.util.ArrayList; 42 | import java.util.HashMap; 43 | 44 | import android.app.Application; 45 | 46 | public class QtApplication extends Application 47 | { 48 | public final static String QtTAG = "Qt"; 49 | public static Object m_delegateObject = null; 50 | public static HashMap> m_delegateMethods= new HashMap>(); 51 | public static Method dispatchKeyEvent = null; 52 | public static Method dispatchPopulateAccessibilityEvent = null; 53 | public static Method dispatchTouchEvent = null; 54 | public static Method dispatchTrackballEvent = null; 55 | public static Method onKeyDown = null; 56 | public static Method onKeyMultiple = null; 57 | public static Method onKeyUp = null; 58 | public static Method onTouchEvent = null; 59 | public static Method onTrackballEvent = null; 60 | public static Method onActivityResult = null; 61 | public static Method onCreate = null; 62 | public static Method onKeyLongPress = null; 63 | public static Method dispatchKeyShortcutEvent = null; 64 | public static Method onKeyShortcut = null; 65 | public static Method dispatchGenericMotionEvent = null; 66 | public static Method onGenericMotionEvent = null; 67 | 68 | public static void setQtActivityDelegate(Object listener) 69 | { 70 | QtApplication.m_delegateObject = listener; 71 | 72 | ArrayList delegateMethods = new ArrayList(); 73 | for (Method m : listener.getClass().getMethods()) { 74 | if (m.getDeclaringClass().getName().startsWith("org.qtproject.qt5.android")) 75 | delegateMethods.add(m); 76 | } 77 | 78 | ArrayList applicationFields = new ArrayList(); 79 | for (Field f : QtApplication.class.getFields()) { 80 | if (f.getDeclaringClass().getName().equals(QtApplication.class.getName())) 81 | applicationFields.add(f); 82 | } 83 | 84 | for (Method delegateMethod : delegateMethods) { 85 | try { 86 | QtActivity.class.getDeclaredMethod(delegateMethod.getName(), delegateMethod.getParameterTypes()); 87 | if (QtApplication.m_delegateMethods.containsKey(delegateMethod.getName())) { 88 | QtApplication.m_delegateMethods.get(delegateMethod.getName()).add(delegateMethod); 89 | } else { 90 | ArrayList delegateSet = new ArrayList(); 91 | delegateSet.add(delegateMethod); 92 | QtApplication.m_delegateMethods.put(delegateMethod.getName(), delegateSet); 93 | } 94 | for (Field applicationField:applicationFields) { 95 | if (applicationField.getName().equals(delegateMethod.getName())) { 96 | try { 97 | applicationField.set(null, delegateMethod); 98 | } catch (Exception e) { 99 | e.printStackTrace(); 100 | } 101 | } 102 | } 103 | } catch (Exception e) { 104 | } 105 | } 106 | } 107 | 108 | @Override 109 | public void onTerminate() { 110 | if (m_delegateObject != null && m_delegateMethods.containsKey("onTerminate")) 111 | invokeDelegateMethod(m_delegateMethods.get("onTerminate").get(0)); 112 | super.onTerminate(); 113 | } 114 | 115 | public static class InvokeResult 116 | { 117 | public boolean invoked = false; 118 | public Object methodReturns = null; 119 | } 120 | 121 | private static int stackDeep=-1; 122 | public static InvokeResult invokeDelegate(Object... args) 123 | { 124 | InvokeResult result = new InvokeResult(); 125 | if (m_delegateObject == null) 126 | return result; 127 | StackTraceElement[] elements = Thread.currentThread().getStackTrace(); 128 | if (-1 == stackDeep) { 129 | String activityClassName = QtActivity.class.getCanonicalName(); 130 | for (int it=0;it 2 | 3 | AndroidManifest.xml 4 | libs.xml 5 | logo.png 6 | icon.png 7 | 8 | 9 | -------------------------------------------------------------------------------- /main.cpp: -------------------------------------------------------------------------------- 1 | #include "mainwindow.h" 2 | #include 3 | 4 | int main(int argc, char *argv[]) 5 | { 6 | QApplication a(argc, argv); 7 | MainWindow w; 8 | w.show(); 9 | 10 | return a.exec(); 11 | } 12 | -------------------------------------------------------------------------------- /mainwindow.cpp: -------------------------------------------------------------------------------- 1 | #include "mainwindow.h" 2 | #include "ui_mainwindow.h" 3 | 4 | MainWindow::MainWindow( QWidget *parent ) 5 | : QMainWindow( parent ) 6 | , ui( new Ui::MainWindow ) 7 | , m_webVeiw( NULL ) 8 | { 9 | ui->setupUi(this); 10 | } 11 | 12 | MainWindow::~MainWindow() 13 | { 14 | delete ui; 15 | 16 | if( m_webVeiw ) 17 | delete m_webVeiw; 18 | } 19 | 20 | void MainWindow::on_pushButton_clicked() 21 | { 22 | if( !m_webVeiw ) 23 | { 24 | m_webVeiw = new QtCustomAndroidWebView( this ); 25 | m_webVeiw->move( 10, 45 ); 26 | m_webVeiw->resize( 700, 600 ); 27 | } 28 | 29 | m_webVeiw->loadURL( ui->lineEdit->text() ); 30 | } 31 | -------------------------------------------------------------------------------- /mainwindow.h: -------------------------------------------------------------------------------- 1 | #ifndef MAINWINDOW_H 2 | #define MAINWINDOW_H 3 | 4 | #include 5 | #include "QtCustomAndroidWebView.h" 6 | 7 | namespace Ui { 8 | class MainWindow; 9 | } 10 | 11 | class MainWindow : public QMainWindow 12 | { 13 | Q_OBJECT 14 | 15 | public: 16 | explicit MainWindow(QWidget *parent = 0); 17 | ~MainWindow(); 18 | 19 | private slots: 20 | void on_pushButton_clicked(); 21 | 22 | private: 23 | Ui::MainWindow *ui; 24 | QtCustomAndroidWebView *m_webVeiw; 25 | }; 26 | 27 | #endif // MAINWINDOW_H 28 | -------------------------------------------------------------------------------- /mainwindow.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | MainWindow 4 | 5 | 6 | 7 | 0 8 | 0 9 | 800 10 | 480 11 | 12 | 13 | 14 | MainWindow 15 | 16 | 17 | 18 | 19 | 20 | 10 21 | 10 22 | 271 23 | 31 24 | 25 | 26 | 27 | http://qt-project.org 28 | 29 | 30 | 31 | 32 | 33 | 290 34 | 10 35 | 51 36 | 31 37 | 38 | 39 | 40 | Go! 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | --------------------------------------------------------------------------------