├── README.md ├── android ├── Activity-AndroidManifest.xml ├── Service-AndroidManifest.xml ├── jni │ ├── Android.mk │ └── QtAndroidService.cpp ├── libs │ └── guava-10.0.1.jar ├── res │ ├── layout │ │ └── serviceconfigactivity.xml │ └── values │ │ ├── dimens.xml │ │ └── style.xml ├── setup.sh └── src │ └── org │ └── qtproject │ └── qt5 │ └── android │ ├── QtServiceDelegate.java │ └── addons │ ├── qtactivityapp │ ├── QtService.java │ └── QtServiceActivity.java │ └── qtserviceapp │ ├── QtService.java │ ├── QtServiceActivity.java │ └── QtServiceBroadcastReceiver.java └── example └── MyTestService ├── MyTestService.pro ├── android ├── Activity-AndroidManifest.xml ├── AndroidManifest.xml ├── README.md ├── Service-AndroidManifest.xml ├── jni │ ├── Android.mk │ └── QtAndroidService.cpp ├── libs │ ├── armeabi │ │ └── libQtAndroidService.so │ └── guava-10.0.1.jar ├── obj │ └── local │ │ └── armeabi │ │ ├── libQtAndroidService.so │ │ ├── libstdc++.a │ │ └── objs │ │ └── QtAndroidService │ │ ├── QtAndroidService.o │ │ └── QtAndroidService.o.d ├── res │ ├── drawable-hdpi-v11 │ │ └── notificon.png │ ├── drawable-hdpi │ │ ├── icon.png │ │ └── notificon.png │ ├── drawable-mdpi-v11 │ │ └── notificon.png │ ├── drawable-mdpi │ │ ├── icon.png │ │ └── notificon.png │ ├── drawable-xhdpi-v11 │ │ └── notificon.png │ ├── drawable-xhdpi │ │ ├── icon.png │ │ └── notificon.png │ ├── drawable-xxhdpi-v11 │ │ └── notificon.png │ ├── drawable-xxhdpi │ │ ├── icon.png │ │ └── notificon.png │ ├── drawable-xxxhdpi │ │ └── icon.png │ ├── layout │ │ └── serviceconfigactivity.xml │ └── values │ │ ├── dimens.xml │ │ └── style.xml ├── setup.sh └── src │ ├── com │ └── mycompany │ │ └── test1 │ │ ├── MyTestService.java │ │ ├── MyTestServiceActivity.java │ │ └── MyTestServiceBroadcastReceiver.java │ └── org │ └── qtproject │ └── qt5 │ └── android │ ├── QtServiceDelegate.java │ └── addons │ └── qtserviceapp │ ├── QtService.java │ ├── QtServiceActivity.java │ └── QtServiceBroadcastReceiver.java └── main.cpp /README.md: -------------------------------------------------------------------------------- 1 | Qt Android service and activity helper classes 2 | ============================================== 3 | 4 | - First create a project in QtCreator QtQuick or QtWidget for activity based application or "Qt Console Application" for a service based one 5 | 6 | - In project - Android - Run - Advanced actions, create an AndroidManifest 7 | or put the following lines to your .pro 8 | 9 | ANDROID_PACKAGE_SOURCE_DIR = $$PWD/android 10 | 11 | OTHER_FILES += \ 12 | android/AndroidManifest.xml 13 | 14 | 15 | - ! Only bundled Qt librairies have been tested ... 16 | 17 | - Replace the "android" folder that qtcreator have created in your project by this one or if your edited the .pro just put it in your project. 18 | 19 | - Run ./setup.sh in the android folder 20 | - Put your icon.png and notificon.png 21 | -------------------------------------------------------------------------------- /android/Activity-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 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /android/Service-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 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /android/jni/Android.mk: -------------------------------------------------------------------------------- 1 | LOCAL_PATH:= $(call my-dir) 2 | 3 | include $(CLEAR_VARS) 4 | 5 | LOCAL_MODULE := QtAndroidService 6 | LOCAL_CFLAGS := -Werror 7 | LOCAL_SRC_FILES := QtAndroidService.cpp 8 | LOCAL_LDLIBS := -llog 9 | 10 | include $(BUILD_SHARED_LIBRARY) -------------------------------------------------------------------------------- /android/jni/QtAndroidService.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | // Global variables 12 | 13 | static jclass m_applicationClass = NULL; 14 | static jobject m_classLoaderObject = NULL; 15 | static jmethodID m_loadClassMethodID = NULL; 16 | static jobject m_resourcesObj; 17 | static jobject m_activityObject = NULL; 18 | 19 | extern "C" typedef int (*Main)(int, char **); //use the standard main method to start the application 20 | static JavaVM *m_javaVM = NULL; 21 | static Main m_main = NULL; 22 | static void *m_mainLibraryHnd = NULL; 23 | 24 | static const char m_classErrorMsg[] = "Can't find class \"%s\""; 25 | static const char m_methodErrorMsg[] = "Can't find method \"%s%s\""; 26 | 27 | // Methods definition 28 | 29 | static jboolean startQtAndroidPlugin(JNIEnv* env, jobject object /*, jobject applicationAssetManager*/) 30 | { 31 | return 1; 32 | } 33 | 34 | static void setDisplayMetrics(JNIEnv */*env*/, jclass /*clazz*/, 35 | jint /*widthPixels*/, jint /*heightPixels*/, 36 | jint desktopWidthPixels, jint desktopHeightPixels, 37 | jdouble xdpi, jdouble ydpi, jdouble scaledDensity) 38 | {} 39 | 40 | // Methods definition 41 | 42 | static void *startMainMethod(void *ar) 43 | { 44 | __android_log_print(ANDROID_LOG_INFO, "Qt", "Calling main method"); 45 | 46 | char *argv[] = { NULL}; 47 | int argc = sizeof(argv) / sizeof(char*) - 1; 48 | 49 | int ret = m_main(argc, argv); 50 | 51 | return NULL; 52 | } 53 | 54 | static jboolean startQtApplication(JNIEnv *env, jobject object, jstring paramsString, jstring environmentString) 55 | { 56 | // Get native 57 | 58 | const char *nativeEnvironmentString = (env)->GetStringUTFChars(environmentString, NULL); // C++ 59 | const char *nativeParamsString = (env)->GetStringUTFChars(paramsString, NULL); // C++ 60 | 61 | // Print info 62 | 63 | __android_log_print(ANDROID_LOG_FATAL, "Qt", "Starting the Qt service"); 64 | 65 | char cwd[1024]; 66 | if (getcwd(cwd, sizeof(cwd)) != NULL) 67 | __android_log_print(ANDROID_LOG_INFO, "Qt", "Current working dir : %s", cwd); 68 | 69 | __android_log_print(ANDROID_LOG_FATAL, "Qt", "Param : %s", nativeParamsString ); 70 | __android_log_print(ANDROID_LOG_FATAL, "Qt", "Env : %s", nativeEnvironmentString ); 71 | 72 | // Start 73 | 74 | m_mainLibraryHnd = NULL; 75 | 76 | // Obtain a handle to the main library (the library that contains the main() function). 77 | // This library should already be loaded, and calling dlopen() will just return a reference to it. 78 | __android_log_print(ANDROID_LOG_INFO, "Qt", "Trying to open %s", nativeParamsString); 79 | m_mainLibraryHnd = dlopen(nativeParamsString, 0); 80 | 81 | if (m_mainLibraryHnd == NULL) { 82 | 83 | __android_log_print(ANDROID_LOG_INFO, "Qt", "No main library was specified; searching entire process (this is slow!)"); 84 | m_main = (Main)dlsym(RTLD_DEFAULT, "main"); 85 | } 86 | else { 87 | 88 | __android_log_print(ANDROID_LOG_INFO, "Qt", "Getting the main method from handler"); 89 | m_main = (Main)dlsym(m_mainLibraryHnd, "main"); 90 | } 91 | 92 | 93 | if (!m_main) { 94 | 95 | __android_log_print(ANDROID_LOG_INFO, "Qt", "Could not find main method"); 96 | return 0; 97 | } 98 | else{ 99 | 100 | __android_log_print(ANDROID_LOG_INFO, "Qt", "Main method found, starting"); 101 | } 102 | 103 | 104 | pthread_t appThread; 105 | return pthread_create(&appThread, NULL, startMainMethod, NULL) == 0; 106 | 107 | //env->ReleaseStringUTFChars(environmentString, nativeString); 108 | } 109 | 110 | static void quitQtAndroidPlugin(JNIEnv *env, jclass clazz) 111 | { 112 | 113 | } 114 | 115 | static void terminateQt(JNIEnv *env, jclass clazz) 116 | { 117 | 118 | } 119 | 120 | // Native methods 121 | 122 | static JNINativeMethod methods[] = { 123 | {"startQtAndroidPlugin", "()Z", (void *)startQtAndroidPlugin}, 124 | {"setDisplayMetrics", "(IIIIDDD)V", (void *)setDisplayMetrics}, 125 | {"startQtApplication", "(Ljava/lang/String;Ljava/lang/String;)V", (void *)startQtApplication}, 126 | {"quitQtAndroidPlugin", "()V", (void *)quitQtAndroidPlugin}, 127 | {"terminateQt", "()V", (void *)terminateQt} 128 | }; 129 | 130 | 131 | // Helpers functions 132 | 133 | #define FIND_AND_CHECK_CLASS(CLASS_NAME) \ 134 | clazz = env->FindClass(CLASS_NAME); \ 135 | if (!clazz) { \ 136 | __android_log_print(ANDROID_LOG_FATAL, "Qt", m_classErrorMsg, CLASS_NAME); \ 137 | return JNI_FALSE; \ 138 | } 139 | 140 | #define GET_AND_CHECK_METHOD(VAR, CLASS, METHOD_NAME, METHOD_SIGNATURE) \ 141 | VAR = env->GetMethodID(CLASS, METHOD_NAME, METHOD_SIGNATURE); \ 142 | if (!VAR) { \ 143 | __android_log_print(ANDROID_LOG_FATAL, "Qt", m_methodErrorMsg, METHOD_NAME, METHOD_SIGNATURE); \ 144 | return JNI_FALSE; \ 145 | } 146 | 147 | #define GET_AND_CHECK_STATIC_METHOD(VAR, CLASS, METHOD_NAME, METHOD_SIGNATURE) \ 148 | VAR = env->GetStaticMethodID(CLASS, METHOD_NAME, METHOD_SIGNATURE); \ 149 | if (!VAR) { \ 150 | __android_log_print(ANDROID_LOG_FATAL, "Qt", m_methodErrorMsg, METHOD_NAME, METHOD_SIGNATURE); \ 151 | return JNI_FALSE; \ 152 | } 153 | 154 | #define GET_AND_CHECK_FIELD(VAR, CLASS, FIELD_NAME, FIELD_SIGNATURE) \ 155 | VAR = env->GetFieldID(CLASS, FIELD_NAME, FIELD_SIGNATURE); \ 156 | if (!VAR) { \ 157 | __android_log_print(ANDROID_LOG_FATAL, "Qt", m_methodErrorMsg, FIELD_NAME, FIELD_SIGNATURE); \ 158 | return JNI_FALSE; \ 159 | } 160 | 161 | #define GET_AND_CHECK_STATIC_FIELD(VAR, CLASS, FIELD_NAME, FIELD_SIGNATURE) \ 162 | VAR = env->GetStaticFieldID(CLASS, FIELD_NAME, FIELD_SIGNATURE); \ 163 | if (!VAR) { \ 164 | __android_log_print(ANDROID_LOG_FATAL, "Qt", m_methodErrorMsg, FIELD_NAME, FIELD_SIGNATURE); \ 165 | return JNI_FALSE; \ 166 | } 167 | 168 | // On load 169 | 170 | jint JNICALL JNI_OnLoad(JavaVM *vm, void *ld) 171 | { 172 | 173 | __android_log_print(ANDROID_LOG_INFO, "Qt", "Qt Android service wrapper start"); 174 | 175 | JNIEnv* env; 176 | if (vm->GetEnv(reinterpret_cast(&env), JNI_VERSION_1_6) != JNI_OK) { 177 | __android_log_print(ANDROID_LOG_FATAL, "Qt", "Can't get env in wrapper start"); \ 178 | return -1; 179 | } 180 | 181 | m_javaVM = vm; 182 | 183 | jclass clazz; 184 | FIND_AND_CHECK_CLASS("org/qtproject/qt5/android/QtNative"); 185 | m_applicationClass = static_cast(env->NewGlobalRef(clazz)); 186 | 187 | __android_log_print(ANDROID_LOG_INFO, "Qt", "Registering native classes for service wrapper"); 188 | 189 | if (env->RegisterNatives(m_applicationClass, methods, sizeof(methods) / sizeof(methods[0])) < 0) { 190 | __android_log_print(ANDROID_LOG_FATAL,"Qt", "RegisterNatives failed for service wrapper"); 191 | return JNI_FALSE; 192 | } 193 | 194 | return JNI_VERSION_1_4; 195 | } 196 | 197 | 198 | -------------------------------------------------------------------------------- /android/libs/guava-10.0.1.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/think-free-backup/QtAndroidHelper/e50daeaa54c9a08633f645e5cd174f3c1f4a2ba4/android/libs/guava-10.0.1.jar -------------------------------------------------------------------------------- /android/res/layout/serviceconfigactivity.xml: -------------------------------------------------------------------------------- 1 | 10 | 11 | 21 | 22 | 30 | 31 | 40 | 41 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /android/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 16dp 5 | 16dp 6 | 7 | 8 | -------------------------------------------------------------------------------- /android/res/values/style.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 | 9 | -------------------------------------------------------------------------------- /android/setup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # This script will setup the android folder for an activity or a service based qt application 4 | 5 | # Functions 6 | 7 | function setup(){ 8 | 9 | clear 10 | 11 | echo "" 12 | echo "Please enter your package name (ex : org.qt-project.myqtapplication) : " 13 | read package 14 | 15 | app=`ls ../*.pro | cut -d '/' -f 2 | cut -d '.' -f 1` 16 | 17 | if [ "$app" == "" ]; 18 | then 19 | echo "Can't find .pro in ../ exiting" 20 | exit 1 21 | fi 22 | 23 | echo "" 24 | echo "Do you want to create an activity or a service based application ? [a/s]" 25 | read tp 26 | 27 | if [ "$tp" == "a" ]; 28 | then 29 | 30 | activity $package $app 31 | 32 | elif [ "$tp" == "s" ]; 33 | then 34 | 35 | service $package $app 36 | 37 | else 38 | 39 | clear 40 | echo "Bad selection" 41 | sleep 2 42 | setup 43 | fi 44 | } 45 | 46 | function activity(){ 47 | 48 | echo "You've selected an activity based application" 49 | 50 | cp Activity-AndroidManifest.xml AndroidManifest.xml 51 | 52 | echo "Cleaning un-necesary files" 53 | ################################# 54 | 55 | rm -rf src/org/qtproject/qt5/android/addons/qtserviceapp 56 | rm src/org/qtproject/qt5/android/QtServiceDelegate.java 57 | 58 | echo "Configuring manifest" 59 | ########################### 60 | 61 | sed -i "s|org.qtproject.qt5.android.addons|$1|" AndroidManifest.xml 62 | sed -i "s|qtactivityapp.QtServiceActivity|$2Activity|g" AndroidManifest.xml 63 | sed -i "s|qtactivityapp.QtService|$2Service|g" AndroidManifest.xml 64 | 65 | echo "Creating package folders" 66 | ############################### 67 | 68 | fld=src/$(sed 's|\.|/|g' <<< $1) 69 | mkdir -p $fld 70 | 71 | 72 | echo "Configuring activity" 73 | ########################### 74 | 75 | 76 | echo "" 77 | echo "Do you want to use a sticky notification with service ? [y/n]" 78 | read sticky 79 | 80 | 81 | echo "package $1;" >> $fld/$2Activity.java 82 | 83 | echo "import org.qtproject.qt5.android.addons.qtactivityapp.QtServiceActivity;" >> $fld/$2Activity.java 84 | echo "import org.qtproject.qt5.android.addons.qtactivityapp.QtService;" >> $fld/$2Activity.java 85 | echo "import android.os.Bundle;" >> $fld/$2Activity.java 86 | echo "import android.content.Intent;" >> $fld/$2Activity.java 87 | echo "import android.content.ComponentName;" >> $fld/$2Activity.java 88 | echo "import android.util.Log;" >> $fld/$2Activity.java 89 | 90 | echo "public class $2Activity extends QtServiceActivity" >> $fld/$2Activity.java 91 | echo "{" >> $fld/$2Activity.java 92 | echo " public void onCreate(Bundle savedInstanceState)" >> $fld/$2Activity.java 93 | echo " {" >> $fld/$2Activity.java 94 | echo " Log.w(getClass().getName(), "Starting config editor");" >> $fld/$2Activity.java 95 | 96 | if [ "$sticky" == "y" ]; 97 | then 98 | echo " super.setServiceClass($2Service.java);" >> $fld/$2Activity.java 99 | else 100 | echo " super.setServiceClass(null);" >> $fld/$2Activity.java 101 | fi 102 | 103 | echo " super.onCreate(savedInstanceState);" >> $fld/$2Activity.java 104 | echo " }" >> $fld/$2Activity.java 105 | echo "}" >> $fld/$2Activity.java 106 | 107 | 108 | echo "Configuring service" 109 | ########################## 110 | 111 | echo "package $1;" >> $fld/$2Service.java 112 | 113 | echo "import org.qtproject.qt5.android.addons.qtactivityapp.QtService;" >> $fld/$2Service.java 114 | echo "import android.util.Log;" >> $fld/$2Service.java 115 | 116 | echo "public class $2Service extends QtService" >> $fld/$2Service.java 117 | echo "{" >> $fld/$2Service.java 118 | echo " public void onCreate()" >> $fld/$2Service.java 119 | echo " {" >> $fld/$2Service.java 120 | echo " Log.w(getClass().getName(), "Starting config editor service");" >> $fld/$2Service.java 121 | echo " super.setActivityClass($2Activity.class);" >> $fld/$2Service.java 122 | echo " super.onCreate();" >> $fld/$2Service.java 123 | echo " }" >> $fld/$2Service.java 124 | echo "}" >> $fld/$2Service.java 125 | 126 | } 127 | 128 | function service(){ 129 | 130 | echo "You've selected a service based application" 131 | ################################################## 132 | 133 | cp Service-AndroidManifest.xml AndroidManifest.xml 134 | 135 | echo "Compiling helper librairy" 136 | ################################ 137 | 138 | cd jni 139 | ndk-build 140 | cd .. 141 | 142 | echo "Cleaning un-necesary files" 143 | ################################# 144 | 145 | rm -rf src/org/qtproject/qt5/android/addons/qtactivityapp 146 | 147 | echo "Configuring manifest" 148 | ########################### 149 | 150 | sed -i "s|org.qtproject.qt5.android.addons|$1|" AndroidManifest.xml 151 | sed -i "s|qtserviceapp.QtService|$2|g" AndroidManifest.xml 152 | sed -i "s|QtServiceActivity|$2|g" AndroidManifest.xml 153 | 154 | sed -i "s|import R;|import $1.R;|" src/org/qtproject/qt5/android/addons/qtserviceapp/QtServiceActivity.java # FIXME !!!! 155 | 156 | 157 | echo "Creating package folders" 158 | ############################### 159 | 160 | fld=src/$(sed 's|\.|/|g' <<< $1) 161 | mkdir -p $fld 162 | 163 | 164 | echo "Configuring Service" 165 | ########################## 166 | 167 | echo "package $1;" >> $fld/$2.java 168 | 169 | echo "import org.qtproject.qt5.android.addons.qtserviceapp.QtService;" >> $fld/$2.java 170 | echo "import android.util.Log;" >> $fld/$2.java 171 | 172 | echo "public class $2 extends QtService {" >> $fld/$2.java 173 | 174 | echo " public void onCreate()" >> $fld/$2.java 175 | echo " {" >> $fld/$2.java 176 | echo " Log.w(getClass().getName(), \"Starting datasync service\");" >> $fld/$2.java 177 | echo " super.setActivityClass($2Activity.class);" >> $fld/$2.java 178 | echo " super.onCreate();" >> $fld/$2.java 179 | echo " }" >> $fld/$2.java 180 | echo "}" >> $fld/$2.java 181 | echo "" >> $fld/$2.java 182 | 183 | 184 | echo "Configuring service activity" 185 | ################################### 186 | 187 | echo "package $1;" >> $fld/$2Activity.java 188 | 189 | echo "import $1.R;" >> $fld/$2Activity.java 190 | 191 | echo "import org.qtproject.qt5.android.addons.qtserviceapp.QtServiceActivity;" >> $fld/$2Activity.java 192 | 193 | echo "import android.os.Bundle;" >> $fld/$2Activity.java 194 | echo "import android.util.Log;" >> $fld/$2Activity.java 195 | 196 | echo "public class $2Activity extends QtServiceActivity {" >> $fld/$2Activity.java 197 | 198 | echo " @Override" >> $fld/$2Activity.java 199 | echo " public void onCreate(Bundle savedInstanceState)" >> $fld/$2Activity.java 200 | echo " {" >> $fld/$2Activity.java 201 | echo " Log.w(getClass().getName(), \"Starting datasync service activity\");" >> $fld/$2Activity.java 202 | echo " super.setActivityClass($2.class);" >> $fld/$2Activity.java 203 | echo " super.onCreate(savedInstanceState);" >> $fld/$2Activity.java 204 | echo " }" >> $fld/$2Activity.java 205 | echo "}" >> $fld/$2Activity.java 206 | echo "" >> $fld/$2Activity.java 207 | 208 | 209 | echo "Configuring broadcast receiver (to be run at startup)" 210 | ############################################################ 211 | 212 | echo "package $1;" >> $fld/$2BroadcastReceiver.java 213 | 214 | echo "import org.qtproject.qt5.android.addons.qtserviceapp.QtServiceBroadcastReceiver;" >> $fld/$2BroadcastReceiver.java 215 | 216 | echo "import android.content.Context;" >> $fld/$2BroadcastReceiver.java 217 | echo "import android.content.Intent;" >> $fld/$2BroadcastReceiver.java 218 | echo "import android.util.Log;" >> $fld/$2BroadcastReceiver.java 219 | 220 | echo "public class $2BroadcastReceiver extends QtServiceBroadcastReceiver {" >> $fld/$2BroadcastReceiver.java 221 | 222 | echo " @Override" >> $fld/$2BroadcastReceiver.java 223 | echo " public void onReceive(Context context, Intent intent) {" >> $fld/$2BroadcastReceiver.java 224 | 225 | echo " Log.w(getClass().getName(), \"Broadcast received for Comservice\");" >> $fld/$2BroadcastReceiver.java 226 | 227 | echo " super.setActivityClass($2.class);" >> $fld/$2BroadcastReceiver.java 228 | echo " super.onReceive(context, intent);" >> $fld/$2BroadcastReceiver.java 229 | echo " }" >> $fld/$2BroadcastReceiver.java 230 | echo "}" >> $fld/$2BroadcastReceiver.java 231 | echo "" >> $fld/$2BroadcastReceiver.java 232 | } 233 | 234 | # Main 235 | 236 | clear 237 | echo "" 238 | echo "This script will allow you to setup a qt activity based application with a service that run a sticky notification or a service based application (without grafical interface)" 239 | echo "First create a qt project in qtcreator " 240 | echo "Please ensure that ndk-build (android-ndk) is in your path before continuing" 241 | echo "" 242 | echo "Press any key to continue" 243 | read 244 | 245 | setup 246 | 247 | clear 248 | echo "Almost done, please create an icon.png and a notificon.png for every resolution you want to support in the res folder" 249 | echo "You can use : http://android-ui-utils.googlecode.com/hg/asset-studio/dist/index.html to create it" 250 | -------------------------------------------------------------------------------- /android/src/org/qtproject/qt5/android/QtServiceDelegate.java: -------------------------------------------------------------------------------- 1 | 2 | package org.qtproject.qt5.android; 3 | 4 | import java.io.File; 5 | import java.io.FileWriter; 6 | import java.io.IOException; 7 | import java.lang.reflect.Method; 8 | import java.util.ArrayList; 9 | import java.util.Iterator; 10 | 11 | import android.app.Service; 12 | import android.content.Context; 13 | import android.content.pm.ApplicationInfo; 14 | import android.content.pm.PackageManager; 15 | import android.content.pm.PackageManager.NameNotFoundException; 16 | import android.content.res.Configuration; 17 | import android.graphics.Rect; 18 | import android.os.Build; 19 | import android.os.Bundle; 20 | import android.util.Log; 21 | 22 | public class QtServiceDelegate 23 | { 24 | private Service m_service = null; 25 | 26 | private static final String NATIVE_LIBRARIES_KEY = "native.libraries"; 27 | private static final String BUNDLED_LIBRARIES_KEY = "bundled.libraries"; 28 | private static final String MAIN_LIBRARY_KEY = "main.library"; 29 | private static final String ENVIRONMENT_VARIABLES_KEY = "environment.variables"; 30 | private static final String APPLICATION_PARAMETERS_KEY = "application.parameters"; 31 | private static final String STATIC_INIT_CLASSES_KEY = "static.init.classes"; 32 | private static final String NECESSITAS_API_LEVEL_KEY = "necessitas.api.level"; 33 | 34 | private static String m_environmentVariables = null; 35 | private static String m_applicationParameters = null; 36 | 37 | private String m_mainLib; 38 | 39 | public boolean loadApplication(Service service, ClassLoader classLoader, Bundle loaderParams) 40 | { 41 | if (!loaderParams.containsKey(NATIVE_LIBRARIES_KEY)) 42 | Log.w(getClass().getName(), "Missing parameters1 in loaderParams"); 43 | 44 | if (!loaderParams.containsKey(BUNDLED_LIBRARIES_KEY)) 45 | Log.w(getClass().getName(), "Missing parameters2 in loaderParams"); 46 | 47 | /// check parameters integrity 48 | if (!loaderParams.containsKey(NATIVE_LIBRARIES_KEY) 49 | || !loaderParams.containsKey(BUNDLED_LIBRARIES_KEY)) { 50 | 51 | Log.w(getClass().getName(), "Missing parameters in loaderParams"); 52 | return false; 53 | } 54 | 55 | m_service = service; 56 | //QtNative.setActivity(m_activity, this); 57 | QtNative.setClassLoader(classLoader); 58 | if (loaderParams.containsKey(STATIC_INIT_CLASSES_KEY)) { 59 | for (String className: loaderParams.getStringArray(STATIC_INIT_CLASSES_KEY)) { 60 | Log.w(getClass().getName(), className); 61 | if (className.length() == 0) 62 | continue; 63 | 64 | try { 65 | @SuppressWarnings("rawtypes") 66 | Class initClass = classLoader.loadClass(className); 67 | Object staticInitDataObject = initClass.newInstance(); // create an instance 68 | //Method m = initClass.getMethod("setActivity", Activity.class, Object.class); 69 | //m.invoke(staticInitDataObject, m_activity, this); 70 | } catch (Exception e) { 71 | e.printStackTrace(); 72 | } 73 | } 74 | } 75 | 76 | QtNative.loadQtLibraries(loaderParams.getStringArrayList(NATIVE_LIBRARIES_KEY)); 77 | ArrayList libraries = loaderParams.getStringArrayList(BUNDLED_LIBRARIES_KEY); 78 | QtNative.loadBundledLibraries(libraries, QtNativeNativeLibrariesDir(m_service)); 79 | m_mainLib = loaderParams.getString(MAIN_LIBRARY_KEY); 80 | // older apps provide the main library as the last bundled library; look for this if the main library isn't provided 81 | if (null == m_mainLib && libraries.size() > 0) 82 | m_mainLib = libraries.get(libraries.size() - 1); 83 | 84 | 85 | int necessitasApiLevel = 1; 86 | if (loaderParams.containsKey(NECESSITAS_API_LEVEL_KEY)) 87 | necessitasApiLevel = loaderParams.getInt(NECESSITAS_API_LEVEL_KEY); 88 | 89 | m_environmentVariables =""; 90 | 91 | if (loaderParams.containsKey(APPLICATION_PARAMETERS_KEY)) 92 | m_applicationParameters = loaderParams.getString(APPLICATION_PARAMETERS_KEY); 93 | else 94 | m_applicationParameters = ""; 95 | 96 | return true; 97 | } 98 | 99 | public void debugLog(String msg) 100 | { 101 | Log.i(QtNative.QtTAG, "DEBUGGER: " + msg); 102 | } 103 | 104 | public boolean startApplication() 105 | { 106 | 107 | try { 108 | 109 | String nativeLibraryDir = QtNativeNativeLibrariesDir(m_service); 110 | 111 | Log.i(QtNative.QtTAG, "LIB DIR : " + nativeLibraryDir); 112 | 113 | //QtNativeStartApplication 114 | QtNative.startApplication 115 | ( m_applicationParameters, 116 | m_environmentVariables, 117 | m_mainLib, 118 | nativeLibraryDir); 119 | return true; 120 | } 121 | catch (Exception e) { 122 | 123 | e.printStackTrace(); 124 | return false; 125 | } 126 | } 127 | 128 | public static String QtNativeNativeLibrariesDir(Service service) 129 | { 130 | String m_nativeLibraryDir = null; 131 | try { 132 | ApplicationInfo ai = service.getPackageManager().getApplicationInfo(service.getPackageName(), 0); 133 | m_nativeLibraryDir = ai.nativeLibraryDir+"/"; 134 | } catch (NameNotFoundException e) { 135 | e.printStackTrace(); 136 | } 137 | return m_nativeLibraryDir; 138 | } 139 | 140 | 141 | public static boolean QtNativeStartApplication(String params, 142 | String environment, 143 | String mainLibrary, 144 | String nativeLibraryDir) throws Exception 145 | { 146 | File f = new File(nativeLibraryDir + "lib" + mainLibrary + ".so"); 147 | if (!f.exists()) 148 | throw new Exception("Can't find main library '" + mainLibrary + "'"); 149 | 150 | if (params == null) 151 | params = "-platform\tandroid"; 152 | 153 | boolean res = false; 154 | 155 | if (params.length() > 0 && !params.startsWith("\t")) 156 | params = "\t" + params; 157 | startQtApplication(f.getAbsolutePath() + params, environment); 158 | 159 | return res; 160 | } 161 | 162 | public static native void startQtApplication(String params, String env); 163 | } 164 | -------------------------------------------------------------------------------- /android/src/org/qtproject/qt5/android/addons/qtactivityapp/QtService.java: -------------------------------------------------------------------------------- 1 | package org.qtproject.qt5.android.addons.qtactivityapp; 2 | 3 | import java.lang.reflect.Method; 4 | import java.util.ArrayList; 5 | import java.util.Arrays; 6 | 7 | import dalvik.system.DexClassLoader; 8 | 9 | import android.annotation.SuppressLint; 10 | import android.app.Notification; 11 | import android.app.NotificationManager; 12 | import android.app.PendingIntent; 13 | import android.app.Service; 14 | import android.content.ComponentName; 15 | import android.content.Context; 16 | import android.content.pm.PackageManager; 17 | import android.content.pm.ServiceInfo; 18 | import android.content.Intent; 19 | import android.os.Bundle; 20 | import android.os.IBinder; 21 | import android.util.Log; 22 | import android.os.Process; 23 | import android.widget.Toast; 24 | 25 | public class QtService extends Service 26 | { 27 | public static final String EXTRA_MESSAGE="EXTRA_MESSAGE"; 28 | 29 | private boolean isRunning=false; 30 | private ComponentName myService; 31 | private Class m_class = QtServiceActivity.class; 32 | 33 | private static ServiceInfo m_serviceInfo = null; 34 | private static NotificationManager m_notificationManager; 35 | private static Notification.Builder m_builder; 36 | private static QtService m_instance; 37 | private static String m_lib_name; 38 | private static PendingIntent pi; 39 | 40 | /* Event handling */ 41 | 42 | public void onCreate (){ 43 | 44 | Log.w(getClass().getName(), "Service created ..."); 45 | 46 | m_instance = this; 47 | 48 | try{ 49 | ComponentName myService = new ComponentName(this, this.getClass()); 50 | m_serviceInfo = getPackageManager().getServiceInfo(myService, PackageManager.GET_META_DATA); 51 | m_lib_name = splitCamelCase (m_serviceInfo.metaData.getString("android.app.lib_name")); 52 | } 53 | catch (Exception e) { 54 | 55 | e.printStackTrace(); 56 | } 57 | } 58 | 59 | public IBinder onBind(Intent intent){ 60 | 61 | return(null); 62 | } 63 | 64 | public int onStartCommand(Intent intent, int flags, int startId){ 65 | 66 | /* Notifiication */ 67 | 68 | Notification note=new Notification(m_serviceInfo.metaData.getInt("android.app.notificon"),"",System.currentTimeMillis()); 69 | 70 | Intent i=new Intent(m_instance, m_class); 71 | i.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP|Intent.FLAG_ACTIVITY_SINGLE_TOP); 72 | 73 | pi=PendingIntent.getActivity(this, 0, 74 | i, 0); 75 | 76 | note.setLatestEventInfo(this, m_lib_name , 77 | "Running", 78 | pi); 79 | note.flags|=Notification.FLAG_NO_CLEAR; 80 | 81 | startForeground(1337, note); 82 | 83 | /* Return */ 84 | 85 | return(START_STICKY); 86 | } 87 | 88 | public void onDestroy(){ 89 | 90 | Log.w(getClass().getName(), "Service destroyed ..."); 91 | 92 | Process.killProcess(Process.myPid()); 93 | } 94 | 95 | /* Activity class */ 96 | 97 | public void setActivityClass(Class cl){ 98 | 99 | m_class = cl; 100 | } 101 | 102 | /* Notification methods */ 103 | 104 | public static void notify(String s){ 105 | 106 | if (m_notificationManager == null) { 107 | 108 | m_notificationManager = (NotificationManager)m_instance.getSystemService(Context.NOTIFICATION_SERVICE); 109 | m_builder = new Notification.Builder(m_instance); 110 | m_builder.setSmallIcon(m_serviceInfo.metaData.getInt("android.app.notificon")); 111 | m_builder.setContentTitle(m_lib_name); 112 | m_builder.setContentIntent(pi); 113 | } 114 | 115 | m_builder.setContentText(s); 116 | Notification note = m_builder.build(); 117 | note.flags |= Notification.FLAG_NO_CLEAR; 118 | 119 | m_notificationManager.notify(1337, note); 120 | } 121 | 122 | /* Helper classes */ 123 | 124 | static String splitCamelCase(String sp) { 125 | 126 | String s = Character.toUpperCase(sp.charAt(0)) + sp.substring(1); 127 | 128 | return s.replaceAll( 129 | String.format("%s|%s|%s", 130 | "(?<=[A-Z])(?=[A-Z][a-z])", 131 | "(?<=[^A-Z])(?=[A-Z])", 132 | "(?<=[A-Za-z])(?=[^A-Za-z])" 133 | ), 134 | " " 135 | ); 136 | } 137 | } 138 | -------------------------------------------------------------------------------- /android/src/org/qtproject/qt5/android/addons/qtactivityapp/QtServiceActivity.java: -------------------------------------------------------------------------------- 1 | package org.qtproject.qt5.android.addons.qtactivityapp; 2 | 3 | import org.qtproject.qt5.android.bindings.QtActivity; 4 | 5 | import android.app.Activity; 6 | import android.content.pm.ActivityInfo; 7 | import android.content.ComponentName; 8 | import android.os.Bundle; 9 | import android.content.pm.PackageManager; 10 | import android.content.pm.PackageManager.NameNotFoundException; 11 | import android.util.Log; 12 | import android.content.Intent; 13 | import android.view.Window; 14 | import android.view.WindowManager; 15 | 16 | public class QtServiceActivity extends QtActivity 17 | { 18 | private ActivityInfo m_activityInfo = null; 19 | private Class m_class = QtService.class; 20 | 21 | @Override 22 | public void onCreate(Bundle savedInstanceState) 23 | { 24 | requestWindowFeature(Window.FEATURE_NO_TITLE); 25 | getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); 26 | 27 | super.onCreate(savedInstanceState); 28 | 29 | try { 30 | m_activityInfo = getPackageManager().getActivityInfo(getComponentName(), PackageManager.GET_META_DATA); 31 | } 32 | catch (NameNotFoundException e) { 33 | e.printStackTrace(); 34 | finish(); 35 | return; 36 | } 37 | 38 | loadService(); 39 | } 40 | 41 | public void setServiceClass(Class cl){ 42 | 43 | m_class = cl; 44 | } 45 | 46 | private int loadService() 47 | { 48 | int retVal = -1; 49 | Log.w("Qt", "loadService"); 50 | try 51 | { 52 | if (m_class != null){ 53 | Intent i = new Intent(this, m_class); 54 | i.putExtra(QtService.EXTRA_MESSAGE, "Loading " + m_activityInfo.metaData.getString("android.app.lib_name")); 55 | ComponentName cn = startService(i); 56 | retVal = 0; 57 | } 58 | } 59 | catch (Exception e) 60 | { 61 | Log.e("Qt", "Can't create service " + e); 62 | } 63 | 64 | return retVal; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /android/src/org/qtproject/qt5/android/addons/qtserviceapp/QtService.java: -------------------------------------------------------------------------------- 1 | package org.qtproject.qt5.android.addons.qtserviceapp; 2 | 3 | import java.lang.reflect.Method; 4 | import java.util.ArrayList; 5 | import java.util.Arrays; 6 | 7 | import dalvik.system.DexClassLoader; 8 | 9 | import android.annotation.SuppressLint; 10 | import android.app.Notification; 11 | import android.app.NotificationManager; 12 | import android.app.PendingIntent; 13 | import android.app.Service; 14 | import android.content.ComponentName; 15 | import android.content.Context; 16 | import android.content.pm.PackageManager; 17 | import android.content.pm.ServiceInfo; 18 | import android.content.Intent; 19 | import android.os.Bundle; 20 | import android.os.IBinder; 21 | import android.util.Log; 22 | import android.os.Process; 23 | import android.widget.Toast; 24 | 25 | @SuppressLint("NewApi") 26 | public class QtService extends Service { 27 | 28 | /* Private variables */ 29 | 30 | public Boolean started=false; 31 | private String[] m_qtLibs = null; 32 | private DexClassLoader m_classLoader = null; 33 | 34 | private Class m_class = QtServiceActivity.class; 35 | 36 | private static ServiceInfo m_serviceInfo = null; 37 | protected static NotificationManager m_notificationManager; 38 | protected static Notification.Builder m_builder; 39 | protected static PendingIntent pi; 40 | private static QtService m_instance; 41 | private static String m_lib_name; 42 | 43 | private static final String ERROR_CODE_KEY = "error.code"; 44 | private static final String DEX_PATH_KEY = "dex.path"; 45 | private static final String STATIC_INIT_CLASSES_KEY = "static.init.classes"; 46 | private static final String NATIVE_LIBRARIES_KEY = "native.libraries"; 47 | private static final String MAIN_LIBRARY_KEY = "main.library"; 48 | private static final String BUNDLED_LIBRARIES_KEY = "bundled.libraries"; 49 | private static final String LOADER_CLASS_NAME_KEY = "loader.class.name"; 50 | private static final String LIB_PATH_KEY = "lib.path"; 51 | private static final String ENVIRONMENT_VARIABLES_KEY = "env.variable"; 52 | 53 | /* Service methods */ 54 | 55 | public void onCreate (){ 56 | 57 | Log.w(getClass().getName(), "Service created ..."); 58 | 59 | m_instance = this; 60 | 61 | try{ 62 | ComponentName myService = new ComponentName(this, this.getClass()); 63 | m_serviceInfo = getPackageManager().getServiceInfo(myService, PackageManager.GET_META_DATA); 64 | m_lib_name = splitCamelCase (m_serviceInfo.metaData.getString("android.app.lib_name")); 65 | } 66 | catch (Exception e) { 67 | 68 | e.printStackTrace(); 69 | } 70 | } 71 | 72 | public IBinder onBind(Intent intent) { 73 | 74 | return null; 75 | } 76 | 77 | @SuppressWarnings("deprecation") 78 | public int onStartCommand(Intent intent, int flags, int startId) 79 | { 80 | 81 | /* Notification */ 82 | 83 | createNotification(); 84 | 85 | /* Start the app */ 86 | 87 | startApp(); 88 | 89 | /* Return */ 90 | 91 | return(START_STICKY); 92 | } 93 | 94 | public void onDestroy(){ 95 | 96 | Log.w(getClass().getName(), "Service destroyed ..."); 97 | 98 | Process.killProcess(Process.myPid()); 99 | } 100 | 101 | /* Internals methods */ 102 | 103 | private void startApp(){ 104 | 105 | if (!started){ 106 | 107 | started = true; 108 | Toast.makeText(getBaseContext(), m_lib_name + " starting", Toast.LENGTH_LONG).show(); 109 | 110 | try{ 111 | 112 | if (m_serviceInfo.metaData.containsKey("android.app.qt_libs_resource_id")) { 113 | int resourceId = m_serviceInfo.metaData.getInt("android.app.qt_libs_resource_id"); 114 | m_qtLibs = getResources().getStringArray(resourceId); 115 | } 116 | 117 | if (m_serviceInfo.metaData.containsKey("android.app.use_local_qt_libs") 118 | && m_serviceInfo.metaData.getInt("android.app.use_local_qt_libs") == 1) { 119 | ArrayList libraryList = new ArrayList(); 120 | 121 | 122 | String localPrefix = "/data/local/tmp/qt/"; 123 | if (m_serviceInfo.metaData.containsKey("android.app.libs_prefix")) 124 | localPrefix = m_serviceInfo.metaData.getString("android.app.libs_prefix"); 125 | 126 | boolean bundlingQtLibs = false; 127 | if (m_serviceInfo.metaData.containsKey("android.app.bundle_local_qt_libs") 128 | && m_serviceInfo.metaData.getInt("android.app.bundle_local_qt_libs") == 1) { 129 | localPrefix = getApplicationInfo().dataDir + "/"; 130 | bundlingQtLibs = true; 131 | } 132 | 133 | if (m_qtLibs != null) { 134 | for (int i=0;i 0) { 150 | if (dexPaths.length() > 0) 151 | dexPaths += pathSeparator; 152 | dexPaths += localPrefix + jar; 153 | } 154 | } 155 | } 156 | 157 | Bundle loaderParams = new Bundle(); 158 | loaderParams.putInt(ERROR_CODE_KEY, 0); 159 | loaderParams.putString(DEX_PATH_KEY, dexPaths); 160 | loaderParams.putString(LOADER_CLASS_NAME_KEY, "org.qtproject.qt5.android.QtServiceDelegate"); 161 | loaderParams.putString(ENVIRONMENT_VARIABLES_KEY, ""); 162 | if (m_serviceInfo.metaData.containsKey("android.app.static_init_classes")) { 163 | loaderParams.putStringArray(STATIC_INIT_CLASSES_KEY, 164 | m_serviceInfo.metaData.getString("android.app.static_init_classes").split(":")); 165 | } 166 | loaderParams.putStringArrayList(NATIVE_LIBRARIES_KEY, libraryList); 167 | 168 | loadApplication(loaderParams); 169 | return; 170 | } 171 | } 172 | catch (Exception e) { 173 | started = false; 174 | e.printStackTrace(); 175 | } 176 | } 177 | } 178 | 179 | @SuppressLint("NewApi") 180 | public void loadApplication(Bundle loaderParams){ 181 | 182 | try{ 183 | 184 | ArrayList libs = new ArrayList(); 185 | if ( m_serviceInfo.metaData.containsKey("android.app.bundled_libs_resource_id") ) 186 | libs.addAll(Arrays.asList(getResources().getStringArray(m_serviceInfo.metaData.getInt("android.app.bundled_libs_resource_id")))); 187 | 188 | String libName = null; 189 | if ( m_serviceInfo.metaData.containsKey("android.app.lib_name") ) { 190 | libName = m_serviceInfo.metaData.getString("android.app.lib_name"); 191 | loaderParams.putString(MAIN_LIBRARY_KEY, libName); //main library contains main() function 192 | } 193 | 194 | loaderParams.putStringArrayList(BUNDLED_LIBRARIES_KEY, libs); 195 | loaderParams.putString(ENVIRONMENT_VARIABLES_KEY, ""); 196 | 197 | m_classLoader = new DexClassLoader(loaderParams.getString(DEX_PATH_KEY), // .jar/.apk files 198 | getDir("outdex", Context.MODE_PRIVATE).getAbsolutePath(), // directory where optimized DEX files should be written. 199 | loaderParams.containsKey(LIB_PATH_KEY) ? loaderParams.getString(LIB_PATH_KEY) : null, // libs folder (if exists) 200 | getClassLoader()); // parent loader 201 | 202 | String loaderClassName = loaderParams.getString(LOADER_CLASS_NAME_KEY); 203 | 204 | Log.w(getClass().getName(), "Loader : " + loaderClassName); 205 | 206 | Class loaderClass = m_classLoader.loadClass(loaderClassName); // load QtLoader class 207 | Object qtLoader = loaderClass.newInstance(); // create an instance 208 | 209 | Method perpareAppMethod = qtLoader.getClass().getMethod("loadApplication", 210 | Service.class, 211 | ClassLoader.class, 212 | Bundle.class); 213 | 214 | if (!(Boolean)perpareAppMethod.invoke(qtLoader, this, m_classLoader, loaderParams)) 215 | throw new Exception(""); 216 | 217 | // now load the application library so it's accessible from this class loader 218 | if (libName != null) 219 | System.loadLibrary(libName); 220 | 221 | Method startAppMethod=qtLoader.getClass().getMethod("startApplication"); 222 | if (!(Boolean)startAppMethod.invoke(qtLoader)) 223 | throw new Exception(""); 224 | 225 | 226 | } 227 | catch (Exception e) { 228 | e.printStackTrace(); 229 | } 230 | } 231 | 232 | /* Activity class */ 233 | 234 | public void setActivityClass(Class cl){ 235 | 236 | m_class = cl; 237 | } 238 | 239 | 240 | /* Notification methods */ 241 | 242 | protected void createNotification(){ 243 | 244 | Notification note=new Notification(m_serviceInfo.metaData.getInt("android.app.notificon"),"",System.currentTimeMillis()); 245 | 246 | Intent i=new Intent(m_instance, m_class); 247 | i.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP|Intent.FLAG_ACTIVITY_SINGLE_TOP); 248 | 249 | pi=PendingIntent.getActivity(this, 0, 250 | i, 0); 251 | 252 | note.setLatestEventInfo(this, m_lib_name , 253 | "Running", 254 | pi); 255 | note.flags|=Notification.FLAG_NO_CLEAR; 256 | 257 | startForeground(1337, note); 258 | } 259 | 260 | public static void notify(String s) 261 | { 262 | if (m_notificationManager == null) { 263 | 264 | m_notificationManager = (NotificationManager)m_instance.getSystemService(Context.NOTIFICATION_SERVICE); 265 | m_builder = new Notification.Builder(m_instance); 266 | m_builder.setSmallIcon(m_serviceInfo.metaData.getInt("android.app.notificon")); 267 | m_builder.setContentTitle(m_lib_name); 268 | m_builder.setContentIntent(pi); 269 | } 270 | 271 | m_builder.setContentText(s); 272 | Notification note = m_builder.build(); 273 | note.flags |= Notification.FLAG_NO_CLEAR; 274 | 275 | m_notificationManager.notify(1337, note); 276 | } 277 | 278 | /* Helpers */ 279 | 280 | static String splitCamelCase(String sp) { 281 | 282 | String s = Character.toUpperCase(sp.charAt(0)) + sp.substring(1); 283 | 284 | return s.replaceAll( 285 | String.format("%s|%s|%s", 286 | "(?<=[A-Z])(?=[A-Z][a-z])", 287 | "(?<=[^A-Z])(?=[A-Z])", 288 | "(?<=[A-Za-z])(?=[^A-Za-z])" 289 | ), 290 | " " 291 | ); 292 | } 293 | } 294 | -------------------------------------------------------------------------------- /android/src/org/qtproject/qt5/android/addons/qtserviceapp/QtServiceActivity.java: -------------------------------------------------------------------------------- 1 | package org.qtproject.qt5.android.addons.qtserviceapp; 2 | 3 | import R; 4 | 5 | import android.app.Activity; 6 | import android.app.ActivityManager; 7 | import android.app.ActivityManager.RunningServiceInfo; 8 | import android.os.Bundle; 9 | import android.content.ComponentName; 10 | import android.content.Context; 11 | import android.content.Intent; 12 | import android.content.SharedPreferences; 13 | import android.content.SharedPreferences.Editor; 14 | import android.content.pm.ActivityInfo; 15 | import android.content.pm.PackageManager; 16 | import android.content.pm.ServiceInfo; 17 | import android.content.pm.PackageManager.NameNotFoundException; 18 | import android.widget.CompoundButton; 19 | import android.widget.Switch; 20 | 21 | public class QtServiceActivity extends Activity { 22 | 23 | private Intent i; 24 | private Class m_class = QtService.class; 25 | 26 | @Override 27 | public void onCreate(Bundle savedInstanceState) 28 | { 29 | 30 | super.onCreate(savedInstanceState); 31 | setContentView(R.layout.serviceconfigactivity); 32 | 33 | i = new Intent(this, m_class); 34 | 35 | final Switch sRun = (Switch) findViewById(R.id.switch_run); 36 | sRun.setChecked(isMyServiceRunning()); 37 | sRun.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { 38 | 39 | @Override 40 | public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { 41 | 42 | if (isChecked) 43 | startService(i); 44 | else 45 | stopService(i); 46 | } 47 | }); 48 | 49 | ComponentName myActivity = new ComponentName(this, this.getClass()); 50 | ActivityInfo activityInfo = null; 51 | try { 52 | activityInfo = getPackageManager().getActivityInfo(myActivity, PackageManager.GET_META_DATA); 53 | } 54 | catch (NameNotFoundException e) { 55 | e.printStackTrace(); 56 | } 57 | 58 | SharedPreferences settings = getBaseContext().getSharedPreferences(activityInfo.metaData.getString("android.app.lib_name"), 0); 59 | final Editor editor = settings.edit(); 60 | 61 | boolean startup = settings.getBoolean("runStartup", true); 62 | 63 | final Switch sRunStartup = (Switch) findViewById(R.id.switch_runstartup); 64 | sRunStartup.setChecked(startup); 65 | sRunStartup.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { 66 | 67 | @Override 68 | public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { 69 | 70 | editor.putBoolean("runStartup", isChecked); 71 | editor.commit(); 72 | } 73 | }); 74 | } 75 | 76 | private boolean isMyServiceRunning() { 77 | ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE); 78 | for (RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) { 79 | if (m_class.getName().equals(service.service.getClassName())) { 80 | return true; 81 | } 82 | } 83 | return false; 84 | } 85 | 86 | /* Activity class */ 87 | 88 | public void setActivityClass(Class cl){ 89 | 90 | m_class = cl; 91 | } 92 | 93 | } 94 | -------------------------------------------------------------------------------- /android/src/org/qtproject/qt5/android/addons/qtserviceapp/QtServiceBroadcastReceiver.java: -------------------------------------------------------------------------------- 1 | package org.qtproject.qt5.android.addons.qtserviceapp; 2 | 3 | import android.content.BroadcastReceiver; 4 | import android.content.ComponentName; 5 | import android.content.Context; 6 | import android.content.Intent; 7 | import android.content.SharedPreferences; 8 | import android.content.pm.ActivityInfo; 9 | import android.content.pm.PackageManager; 10 | import android.os.Bundle; 11 | import android.util.Log; 12 | 13 | public class QtServiceBroadcastReceiver extends BroadcastReceiver { 14 | 15 | private Class m_class = QtService.class; 16 | 17 | @Override 18 | public void onReceive(Context context, Intent intent) { 19 | 20 | Log.w("Qt", "Starting service"); 21 | 22 | try 23 | { 24 | ActivityInfo activityInfo = context.getPackageManager().getReceiverInfo(new ComponentName(context, this.getClass()), PackageManager.GET_META_DATA); 25 | Bundle meta = activityInfo.metaData; 26 | 27 | SharedPreferences settings = context.getSharedPreferences(meta.getString("android.app.lib_name"), 0); 28 | boolean startup = settings.getBoolean("runStartup", true); 29 | 30 | if (startup){ 31 | 32 | Intent i = new Intent(context, m_class); 33 | context.startService(i); 34 | } 35 | } 36 | catch (Exception e) 37 | { 38 | Log.e("Qt", "Can't create service" + e); 39 | } 40 | 41 | } 42 | 43 | /* Activity class */ 44 | 45 | public void setActivityClass(Class cl){ 46 | 47 | m_class = cl; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /example/MyTestService/MyTestService.pro: -------------------------------------------------------------------------------- 1 | #------------------------------------------------- 2 | # 3 | # Project created by QtCreator 2014-03-26T12:42:37 4 | # 5 | #------------------------------------------------- 6 | 7 | QT += core 8 | 9 | QT -= gui 10 | 11 | TARGET = MyTestService 12 | CONFIG += console 13 | CONFIG -= app_bundle 14 | 15 | TEMPLATE = app 16 | 17 | 18 | SOURCES += main.cpp 19 | 20 | ANDROID_PACKAGE_SOURCE_DIR = $$PWD/android 21 | 22 | OTHER_FILES += \ 23 | android/AndroidManifest.xml 24 | -------------------------------------------------------------------------------- /example/MyTestService/android/Activity-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 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /example/MyTestService/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 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /example/MyTestService/android/README.md: -------------------------------------------------------------------------------- 1 | Qt Android service and activity helper classes 2 | ============================================== 3 | 4 | - First create a project in QtCreator QtQuick or QtWidget for activity based application or "Qt Console Application" for a service based one 5 | 6 | - In project - Android - Run - Advanced actions, create an AndroidManifest 7 | or put the following lines to your .pro 8 | 9 | ANDROID_PACKAGE_SOURCE_DIR = $$PWD/android 10 | 11 | OTHER_FILES += \ 12 | android/AndroidManifest.xml 13 | 14 | 15 | - ! Only bundled Qt librairies have been tested ... 16 | 17 | - Replace the "android" folder that qtcreator have created in your project by this one or if your edited the .pro just put it in your project. 18 | 19 | - Run ./setup.sh in the android folder 20 | - Put your icon.png and notificon.png 21 | -------------------------------------------------------------------------------- /example/MyTestService/android/Service-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 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /example/MyTestService/android/jni/Android.mk: -------------------------------------------------------------------------------- 1 | LOCAL_PATH:= $(call my-dir) 2 | 3 | include $(CLEAR_VARS) 4 | 5 | LOCAL_MODULE := QtAndroidService 6 | LOCAL_CFLAGS := -Werror 7 | LOCAL_SRC_FILES := QtAndroidService.cpp 8 | LOCAL_LDLIBS := -llog 9 | 10 | include $(BUILD_SHARED_LIBRARY) -------------------------------------------------------------------------------- /example/MyTestService/android/jni/QtAndroidService.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | // Global variables 12 | 13 | static jclass m_applicationClass = NULL; 14 | static jobject m_classLoaderObject = NULL; 15 | static jmethodID m_loadClassMethodID = NULL; 16 | static jobject m_resourcesObj; 17 | static jobject m_activityObject = NULL; 18 | 19 | extern "C" typedef int (*Main)(int, char **); //use the standard main method to start the application 20 | static JavaVM *m_javaVM = NULL; 21 | static Main m_main = NULL; 22 | static void *m_mainLibraryHnd = NULL; 23 | 24 | static const char m_classErrorMsg[] = "Can't find class \"%s\""; 25 | static const char m_methodErrorMsg[] = "Can't find method \"%s%s\""; 26 | 27 | // Methods definition 28 | 29 | static jboolean startQtAndroidPlugin(JNIEnv* env, jobject object /*, jobject applicationAssetManager*/) 30 | { 31 | return 1; 32 | } 33 | 34 | static void setDisplayMetrics(JNIEnv */*env*/, jclass /*clazz*/, 35 | jint /*widthPixels*/, jint /*heightPixels*/, 36 | jint desktopWidthPixels, jint desktopHeightPixels, 37 | jdouble xdpi, jdouble ydpi, jdouble scaledDensity) 38 | {} 39 | 40 | // Methods definition 41 | 42 | static void *startMainMethod(void *ar) 43 | { 44 | __android_log_print(ANDROID_LOG_INFO, "Qt", "Calling main method"); 45 | 46 | char *argv[] = { NULL}; 47 | int argc = sizeof(argv) / sizeof(char*) - 1; 48 | 49 | int ret = m_main(argc, argv); 50 | 51 | return NULL; 52 | } 53 | 54 | static jboolean startQtApplication(JNIEnv *env, jobject object, jstring paramsString, jstring environmentString) 55 | { 56 | // Get native 57 | 58 | const char *nativeEnvironmentString = (env)->GetStringUTFChars(environmentString, NULL); // C++ 59 | const char *nativeParamsString = (env)->GetStringUTFChars(paramsString, NULL); // C++ 60 | 61 | // Print info 62 | 63 | __android_log_print(ANDROID_LOG_FATAL, "Qt", "Starting the Qt service"); 64 | 65 | char cwd[1024]; 66 | if (getcwd(cwd, sizeof(cwd)) != NULL) 67 | __android_log_print(ANDROID_LOG_INFO, "Qt", "Current working dir : %s", cwd); 68 | 69 | __android_log_print(ANDROID_LOG_FATAL, "Qt", "Param : %s", nativeParamsString ); 70 | __android_log_print(ANDROID_LOG_FATAL, "Qt", "Env : %s", nativeEnvironmentString ); 71 | 72 | // Start 73 | 74 | m_mainLibraryHnd = NULL; 75 | 76 | // Obtain a handle to the main library (the library that contains the main() function). 77 | // This library should already be loaded, and calling dlopen() will just return a reference to it. 78 | __android_log_print(ANDROID_LOG_INFO, "Qt", "Trying to open %s", nativeParamsString); 79 | m_mainLibraryHnd = dlopen(nativeParamsString, 0); 80 | 81 | if (m_mainLibraryHnd == NULL) { 82 | 83 | __android_log_print(ANDROID_LOG_INFO, "Qt", "No main library was specified; searching entire process (this is slow!)"); 84 | m_main = (Main)dlsym(RTLD_DEFAULT, "main"); 85 | } 86 | else { 87 | 88 | __android_log_print(ANDROID_LOG_INFO, "Qt", "Getting the main method from handler"); 89 | m_main = (Main)dlsym(m_mainLibraryHnd, "main"); 90 | } 91 | 92 | 93 | if (!m_main) { 94 | 95 | __android_log_print(ANDROID_LOG_INFO, "Qt", "Could not find main method"); 96 | return 0; 97 | } 98 | else{ 99 | 100 | __android_log_print(ANDROID_LOG_INFO, "Qt", "Main method found, starting"); 101 | } 102 | 103 | 104 | pthread_t appThread; 105 | return pthread_create(&appThread, NULL, startMainMethod, NULL) == 0; 106 | 107 | //env->ReleaseStringUTFChars(environmentString, nativeString); 108 | } 109 | 110 | static void quitQtAndroidPlugin(JNIEnv *env, jclass clazz) 111 | { 112 | 113 | } 114 | 115 | static void terminateQt(JNIEnv *env, jclass clazz) 116 | { 117 | 118 | } 119 | 120 | // Native methods 121 | 122 | static JNINativeMethod methods[] = { 123 | {"startQtAndroidPlugin", "()Z", (void *)startQtAndroidPlugin}, 124 | {"setDisplayMetrics", "(IIIIDDD)V", (void *)setDisplayMetrics}, 125 | {"startQtApplication", "(Ljava/lang/String;Ljava/lang/String;)V", (void *)startQtApplication}, 126 | {"quitQtAndroidPlugin", "()V", (void *)quitQtAndroidPlugin}, 127 | {"terminateQt", "()V", (void *)terminateQt} 128 | }; 129 | 130 | 131 | // Helpers functions 132 | 133 | #define FIND_AND_CHECK_CLASS(CLASS_NAME) \ 134 | clazz = env->FindClass(CLASS_NAME); \ 135 | if (!clazz) { \ 136 | __android_log_print(ANDROID_LOG_FATAL, "Qt", m_classErrorMsg, CLASS_NAME); \ 137 | return JNI_FALSE; \ 138 | } 139 | 140 | #define GET_AND_CHECK_METHOD(VAR, CLASS, METHOD_NAME, METHOD_SIGNATURE) \ 141 | VAR = env->GetMethodID(CLASS, METHOD_NAME, METHOD_SIGNATURE); \ 142 | if (!VAR) { \ 143 | __android_log_print(ANDROID_LOG_FATAL, "Qt", m_methodErrorMsg, METHOD_NAME, METHOD_SIGNATURE); \ 144 | return JNI_FALSE; \ 145 | } 146 | 147 | #define GET_AND_CHECK_STATIC_METHOD(VAR, CLASS, METHOD_NAME, METHOD_SIGNATURE) \ 148 | VAR = env->GetStaticMethodID(CLASS, METHOD_NAME, METHOD_SIGNATURE); \ 149 | if (!VAR) { \ 150 | __android_log_print(ANDROID_LOG_FATAL, "Qt", m_methodErrorMsg, METHOD_NAME, METHOD_SIGNATURE); \ 151 | return JNI_FALSE; \ 152 | } 153 | 154 | #define GET_AND_CHECK_FIELD(VAR, CLASS, FIELD_NAME, FIELD_SIGNATURE) \ 155 | VAR = env->GetFieldID(CLASS, FIELD_NAME, FIELD_SIGNATURE); \ 156 | if (!VAR) { \ 157 | __android_log_print(ANDROID_LOG_FATAL, "Qt", m_methodErrorMsg, FIELD_NAME, FIELD_SIGNATURE); \ 158 | return JNI_FALSE; \ 159 | } 160 | 161 | #define GET_AND_CHECK_STATIC_FIELD(VAR, CLASS, FIELD_NAME, FIELD_SIGNATURE) \ 162 | VAR = env->GetStaticFieldID(CLASS, FIELD_NAME, FIELD_SIGNATURE); \ 163 | if (!VAR) { \ 164 | __android_log_print(ANDROID_LOG_FATAL, "Qt", m_methodErrorMsg, FIELD_NAME, FIELD_SIGNATURE); \ 165 | return JNI_FALSE; \ 166 | } 167 | 168 | // On load 169 | 170 | jint JNICALL JNI_OnLoad(JavaVM *vm, void *ld) 171 | { 172 | 173 | __android_log_print(ANDROID_LOG_INFO, "Qt", "Qt Android service wrapper start"); 174 | 175 | JNIEnv* env; 176 | if (vm->GetEnv(reinterpret_cast(&env), JNI_VERSION_1_6) != JNI_OK) { 177 | __android_log_print(ANDROID_LOG_FATAL, "Qt", "Can't get env in wrapper start"); \ 178 | return -1; 179 | } 180 | 181 | m_javaVM = vm; 182 | 183 | jclass clazz; 184 | FIND_AND_CHECK_CLASS("org/qtproject/qt5/android/QtNative"); 185 | m_applicationClass = static_cast(env->NewGlobalRef(clazz)); 186 | 187 | __android_log_print(ANDROID_LOG_INFO, "Qt", "Registering native classes for service wrapper"); 188 | 189 | if (env->RegisterNatives(m_applicationClass, methods, sizeof(methods) / sizeof(methods[0])) < 0) { 190 | __android_log_print(ANDROID_LOG_FATAL,"Qt", "RegisterNatives failed for service wrapper"); 191 | return JNI_FALSE; 192 | } 193 | 194 | return JNI_VERSION_1_4; 195 | } 196 | 197 | 198 | -------------------------------------------------------------------------------- /example/MyTestService/android/libs/armeabi/libQtAndroidService.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/think-free-backup/QtAndroidHelper/e50daeaa54c9a08633f645e5cd174f3c1f4a2ba4/example/MyTestService/android/libs/armeabi/libQtAndroidService.so -------------------------------------------------------------------------------- /example/MyTestService/android/libs/guava-10.0.1.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/think-free-backup/QtAndroidHelper/e50daeaa54c9a08633f645e5cd174f3c1f4a2ba4/example/MyTestService/android/libs/guava-10.0.1.jar -------------------------------------------------------------------------------- /example/MyTestService/android/obj/local/armeabi/libQtAndroidService.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/think-free-backup/QtAndroidHelper/e50daeaa54c9a08633f645e5cd174f3c1f4a2ba4/example/MyTestService/android/obj/local/armeabi/libQtAndroidService.so -------------------------------------------------------------------------------- /example/MyTestService/android/obj/local/armeabi/libstdc++.a: -------------------------------------------------------------------------------- 1 | ! 2 | -------------------------------------------------------------------------------- /example/MyTestService/android/obj/local/armeabi/objs/QtAndroidService/QtAndroidService.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/think-free-backup/QtAndroidHelper/e50daeaa54c9a08633f645e5cd174f3c1f4a2ba4/example/MyTestService/android/obj/local/armeabi/objs/QtAndroidService/QtAndroidService.o -------------------------------------------------------------------------------- /example/MyTestService/android/obj/local/armeabi/objs/QtAndroidService/QtAndroidService.o.d: -------------------------------------------------------------------------------- 1 | /home/christophe/Devel/Qt/MyTestService/android/obj/local/armeabi/objs/QtAndroidService/QtAndroidService.o: \ 2 | /home/christophe/Devel/Qt/MyTestService/android/jni/QtAndroidService.cpp \ 3 | /opt/Android/android-ndk-r9b/platforms/android-3/arch-arm/usr/include/dlfcn.h \ 4 | /opt/Android/android-ndk-r9b/platforms/android-3/arch-arm/usr/include/sys/cdefs.h \ 5 | /opt/Android/android-ndk-r9b/platforms/android-3/arch-arm/usr/include/sys/cdefs_elf.h \ 6 | /opt/Android/android-ndk-r9b/platforms/android-3/arch-arm/usr/include/android/api-level.h \ 7 | /opt/Android/android-ndk-r9b/platforms/android-3/arch-arm/usr/include/pthread.h \ 8 | /opt/Android/android-ndk-r9b/platforms/android-3/arch-arm/usr/include/time.h \ 9 | /opt/Android/android-ndk-r9b/platforms/android-3/arch-arm/usr/include/sys/time.h \ 10 | /opt/Android/android-ndk-r9b/platforms/android-3/arch-arm/usr/include/sys/types.h \ 11 | /opt/Android/android-ndk-r9b/platforms/android-3/arch-arm/usr/include/stdint.h \ 12 | /opt/Android/android-ndk-r9b/platforms/android-3/arch-arm/usr/include/sys/_types.h \ 13 | /opt/Android/android-ndk-r9b/platforms/android-3/arch-arm/usr/include/machine/_types.h \ 14 | /opt/Android/android-ndk-r9b/platforms/android-3/arch-arm/usr/include/linux/posix_types.h \ 15 | /opt/Android/android-ndk-r9b/platforms/android-3/arch-arm/usr/include/linux/stddef.h \ 16 | /opt/Android/android-ndk-r9b/platforms/android-3/arch-arm/usr/include/linux/compiler.h \ 17 | /opt/Android/android-ndk-r9b/platforms/android-3/arch-arm/usr/include/asm/posix_types.h \ 18 | /opt/Android/android-ndk-r9b/platforms/android-3/arch-arm/usr/include/asm/types.h \ 19 | /opt/Android/android-ndk-r9b/platforms/android-3/arch-arm/usr/include/linux/types.h \ 20 | /opt/Android/android-ndk-r9b/platforms/android-3/arch-arm/usr/include/machine/kernel.h \ 21 | /opt/Android/android-ndk-r9b/platforms/android-3/arch-arm/usr/include/sys/sysmacros.h \ 22 | /opt/Android/android-ndk-r9b/platforms/android-3/arch-arm/usr/include/linux/time.h \ 23 | /opt/Android/android-ndk-r9b/platforms/android-3/arch-arm/usr/include/asm/siginfo.h \ 24 | /opt/Android/android-ndk-r9b/platforms/android-3/arch-arm/usr/include/asm-generic/siginfo.h \ 25 | /opt/Android/android-ndk-r9b/platforms/android-3/arch-arm/usr/include/signal.h \ 26 | /opt/Android/android-ndk-r9b/platforms/android-3/arch-arm/usr/include/limits.h \ 27 | /opt/Android/android-ndk-r9b/platforms/android-3/arch-arm/usr/include/sys/limits.h \ 28 | /opt/Android/android-ndk-r9b/platforms/android-3/arch-arm/usr/include/linux/limits.h \ 29 | /opt/Android/android-ndk-r9b/platforms/android-3/arch-arm/usr/include/machine/internal_types.h \ 30 | /opt/Android/android-ndk-r9b/platforms/android-3/arch-arm/usr/include/machine/limits.h \ 31 | /opt/Android/android-ndk-r9b/platforms/android-3/arch-arm/usr/include/sys/syslimits.h \ 32 | /opt/Android/android-ndk-r9b/platforms/android-3/arch-arm/usr/include/asm/page.h \ 33 | /opt/Android/android-ndk-r9b/platforms/android-3/arch-arm/usr/include/string.h \ 34 | /opt/Android/android-ndk-r9b/platforms/android-3/arch-arm/usr/include/malloc.h \ 35 | /opt/Android/android-ndk-r9b/platforms/android-3/arch-arm/usr/include/asm/signal.h \ 36 | /opt/Android/android-ndk-r9b/platforms/android-3/arch-arm/usr/include/asm-generic/signal.h \ 37 | /opt/Android/android-ndk-r9b/platforms/android-3/arch-arm/usr/include/sched.h \ 38 | /opt/Android/android-ndk-r9b/platforms/android-3/arch-arm/usr/include/stdlib.h \ 39 | /opt/Android/android-ndk-r9b/platforms/android-3/arch-arm/usr/include/alloca.h \ 40 | /opt/Android/android-ndk-r9b/platforms/android-3/arch-arm/usr/include/strings.h \ 41 | /opt/Android/android-ndk-r9b/platforms/android-3/arch-arm/usr/include/memory.h \ 42 | /opt/Android/android-ndk-r9b/platforms/android-3/arch-arm/usr/include/unistd.h \ 43 | /opt/Android/android-ndk-r9b/platforms/android-3/arch-arm/usr/include/sys/select.h \ 44 | /opt/Android/android-ndk-r9b/platforms/android-3/arch-arm/usr/include/sys/sysconf.h \ 45 | /opt/Android/android-ndk-r9b/platforms/android-3/arch-arm/usr/include/linux/capability.h \ 46 | /opt/Android/android-ndk-r9b/platforms/android-3/arch-arm/usr/include/pathconf.h \ 47 | /opt/Android/android-ndk-r9b/platforms/android-3/arch-arm/usr/include/jni.h \ 48 | /opt/Android/android-ndk-r9b/platforms/android-3/arch-arm/usr/include/android/log.h 49 | 50 | /opt/Android/android-ndk-r9b/platforms/android-3/arch-arm/usr/include/dlfcn.h: 51 | 52 | /opt/Android/android-ndk-r9b/platforms/android-3/arch-arm/usr/include/sys/cdefs.h: 53 | 54 | /opt/Android/android-ndk-r9b/platforms/android-3/arch-arm/usr/include/sys/cdefs_elf.h: 55 | 56 | /opt/Android/android-ndk-r9b/platforms/android-3/arch-arm/usr/include/android/api-level.h: 57 | 58 | /opt/Android/android-ndk-r9b/platforms/android-3/arch-arm/usr/include/pthread.h: 59 | 60 | /opt/Android/android-ndk-r9b/platforms/android-3/arch-arm/usr/include/time.h: 61 | 62 | /opt/Android/android-ndk-r9b/platforms/android-3/arch-arm/usr/include/sys/time.h: 63 | 64 | /opt/Android/android-ndk-r9b/platforms/android-3/arch-arm/usr/include/sys/types.h: 65 | 66 | /opt/Android/android-ndk-r9b/platforms/android-3/arch-arm/usr/include/stdint.h: 67 | 68 | /opt/Android/android-ndk-r9b/platforms/android-3/arch-arm/usr/include/sys/_types.h: 69 | 70 | /opt/Android/android-ndk-r9b/platforms/android-3/arch-arm/usr/include/machine/_types.h: 71 | 72 | /opt/Android/android-ndk-r9b/platforms/android-3/arch-arm/usr/include/linux/posix_types.h: 73 | 74 | /opt/Android/android-ndk-r9b/platforms/android-3/arch-arm/usr/include/linux/stddef.h: 75 | 76 | /opt/Android/android-ndk-r9b/platforms/android-3/arch-arm/usr/include/linux/compiler.h: 77 | 78 | /opt/Android/android-ndk-r9b/platforms/android-3/arch-arm/usr/include/asm/posix_types.h: 79 | 80 | /opt/Android/android-ndk-r9b/platforms/android-3/arch-arm/usr/include/asm/types.h: 81 | 82 | /opt/Android/android-ndk-r9b/platforms/android-3/arch-arm/usr/include/linux/types.h: 83 | 84 | /opt/Android/android-ndk-r9b/platforms/android-3/arch-arm/usr/include/machine/kernel.h: 85 | 86 | /opt/Android/android-ndk-r9b/platforms/android-3/arch-arm/usr/include/sys/sysmacros.h: 87 | 88 | /opt/Android/android-ndk-r9b/platforms/android-3/arch-arm/usr/include/linux/time.h: 89 | 90 | /opt/Android/android-ndk-r9b/platforms/android-3/arch-arm/usr/include/asm/siginfo.h: 91 | 92 | /opt/Android/android-ndk-r9b/platforms/android-3/arch-arm/usr/include/asm-generic/siginfo.h: 93 | 94 | /opt/Android/android-ndk-r9b/platforms/android-3/arch-arm/usr/include/signal.h: 95 | 96 | /opt/Android/android-ndk-r9b/platforms/android-3/arch-arm/usr/include/limits.h: 97 | 98 | /opt/Android/android-ndk-r9b/platforms/android-3/arch-arm/usr/include/sys/limits.h: 99 | 100 | /opt/Android/android-ndk-r9b/platforms/android-3/arch-arm/usr/include/linux/limits.h: 101 | 102 | /opt/Android/android-ndk-r9b/platforms/android-3/arch-arm/usr/include/machine/internal_types.h: 103 | 104 | /opt/Android/android-ndk-r9b/platforms/android-3/arch-arm/usr/include/machine/limits.h: 105 | 106 | /opt/Android/android-ndk-r9b/platforms/android-3/arch-arm/usr/include/sys/syslimits.h: 107 | 108 | /opt/Android/android-ndk-r9b/platforms/android-3/arch-arm/usr/include/asm/page.h: 109 | 110 | /opt/Android/android-ndk-r9b/platforms/android-3/arch-arm/usr/include/string.h: 111 | 112 | /opt/Android/android-ndk-r9b/platforms/android-3/arch-arm/usr/include/malloc.h: 113 | 114 | /opt/Android/android-ndk-r9b/platforms/android-3/arch-arm/usr/include/asm/signal.h: 115 | 116 | /opt/Android/android-ndk-r9b/platforms/android-3/arch-arm/usr/include/asm-generic/signal.h: 117 | 118 | /opt/Android/android-ndk-r9b/platforms/android-3/arch-arm/usr/include/sched.h: 119 | 120 | /opt/Android/android-ndk-r9b/platforms/android-3/arch-arm/usr/include/stdlib.h: 121 | 122 | /opt/Android/android-ndk-r9b/platforms/android-3/arch-arm/usr/include/alloca.h: 123 | 124 | /opt/Android/android-ndk-r9b/platforms/android-3/arch-arm/usr/include/strings.h: 125 | 126 | /opt/Android/android-ndk-r9b/platforms/android-3/arch-arm/usr/include/memory.h: 127 | 128 | /opt/Android/android-ndk-r9b/platforms/android-3/arch-arm/usr/include/unistd.h: 129 | 130 | /opt/Android/android-ndk-r9b/platforms/android-3/arch-arm/usr/include/sys/select.h: 131 | 132 | /opt/Android/android-ndk-r9b/platforms/android-3/arch-arm/usr/include/sys/sysconf.h: 133 | 134 | /opt/Android/android-ndk-r9b/platforms/android-3/arch-arm/usr/include/linux/capability.h: 135 | 136 | /opt/Android/android-ndk-r9b/platforms/android-3/arch-arm/usr/include/pathconf.h: 137 | 138 | /opt/Android/android-ndk-r9b/platforms/android-3/arch-arm/usr/include/jni.h: 139 | 140 | /opt/Android/android-ndk-r9b/platforms/android-3/arch-arm/usr/include/android/log.h: 141 | -------------------------------------------------------------------------------- /example/MyTestService/android/res/drawable-hdpi-v11/notificon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/think-free-backup/QtAndroidHelper/e50daeaa54c9a08633f645e5cd174f3c1f4a2ba4/example/MyTestService/android/res/drawable-hdpi-v11/notificon.png -------------------------------------------------------------------------------- /example/MyTestService/android/res/drawable-hdpi/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/think-free-backup/QtAndroidHelper/e50daeaa54c9a08633f645e5cd174f3c1f4a2ba4/example/MyTestService/android/res/drawable-hdpi/icon.png -------------------------------------------------------------------------------- /example/MyTestService/android/res/drawable-hdpi/notificon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/think-free-backup/QtAndroidHelper/e50daeaa54c9a08633f645e5cd174f3c1f4a2ba4/example/MyTestService/android/res/drawable-hdpi/notificon.png -------------------------------------------------------------------------------- /example/MyTestService/android/res/drawable-mdpi-v11/notificon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/think-free-backup/QtAndroidHelper/e50daeaa54c9a08633f645e5cd174f3c1f4a2ba4/example/MyTestService/android/res/drawable-mdpi-v11/notificon.png -------------------------------------------------------------------------------- /example/MyTestService/android/res/drawable-mdpi/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/think-free-backup/QtAndroidHelper/e50daeaa54c9a08633f645e5cd174f3c1f4a2ba4/example/MyTestService/android/res/drawable-mdpi/icon.png -------------------------------------------------------------------------------- /example/MyTestService/android/res/drawable-mdpi/notificon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/think-free-backup/QtAndroidHelper/e50daeaa54c9a08633f645e5cd174f3c1f4a2ba4/example/MyTestService/android/res/drawable-mdpi/notificon.png -------------------------------------------------------------------------------- /example/MyTestService/android/res/drawable-xhdpi-v11/notificon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/think-free-backup/QtAndroidHelper/e50daeaa54c9a08633f645e5cd174f3c1f4a2ba4/example/MyTestService/android/res/drawable-xhdpi-v11/notificon.png -------------------------------------------------------------------------------- /example/MyTestService/android/res/drawable-xhdpi/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/think-free-backup/QtAndroidHelper/e50daeaa54c9a08633f645e5cd174f3c1f4a2ba4/example/MyTestService/android/res/drawable-xhdpi/icon.png -------------------------------------------------------------------------------- /example/MyTestService/android/res/drawable-xhdpi/notificon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/think-free-backup/QtAndroidHelper/e50daeaa54c9a08633f645e5cd174f3c1f4a2ba4/example/MyTestService/android/res/drawable-xhdpi/notificon.png -------------------------------------------------------------------------------- /example/MyTestService/android/res/drawable-xxhdpi-v11/notificon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/think-free-backup/QtAndroidHelper/e50daeaa54c9a08633f645e5cd174f3c1f4a2ba4/example/MyTestService/android/res/drawable-xxhdpi-v11/notificon.png -------------------------------------------------------------------------------- /example/MyTestService/android/res/drawable-xxhdpi/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/think-free-backup/QtAndroidHelper/e50daeaa54c9a08633f645e5cd174f3c1f4a2ba4/example/MyTestService/android/res/drawable-xxhdpi/icon.png -------------------------------------------------------------------------------- /example/MyTestService/android/res/drawable-xxhdpi/notificon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/think-free-backup/QtAndroidHelper/e50daeaa54c9a08633f645e5cd174f3c1f4a2ba4/example/MyTestService/android/res/drawable-xxhdpi/notificon.png -------------------------------------------------------------------------------- /example/MyTestService/android/res/drawable-xxxhdpi/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/think-free-backup/QtAndroidHelper/e50daeaa54c9a08633f645e5cd174f3c1f4a2ba4/example/MyTestService/android/res/drawable-xxxhdpi/icon.png -------------------------------------------------------------------------------- /example/MyTestService/android/res/layout/serviceconfigactivity.xml: -------------------------------------------------------------------------------- 1 | 10 | 11 | 21 | 22 | 30 | 31 | 40 | 41 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /example/MyTestService/android/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 16dp 5 | 16dp 6 | 7 | 8 | -------------------------------------------------------------------------------- /example/MyTestService/android/res/values/style.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 | 9 | -------------------------------------------------------------------------------- /example/MyTestService/android/setup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # This script will setup the android folder for an activity or a service based qt application 4 | 5 | # Functions 6 | 7 | function setup(){ 8 | 9 | clear 10 | 11 | echo "" 12 | echo "Please enter your package name (ex : org.qt-project.myqtapplication) : " 13 | read package 14 | 15 | app=`ls ../*.pro | cut -d '/' -f 2 | cut -d '.' -f 1` 16 | 17 | if [ "$app" == "" ]; 18 | then 19 | echo "Can't find .pro in ../ exiting" 20 | exit 1 21 | fi 22 | 23 | echo "" 24 | echo "Do you want to create an activity or a service based application ? [a/s]" 25 | read tp 26 | 27 | if [ "$tp" == "a" ]; 28 | then 29 | 30 | activity $package $app 31 | 32 | elif [ "$tp" == "s" ]; 33 | then 34 | 35 | service $package $app 36 | 37 | else 38 | 39 | clear 40 | echo "Bad selection" 41 | sleep 2 42 | setup 43 | fi 44 | } 45 | 46 | function activity(){ 47 | 48 | echo "You've selected an activity based application" 49 | 50 | cp Activity-AndroidManifest.xml AndroidManifest.xml 51 | 52 | echo "Cleaning un-necesary files" 53 | ################################# 54 | 55 | rm -rf src/org/qtproject/qt5/android/addons/qtserviceapp 56 | rm src/org/qtproject/qt5/android/QtServiceDelegate.java 57 | 58 | echo "Configuring manifest" 59 | ########################### 60 | 61 | sed -i "s|org.qtproject.qt5.android.addons|$1|" AndroidManifest.xml 62 | sed -i "s|qtactivityapp.QtServiceActivity|$2Activity|g" AndroidManifest.xml 63 | sed -i "s|qtactivityapp.QtService|$2Service|g" AndroidManifest.xml 64 | 65 | echo "Creating package folders" 66 | ############################### 67 | 68 | fld=src/$(sed 's|\.|/|g' <<< $1) 69 | mkdir -p $fld 70 | 71 | 72 | echo "Configuring activity" 73 | ########################### 74 | 75 | 76 | echo "" 77 | echo "Do you want to use a sticky notification with service ? [y/n]" 78 | read sticky 79 | 80 | 81 | echo "package $1;" >> $fld/$2Activity.java 82 | 83 | echo "import org.qtproject.qt5.android.addons.qtactivityapp.QtServiceActivity;" >> $fld/$2Activity.java 84 | echo "import org.qtproject.qt5.android.addons.qtactivityapp.QtService;" >> $fld/$2Activity.java 85 | echo "import android.os.Bundle;" >> $fld/$2Activity.java 86 | echo "import android.content.Intent;" >> $fld/$2Activity.java 87 | echo "import android.content.ComponentName;" >> $fld/$2Activity.java 88 | echo "import android.util.Log;" >> $fld/$2Activity.java 89 | 90 | echo "public class $2Activity extends QtServiceActivity" >> $fld/$2Activity.java 91 | echo "{" >> $fld/$2Activity.java 92 | echo " public void onCreate(Bundle savedInstanceState)" >> $fld/$2Activity.java 93 | echo " {" >> $fld/$2Activity.java 94 | echo " Log.w(getClass().getName(), "Starting config editor");" >> $fld/$2Activity.java 95 | 96 | if [ "$sticky" == "y" ]; 97 | then 98 | echo " super.setServiceClass($2Service.java);" >> $fld/$2Activity.java 99 | else 100 | echo " super.setServiceClass(null);" >> $fld/$2Activity.java 101 | fi 102 | 103 | echo " super.onCreate(savedInstanceState);" >> $fld/$2Activity.java 104 | echo " }" >> $fld/$2Activity.java 105 | echo "}" >> $fld/$2Activity.java 106 | 107 | 108 | echo "Configuring service" 109 | ########################## 110 | 111 | echo "package $1;" >> $fld/$2Service.java 112 | 113 | echo "import org.qtproject.qt5.android.addons.qtactivityapp.QtService;" >> $fld/$2Service.java 114 | echo "import android.util.Log;" >> $fld/$2Service.java 115 | 116 | echo "public class $2Service extends QtService" >> $fld/$2Service.java 117 | echo "{" >> $fld/$2Service.java 118 | echo " public void onCreate()" >> $fld/$2Service.java 119 | echo " {" >> $fld/$2Service.java 120 | echo " Log.w(getClass().getName(), "Starting config editor service");" >> $fld/$2Service.java 121 | echo " super.setActivityClass($2Activity.class);" >> $fld/$2Service.java 122 | echo " super.onCreate();" >> $fld/$2Service.java 123 | echo " }" >> $fld/$2Service.java 124 | echo "}" >> $fld/$2Service.java 125 | 126 | } 127 | 128 | function service(){ 129 | 130 | echo "You've selected a service based application" 131 | ################################################## 132 | 133 | cp Service-AndroidManifest.xml AndroidManifest.xml 134 | 135 | echo "Compiling helper librairy" 136 | ################################ 137 | 138 | cd jni 139 | ndk-build 140 | cd .. 141 | 142 | echo "Cleaning un-necesary files" 143 | ################################# 144 | 145 | rm -rf src/org/qtproject/qt5/android/addons/qtactivityapp 146 | 147 | echo "Configuring manifest" 148 | ########################### 149 | 150 | sed -i "s|org.qtproject.qt5.android.addons|$1|" AndroidManifest.xml 151 | sed -i "s|qtserviceapp.QtService|$2|g" AndroidManifest.xml 152 | sed -i "s|QtServiceActivity|$2|g" AndroidManifest.xml 153 | 154 | sed -i "s|import R;|import $1.R;|" src/org/qtproject/qt5/android/addons/qtserviceapp/QtServiceActivity.java # FIXME !!!! 155 | 156 | 157 | echo "Creating package folders" 158 | ############################### 159 | 160 | fld=src/$(sed 's|\.|/|g' <<< $1) 161 | mkdir -p $fld 162 | 163 | 164 | echo "Configuring Service" 165 | ########################## 166 | 167 | echo "package $1;" >> $fld/$2.java 168 | 169 | echo "import org.qtproject.qt5.android.addons.qtserviceapp.QtService;" >> $fld/$2.java 170 | echo "import android.util.Log;" >> $fld/$2.java 171 | 172 | echo "public class $2 extends QtService {" >> $fld/$2.java 173 | 174 | echo " public void onCreate()" >> $fld/$2.java 175 | echo " {" >> $fld/$2.java 176 | echo " Log.w(getClass().getName(), \"Starting datasync service\");" >> $fld/$2.java 177 | echo " super.setActivityClass($2Activity.class);" >> $fld/$2.java 178 | echo " super.onCreate();" >> $fld/$2.java 179 | echo " }" >> $fld/$2.java 180 | echo "}" >> $fld/$2.java 181 | echo "" >> $fld/$2.java 182 | 183 | 184 | echo "Configuring service activity" 185 | ################################### 186 | 187 | echo "package $1;" >> $fld/$2Activity.java 188 | 189 | echo "import $1.R;" >> $fld/$2Activity.java 190 | 191 | echo "import org.qtproject.qt5.android.addons.qtserviceapp.QtServiceActivity;" >> $fld/$2Activity.java 192 | 193 | echo "import android.os.Bundle;" >> $fld/$2Activity.java 194 | echo "import android.util.Log;" >> $fld/$2Activity.java 195 | 196 | echo "public class $2Activity extends QtServiceActivity {" >> $fld/$2Activity.java 197 | 198 | echo " @Override" >> $fld/$2Activity.java 199 | echo " public void onCreate(Bundle savedInstanceState)" >> $fld/$2Activity.java 200 | echo " {" >> $fld/$2Activity.java 201 | echo " Log.w(getClass().getName(), \"Starting datasync service activity\");" >> $fld/$2Activity.java 202 | echo " super.setActivityClass($2.class);" >> $fld/$2Activity.java 203 | echo " super.onCreate(savedInstanceState);" >> $fld/$2Activity.java 204 | echo " }" >> $fld/$2Activity.java 205 | echo "}" >> $fld/$2Activity.java 206 | echo "" >> $fld/$2Activity.java 207 | 208 | 209 | echo "Configuring broadcast receiver (to be run at startup)" 210 | ############################################################ 211 | 212 | echo "package $1;" >> $fld/$2BroadcastReceiver.java 213 | 214 | echo "import org.qtproject.qt5.android.addons.qtserviceapp.QtServiceBroadcastReceiver;" >> $fld/$2BroadcastReceiver.java 215 | 216 | echo "import android.content.Context;" >> $fld/$2BroadcastReceiver.java 217 | echo "import android.content.Intent;" >> $fld/$2BroadcastReceiver.java 218 | echo "import android.util.Log;" >> $fld/$2BroadcastReceiver.java 219 | 220 | echo "public class $2BroadcastReceiver extends QtServiceBroadcastReceiver {" >> $fld/$2BroadcastReceiver.java 221 | 222 | echo " @Override" >> $fld/$2BroadcastReceiver.java 223 | echo " public void onReceive(Context context, Intent intent) {" >> $fld/$2BroadcastReceiver.java 224 | 225 | echo " Log.w(getClass().getName(), \"Broadcast received for Comservice\");" >> $fld/$2BroadcastReceiver.java 226 | 227 | echo " super.setActivityClass($2.class);" >> $fld/$2BroadcastReceiver.java 228 | echo " super.onReceive(context, intent);" >> $fld/$2BroadcastReceiver.java 229 | echo " }" >> $fld/$2BroadcastReceiver.java 230 | echo "}" >> $fld/$2BroadcastReceiver.java 231 | echo "" >> $fld/$2BroadcastReceiver.java 232 | } 233 | 234 | # Main 235 | 236 | clear 237 | echo "" 238 | echo "This script will allow you to setup a qt activity based application with a service that run a sticky notification or a service based application (without grafical interface)" 239 | echo "First create a qt project in qtcreator " 240 | echo "Please ensure that ndk-build (android-ndk) is in your path before continuing" 241 | echo "" 242 | echo "Press any key to continue" 243 | read 244 | 245 | setup 246 | 247 | clear 248 | echo "Almost done, please create an icon.png and a notificon.png for every resolution you want to support in the res folder" 249 | echo "You can use : http://android-ui-utils.googlecode.com/hg/asset-studio/dist/index.html to create it" 250 | -------------------------------------------------------------------------------- /example/MyTestService/android/src/com/mycompany/test1/MyTestService.java: -------------------------------------------------------------------------------- 1 | package com.mycompany.test1; 2 | import org.qtproject.qt5.android.addons.qtserviceapp.QtService; 3 | import android.util.Log; 4 | public class MyTestService extends QtService { 5 | public void onCreate() 6 | { 7 | Log.w(getClass().getName(), "Starting datasync service"); 8 | super.setActivityClass(MyTestServiceActivity.class); 9 | super.onCreate(); 10 | } 11 | } 12 | 13 | -------------------------------------------------------------------------------- /example/MyTestService/android/src/com/mycompany/test1/MyTestServiceActivity.java: -------------------------------------------------------------------------------- 1 | package com.mycompany.test1; 2 | import com.mycompany.test1.R; 3 | import org.qtproject.qt5.android.addons.qtserviceapp.QtServiceActivity; 4 | import android.os.Bundle; 5 | import android.util.Log; 6 | public class MyTestServiceActivity extends QtServiceActivity { 7 | @Override 8 | public void onCreate(Bundle savedInstanceState) 9 | { 10 | Log.w(getClass().getName(), "Starting datasync service activity"); 11 | super.setActivityClass(MyTestService.class); 12 | super.onCreate(savedInstanceState); 13 | } 14 | } 15 | 16 | -------------------------------------------------------------------------------- /example/MyTestService/android/src/com/mycompany/test1/MyTestServiceBroadcastReceiver.java: -------------------------------------------------------------------------------- 1 | package com.mycompany.test1; 2 | import org.qtproject.qt5.android.addons.qtserviceapp.QtServiceBroadcastReceiver; 3 | import android.content.Context; 4 | import android.content.Intent; 5 | import android.util.Log; 6 | public class MyTestServiceBroadcastReceiver extends QtServiceBroadcastReceiver { 7 | @Override 8 | public void onReceive(Context context, Intent intent) { 9 | Log.w(getClass().getName(), "Broadcast received for Comservice"); 10 | super.setActivityClass(MyTestService.class); 11 | super.onReceive(context, intent); 12 | } 13 | } 14 | 15 | -------------------------------------------------------------------------------- /example/MyTestService/android/src/org/qtproject/qt5/android/QtServiceDelegate.java: -------------------------------------------------------------------------------- 1 | 2 | package org.qtproject.qt5.android; 3 | 4 | import java.io.File; 5 | import java.io.FileWriter; 6 | import java.io.IOException; 7 | import java.lang.reflect.Method; 8 | import java.util.ArrayList; 9 | import java.util.Iterator; 10 | 11 | import android.app.Service; 12 | import android.content.Context; 13 | import android.content.pm.ApplicationInfo; 14 | import android.content.pm.PackageManager; 15 | import android.content.pm.PackageManager.NameNotFoundException; 16 | import android.content.res.Configuration; 17 | import android.graphics.Rect; 18 | import android.os.Build; 19 | import android.os.Bundle; 20 | import android.util.Log; 21 | 22 | public class QtServiceDelegate 23 | { 24 | private Service m_service = null; 25 | 26 | private static final String NATIVE_LIBRARIES_KEY = "native.libraries"; 27 | private static final String BUNDLED_LIBRARIES_KEY = "bundled.libraries"; 28 | private static final String MAIN_LIBRARY_KEY = "main.library"; 29 | private static final String ENVIRONMENT_VARIABLES_KEY = "environment.variables"; 30 | private static final String APPLICATION_PARAMETERS_KEY = "application.parameters"; 31 | private static final String STATIC_INIT_CLASSES_KEY = "static.init.classes"; 32 | private static final String NECESSITAS_API_LEVEL_KEY = "necessitas.api.level"; 33 | 34 | private static String m_environmentVariables = null; 35 | private static String m_applicationParameters = null; 36 | 37 | private String m_mainLib; 38 | 39 | public boolean loadApplication(Service service, ClassLoader classLoader, Bundle loaderParams) 40 | { 41 | if (!loaderParams.containsKey(NATIVE_LIBRARIES_KEY)) 42 | Log.w(getClass().getName(), "Missing parameters1 in loaderParams"); 43 | 44 | if (!loaderParams.containsKey(BUNDLED_LIBRARIES_KEY)) 45 | Log.w(getClass().getName(), "Missing parameters2 in loaderParams"); 46 | 47 | /// check parameters integrity 48 | if (!loaderParams.containsKey(NATIVE_LIBRARIES_KEY) 49 | || !loaderParams.containsKey(BUNDLED_LIBRARIES_KEY)) { 50 | 51 | Log.w(getClass().getName(), "Missing parameters in loaderParams"); 52 | return false; 53 | } 54 | 55 | m_service = service; 56 | //QtNative.setActivity(m_activity, this); 57 | QtNative.setClassLoader(classLoader); 58 | if (loaderParams.containsKey(STATIC_INIT_CLASSES_KEY)) { 59 | for (String className: loaderParams.getStringArray(STATIC_INIT_CLASSES_KEY)) { 60 | Log.w(getClass().getName(), className); 61 | if (className.length() == 0) 62 | continue; 63 | 64 | try { 65 | @SuppressWarnings("rawtypes") 66 | Class initClass = classLoader.loadClass(className); 67 | Object staticInitDataObject = initClass.newInstance(); // create an instance 68 | //Method m = initClass.getMethod("setActivity", Activity.class, Object.class); 69 | //m.invoke(staticInitDataObject, m_activity, this); 70 | } catch (Exception e) { 71 | e.printStackTrace(); 72 | } 73 | } 74 | } 75 | 76 | QtNative.loadQtLibraries(loaderParams.getStringArrayList(NATIVE_LIBRARIES_KEY)); 77 | ArrayList libraries = loaderParams.getStringArrayList(BUNDLED_LIBRARIES_KEY); 78 | QtNative.loadBundledLibraries(libraries, QtNativeNativeLibrariesDir(m_service)); 79 | m_mainLib = loaderParams.getString(MAIN_LIBRARY_KEY); 80 | // older apps provide the main library as the last bundled library; look for this if the main library isn't provided 81 | if (null == m_mainLib && libraries.size() > 0) 82 | m_mainLib = libraries.get(libraries.size() - 1); 83 | 84 | 85 | int necessitasApiLevel = 1; 86 | if (loaderParams.containsKey(NECESSITAS_API_LEVEL_KEY)) 87 | necessitasApiLevel = loaderParams.getInt(NECESSITAS_API_LEVEL_KEY); 88 | 89 | m_environmentVariables =""; 90 | 91 | if (loaderParams.containsKey(APPLICATION_PARAMETERS_KEY)) 92 | m_applicationParameters = loaderParams.getString(APPLICATION_PARAMETERS_KEY); 93 | else 94 | m_applicationParameters = ""; 95 | 96 | return true; 97 | } 98 | 99 | public void debugLog(String msg) 100 | { 101 | Log.i(QtNative.QtTAG, "DEBUGGER: " + msg); 102 | } 103 | 104 | public boolean startApplication() 105 | { 106 | 107 | try { 108 | 109 | String nativeLibraryDir = QtNativeNativeLibrariesDir(m_service); 110 | 111 | Log.i(QtNative.QtTAG, "LIB DIR : " + nativeLibraryDir); 112 | 113 | //QtNativeStartApplication 114 | QtNative.startApplication 115 | ( m_applicationParameters, 116 | m_environmentVariables, 117 | m_mainLib, 118 | nativeLibraryDir); 119 | return true; 120 | } 121 | catch (Exception e) { 122 | 123 | e.printStackTrace(); 124 | return false; 125 | } 126 | } 127 | 128 | public static String QtNativeNativeLibrariesDir(Service service) 129 | { 130 | String m_nativeLibraryDir = null; 131 | try { 132 | ApplicationInfo ai = service.getPackageManager().getApplicationInfo(service.getPackageName(), 0); 133 | m_nativeLibraryDir = ai.nativeLibraryDir+"/"; 134 | } catch (NameNotFoundException e) { 135 | e.printStackTrace(); 136 | } 137 | return m_nativeLibraryDir; 138 | } 139 | 140 | 141 | public static boolean QtNativeStartApplication(String params, 142 | String environment, 143 | String mainLibrary, 144 | String nativeLibraryDir) throws Exception 145 | { 146 | File f = new File(nativeLibraryDir + "lib" + mainLibrary + ".so"); 147 | if (!f.exists()) 148 | throw new Exception("Can't find main library '" + mainLibrary + "'"); 149 | 150 | if (params == null) 151 | params = "-platform\tandroid"; 152 | 153 | boolean res = false; 154 | 155 | if (params.length() > 0 && !params.startsWith("\t")) 156 | params = "\t" + params; 157 | startQtApplication(f.getAbsolutePath() + params, environment); 158 | 159 | return res; 160 | } 161 | 162 | public static native void startQtApplication(String params, String env); 163 | } 164 | -------------------------------------------------------------------------------- /example/MyTestService/android/src/org/qtproject/qt5/android/addons/qtserviceapp/QtService.java: -------------------------------------------------------------------------------- 1 | package org.qtproject.qt5.android.addons.qtserviceapp; 2 | 3 | import java.lang.reflect.Method; 4 | import java.util.ArrayList; 5 | import java.util.Arrays; 6 | 7 | import dalvik.system.DexClassLoader; 8 | 9 | import android.annotation.SuppressLint; 10 | import android.app.Notification; 11 | import android.app.NotificationManager; 12 | import android.app.PendingIntent; 13 | import android.app.Service; 14 | import android.content.ComponentName; 15 | import android.content.Context; 16 | import android.content.pm.PackageManager; 17 | import android.content.pm.ServiceInfo; 18 | import android.content.Intent; 19 | import android.os.Bundle; 20 | import android.os.IBinder; 21 | import android.util.Log; 22 | import android.os.Process; 23 | import android.widget.Toast; 24 | 25 | @SuppressLint("NewApi") 26 | public class QtService extends Service { 27 | 28 | /* Private variables */ 29 | 30 | public Boolean started=false; 31 | private String[] m_qtLibs = null; 32 | private DexClassLoader m_classLoader = null; 33 | 34 | private Class m_class = QtServiceActivity.class; 35 | 36 | private static ServiceInfo m_serviceInfo = null; 37 | protected static NotificationManager m_notificationManager; 38 | protected static Notification.Builder m_builder; 39 | protected static PendingIntent pi; 40 | private static QtService m_instance; 41 | private static String m_lib_name; 42 | 43 | private static final String ERROR_CODE_KEY = "error.code"; 44 | private static final String DEX_PATH_KEY = "dex.path"; 45 | private static final String STATIC_INIT_CLASSES_KEY = "static.init.classes"; 46 | private static final String NATIVE_LIBRARIES_KEY = "native.libraries"; 47 | private static final String MAIN_LIBRARY_KEY = "main.library"; 48 | private static final String BUNDLED_LIBRARIES_KEY = "bundled.libraries"; 49 | private static final String LOADER_CLASS_NAME_KEY = "loader.class.name"; 50 | private static final String LIB_PATH_KEY = "lib.path"; 51 | private static final String ENVIRONMENT_VARIABLES_KEY = "env.variable"; 52 | 53 | /* Service methods */ 54 | 55 | public void onCreate (){ 56 | 57 | Log.w(getClass().getName(), "Service created ..."); 58 | 59 | m_instance = this; 60 | 61 | try{ 62 | ComponentName myService = new ComponentName(this, this.getClass()); 63 | m_serviceInfo = getPackageManager().getServiceInfo(myService, PackageManager.GET_META_DATA); 64 | m_lib_name = splitCamelCase (m_serviceInfo.metaData.getString("android.app.lib_name")); 65 | } 66 | catch (Exception e) { 67 | 68 | e.printStackTrace(); 69 | } 70 | } 71 | 72 | public IBinder onBind(Intent intent) { 73 | 74 | return null; 75 | } 76 | 77 | @SuppressWarnings("deprecation") 78 | public int onStartCommand(Intent intent, int flags, int startId) 79 | { 80 | 81 | /* Notification */ 82 | 83 | createNotification(); 84 | 85 | /* Start the app */ 86 | 87 | startApp(); 88 | 89 | /* Return */ 90 | 91 | return(START_STICKY); 92 | } 93 | 94 | public void onDestroy(){ 95 | 96 | Log.w(getClass().getName(), "Service destroyed ..."); 97 | 98 | Process.killProcess(Process.myPid()); 99 | } 100 | 101 | /* Internals methods */ 102 | 103 | private void startApp(){ 104 | 105 | if (!started){ 106 | 107 | started = true; 108 | Toast.makeText(getBaseContext(), m_lib_name + " starting", Toast.LENGTH_LONG).show(); 109 | 110 | try{ 111 | 112 | if (m_serviceInfo.metaData.containsKey("android.app.qt_libs_resource_id")) { 113 | int resourceId = m_serviceInfo.metaData.getInt("android.app.qt_libs_resource_id"); 114 | m_qtLibs = getResources().getStringArray(resourceId); 115 | } 116 | 117 | if (m_serviceInfo.metaData.containsKey("android.app.use_local_qt_libs") 118 | && m_serviceInfo.metaData.getInt("android.app.use_local_qt_libs") == 1) { 119 | ArrayList libraryList = new ArrayList(); 120 | 121 | 122 | String localPrefix = "/data/local/tmp/qt/"; 123 | if (m_serviceInfo.metaData.containsKey("android.app.libs_prefix")) 124 | localPrefix = m_serviceInfo.metaData.getString("android.app.libs_prefix"); 125 | 126 | boolean bundlingQtLibs = false; 127 | if (m_serviceInfo.metaData.containsKey("android.app.bundle_local_qt_libs") 128 | && m_serviceInfo.metaData.getInt("android.app.bundle_local_qt_libs") == 1) { 129 | localPrefix = getApplicationInfo().dataDir + "/"; 130 | bundlingQtLibs = true; 131 | } 132 | 133 | if (m_qtLibs != null) { 134 | for (int i=0;i 0) { 150 | if (dexPaths.length() > 0) 151 | dexPaths += pathSeparator; 152 | dexPaths += localPrefix + jar; 153 | } 154 | } 155 | } 156 | 157 | Bundle loaderParams = new Bundle(); 158 | loaderParams.putInt(ERROR_CODE_KEY, 0); 159 | loaderParams.putString(DEX_PATH_KEY, dexPaths); 160 | loaderParams.putString(LOADER_CLASS_NAME_KEY, "org.qtproject.qt5.android.QtServiceDelegate"); 161 | loaderParams.putString(ENVIRONMENT_VARIABLES_KEY, ""); 162 | if (m_serviceInfo.metaData.containsKey("android.app.static_init_classes")) { 163 | loaderParams.putStringArray(STATIC_INIT_CLASSES_KEY, 164 | m_serviceInfo.metaData.getString("android.app.static_init_classes").split(":")); 165 | } 166 | loaderParams.putStringArrayList(NATIVE_LIBRARIES_KEY, libraryList); 167 | 168 | loadApplication(loaderParams); 169 | return; 170 | } 171 | } 172 | catch (Exception e) { 173 | started = false; 174 | e.printStackTrace(); 175 | } 176 | } 177 | } 178 | 179 | @SuppressLint("NewApi") 180 | public void loadApplication(Bundle loaderParams){ 181 | 182 | try{ 183 | 184 | ArrayList libs = new ArrayList(); 185 | if ( m_serviceInfo.metaData.containsKey("android.app.bundled_libs_resource_id") ) 186 | libs.addAll(Arrays.asList(getResources().getStringArray(m_serviceInfo.metaData.getInt("android.app.bundled_libs_resource_id")))); 187 | 188 | String libName = null; 189 | if ( m_serviceInfo.metaData.containsKey("android.app.lib_name") ) { 190 | libName = m_serviceInfo.metaData.getString("android.app.lib_name"); 191 | loaderParams.putString(MAIN_LIBRARY_KEY, libName); //main library contains main() function 192 | } 193 | 194 | loaderParams.putStringArrayList(BUNDLED_LIBRARIES_KEY, libs); 195 | loaderParams.putString(ENVIRONMENT_VARIABLES_KEY, ""); 196 | 197 | m_classLoader = new DexClassLoader(loaderParams.getString(DEX_PATH_KEY), // .jar/.apk files 198 | getDir("outdex", Context.MODE_PRIVATE).getAbsolutePath(), // directory where optimized DEX files should be written. 199 | loaderParams.containsKey(LIB_PATH_KEY) ? loaderParams.getString(LIB_PATH_KEY) : null, // libs folder (if exists) 200 | getClassLoader()); // parent loader 201 | 202 | String loaderClassName = loaderParams.getString(LOADER_CLASS_NAME_KEY); 203 | 204 | Log.w(getClass().getName(), "Loader : " + loaderClassName); 205 | 206 | Class loaderClass = m_classLoader.loadClass(loaderClassName); // load QtLoader class 207 | Object qtLoader = loaderClass.newInstance(); // create an instance 208 | 209 | Method perpareAppMethod = qtLoader.getClass().getMethod("loadApplication", 210 | Service.class, 211 | ClassLoader.class, 212 | Bundle.class); 213 | 214 | if (!(Boolean)perpareAppMethod.invoke(qtLoader, this, m_classLoader, loaderParams)) 215 | throw new Exception(""); 216 | 217 | // now load the application library so it's accessible from this class loader 218 | if (libName != null) 219 | System.loadLibrary(libName); 220 | 221 | Method startAppMethod=qtLoader.getClass().getMethod("startApplication"); 222 | if (!(Boolean)startAppMethod.invoke(qtLoader)) 223 | throw new Exception(""); 224 | 225 | 226 | } 227 | catch (Exception e) { 228 | e.printStackTrace(); 229 | } 230 | } 231 | 232 | /* Activity class */ 233 | 234 | public void setActivityClass(Class cl){ 235 | 236 | m_class = cl; 237 | } 238 | 239 | 240 | /* Notification methods */ 241 | 242 | protected void createNotification(){ 243 | 244 | Notification note=new Notification(m_serviceInfo.metaData.getInt("android.app.notificon"),"",System.currentTimeMillis()); 245 | 246 | Intent i=new Intent(m_instance, m_class); 247 | i.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP|Intent.FLAG_ACTIVITY_SINGLE_TOP); 248 | 249 | pi=PendingIntent.getActivity(this, 0, 250 | i, 0); 251 | 252 | note.setLatestEventInfo(this, m_lib_name , 253 | "Running", 254 | pi); 255 | note.flags|=Notification.FLAG_NO_CLEAR; 256 | 257 | startForeground(1337, note); 258 | } 259 | 260 | public static void notify(String s) 261 | { 262 | if (m_notificationManager == null) { 263 | 264 | m_notificationManager = (NotificationManager)m_instance.getSystemService(Context.NOTIFICATION_SERVICE); 265 | m_builder = new Notification.Builder(m_instance); 266 | m_builder.setSmallIcon(m_serviceInfo.metaData.getInt("android.app.notificon")); 267 | m_builder.setContentTitle(m_lib_name); 268 | m_builder.setContentIntent(pi); 269 | } 270 | 271 | m_builder.setContentText(s); 272 | Notification note = m_builder.build(); 273 | note.flags |= Notification.FLAG_NO_CLEAR; 274 | 275 | m_notificationManager.notify(1337, note); 276 | } 277 | 278 | /* Helpers */ 279 | 280 | static String splitCamelCase(String sp) { 281 | 282 | String s = Character.toUpperCase(sp.charAt(0)) + sp.substring(1); 283 | 284 | return s.replaceAll( 285 | String.format("%s|%s|%s", 286 | "(?<=[A-Z])(?=[A-Z][a-z])", 287 | "(?<=[^A-Z])(?=[A-Z])", 288 | "(?<=[A-Za-z])(?=[^A-Za-z])" 289 | ), 290 | " " 291 | ); 292 | } 293 | } 294 | -------------------------------------------------------------------------------- /example/MyTestService/android/src/org/qtproject/qt5/android/addons/qtserviceapp/QtServiceActivity.java: -------------------------------------------------------------------------------- 1 | package org.qtproject.qt5.android.addons.qtserviceapp; 2 | 3 | import com.mycompany.test1.R; 4 | 5 | import android.app.Activity; 6 | import android.app.ActivityManager; 7 | import android.app.ActivityManager.RunningServiceInfo; 8 | import android.os.Bundle; 9 | import android.content.ComponentName; 10 | import android.content.Context; 11 | import android.content.Intent; 12 | import android.content.SharedPreferences; 13 | import android.content.SharedPreferences.Editor; 14 | import android.content.pm.ActivityInfo; 15 | import android.content.pm.PackageManager; 16 | import android.content.pm.ServiceInfo; 17 | import android.content.pm.PackageManager.NameNotFoundException; 18 | import android.widget.CompoundButton; 19 | import android.widget.Switch; 20 | 21 | public class QtServiceActivity extends Activity { 22 | 23 | private Intent i; 24 | private Class m_class = QtService.class; 25 | 26 | @Override 27 | public void onCreate(Bundle savedInstanceState) 28 | { 29 | 30 | super.onCreate(savedInstanceState); 31 | setContentView(R.layout.serviceconfigactivity); 32 | 33 | i = new Intent(this, m_class); 34 | 35 | final Switch sRun = (Switch) findViewById(R.id.switch_run); 36 | sRun.setChecked(isMyServiceRunning()); 37 | sRun.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { 38 | 39 | @Override 40 | public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { 41 | 42 | if (isChecked) 43 | startService(i); 44 | else 45 | stopService(i); 46 | } 47 | }); 48 | 49 | ComponentName myActivity = new ComponentName(this, this.getClass()); 50 | ActivityInfo activityInfo = null; 51 | try { 52 | activityInfo = getPackageManager().getActivityInfo(myActivity, PackageManager.GET_META_DATA); 53 | } 54 | catch (NameNotFoundException e) { 55 | e.printStackTrace(); 56 | } 57 | 58 | SharedPreferences settings = getBaseContext().getSharedPreferences(activityInfo.metaData.getString("android.app.lib_name"), 0); 59 | final Editor editor = settings.edit(); 60 | 61 | boolean startup = settings.getBoolean("runStartup", true); 62 | 63 | final Switch sRunStartup = (Switch) findViewById(R.id.switch_runstartup); 64 | sRunStartup.setChecked(startup); 65 | sRunStartup.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { 66 | 67 | @Override 68 | public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { 69 | 70 | editor.putBoolean("runStartup", isChecked); 71 | editor.commit(); 72 | } 73 | }); 74 | } 75 | 76 | private boolean isMyServiceRunning() { 77 | ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE); 78 | for (RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) { 79 | if (m_class.getName().equals(service.service.getClassName())) { 80 | return true; 81 | } 82 | } 83 | return false; 84 | } 85 | 86 | /* Activity class */ 87 | 88 | public void setActivityClass(Class cl){ 89 | 90 | m_class = cl; 91 | } 92 | 93 | } 94 | -------------------------------------------------------------------------------- /example/MyTestService/android/src/org/qtproject/qt5/android/addons/qtserviceapp/QtServiceBroadcastReceiver.java: -------------------------------------------------------------------------------- 1 | package org.qtproject.qt5.android.addons.qtserviceapp; 2 | 3 | import android.content.BroadcastReceiver; 4 | import android.content.ComponentName; 5 | import android.content.Context; 6 | import android.content.Intent; 7 | import android.content.SharedPreferences; 8 | import android.content.pm.ActivityInfo; 9 | import android.content.pm.PackageManager; 10 | import android.os.Bundle; 11 | import android.util.Log; 12 | 13 | public class QtServiceBroadcastReceiver extends BroadcastReceiver { 14 | 15 | private Class m_class = QtService.class; 16 | 17 | @Override 18 | public void onReceive(Context context, Intent intent) { 19 | 20 | Log.w("Qt", "Starting service"); 21 | 22 | try 23 | { 24 | ActivityInfo activityInfo = context.getPackageManager().getReceiverInfo(new ComponentName(context, this.getClass()), PackageManager.GET_META_DATA); 25 | Bundle meta = activityInfo.metaData; 26 | 27 | SharedPreferences settings = context.getSharedPreferences(meta.getString("android.app.lib_name"), 0); 28 | boolean startup = settings.getBoolean("runStartup", true); 29 | 30 | if (startup){ 31 | 32 | Intent i = new Intent(context, m_class); 33 | context.startService(i); 34 | } 35 | } 36 | catch (Exception e) 37 | { 38 | Log.e("Qt", "Can't create service" + e); 39 | } 40 | 41 | } 42 | 43 | /* Activity class */ 44 | 45 | public void setActivityClass(Class cl){ 46 | 47 | m_class = cl; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /example/MyTestService/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(int argc, char *argv[]) 4 | { 5 | QCoreApplication a(argc, argv); 6 | 7 | qDebug("Qt running !"); 8 | 9 | return a.exec(); 10 | } 11 | --------------------------------------------------------------------------------