From 7ecb81c2303b73ef7c4bf388e5dd1b5d0e598d64 Mon Sep 17 00:00:00 2001 From: iwgeric Date: Mon, 2 May 2016 23:14:26 -0400 Subject: [PATCH] Update AndroidLocator to allow assets to be stored in Android assets, drawable, or mipmap directories. Texture assets can now be stored in Android Drawable and Mipmap directories. Allows Android to automatically select the closest matching image asset for the actual device configuration (ie. lower resolution textures for lower-end devices). Search order is: assets -> drawable -> mipmap. First match found is returned. (cherry picked from commit c219ce1) --- .../jme3/asset/plugins/AndroidLocator.java | 158 ++++++++++++------ 1 file changed, 107 insertions(+), 51 deletions(-) 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(); } } }