Skip to content

Commit 04d6dcd

Browse files
committed
enable services and other features in sdl2 bootstrap
1 parent fdb2b5f commit 04d6dcd

File tree

9 files changed

+336
-86
lines changed

9 files changed

+336
-86
lines changed

pythonforandroid/bootstraps/sdl2/build/build.py

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,7 @@ def make_package(args):
221221
os.unlink('assets/private.mp3')
222222

223223
# In order to speedup import and initial depack,
224-
# construct a python27.zip if not using CrystaX's pre-zipped package
224+
# construct a python27.zip
225225
make_python_zip()
226226

227227
# Package up the private and public data.
@@ -281,10 +281,16 @@ def make_package(args):
281281
with open(args.intent_filters) as fd:
282282
args.intent_filters = fd.read()
283283

284+
service = False
285+
service_main = join(realpath(args.private), 'service', 'main.py')
286+
if os.path.exists(service_main) or os.path.exists(service_main + 'o'):
287+
service = True
288+
284289
render(
285290
'AndroidManifest.tmpl.xml',
286291
'AndroidManifest.xml',
287292
args=args,
293+
service=service,
288294
)
289295

290296
render(
@@ -311,6 +317,7 @@ def make_package(args):
311317

312318
def parse_args(args=None):
313319
global BLACKLIST_PATTERNS, WHITELIST_PATTERNS
320+
default_android_api = 12
314321
import argparse
315322
ap = argparse.ArgumentParser(description='''\
316323
Package a Python application for Android.
@@ -367,18 +374,35 @@ def parse_args(args=None):
367374
help=('Add a Java .jar to the libs, so you can access its '
368375
'classes with pyjnius. You can specify this '
369376
'argument more than once to include multiple jars'))
377+
ap.add_argument('--sdk', dest='sdk_version', default=-1,
378+
type=int, help=('Android SDK version to use. Default to '
379+
'the value of minsdk'))
380+
ap.add_argument('--minsdk', dest='min_sdk_version',
381+
default=default_android_api, type=int,
382+
help=('Minimum Android SDK version to use. Default to '
383+
'the value of ANDROIDAPI, or {} if not set'
384+
.format(default_android_api)))
370385
ap.add_argument('--intent-filters', dest='intent_filters',
371386
help=('Add intent-filters xml rules to the '
372387
'AndroidManifest.xml file. The argument is a '
373388
'filename containing xml. The filename should be '
374389
'located relative to the python-for-android '
375390
'directory'))
391+
ap.add_argument('--with-billing', dest='billing_pubkey',
392+
help='If set, the billing service will be added (not implemented)')
376393

377394
if args is None:
378395
args = sys.argv[1:]
379396
args = ap.parse_args(args)
380397
args.ignore_path = []
381398

399+
if args.billing_pubkey:
400+
print('Billing not yet supported in sdl2 bootstrap!')
401+
exit(1)
402+
403+
if args.sdk_version == -1:
404+
args.sdk_version = args.min_sdk_version
405+
382406
if args.permissions is None:
383407
args.permissions = []
384408

pythonforandroid/bootstraps/sdl2/build/jni/src/start.c

Lines changed: 28 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ int main(int argc, char *argv[]) {
122122
LOG("Initialize Python for Android");
123123
/* env_argument = "/data/data/org.kivy.android/files"; */
124124
env_argument = getenv("ANDROID_ARGUMENT");
125-
/* setenv("ANDROID_APP_PATH", env_argument, 1); */
125+
setenv("ANDROID_APP_PATH", env_argument, 1);
126126

127127
/* setenv("ANDROID_ARGUMENT", env_argument, 1); */
128128
/* setenv("ANDROID_PRIVATE", env_argument, 1); */
@@ -314,32 +314,32 @@ int main(int argc, char *argv[]) {
314314
return ret;
315315
}
316316

317-
/* JNIEXPORT void JNICALL JAVA_EXPORT_NAME(PythonService_nativeStart) ( JNIEnv* env, jobject thiz, */
318-
/* jstring j_android_private, */
319-
/* jstring j_android_argument, */
320-
/* jstring j_python_home, */
321-
/* jstring j_python_path, */
322-
/* jstring j_arg ) */
323-
/* { */
324-
/* jboolean iscopy; */
325-
/* const char *android_private = (*env)->GetStringUTFChars(env, j_android_private, &iscopy); */
326-
/* const char *android_argument = (*env)->GetStringUTFChars(env, j_android_argument, &iscopy); */
327-
/* const char *python_home = (*env)->GetStringUTFChars(env, j_python_home, &iscopy); */
328-
/* const char *python_path = (*env)->GetStringUTFChars(env, j_python_path, &iscopy); */
329-
/* const char *arg = (*env)->GetStringUTFChars(env, j_arg, &iscopy); */
330-
331-
/* setenv("ANDROID_PRIVATE", android_private, 1); */
332-
/* setenv("ANDROID_ARGUMENT", android_argument, 1); */
333-
/* setenv("PYTHONOPTIMIZE", "2", 1); */
334-
/* setenv("PYTHONHOME", python_home, 1); */
335-
/* setenv("PYTHONPATH", python_path, 1); */
336-
/* setenv("PYTHON_SERVICE_ARGUMENT", arg, 1); */
337-
338-
/* char *argv[] = { "service" }; */
339-
/* /\* ANDROID_ARGUMENT points to service subdir, */
340-
/* * so main() will run main.py from this dir */
341-
/* *\/ */
342-
/* main(1, argv); */
343-
/* } */
317+
JNIEXPORT void JNICALL Java_org_kivy_android_PythonService_nativeStart ( JNIEnv* env, jobject thiz,
318+
jstring j_android_private,
319+
jstring j_android_argument,
320+
jstring j_python_home,
321+
jstring j_python_path,
322+
jstring j_arg )
323+
{
324+
jboolean iscopy;
325+
const char *android_private = (*env)->GetStringUTFChars(env, j_android_private, &iscopy);
326+
const char *android_argument = (*env)->GetStringUTFChars(env, j_android_argument, &iscopy);
327+
const char *python_home = (*env)->GetStringUTFChars(env, j_python_home, &iscopy);
328+
const char *python_path = (*env)->GetStringUTFChars(env, j_python_path, &iscopy);
329+
const char *arg = (*env)->GetStringUTFChars(env, j_arg, &iscopy);
330+
331+
setenv("ANDROID_PRIVATE", android_private, 1);
332+
setenv("ANDROID_ARGUMENT", android_argument, 1);
333+
setenv("PYTHONOPTIMIZE", "2", 1);
334+
setenv("PYTHONHOME", python_home, 1);
335+
setenv("PYTHONPATH", python_path, 1);
336+
setenv("PYTHON_SERVICE_ARGUMENT", arg, 1);
337+
338+
char *argv[] = { "service" };
339+
/* ANDROID_ARGUMENT points to service subdir,
340+
* so main() will run main.py from this dir
341+
*/
342+
main(1, argv);
343+
}
344344

345345
#endif

pythonforandroid/bootstraps/sdl2/build/src/org/kivy/android/PythonActivity.java

Lines changed: 34 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,12 @@
2424
import android.content.Context;
2525
import android.content.pm.PackageManager;
2626
import android.content.pm.ApplicationInfo;
27+
import android.content.Intent;
2728

2829
import org.libsdl.app.SDLActivity;
2930

31+
import org.kivy.android.PythonUtil;
32+
3033
import org.renpy.android.ResourceManager;
3134
import org.renpy.android.AssetExtract;
3235

@@ -35,7 +38,7 @@ public class PythonActivity extends SDLActivity {
3538
private static final String TAG = "PythonActivity";
3639

3740
public static PythonActivity mActivity = null;
38-
41+
3942
private ResourceManager resourceManager = null;
4043
private Bundle mMetaData = null;
4144
private PowerManager.WakeLock mWakeLock = null;
@@ -51,9 +54,9 @@ protected void onCreate(Bundle savedInstanceState) {
5154
Log.v(TAG, "About to do super onCreate");
5255
super.onCreate(savedInstanceState);
5356
Log.v(TAG, "Did super onCreate");
54-
57+
5558
this.mActivity = this;
56-
59+
5760
String mFilesDirectory = mActivity.getFilesDir().getAbsolutePath();
5861
Log.v(TAG, "Setting env vars for start.c and Python to use");
5962
SDLActivity.nativeSetEnv("ANDROID_PRIVATE", mFilesDirectory);
@@ -62,7 +65,7 @@ protected void onCreate(Bundle savedInstanceState) {
6265
SDLActivity.nativeSetEnv("PYTHONHOME", mFilesDirectory);
6366
SDLActivity.nativeSetEnv("PYTHONPATH", mFilesDirectory + ":" + mFilesDirectory + "/lib");
6467

65-
68+
6669
// nativeSetEnv("ANDROID_ARGUMENT", getFilesDir());
6770

6871
try {
@@ -84,54 +87,11 @@ protected void onCreate(Bundle savedInstanceState) {
8487
} catch (PackageManager.NameNotFoundException e) {
8588
}
8689
}
87-
88-
// This is just overrides the normal SDLActivity, which just loads
89-
// SDL2 and main
90-
protected String[] getLibraries() {
91-
return new String[] {
92-
"SDL2",
93-
"SDL2_image",
94-
"SDL2_mixer",
95-
"SDL2_ttf",
96-
"main"
97-
};
98-
}
99-
90+
10091
public void loadLibraries() {
101-
// AND: This should probably be replaced by a call to super
102-
for (String lib : getLibraries()) {
103-
System.loadLibrary(lib);
104-
}
105-
106-
try {
107-
System.loadLibrary("python2.7");
108-
} catch(UnsatisfiedLinkError e) {
109-
Log.v(TAG, "Failed to load libpython2.7");
110-
}
111-
112-
try {
113-
System.loadLibrary("python3.5m");
114-
} catch(UnsatisfiedLinkError e) {
115-
Log.v(TAG, "Failed to load libpython3.5m");
116-
}
117-
118-
try {
119-
System.load(getFilesDir() + "/lib/python2.7/lib-dynload/_io.so");
120-
System.load(getFilesDir() + "/lib/python2.7/lib-dynload/unicodedata.so");
121-
} catch(UnsatisfiedLinkError e) {
122-
Log.v(TAG, "Failed to load _io.so or unicodedata.so...but that's okay.");
123-
}
124-
125-
try {
126-
// System.loadLibrary("ctypes");
127-
System.load(getFilesDir() + "/lib/python2.7/lib-dynload/_ctypes.so");
128-
} catch(UnsatisfiedLinkError e) {
129-
Log.v(TAG, "Unsatisfied linker when loading ctypes");
130-
}
131-
132-
Log.v(TAG, "Loaded everything!");
92+
PythonUtil.loadLibraries(getFilesDir());
13393
}
134-
94+
13595
public void recursiveDelete(File f) {
13696
if (f.isDirectory()) {
13797
for (File r : f.listFiles()) {
@@ -163,15 +123,15 @@ public void run() {
163123
}
164124
}
165125
}
166-
126+
167127
public void unpackData(final String resource, File target) {
168-
128+
169129
Log.v(TAG, "UNPACKING!!! " + resource + " " + target.getName());
170-
130+
171131
// The version of data in memory and on disk.
172132
String data_version = resourceManager.getString(resource + "_version");
173133
String disk_version = null;
174-
134+
175135
Log.v(TAG, "Data version is " + data_version);
176136

177137
// If no version, no unpacking is necessary.
@@ -220,7 +180,7 @@ public void unpackData(final String resource, File target) {
220180
}
221181
}
222182
}
223-
183+
224184
public static ViewGroup getLayout() {
225185
return mLayout;
226186
}
@@ -298,4 +258,23 @@ protected void onActivityResult(int requestCode, int resultCode, Intent intent)
298258
}
299259
}
300260

261+
public static void start_service(String serviceTitle, String serviceDescription,
262+
String pythonServiceArgument) {
263+
Intent serviceIntent = new Intent(PythonActivity.mActivity, PythonService.class);
264+
String argument = PythonActivity.mActivity.getFilesDir().getAbsolutePath();
265+
String filesDirectory = argument;
266+
serviceIntent.putExtra("androidPrivate", argument);
267+
serviceIntent.putExtra("androidArgument", filesDirectory);
268+
serviceIntent.putExtra("pythonHome", argument);
269+
serviceIntent.putExtra("pythonPath", argument + ":" + filesDirectory + "/lib");
270+
serviceIntent.putExtra("serviceTitle", serviceTitle);
271+
serviceIntent.putExtra("serviceDescription", serviceDescription);
272+
serviceIntent.putExtra("pythonServiceArgument", pythonServiceArgument);
273+
PythonActivity.mActivity.startService(serviceIntent);
274+
}
275+
276+
public static void stop_service() {
277+
Intent serviceIntent = new Intent(PythonActivity.mActivity, PythonService.class);
278+
PythonActivity.mActivity.stopService(serviceIntent);
279+
}
301280
}
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
package org.kivy.android;
2+
3+
import android.app.Service;
4+
import android.os.IBinder;
5+
import android.os.Bundle;
6+
import android.content.Intent;
7+
import android.content.Context;
8+
import android.util.Log;
9+
import android.app.Notification;
10+
import android.app.PendingIntent;
11+
import android.os.Process;
12+
13+
import org.kivy.android.PythonUtil;
14+
15+
import org.renpy.android.Hardware;
16+
17+
18+
public class PythonService extends Service implements Runnable {
19+
20+
// Thread for Python code
21+
private Thread pythonThread = null;
22+
23+
// Python environment variables
24+
private String androidPrivate;
25+
private String androidArgument;
26+
private String pythonHome;
27+
private String pythonPath;
28+
// Argument to pass to Python code,
29+
private String pythonServiceArgument;
30+
public static Service mService = null;
31+
32+
@Override
33+
public IBinder onBind(Intent arg0) {
34+
return null;
35+
}
36+
37+
@Override
38+
public void onCreate() {
39+
super.onCreate();
40+
//Hardware.context = this;
41+
}
42+
43+
@Override
44+
public int onStartCommand(Intent intent, int flags, int startId) {
45+
if (pythonThread != null) {
46+
Log.v("python service", "service exists, do not start again");
47+
return START_NOT_STICKY;
48+
}
49+
50+
Bundle extras = intent.getExtras();
51+
androidPrivate = extras.getString("androidPrivate");
52+
// service code is located in service subdir
53+
androidArgument = extras.getString("androidArgument") + "/service";
54+
pythonHome = extras.getString("pythonHome");
55+
pythonPath = extras.getString("pythonPath");
56+
pythonServiceArgument = extras.getString("pythonServiceArgument");
57+
String serviceTitle = extras.getString("serviceTitle");
58+
String serviceDescription = extras.getString("serviceDescription");
59+
60+
pythonThread = new Thread(this);
61+
pythonThread.start();
62+
63+
Context context = getApplicationContext();
64+
Notification notification = new Notification(context.getApplicationInfo().icon,
65+
serviceTitle,
66+
System.currentTimeMillis());
67+
Intent contextIntent = new Intent(context, PythonActivity.class);
68+
PendingIntent pIntent = PendingIntent.getActivity(context, 0, contextIntent,
69+
PendingIntent.FLAG_UPDATE_CURRENT);
70+
notification.setLatestEventInfo(context, serviceTitle, serviceDescription, pIntent);
71+
startForeground(1, notification);
72+
73+
return START_NOT_STICKY;
74+
}
75+
76+
@Override
77+
public void onDestroy() {
78+
super.onDestroy();
79+
pythonThread = null;
80+
Process.killProcess(Process.myPid());
81+
}
82+
83+
@Override
84+
public void run(){
85+
PythonUtil.loadLibraries(getFilesDir());
86+
87+
this.mService = this;
88+
nativeStart(androidPrivate, androidArgument, pythonHome, pythonPath,
89+
pythonServiceArgument);
90+
}
91+
92+
// Native part
93+
public static native void nativeStart(String androidPrivate, String androidArgument,
94+
String pythonHome, String pythonPath,
95+
String pythonServiceArgument);
96+
97+
}

0 commit comments

Comments
 (0)