diff --git a/jme3-android/src/main/java/com/jme3/asset/plugins/AndroidLocator.java b/jme3-android/src/main/java/com/jme3/asset/plugins/AndroidLocator.java index 4c0bae82f..cb102e582 100644 --- a/jme3-android/src/main/java/com/jme3/asset/plugins/AndroidLocator.java +++ b/jme3-android/src/main/java/com/jme3/asset/plugins/AndroidLocator.java @@ -1,6 +1,7 @@ package com.jme3.asset.plugins; import android.content.res.AssetFileDescriptor; +import android.content.res.Resources; import com.jme3.asset.*; import com.jme3.system.android.JmeAndroidSystem; import java.io.IOException; @@ -12,26 +13,89 @@ public class AndroidLocator implements AssetLocator { private static final Logger logger = Logger.getLogger(AndroidLocator.class.getName()); - private android.content.res.AssetManager androidManager; private String rootPath = ""; + public AndroidLocator() { + } + + public void setRootPath(String rootPath) { + this.rootPath = rootPath; + } + + @Override + public AssetInfo locate(AssetManager manager, AssetKey key) { + String assetPath = rootPath + key.getName(); + // Fix path issues + if (assetPath.startsWith("/")) { + // Remove leading / + assetPath = assetPath.substring(1); + } + assetPath = assetPath.replace("//", "/"); + + // Not making this a property and storing for future use in case the view stored in JmeAndroidSystem + // is replaced due to device orientation change. Not sure it is necessary to do this yet, but am for now. + android.content.res.Resources androidResources = JmeAndroidSystem.getView().getContext().getResources(); + String androidPackageName = JmeAndroidSystem.getView().getContext().getPackageName(); + +// logger.log(Level.INFO, "Asset Key: {0}", key); +// logger.log(Level.INFO, "Asset Name: {0}", key.getName()); +// logger.log(Level.INFO, "Asset Path: {0}", assetPath); +// logger.log(Level.INFO, "Asset Extension: {0}", key.getExtension()); +// logger.log(Level.INFO, "Asset Key Class: {0}", key.getClass().getName()); +// logger.log(Level.INFO, "androidPackageName: {0}", androidPackageName); +// logger.log(Level.INFO, "Resource Name: {0}", getResourceName(assetPath)); + + // check the assets directory for the asset using assetPath + try { + InputStream in = androidResources.getAssets().open(assetPath); + if (in != null){ + return new AndroidAssetInfo(manager, key, assetPath, in, 0); + } + } catch (IOException ex) { + // allow to fall through to the other checks in the resources directories. +// logger.log(Level.INFO, "Resource[{0}] not found in assets directory.", assetPath); + } + + // if not found in the assets directory, check the drawable and mipmap directories (only valid for images) + String resourceName = getResourceName(assetPath); + int resourceId = androidResources.getIdentifier(resourceName, "drawable", androidPackageName); +// logger.log(Level.INFO, "drawable resourceId: {0}", resourceId); + if (resourceId == 0) { // drawable resource not found, check mipmap resource type + resourceId = androidResources.getIdentifier(resourceName, "mipmap", androidPackageName); +// logger.log(Level.INFO, "mipmap resourceId: {0}", resourceId); + } + if (resourceId == 0) { // not found in resource directories, return null; + return null; + } + + // try to open a stream with the resourceId returned by Android + try { + InputStream in = androidResources.openRawResource(resourceId); + if (in != null){ +// logger.log(Level.INFO, "Creating new AndroidResourceInfo."); + return new AndroidAssetInfo(manager, key, assetPath, in, resourceId); + } + } catch (Resources.NotFoundException ex) { + // input stream failed to open, return null + return null; + } + + return null; + } + + + public class AndroidAssetInfo extends AssetInfo { private InputStream in; private final String assetPath; + private int resourceId; - public AndroidAssetInfo(com.jme3.asset.AssetManager assetManager, AssetKey key, String assetPath, InputStream in) { + AndroidAssetInfo(AssetManager assetManager, AssetKey key, String assetPath, InputStream in, int resourceId) { super(assetManager, key); this.assetPath = assetPath; this.in = in; - } - - public AssetFileDescriptor openFileDescriptor() { - try { - return androidManager.openFd(assetPath); - } catch (IOException ex) { - throw new AssetLoadException("Failed to open asset " + assetPath, ex); - } + this.resourceId = resourceId; } @Override @@ -43,55 +107,47 @@ public class AndroidLocator implements AssetLocator { return in2; }else{ // Create a new stream for subsequent invocations. + android.content.res.Resources androidResources = JmeAndroidSystem.getView().getContext().getResources(); + if (resourceId == 0) { + try { + return androidResources.getAssets().open(assetPath); + } catch (IOException ex) { + throw new AssetLoadException("Failed to open asset " + assetPath, ex); + } + } else { + try { + return androidResources.openRawResource(resourceId); + } catch (Resources.NotFoundException ex) { + throw new AssetLoadException("Failed to open asset " + assetPath, ex); + } + } + } + } + + public AssetFileDescriptor openFileDescriptor() { + android.content.res.Resources androidResources = JmeAndroidSystem.getView().getContext().getResources(); + if (resourceId == 0) { try { - return androidManager.open(assetPath); + return androidResources.getAssets().openFd(assetPath); } catch (IOException ex) { throw new AssetLoadException("Failed to open asset " + assetPath, ex); } + } else { + try { + return androidResources.openRawResourceFd(resourceId); + } catch (Resources.NotFoundException ex) { + throw new AssetLoadException("Failed to open asset " + assetPath, ex); + } } } } - private AndroidAssetInfo create(AssetManager assetManager, AssetKey key, String assetPath) throws IOException { - try { - InputStream in = androidManager.open(assetPath); - if (in == null){ - return null; - }else{ - return new AndroidAssetInfo(assetManager, key, assetPath, in); - } - } catch (IOException ex) { - // XXX: Prefer to show warning here? - // Should only surpress exceptions for "file missing" type errors. - return null; - } - } - - public AndroidLocator() { - androidManager = JmeAndroidSystem.getView().getContext().getAssets(); - } - - public void setRootPath(String rootPath) { - this.rootPath = rootPath; - } - - @SuppressWarnings("rawtypes") - @Override - public AssetInfo locate(com.jme3.asset.AssetManager manager, AssetKey key) { - String assetPath = rootPath + key.getName(); - // Fix path issues - if (assetPath.startsWith("/")) { - // Remove leading / - assetPath = assetPath.substring(1); - } - assetPath = assetPath.replace("//", "/"); - try { - return create(manager, key, assetPath); - } catch (IOException ex) { - // This is different handling than URL locator - // since classpath locating would return null at the getResource() - // call, otherwise there's a more critical error... - throw new AssetLoadException("Failed to open asset " + assetPath, ex); + private String getResourceName(String name) { + int idx = name.lastIndexOf('.'); + if (idx <= 0 || idx == name.length() - 1) { + return name; + } else { + return name.substring(0, idx).toLowerCase(); } } }