package org.bbs.osgi.activity; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.net.URL; import org.bbs.felix.FelixWrapper; import org.osgi.framework.BundleContext; import org.osgi.framework.InvalidSyntaxException; import org.osgi.framework.ServiceReference; import android.content.Context; import android.content.Intent; import android.content.res.AssetManager; import android.content.res.Configuration; import android.content.res.Resources; import android.content.res.Resources.Theme; import android.os.Bundle; import android.support.v4.app.FragmentActivity; import android.text.TextUtils; import android.util.DisplayMetrics; import android.util.Log; import android.view.Menu; import android.view.MenuItem; import android.widget.TextView; /** * if android call us we call through to {@link #mActivityAgent}; * otherwise call super or do ourself. * * <p> * when add new function, keep it in section, in order. * * @author luoqii * * @see {@link ActivityAgent} */ public class BundleActivity extends //Activity FragmentActivity { private static final String RES_PATH_APK_RES = "res.apk"; private static final String TAG = BundleActivity.class.getSimpleName(); /** * type {@link String} */ public static final String EXTRA_SERVICE_NAME = ".extra_service_name"; /** * type {@link String} */ public static final String EXTRA_SERVICE_FILTER = ".extra_service_filter_name"; public static final String DEFAULT_LAUNCHER_SERVICE_NAME = // "org.bbs.bundlemgr.BundleList" // "org.bbs.bundlemgr.SimpleBundleList" // "com.example.android.apis.ApiDemos" "com.example.android.apis.Activator$EmbeddedApiDemos" ; public static final String DEFAULT_LAUNCHER_SERVICE_FILTER = ""; public static final String EXTRA_EMBEDED_ACTIVITY_CLASS_NAME = ".extra_embed_activity_class_name"; private static final boolean FORCE_CLOSE = true; ActivityAgent mActivityAgent; private String mServiceName; private String mServiceFilter; private Resources mSourceMerger; private LazyContext mLazyContext; @Override protected void attachBaseContext(Context newBase) { mLazyContext = new LazyContext(newBase); super.attachBaseContext(mLazyContext); } @Override public void setTheme(int resid) { super.setTheme(resid); } @Override public Theme getTheme() { return super.getTheme(); } public Resources getResources() { // this will call before onCreate(). // initActivityAgent(); // return super.getResources(); return mLazyContext.getResources(); // return mSourceMerger == null ? super.getResources() : mSourceMerger; } // life-cycle @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // call this as early as possible. initActivityAgent(); if (null != mActivityAgent) { mActivityAgent.mHostActivity = this; mActivityAgent.onCreate(savedInstanceState); } else { TextView t = new TextView(this); t.setText("no service avaiable: \n" + "serviceName: " + mServiceName + " serviceFilter: " + mServiceFilter); setContentView(t); if (FORCE_CLOSE) { throw new IllegalArgumentException("no ActivityAgent avaiable."); } } } private void initActivityAgent() { if (null == mActivityAgent) { mActivityAgent = getActivityAgent(); } } @Override protected void onPostCreate(Bundle savedInstanceState) { super.onPostCreate(savedInstanceState); mActivityAgent.onPostCreate(savedInstanceState); } @Override protected void onResume() { super.onResume(); mActivityAgent.onResume(); } @Override protected void onPause() { super.onPause(); mActivityAgent.onPause(); } @Override protected void onDestroy() { super.onDestroy(); mActivityAgent.onDestroy(); } @Override protected void onRestoreInstanceState(Bundle savedInstanceState) { super.onRestoreInstanceState(savedInstanceState); mActivityAgent.onRestoreInstanceState(savedInstanceState); } @Override protected void onRestart() { // TODO Auto-generated method stub super.onRestart(); mActivityAgent.onRestart(); } // menu @Override public boolean onCreateOptionsMenu(Menu menu) { return mActivityAgent.onCreateOptionsMenu(menu); } // @Override // public boolean onPreparePanel(int arg0, View arg1, Menu arg2) { // return mActivityAgent.onPreparePanel(arg0, arg1, arg2); // } // @Override // public boolean onPrepareOptionsMenu(Menu menu) { // return mActivityAgent.onPrepareOptionsMenu(menu); // } @Override public boolean onOptionsItemSelected(MenuItem item) { return mActivityAgent.onOptionsItemSelected(item); } // @Override // public void onCreateContextMenu(ContextMenu menu, View v, // ContextMenuInfo menuInfo) { // mActivityAgent.onCreateContextMenu(menu, v, menuInfo); // } // @Override // public boolean onContextItemSelected(MenuItem item) { // return mActivityAgent.onContextItemSelected(item); // } // @Override // public void onContextMenuClosed(Menu menu) { // mActivityAgent.onContextMenuClosed(menu); // } // keyevent // @Override // public boolean dispatchKeyEvent(KeyEvent event) { // if (mActivityAgent.dispatchKeyEvent(event)) { // return true; // } // return super.dispatchKeyEvent(event); // } // @Override // public boolean dispatchKeyShortcutEvent(KeyEvent event) { // if (mActivityAgent.dispatchKeyEvent(event)) { // return true; // } // return super.dispatchKeyShortcutEvent(event); // } // @Override // public boolean dispatchTouchEvent(MotionEvent ev) { // if (mActivityAgent.dispatchTouchEvent(ev)) { // return true; // } // return super.dispatchTouchEvent(ev); // } // @Override // public boolean dispatchTrackballEvent(MotionEvent ev) { // if (mActivityAgent.dispatchTrackballEvent(ev)) { // return true; // } // return super.dispatchTrackballEvent(ev); // } // @Override // public boolean dispatchGenericMotionEvent(MotionEvent ev) { // if (mActivityAgent.dispatchGenericMotionEvent(ev)) { // return true; // } // return super.dispatchGenericMotionEvent(ev); // } // private method. private ActivityAgent getActivityAgent() { ActivityAgent agent = null; Intent intent = getIntent(); mServiceName = intent.getStringExtra(EXTRA_SERVICE_NAME); if (TextUtils.isEmpty(mServiceName)) { mServiceName = DEFAULT_LAUNCHER_SERVICE_NAME; } mServiceFilter = intent.getStringExtra(EXTRA_SERVICE_FILTER); BundleContext bundleContext = FelixWrapper.getInstance(null).getFramework().getBundleContext(); ServiceReference<?> s = null; if (TextUtils.isEmpty(mServiceFilter)) { s = bundleContext.getServiceReference(mServiceName); } else { try { s = bundleContext.getServiceReferences(mServiceName, mServiceFilter)[0]; } catch (InvalidSyntaxException e) { e.printStackTrace(); } } if (null != s) { // FIXME update theme. Resources bundleRes = getBundleResources(s.getBundle()); if (bundleRes != null) { mSourceMerger = new ResourcesMerger(bundleRes, super.getResources()); mLazyContext.bundleResReady(mSourceMerger); } agent = (ActivityAgent) bundleContext.getService(s); } return agent; } private Resources getBundleResources(org.osgi.framework.Bundle bundle) { File resApk = getFileStreamPath("id" + bundle.getBundleId() + "_v" + bundle.getVersion()); //debug resApk.delete(); if (!resApk.exists()) { URL url = bundle.getResource("."); try { InputStream ins = url.openStream(); OutputStream ous = new FileOutputStream(resApk); final int LEN = 8 * 1024; byte[] buff = new byte[LEN]; int read = -1; while ((read = ins.read(buff)) != -1){ ous.write(buff, 0, read); // Log.d(TAG, "" + new String(buff, 0, read)); } ins.close(); ous.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } return loadApkResource(resApk.getAbsolutePath()); } private Resources loadApkResource(String apkFilePath) { AssetManager assets = null; try { assets = AssetManager.class.getConstructor(null).newInstance(null); Method method = assets.getClass().getMethod("addAssetPath", new Class[]{String.class}); Object r = method.invoke(assets, apkFilePath); Log.d(TAG, "result: " + r); DisplayMetrics metrics = null; Configuration config = null; Resources res = new Resources(assets, metrics, config); return res; } catch (NoSuchMethodException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalArgumentException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (InstantiationException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalAccessException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (InvocationTargetException e) { // TODO Auto-generated catch block e.printStackTrace(); } return null; } }