package org.bbs.felix;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.HashMap;
import org.bbs.felix.util.OsgiUtil;
import org.knopflerfish.framework.FrameworkFactoryImpl;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleEvent;
import org.osgi.framework.BundleException;
import org.osgi.framework.BundleListener;
import org.osgi.framework.Constants;
import org.osgi.framework.launch.Framework;
import android.content.Context;
import android.content.res.AssetManager;
import android.util.Log;
/**
*
* @see <a href="http://felix.apache.org/site/apache-felix-framework-and-google-android.html">felist-on-android</a>
* @see {felix source}/main/src/main/java/org/apache/felix/main/Main.java
* @author bangbang.song@gmail.com
*
*/
public class FelixWrapper{
private static final String TAG = FelixWrapper.class.getSimpleName();
private static final String OSGI_BUNDLE_DIR = "osgi_bundle";
private static final String OSGI_BUNDLE_CACHE_DIR = "osgi_bundlecache";
private static final String ASSERT_PRELOAD_BUNDLE_DIR = "felix/preloadbundle";
private static final String ASSERT_AUTO_EXTRACT_DIR = "autoExtract";
private static FelixWrapper sInstance;
private Framework mFramework;
private String mCacheDir;
private String mBundleDir;
private FelixWrapper(Context context){
mCacheDir = context.getDir(OSGI_BUNDLE_CACHE_DIR, Context.MODE_WORLD_WRITEABLE).toString();
mBundleDir = context.getDir(OSGI_BUNDLE_DIR, Context.MODE_WORLD_WRITEABLE).toString();;
extractPreloadBundle(context);
extractAssets(context);
HashMap<String, String> configMap = new HashMap<String, String>();
configMap.put(Constants.FRAMEWORK_STORAGE, mCacheDir);
configMap.put(Constants.FRAMEWORK_SYSTEMPACKAGES_EXTRA, ANDROID_PACKAGES_FOR_EXPORT_EXTRA);
// configMap.put(FelixConstants.LOG_LEVEL_PROP, 4 + "");
mFramework = new FrameworkFactoryImpl().newFramework(configMap);
Log.d(TAG, "init & start osgi." );
try {
mFramework.init();
Bundle[] bundles = mFramework.getBundleContext().getBundles();
// for re-deploy bundle.
for (Bundle b : bundles) {
if (0 != b.getBundleId()) {
b.uninstall();
}
}
mFramework.start();
} catch (BundleException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Log.d(TAG, "OSGi framework running, state: " + OsgiUtil.bundleState2Str(mFramework.getState()));
registerListener(mFramework);
Bundle[] bundles = mFramework.getBundleContext().getBundles();
for (Bundle b : bundles) {
Log.d(TAG, "b: " + b.getBundleId() + " " + OsgiUtil.bundleState2Str(b.getState()));
}
}
public Framework getFramework(){
return mFramework;
}
public static void registerListener(Framework f) {
f.getBundleContext().addBundleListener(new BundleListener(){
@Override
public void bundleChanged(BundleEvent e) {
Log.d(TAG, "bundleChanged. e:" + e);
}});
}
private void extractAssets(Context context) {
try {
AssetManager assetsM = context.getResources().getAssets();
String[] files = assetsM.list(ASSERT_AUTO_EXTRACT_DIR);
for (String aFile: files) {
String assertFile = ASSERT_AUTO_EXTRACT_DIR + "/" + aFile;
Log.d(TAG, "prepare bundle: " + aFile);
InputStream in = assetsM.open(assertFile);
String bFile = "/sdcard/autoextract/" + aFile;
File f = new File(bFile);
f.getParentFile().mkdirs();
OutputStream out =
// context.openFileOutput(mBundleDir + "/" + aFile, 0);
new FileOutputStream(bFile);
int byteCount = 8096;
byte[] buffer = new byte[byteCount];
int count = 0;
while ((count = in.read(buffer, 0, byteCount)) != -1){
out.write(buffer, 0, count);
}
in.close();
out.close();
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private void extractPreloadBundle(Context context) {
try {
AssetManager assetsM = context.getResources().getAssets();
String[] files = assetsM.list(ASSERT_PRELOAD_BUNDLE_DIR);
for (String aFile: files) {
String assertFile = ASSERT_PRELOAD_BUNDLE_DIR + "/" + aFile;
Log.d(TAG, "prepare bundle: " + aFile);
InputStream in = assetsM.open(assertFile);
String bFile = mBundleDir + "/" + aFile;
if (aFile.endsWith("apk")) {
bFile = bFile + ".jar";
}
OutputStream out =
// context.openFileOutput(mBundleDir + "/" + aFile, 0);
new FileOutputStream(bFile);
int byteCount = 8096;
byte[] buffer = new byte[byteCount];
int count = 0;
while ((count = in.read(buffer, 0, byteCount)) != -1){
out.write(buffer, 0, count);
}
in.close();
out.close();
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static FelixWrapper getInstance(Context context) {
if (null == sInstance) {
sInstance = new FelixWrapper(context);
}
return sInstance;
}
// copied from http://code.google.com/p/felix-on-android/
private static final String ANDROID_PACKAGES_FOR_EXPORT_EXTRA =
"org.bbs.osgi.activity," +
"org.bbs.felix.activity.ActivityAgent," +
"org.bbs.felix.activity.bundlemanager," +
"org.bbs.felixonandroid," +
//android
"android, " +
"android.app," +
"android.content," +
"android.content.res," +
"android.content.pm," +
"android.database," +
"android.database.sqlite," +
"android.graphics, " +
"android.graphics.drawable, " +
"android.graphics.glutils, " +
"android.hardware, " +
"android.location, " +
"android.media, " +
"android.net, " +
"android.opengl, " +
"android.os, " +
"android.os.bundle, " +
"android.provider, " +
"android.sax, " +
"android.speech.recognition, " +
"android.telephony, " +
"android.telephony.gsm, " +
"android.text, " +
"android.text.method, " +
"android.text.style, " +
"android.text.util, " +
"android.util, " +
"android.view, " +
"android.view.animation, " +
"android.webkit, " +
"android.widget, " +
// support v4
"android.support.v4.app," +
// JAVAx
"javax.crypto; " +
"javax.crypto.interfaces; " +
"javax.crypto.spec; " +
"javax.microedition.khronos.opengles; " +
"javax.net; " +
"javax.net.ssl; " +
"javax.security.auth; " +
"javax.security.auth.callback; " +
"javax.security.auth.login; " +
"javax.security.auth.x500; " +
"javax.security.cert; " +
"javax.sound.midi; " +
"javax.sound.midi.spi; " +
"javax.sound.sampled; " +
"javax.sound.sampled.spi; " +
"javax.sql; " +
"javax.xml.parsers; " +
//JUNIT
"junit.extensions; " +
"junit.framework; " +
//APACHE
"org.apache.commons.codec; " +
"org.apache.commons.codec.binary; " +
"org.apache.commons.codec.language; " +
"org.apache.commons.codec.net; " +
"org.apache.commons.httpclient; " +
"org.apache.commons.httpclient.auth; " +
"org.apache.commons.httpclient.cookie; " +
"org.apache.commons.httpclient.methods; " +
"org.apache.commons.httpclient.methods.multipart; " +
"org.apache.commons.httpclient.params; " +
"org.apache.commons.httpclient.protocol; " +
"org.apache.commons.httpclient.util; " +
//OTHERS
"org.bluez; " +
"org.json; " +
"org.w3c.dom; " +
"org.xml.sax; " +
"org.xml.sax.ext; " +
"org.xml.sax.helpers; " +
// this no ';' or ',' , shit.
"net.neosum.android.view";
}