diff --git a/pythonforandroid/bootstraps/service_only/__init__.py b/pythonforandroid/bootstraps/service_only/__init__.py index 4a00e78c73..ba9e7d85fc 100644 --- a/pythonforandroid/bootstraps/service_only/__init__.py +++ b/pythonforandroid/bootstraps/service_only/__init__.py @@ -1,10 +1,12 @@ -from pythonforandroid.toolchain import Bootstrap, shprint, current_directory, info, warning, ArchARM, info_main -from os.path import join, exists, curdir, abspath -from os import walk import glob +from os import walk +from os.path import join, exists, curdir, abspath import sh +from pythonforandroid.toolchain import Bootstrap, shprint, current_directory, info, warning, ArchARM, info_main + class ServiceOnlyBootstrap(Bootstrap): + name = 'service_only' recipe_depends = ['genericndkbuild', ('python2', 'python3crystax')] @@ -62,7 +64,7 @@ def run_distribute(self): # AND: Copylibs stuff should go here if exists(join('libs', arch.arch, 'libpymodules.so')): shprint(sh.mv, join('libs', arch.arch, 'libpymodules.so'), 'private/') - shprint(sh.cp, join('python-install', 'include' , 'python2.7', 'pyconfig.h'), join('private', 'include', 'python2.7/')) + shprint(sh.cp, join('python-install', 'include', 'python2.7', 'pyconfig.h'), join('private', 'include', 'python2.7/')) info('Removing some unwanted files') shprint(sh.rm, '-f', join('private', 'lib', 'libpython2.7.so')) @@ -118,4 +120,5 @@ def run_distribute(self): self.fry_eggs(site_packages_dir) super(ServiceOnlyBootstrap, self).run_distribute() -bootstrap = ServiceOnlyBootstrap() \ No newline at end of file + +bootstrap = ServiceOnlyBootstrap() diff --git a/pythonforandroid/bootstraps/service_only/build/jni/src/start.c b/pythonforandroid/bootstraps/service_only/build/jni/src/start.c index 37a9b1d90f..7251cdd132 100644 --- a/pythonforandroid/bootstraps/service_only/build/jni/src/start.c +++ b/pythonforandroid/bootstraps/service_only/build/jni/src/start.c @@ -279,7 +279,7 @@ int main(int argc, char *argv[]) { } JNIEXPORT void JNICALL Java_org_kivy_android_PythonService_nativeStart( - JNIEnv *env, jobject thiz, jstring j_android_private, + JNIEnv *env, jobject j_this, jstring j_android_private, jstring j_android_argument, jstring j_service_entrypoint, jstring j_python_name, jstring j_python_home, jstring j_python_path, jstring j_arg) { @@ -296,7 +296,8 @@ JNIEXPORT void JNICALL Java_org_kivy_android_PythonService_nativeStart( (*env)->GetStringUTFChars(env, j_python_home, &iscopy); const char *python_path = (*env)->GetStringUTFChars(env, j_python_path, &iscopy); - const char *arg = (*env)->GetStringUTFChars(env, j_arg, &iscopy); + const char *arg = + (*env)->GetStringUTFChars(env, j_arg, &iscopy); setenv("ANDROID_PRIVATE", android_private, 1); setenv("ANDROID_ARGUMENT", android_argument, 1); diff --git a/pythonforandroid/bootstraps/service_only/build/src/org/kivy/android/PythonService.java b/pythonforandroid/bootstraps/service_only/build/src/org/kivy/android/PythonService.java index a9bc8c9a90..df4fe0d2c8 100644 --- a/pythonforandroid/bootstraps/service_only/build/src/org/kivy/android/PythonService.java +++ b/pythonforandroid/bootstraps/service_only/build/src/org/kivy/android/PythonService.java @@ -1,20 +1,18 @@ package org.kivy.android; -import android.app.Activity; import android.app.PendingIntent; import android.app.Service; import android.content.Context; import android.content.Intent; +import android.content.pm.ApplicationInfo; import android.os.Bundle; -import android.os.IBinder; import android.os.Process; import android.support.v4.app.NotificationCompat; import android.util.Log; -public class PythonService extends Service implements Runnable { +public abstract class PythonService extends Service implements Runnable { private static String TAG = PythonService.class.getSimpleName(); - public static PythonService mService = null; /** * Intent that started the service */ @@ -31,26 +29,16 @@ public class PythonService extends Service implements Runnable { private String serviceEntrypoint; private String pythonServiceArgument; - private boolean autoRestartService = false; - - public void setAutoRestartService(boolean restart) { - autoRestartService = restart; - } - - public boolean canDisplayNotification() { - return true; + public int getStartType() { + return START_NOT_STICKY; } - public int startType() { - return START_NOT_STICKY; + public boolean getStartForeground() { + return false; } - /** - * {@inheritDoc} - */ - @Override - public IBinder onBind(Intent intent) { - return null; + public boolean getAutoRestart() { + return false; } /** @@ -88,28 +76,30 @@ public int onStartCommand(Intent intent, int flags, int startId) { pythonThread = new Thread(this); pythonThread.start(); - if (canDisplayNotification()) { + if (getStartForeground()) { doStartForeground(extras); } - return startType(); + return getStartType(); } protected void doStartForeground(Bundle extras) { - String serviceTitle = extras.getString("serviceTitle"); - String serviceDescription = extras.getString("serviceDescription"); + Context appContext = getApplicationContext(); + ApplicationInfo appInfo = appContext.getApplicationInfo(); - Context context = getApplicationContext(); + String serviceTitle = extras.getString("serviceTitle", TAG); + String serviceDescription = extras.getString("serviceDescription", ""); + int serviceIconId = extras.getInt("serviceIconId", appInfo.icon); NotificationCompat.Builder builder = new NotificationCompat.Builder(this) - .setSmallIcon(context.getApplicationInfo().icon) + .setSmallIcon(serviceIconId) .setContentTitle(serviceTitle) .setContentText(serviceDescription); int NOTIFICATION_ID = 1; - Intent targetIntent = new Intent(this, Activity.class); + Intent targetIntent = new Intent(this, MainActivity.class); PendingIntent contentIntent = PendingIntent.getActivity(this, 0, targetIntent, PendingIntent.FLAG_UPDATE_CURRENT); builder.setContentIntent(contentIntent); @@ -123,7 +113,7 @@ protected void doStartForeground(Bundle extras) { public void onDestroy() { super.onDestroy(); pythonThread = null; - if (autoRestartService && startIntent != null) { + if (getAutoRestart() && startIntent != null) { Log.v(TAG, "Service restart requested"); startService(startIntent); } @@ -136,9 +126,8 @@ public void onDestroy() { @Override public void run() { PythonUtil.loadLibraries(getFilesDir()); - mService = this; - nativeStart(androidPrivate, androidArgument, serviceEntrypoint, - pythonName, pythonHome, pythonPath, pythonServiceArgument); + nativeStart(androidPrivate, androidArgument, serviceEntrypoint, pythonName, pythonHome, + pythonPath, pythonServiceArgument); stopSelf(); } @@ -151,8 +140,8 @@ public void run() { * @param pythonPath Python path * @param pythonServiceArgument Argument to pass to Python code */ - public static native void nativeStart(String androidPrivate, - String androidArgument, String serviceEntrypoint, - String pythonName, String pythonHome, String pythonPath, + public static native void nativeStart(String androidPrivate, String androidArgument, + String serviceEntrypoint, String pythonName, + String pythonHome, String pythonPath, String pythonServiceArgument); } diff --git a/pythonforandroid/bootstraps/service_only/build/templates/Service.tmpl.java b/pythonforandroid/bootstraps/service_only/build/templates/Service.tmpl.java index 3523ecc114..31c4183449 100644 --- a/pythonforandroid/bootstraps/service_only/build/templates/Service.tmpl.java +++ b/pythonforandroid/bootstraps/service_only/build/templates/Service.tmpl.java @@ -4,25 +4,29 @@ import android.content.Context; import org.kivy.android.PythonService; - public class Service{{ name|capitalize }} extends PythonService { + /** + * Binder given to clients + */ + private final IBinder mBinder = new Service{{ name|capitalize }}Binder(); + {% if sticky %} /** * {@inheritDoc} */ @Override - public int startType() { + public int getStartType() { return START_STICKY; } {% endif %} - {% if not foreground %} + {% if foreground %} /** * {@inheritDoc} */ @Override - public boolean canDisplayNotification() { - return false; + public boolean getStartForeground() { + return true; } {% endif %} @@ -46,4 +50,22 @@ public static void stop(Context ctx) { ctx.stopService(intent); } + /** + * {@inheritDoc} + */ + @Override + public IBinder onBind(Intent intent) { + return mBinder; + } + + /** + * Class used for the client Binder. Because we know this service always + * runs in the same process as its clients, we don't need to deal with IPC. + */ + public class Service{{ name|capitalize }}Binder extends Binder { + Service{{ name|capitalize }} getService() { + // Return this instance of Service{{ name|capitalize }} so clients can call public methods + return Service{{ name|capitalize }}.this; + } + } } diff --git a/setup.py b/setup.py index 91bd0edd20..e91d5398e8 100644 --- a/setup.py +++ b/setup.py @@ -34,7 +34,8 @@ def recursively_include(results, directory, patterns): '*.mk', '*.jam', ]) recursively_include(package_data, 'pythonforandroid/bootstraps', ['*.properties', '*.xml', '*.java', '*.tmpl', '*.txt', '*.png', - '*.mk', '*.c', '*.h', '*.py', '*.sh', '*.jpg', '*.aidl', ]) + '*.mk', '*.c', '*.h', '*.py', '*.sh', '*.jpg', '*.aidl', + '*.gradle', ]) recursively_include(package_data, 'pythonforandroid/bootstraps', ['sdl-config', ]) recursively_include(package_data, 'pythonforandroid/bootstraps/webview',