/* Create and attach the activity thread. */
activityThread = method.invoke (null);
+ context = null;
/* Now get an LoadedApk. */
- loadedApkClass = Class.forName ("android.app.LoadedApk");
- /* Get a LoadedApk. How to do this varies by Android version.
- On Android 2.3.3 and earlier, there is no
- ``compatibilityInfo'' argument to getPackageInfo. */
-
- if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.GINGERBREAD_MR1)
+ try
{
- method
- = activityThreadClass.getMethod ("getPackageInfo",
- String.class,
- int.class);
- loadedApk = method.invoke (activityThread, "org.gnu.emacs",
- 0);
+ loadedApkClass = Class.forName ("android.app.LoadedApk");
}
- else
+ catch (ClassNotFoundException exception)
{
- compatibilityInfoClass
- = Class.forName ("android.content.res.CompatibilityInfo");
-
- method
- = activityThreadClass.getMethod ("getPackageInfo",
- String.class,
- compatibilityInfoClass,
- int.class);
- loadedApk = method.invoke (activityThread, "org.gnu.emacs", null,
- 0);
- }
-
- if (loadedApk == null)
- throw new RuntimeException ("getPackageInfo returned NULL");
+ /* Android 2.2 has no LoadedApk class, but fortunately it
+ does not need to be used, since contexts can be
+ directly created. */
- /* Now, get a context. */
- contextImplClass = Class.forName ("android.app.ContextImpl");
+ loadedApkClass = null;
+ contextImplClass = Class.forName ("android.app.ContextImpl");
- try
- {
- method = contextImplClass.getDeclaredMethod ("createAppContext",
- activityThreadClass,
- loadedApkClass);
- method.setAccessible (true);
- context = (Context) method.invoke (null, activityThread, loadedApk);
- }
- catch (NoSuchMethodException exception)
- {
- /* Older Android versions don't have createAppContext, but
- instead require creating a ContextImpl, and then
- calling createPackageContext. */
method = activityThreadClass.getDeclaredMethod ("getSystemContext");
context = (Context) method.invoke (activityThread);
method = contextImplClass.getDeclaredMethod ("createPackageContext",
0);
}
+ /* If the context has not already been created, then do what
+ is appropriate for newer versions of Android. */
+
+ if (context == null)
+ {
+ /* Get a LoadedApk. How to do this varies by Android version.
+ On Android 2.3.3 and earlier, there is no
+ ``compatibilityInfo'' argument to getPackageInfo. */
+
+ if (Build.VERSION.SDK_INT
+ <= Build.VERSION_CODES.GINGERBREAD_MR1)
+ {
+ method
+ = activityThreadClass.getMethod ("getPackageInfo",
+ String.class,
+ int.class);
+ loadedApk = method.invoke (activityThread, "org.gnu.emacs",
+ 0);
+ }
+ else
+ {
+ compatibilityInfoClass
+ = Class.forName ("android.content.res.CompatibilityInfo");
+
+ method
+ = activityThreadClass.getMethod ("getPackageInfo",
+ String.class,
+ compatibilityInfoClass,
+ int.class);
+ loadedApk = method.invoke (activityThread, "org.gnu.emacs",
+ null, 0);
+ }
+
+ if (loadedApk == null)
+ throw new RuntimeException ("getPackageInfo returned NULL");
+
+ /* Now, get a context. */
+ contextImplClass = Class.forName ("android.app.ContextImpl");
+
+ try
+ {
+ method
+ = contextImplClass.getDeclaredMethod ("createAppContext",
+ activityThreadClass,
+ loadedApkClass);
+ method.setAccessible (true);
+ context = (Context) method.invoke (null, activityThread,
+ loadedApk);
+ }
+ catch (NoSuchMethodException exception)
+ {
+ /* Older Android versions don't have createAppContext, but
+ instead require creating a ContextImpl, and then
+ calling createPackageContext. */
+ method
+ = activityThreadClass.getDeclaredMethod ("getSystemContext");
+ context = (Context) method.invoke (activityThread);
+ method
+ = contextImplClass.getDeclaredMethod ("createPackageContext",
+ String.class,
+ int.class);
+ method.setAccessible (true);
+ context = (Context) method.invoke (context, "org.gnu.emacs",
+ 0);
+ }
+ }
+
/* Don't actually start the looper or anything. Instead, obtain
an AssetManager. */
assets = context.getAssets ();
#endif
}
-/* Read two bytes from FD and see if they are ``PK'', denoting ZIP
- archive compressed data. If FD is -1, return -1.
-
- If they are not, rewind the file descriptor to offset 0.
-
- If either operation fails, return -1 and close FD. Else, value is
- FD. */
-
-static int
-android_check_compressed_file (int fd)
-{
- char bytes[2];
-
- if (fd == -1)
- return -1;
-
- if (read (fd, bytes, 2) != 2)
- goto lseek_back;
-
- if (bytes[0] != 'P' || bytes[1] != 'K')
- goto lseek_back;
-
- /* This could be compressed data! */
- return -1;
-
- lseek_back:
- /* Seek back to offset 0. If this fails, return -1. */
- if (lseek (fd, 0, SEEK_SET) != 0)
- {
- close (fd);
- return -1;
- }
-
- return fd;
-}
-
/* Make FD close-on-exec. If any system call fails, do not abort, but
log a warning to the system log. */
return -1;
}
- /* Try to obtain the file descriptor corresponding to this
- asset. */
- fd = AAsset_openFileDescriptor (asset, &out_start,
- &out_length);
+ /* Create a shared memory file descriptor containing the asset
+ contents.
+
+ The documentation misleads people into thinking that
+ AAsset_openFileDescriptor does precisely this. However, it
+ instead returns an offset into any uncompressed assets in the
+ ZIP archive. This cannot be found in its documentation. */
- /* The platform sometimes returns a file descriptor to ZIP
- compressed data. Detect that and fall back to creating a
- shared memory file descriptor. */
- fd = android_check_compressed_file (fd);
+ fd = android_hack_asset_fd (asset);
if (fd == -1)
{
- /* The asset can't be accessed for some reason. Try to
- create a shared memory file descriptor. */
- fd = android_hack_asset_fd (asset);
-
- if (fd == -1)
- {
- AAsset_close (asset);
- errno = ENXIO;
- return -1;
- }
+ AAsset_close (asset);
+ errno = ENXIO;
+ return -1;
}
/* If O_CLOEXEC is specified, make the file descriptor close on