@ -1,6 +1,7 @@
package com.jme3.asset.plugins ;
package com.jme3.asset.plugins ;
import android.content.res.AssetFileDescriptor ;
import android.content.res.AssetFileDescriptor ;
import android.content.res.Resources ;
import com.jme3.asset.* ;
import com.jme3.asset.* ;
import com.jme3.system.android.JmeAndroidSystem ;
import com.jme3.system.android.JmeAndroidSystem ;
import java.io.IOException ;
import java.io.IOException ;
@ -12,26 +13,89 @@ public class AndroidLocator implements AssetLocator {
private static final Logger logger = Logger . getLogger ( AndroidLocator . class . getName ( ) ) ;
private static final Logger logger = Logger . getLogger ( AndroidLocator . class . getName ( ) ) ;
private android . content . res . AssetManager androidManager ;
private String rootPath = "" ;
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 {
public class AndroidAssetInfo extends AssetInfo {
private InputStream in ;
private InputStream in ;
private final String assetPath ;
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 ) ;
super ( assetManager , key ) ;
this . assetPath = assetPath ;
this . assetPath = assetPath ;
this . in = in ;
this . in = in ;
}
this . resourceId = resourceId ;
public AssetFileDescriptor openFileDescriptor ( ) {
try {
return androidManager . openFd ( assetPath ) ;
} catch ( IOException ex ) {
throw new AssetLoadException ( "Failed to open asset " + assetPath , ex ) ;
}
}
}
@Override
@Override
@ -43,55 +107,47 @@ public class AndroidLocator implements AssetLocator {
return in2 ;
return in2 ;
} else {
} else {
// Create a new stream for subsequent invocations.
// Create a new stream for subsequent invocations.
android . content . res . Resources androidResources = JmeAndroidSystem . getView ( ) . getContext ( ) . getResources ( ) ;
if ( resourceId = = 0 ) {
try {
try {
return androidManager . open ( assetPath ) ;
return androidResources . getAssets ( ) . open ( assetPath ) ;
} catch ( IOException ex ) {
} catch ( IOException ex ) {
throw new AssetLoadException ( "Failed to open asset " + assetPath , 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 ) ;
}
}
}
}
}
}
}
private AndroidAssetInfo create ( AssetManager assetManager , AssetKey key , String assetPath ) throws IOException {
public AssetFileDescriptor openFileDescriptor ( ) {
android . content . res . Resources androidResources = JmeAndroidSystem . getView ( ) . getContext ( ) . getResources ( ) ;
if ( resourceId = = 0 ) {
try {
try {
InputStream in = androidManager . open ( assetPath ) ;
return androidResources . getAssets ( ) . openFd ( assetPath ) ;
if ( in = = null ) {
return null ;
} else {
return new AndroidAssetInfo ( assetManager , key , assetPath , in ) ;
}
} catch ( IOException ex ) {
} catch ( IOException ex ) {
// XXX: Prefer to show warning here?
throw new AssetLoadException ( "Failed to open asset " + assetPath , ex ) ;
// Should only surpress exceptions for "file missing" type errors.
return null ;
}
}
} else {
try {
return androidResources . openRawResourceFd ( resourceId ) ;
} catch ( Resources . NotFoundException ex ) {
throw new AssetLoadException ( "Failed to open asset " + assetPath , ex ) ;
}
}
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 {
private String getResourceName ( String name ) {
return create ( manager , key , assetPath ) ;
int idx = name . lastIndexOf ( '.' ) ;
} catch ( IOException ex ) {
if ( idx < = 0 | | idx = = name . length ( ) - 1 ) {
// This is different handling than URL locator
return name ;
// since classpath locating would return null at the getResource()
} else {
// call, otherwise there's a more critical error...
return name . substring ( 0 , idx ) . toLowerCase ( ) ;
throw new AssetLoadException ( "Failed to open asset " + assetPath , ex ) ;
}
}
}
}
}
}