001 /*
002 * To change this template, choose Tools | Templates
003 * and open the template in the editor.
004 */
005 package org.bridj;
006
007 import org.bridj.util.ClassDefiner;
008 import android.app.Application;
009 import android.content.pm.ApplicationInfo;
010 import android.os.Environment;
011 import java.io.File;
012 import java.io.FileNotFoundException;
013 import java.io.IOException;
014 import java.net.URL;
015 import java.util.regex.Matcher;
016 import java.util.regex.Pattern;
017
018 /**
019 *
020 * @author ochafik
021 */
022 public class AndroidSupport extends PlatformSupport {
023 private volatile Application app;
024
025 AndroidSupport() {}
026
027
028 synchronized void setApp(Application application) {
029 if (this.app != null && application != null && this.app != application)
030 throw new IllegalArgumentException("Android Application has already been set to a different value : " + this.app);
031
032 this.app = application;
033 }
034
035 public static void setApplication(Application application) {
036 ((AndroidSupport)PlatformSupport.getInstance()).setApp(application);
037 }
038
039 String adviseToSetApp() {
040 return app == null ? "" : "Please use AndroidSupport.setApplication(Application). ";
041 }
042
043
044 volatile AndroidClassDefiner classDefiner;
045
046 synchronized File getCacheDir() throws FileNotFoundException {
047 File cacheDir = null;
048 if (app != null)
049 cacheDir = app.getCacheDir();
050
051 if (cacheDir == null || !cacheDir.isDirectory() || !cacheDir.canWrite())
052 throw new FileNotFoundException("Failed to find the cache directory. " + adviseToSetApp());
053
054 return cacheDir;
055 }
056 @Override
057 public synchronized ClassDefiner getClassDefiner(ClassDefiner defaultDefiner, ClassLoader parentClassLoader) {
058 if (classDefiner == null)
059 try {
060 classDefiner = new AndroidClassDefiner(getCacheDir(), parentClassLoader);
061 } catch (IOException ex) {
062 throw new RuntimeException("Failed to instantiate the Android class definer : " + ex, ex);
063 }
064 return classDefiner;
065 }
066
067 String getLibFileName(String libName) {
068 return "lib" + libName + ".so";
069 }
070 synchronized File getNativeLibraryDir(String someBundledNativeLibraryName) throws FileNotFoundException {
071 //String someKnownResource =
072 File f = null;
073 if (app != null) {
074 try {
075 // ApplicationInfo.nativeLibraryDir is only available from API level 9 and later
076 // http://developer.android.com/reference/android/content/pm/ApplicationInfo.html#nativeLibraryDir
077 f = (File)ApplicationInfo.class.getField("nativeLibraryDir").get(app.getApplicationInfo());
078 } catch (Throwable th) {}
079 }
080 if (f == null) {
081 String someKnownResource = "lib/armeabi/" + getLibFileName(someBundledNativeLibraryName);
082 f = new File(getApplicationDataDir(someKnownResource), "lib");
083 }
084
085 if (f != null && f.isDirectory())
086 return f;
087
088 throw new FileNotFoundException("Failed to get the native library directory " + (f != null ? "(" + f + " is not a directory). " : ". ") + adviseToSetApp());
089 }
090
091 synchronized File getApplicationDataDir(String someKnownResource) throws FileNotFoundException {
092 if (app != null)
093 return new File(app.getApplicationInfo().dataDir);
094 else
095 return new File(new File(Environment.getDataDirectory(), "data"), getPackageName(someKnownResource));
096 }
097
098 @Override
099 public synchronized NativeLibrary loadNativeLibrary(String name) throws IOException {
100 File f = new File(getNativeLibraryDir(name), getLibFileName(name));
101 if (f.exists()) {
102 return NativeLibrary.load(f == null ? name : f.toString());
103 } else {
104 throw new RuntimeException("File not found : " + f);
105 }
106 }
107
108 synchronized String getPackageName(String someKnownResource) throws FileNotFoundException {
109 if (app != null)
110 return app.getPackageName();
111 else {
112 URL resource = Platform.getResource(someKnownResource);
113 if (resource == null)
114 throw new FileNotFoundException("Resource does not exist : " + someKnownResource);
115
116 return getAndroidPackageNameFromResourceURL(resource.toString());
117 }
118 }
119
120 static String getAndroidPackageNameFromResourceURL(String url) {
121 Pattern p = Pattern.compile("jar:file:/data/[^/]+/([^/]*?)\\.apk!.*");
122 Matcher m = p.matcher(url);
123 String packageName = null;
124 if (!m.matches()) {
125 p = Pattern.compile("jar:file:/.*?/([^/]+)/pkg\\.apk!.*");
126 m = p.matcher(url);
127 }
128 if (m.matches()) {
129 packageName = m.group(1);
130 if (packageName.matches(".*?-\\d+")) {
131 int i = packageName.lastIndexOf("-");
132 packageName = packageName.substring(0, i);
133 }
134 }
135 return packageName;
136 }
137
138 }