Skip to content

SL4A integration: SL4A's extensive API can be used before a total pyjnius port #191

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 48 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
34046cf
AndroidManifest got some SL4A services
alanjds Dec 24, 2013
00a46f8
MinimalService added
alanjds Dec 24, 2013
852b5f7
Forgot intent-filters from Google's APK script template
alanjds Dec 24, 2013
5f0dc28
Proper attribution
alanjds Dec 24, 2013
4ce361c
MinimalService cleanup
alanjds Dec 24, 2013
c4e48c6
--sl4a option to build.py
alanjds Dec 27, 2013
2c197c3
Renamed sl4a to sl4acompat
alanjds Dec 27, 2013
38dd4f2
Minimal jar-copying recipe.sh
alanjds Dec 27, 2013
18c6e73
Clean libs/$ARCH folder from .jar files (dont ask.)
alanjds Dec 27, 2013
88a692d
Hack to copy pre-built jars via recipe
alanjds Dec 27, 2013
1770e08
Fix ant build errors (hopefully)
alanjds Dec 27, 2013
6bba820
Oops: forgot too much debug
alanjds Dec 27, 2013
be5c49b
Fixed MinimalService again
alanjds Dec 27, 2013
db9f92c
Replace ScriptService with MinimalService
alanjds Dec 27, 2013
47a9d9a
Able to build the MinimalService!!
alanjds Dec 27, 2013
4c77510
Disable some stuff
alanjds Dec 27, 2013
eca29e4
Cleanup unused .java files
alanjds Dec 27, 2013
1585b27
Oops: forgot to remove references to ScriptApplication
alanjds Dec 27, 2013
520c7ed
Disable some activity
alanjds Dec 27, 2013
e6c0746
intent-filter to allow start MinimalService with ease
alanjds Dec 27, 2013
199f60d
MinimalServiceStarter to start MinimalService
alanjds Dec 27, 2013
34ef838
Try once again
alanjds Dec 27, 2013
5a6fa9e
Oops
alanjds Dec 27, 2013
7fd415c
Seems to need a category..
alanjds Dec 27, 2013
3301ec5
Oops. Stupid hours spent.
alanjds Dec 27, 2013
850ce97
[WIP] Logs on MinimalService started AndroidProxy?
alanjds Dec 28, 2013
ac7a60d
Merge branch 'custom_intent_filters' into sl4a
alanjds Dec 28, 2013
ad030b2
Pass back the netaddress after AndroidProxy created
alanjds Dec 28, 2013
799ad19
Oops: ' -> "
alanjds Dec 28, 2013
4d2559c
Bugfixes
alanjds Dec 28, 2013
0897e83
Compiling version.
alanjds Dec 28, 2013
a74e7b7
MinimalServiceStarter usage
alanjds Jan 4, 2014
4801ad1
Trying like http://stackoverflow.com/a/14153890/798575
alanjds Jan 4, 2014
d33c6e8
Start AndroiProxy on AsyncTask
alanjds Jan 4, 2014
653d2c6
Catch InterruptedException
alanjds Jan 4, 2014
54c25b6
Tracking strange bug..
alanjds Jan 6, 2014
9e80fab
Oops: is ", not '
alanjds Jan 6, 2014
6fab3e3
Sleep for 1sec before the null pointer
alanjds Jan 6, 2014
3e11f25
WORKING MinimalService
alanjds Jan 6, 2014
54b2479
Simplify by taking out AsyncTask from service
alanjds Jan 6, 2014
6d9629c
Oops: Cleaned too much.
alanjds Jan 6, 2014
7eba72d
Added needed Application scaffold
alanjds Jan 6, 2014
7ac9f72
Our app starts in "ready" state already
alanjds Jan 6, 2014
628fdcc
Application can be Sl4aCompatibleApplication
alanjds Jan 6, 2014
e6bd081
Identation fix
alanjds Jan 7, 2014
41a3301
Merge branch 'custom_intent_filters' into sl4a
alanjds Jan 10, 2014
c6b3ba7
Need no android:debuggable to build
alanjds Jan 11, 2014
28572df
Oops: usually there is nothing to rm.
alanjds Jan 11, 2014
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions distribute.sh
Original file line number Diff line number Diff line change
Expand Up @@ -725,6 +725,7 @@ function run_distribute() {
debug "Copy libs"
try mkdir -p libs/$ARCH
try cp -a $BUILD_PATH/libs/* libs/$ARCH/
rm "$DIST_PATH"/libs/$ARCH/*.jar || true

debug "Copy java files from various libs"
cp -a $BUILD_PATH/java/* src
Expand Down
27 changes: 27 additions & 0 deletions recipes/sl4acompat/recipe.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#!/bin/bash

URL_sl4acompat=https://github.com/damonkohler/sl4a/raw/dcfa832f80/android/script_for_android_template.zip
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If possible, use the same construction as we do in kivy/others libs, ie, extract the version in a variable, then we can use sl4acompat==<version>.
Example in Kivy: VERSION_kivy=${VERSION_kivy:-stable}: stable is the default version.

DEPS_sl4acompat=()
MD5_sl4acompat=eed6a34bdf63e57a94b3c61528b6a577
BUILD_sl4acompat=$BUILD_PATH/sl4acompat/
RECIPE_sl4acompat=$RECIPES_PATH/sl4acompat

function prebuild_sl4acompat() {
true
}

function shouldbuild_sl4acompat() {
true
}

function build_sl4acompat() {
true
}

function postbuild_sl4acompat() {
cd $BUILD_sl4acompat
mkdir "$DIST_PATH"/libs
cp -a libs/* "$DIST_PATH"/libs/
cd -
true
}
2 changes: 2 additions & 0 deletions src/build.py
Original file line number Diff line number Diff line change
Expand Up @@ -383,6 +383,8 @@ def make_package(args):
ap.add_argument('--add-jar', dest='add_jar', action='append', help='Add a Java .jar to the libs, so you can access its classes with pyjnius. You can specify this argument more than once to include multiple jars')
ap.add_argument('--meta-data', dest='meta_data', action='append',
help='Custom key=value to add in application metadata')
ap.add_argument('--sl4acompat', dest='sl4acompat', action='store_true',
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the recipe was included in the distribution, i guess the build.py should not expose this.
I understand that the AndroidManifest.xml should be changed according if the recipe is included or not, and it need a mechanism to extend it. Maybe we can create a AndroidManifest.xml.conf with the token that jinja should add by default? And then, a recipe can add its own token during the distribution part

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hum... I see your point, but I really dont understand what you mean with "the token that jinja should add by default, and then a recipe can add its own token during the distribution part".

If this could be made, is very nice as the recipes can "push" their own needs to the AndroidManifes.xml in the future, like BT permissions for some PyBluez recipe...

Anyway, I am willing to accept your suggestion, as soon as I can understand how to do this.

help='Provide this argument to include SL4A jars and RPC service into the app.')

args = ap.parse_args()

Expand Down
137 changes: 137 additions & 0 deletions src/src/org/alanjds/sl4acompat/MinimalService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
/*
* Copyright (C) 2010 Google Inc.
* Copyright (C) 2014 Alan Justino
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/

package org.alanjds.sl4acompat;

import android.app.Notification;
import android.app.PendingIntent;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.os.AsyncTask;

import com.googlecode.android_scripting.AndroidProxy;
import com.googlecode.android_scripting.ForegroundService;
import com.googlecode.android_scripting.Log;
import com.googlecode.android_scripting.NotificationIdFactory;
import com.googlecode.android_scripting.jsonrpc.RpcReceiverManager;

import java.net.InetSocketAddress;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException;

/**
* A service that allows scripts and the RPC server to run in the background.
*
* @author Alexey Reznichenko (alexey.reznichenko@gmail.com)
* @author Manuel Naranjo (manuel@aircable.net)
* @author Alan Justino (alan.justino@yahoo.com.br)
*/
public class MinimalService extends ForegroundService {
private final static int NOTIFICATION_ID = NotificationIdFactory.create();
private final CountDownLatch mLatch = new CountDownLatch(1);
private final IBinder mBinder;

//private InterpreterConfiguration mInterpreterConfiguration;
private RpcReceiverManager mFacadeManager;
private AndroidProxy mProxy;
private InetSocketAddress mAddressWithPort;
private String mProxyAddress;

public class LocalBinder extends Binder {
public MinimalService getService() {
return MinimalService.this;
}
}

public MinimalService() {
super(NOTIFICATION_ID);
mBinder = new LocalBinder();
}

@Override
public IBinder onBind(Intent intent) {
return mBinder;
}

@Override
public void onCreate() {
super.onCreate();
}

@Override
public void onStart(Intent intent, final int startId) {
Log.v("Starting MinimalService");
super.onStart(intent, startId);

mProxy = new AndroidProxy(this, null, true);
mProxyAddress = startProxy();
mLatch.countDown();
}

private String startProxy() {
Log.v("Starting AndroidProxy");
mAddressWithPort = mProxy.startLocal();
Log.v("Started AndroidProxy");

if (mAddressWithPort == null) { Log.w("Oops: mAddressWithPort == null"); }
Log.v(String.format("Started at %s", mAddressWithPort.toString()));

String host = mAddressWithPort.getHostName();
Integer iPort = mAddressWithPort.getPort();
String port = iPort.toString();
String handshake = mProxy.getSecret();
String proxyAddress = String.format("%s@%s:%s", handshake, host, port);
Log.d(String.format("AndroidProxy at: %s@%s:%s", handshake, host, port));

Intent netaddress = new Intent("org.alanjds.sl4acompat.STORE_RPC_NETADDRESS");
netaddress.putExtra("host", host);
netaddress.putExtra("port", port);
netaddress.putExtra("handshake", handshake);
sendBroadcast(netaddress);
Log.v("Sent 'org.alanjds.sl4acompat.STORE_RPC_NETADDRESS'");

return proxyAddress;
}

RpcReceiverManager getRpcReceiverManager() throws InterruptedException {
mLatch.await();
if (mFacadeManager==null) { // Facade manage may not be available on startup.
mFacadeManager = mProxy.getRpcReceiverManagerFactory()
.getRpcReceiverManagers().get(0);
}
return mFacadeManager;
}

@Override
protected Notification createNotification() {
PendingIntent contentIntent = PendingIntent.getService(this, 0, new Intent(), 0);
// This contentIntent is a noop.

Notification notification = new Notification();
//.setContentTitle("SL4A Facade")
//.setContentText("minimal SL4A facade running")
//.setContentIntent(contentIntent)
//.build();

//NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
notification.flags |= Notification.FLAG_AUTO_CANCEL; // hide the notification after its selected

//notificationManager.notify(0, notification);
return notification;
}
}
21 changes: 21 additions & 0 deletions src/src/org/alanjds/sl4acompat/MinimalServiceStarter.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package org.alanjds.sl4acompat;

import com.googlecode.android_scripting.Log;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;


// Usage: ./adb shell am broadcast -a org.alanjds.sl4acompat.START_MINIMAL_SERVICE

public class MinimalServiceStarter extends BroadcastReceiver {

@Override
public void onReceive(Context context, Intent intent) {
Log.v("Received intent!");
Intent serviceIntent = new Intent(context, MinimalService.class);
context.startService(serviceIntent);
Log.v("Service started?");
}
}
70 changes: 70 additions & 0 deletions src/src/org/alanjds/sl4acompat/ScriptActivity.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
/*
* Copyright (C) 2010 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/

package org.alanjds.sl4acompat;

import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;

import com.googlecode.android_scripting.Constants;
import com.googlecode.android_scripting.facade.ActivityResultFacade;
import com.googlecode.android_scripting.jsonrpc.RpcReceiverManager;

/**
* @author Alexey Reznichenko (alexey.reznichenko@gmail.com)
*/
public class ScriptActivity extends Activity {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (Constants.ACTION_LAUNCH_SCRIPT_FOR_RESULT.equals(getIntent().getAction())) {
setTheme(android.R.style.Theme_Dialog);
//setContentView(R.layout.dialog);
ServiceConnection connection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
MinimalService scriptService = ((MinimalService.LocalBinder) service).getService();
try {
RpcReceiverManager manager = scriptService.getRpcReceiverManager();
ActivityResultFacade resultFacade = manager.getReceiver(ActivityResultFacade.class);
resultFacade.setActivity(ScriptActivity.this);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}

@Override
public void onServiceDisconnected(ComponentName name) {
// Ignore.
}
};
bindService(new Intent(this, MinimalService.class), connection, Context.BIND_AUTO_CREATE);
startService(new Intent(this, MinimalService.class));
} else {
//ScriptApplication application = (ScriptApplication) getApplication();
//if (application.readyToStart()) {
startService(new Intent(this, MinimalService.class));
//}
finish();
}
}
}
33 changes: 33 additions & 0 deletions src/src/org/alanjds/sl4acompat/Sl4aCompatibleApplication.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package org.alanjds.sl4acompat;

import com.googlecode.android_scripting.BaseApplication;
import com.googlecode.android_scripting.Log;
import com.googlecode.android_scripting.interpreter.InterpreterConfiguration;
import com.googlecode.android_scripting.interpreter.InterpreterConstants;
import com.googlecode.android_scripting.interpreter.InterpreterConfiguration.ConfigurationObserver;

import java.util.concurrent.CountDownLatch;

public class Sl4aCompatibleApplication extends BaseApplication implements ConfigurationObserver {

private volatile boolean receivedConfigUpdate = true;
private final CountDownLatch mLatch = new CountDownLatch(1);

@Override
public void onCreate() {
mLatch.countDown();
}

@Override
public void onConfigurationChanged() { }

public boolean readyToStart() {
try {
mLatch.await();
} catch (InterruptedException e) {
Log.e(e);
}
return receivedConfigUpdate;
}

}
30 changes: 30 additions & 0 deletions src/templates/AndroidManifest.tmpl.xml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@
<application android:label="@string/appName"
android:icon="@drawable/icon"
android:hardwareAccelerated="true"
{% if args.sl4acompat %}
android:name="org.alanjds.sl4acompat.Sl4aCompatibleApplication"
{% endif %}
>

{% for m in args.meta_data %}
Expand Down Expand Up @@ -70,6 +73,33 @@
android:process=":PythonService"/>
{% endif %}

{% if args.sl4acompat %}
<!--<service android:name="org.alanjds.sl4acompat.ScriptService" />-->
<service android:name="org.alanjds.sl4acompat.MinimalService" android:enabled="true" />
<receiver android:name="org.alanjds.sl4acompat.MinimalServiceStarter" android:enabled="true" >
<intent-filter>
<action android:name ="org.alanjds.sl4acompat.START_MINIMAL_SERVICE"/>
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</receiver>

<activity android:name="com.googlecode.android_scripting.activity.FutureActivity"
android:configChanges="keyboardHidden|orientation" />

<!--<activity android:name="org.alanjds.sl4acompat.DialogActivity"
android:configChanges="keyboardHidden|orientation"
android:theme="@android:style/Theme.Translucent.NoTitleBar" />-->

<activity android:name="org.alanjds.sl4acompat.ScriptActivity"
android:configChanges="keyboardHidden|orientation"
android:theme="@android:style/Theme.Translucent.NoTitleBar">
<intent-filter>
<action android:name="com.googlecode.android_scripting.action.ACTION_LAUNCH_FOR_RESULT" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
{% endif %}

{% if args.billing_pubkey %}
<service android:name="org.renpy.android.billing.BillingService"
android:process=":python" />
Expand Down