Переглянути джерело

optimized JNI calls to improve loading performance

Tim Newell 12 роки тому
батько
коміт
569bc6fda4

+ 1 - 0
engine/compilers/Xcode/Torque2D.xcodeproj/project.pbxproj

@@ -3575,6 +3575,7 @@
 				GCC_PREPROCESSOR_DEFINITIONS = (
 					TORQUE_OS_OSX,
 					"$(inherited)",
+					TORQUE_ALLOW_DSO_GENERATION,
 				);
 				HEADER_SEARCH_PATHS = (
 					../../source,

+ 1 - 1
engine/compilers/android/.cproject

@@ -22,7 +22,7 @@
 					<folderInfo id="com.android.toolchain.gcc.1442582075.1056020003" name="/" resourcePath="">
 						<toolChain id="com.android.toolchain.gcc.1400756764" name="com.android.toolchain.gcc" superClass="com.android.toolchain.gcc">
 							<targetPlatform binaryParser="org.eclipse.cdt.core.ELF" id="com.android.targetPlatform.1302199400" isAbstract="false" superClass="com.android.targetPlatform"/>
-							<builder arguments="NDK_DEBUG=1" command="ndk-build" id="com.android.builder.1818800065" keepEnvironmentInBuildfile="false" managedBuildOn="false" name="Android Builder" superClass="com.android.builder"/>
+							<builder arguments="" command="ndk-build" id="com.android.builder.1818800065" keepEnvironmentInBuildfile="false" managedBuildOn="false" name="Android Builder" superClass="com.android.builder"/>
 							<tool id="com.android.gcc.compiler.1014866906" name="Android GCC Compiler" superClass="com.android.gcc.compiler">
 								<option id="com.android.gcc.option.includePath.100688008" superClass="com.android.gcc.option.includePath" valueType="includePath">
 									<listOptionValue builtIn="false" value="&quot;${workspace_loc:/Torque2D/jni/include/libpng}&quot;"/>

+ 1 - 1
engine/compilers/android/.project

@@ -19,7 +19,7 @@
 				</dictionary>
 				<dictionary>
 					<key>org.eclipse.cdt.make.core.buildArguments</key>
-					<value>NDK_DEBUG=1</value>
+					<value></value>
 				</dictionary>
 				<dictionary>
 					<key>org.eclipse.cdt.make.core.buildCommand</key>

+ 1 - 1
engine/compilers/android/AndroidManifest.xml

@@ -20,7 +20,7 @@
         android:icon="@drawable/ic_launcher"
         android:label="@string/app_name"
         android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
-        android:hardwareAccelerated="true" android:hasCode="true" android:debuggable="true">
+        android:hardwareAccelerated="true" android:hasCode="true">
         <activity
             android:name="android.app.NativeActivity"
             android:label="@string/app_name"

+ 5 - 2
engine/compilers/android/jni/Android.mk

@@ -543,8 +543,11 @@ LOCAL_SRC_FILES :=  ../../../lib/ljpeg/jcapimin.c \
 #					../../../source/testing/tests/platformStringTests.cc \
 #					../../../source/testing/unitTesting.cc
  
-			   
-LOCAL_CFLAGS := -DENABLE_CONSOLE_MSGS -D__ANDROID__ -DTORQUE_OS_ANDROID -DGL_GLEXT_PROTOTYPES -O0 -fsigned-char   
+ifeq ($(APP_OPTIM),debug)
+	LOCAL_CFLAGS := -DENABLE_CONSOLE_MSGS -D__ANDROID__ -DTORQUE_DEBUG -DTORQUE_OS_ANDROID -DGL_GLEXT_PROTOTYPES -O0 -fsigned-char   
+else
+	LOCAL_CFLAGS := -DENABLE_CONSOLE_MSGS -D__ANDROID__ -DTORQUE_OS_ANDROID -DGL_GLEXT_PROTOTYPES -O3 -fsigned-char   
+endif				   
 LOCAL_LDLIBS    := -llog -landroid -lEGL -lGLESv1_CM -lz -lOpenSLES -L../../../lib/openal/Android/$(TARGET_ARCH_ABI)
 LOCAL_STATIC_LIBRARIES := android_native_app_glue freetype-prebuilt libopenal-prebuilt
 #LOCAL_SHARED_LIBRARIES := libopenal-prebuilt

+ 1 - 1
engine/compilers/android/jni/Application.mk

@@ -1,4 +1,4 @@
 APP_PLATFORM := android-10
 APP_STL := stlport_static
-APP_OPTIM := debug
+APP_OPTIM := release
 APP_ABI   := armeabi-v7a

+ 168 - 0
engine/compilers/android/src/com/garagegames/torque2d/FileWalker.java

@@ -3,6 +3,7 @@ package com.garagegames.torque2d;
 import java.io.IOException;
 import java.io.InputStream;
 import java.util.Hashtable;
+import java.util.List;
 import java.util.Vector;
 
 import android.content.Context;
@@ -16,6 +17,8 @@ public class FileWalker
 {
 	public static Hashtable<String,Vector<String>> directories = new Hashtable<String,Vector<String>>();
 	public static Hashtable<String,Vector<String>> files = new Hashtable<String,Vector<String>>();
+	public static Vector<String> dumpPathVec = new Vector<String>();
+	public static Vector<String> dumpDirVec = new Vector<String>();
 	
 	public static void InitDirList(Context context, String dir)
 	{
@@ -46,6 +49,171 @@ public class FileWalker
 		}
 	}
 	
+	public static String[] DumpDirectories(Context context, String basePath, String path, boolean depth, boolean noBasePath)
+	{
+
+	    dumpPathVec.clear();
+		dumpDirVec.clear();
+		
+		String dirPath = basePath;
+	    
+		if (dirPath.startsWith("/"))
+	    	dirPath = dirPath.substring(1);
+		
+		if (dirPath.endsWith("/"))
+	    	dirPath = dirPath.substring(0,dirPath.length()-1);
+	   
+	    if ( !noBasePath )
+	        dumpPathVec.add(dirPath);
+	   
+	    if (!path.equals(""))
+	    {
+		    dirPath = basePath + "/" + path; 
+		    
+		    if (dirPath.endsWith("/"))
+		    	dirPath = dirPath.substring(0,dirPath.length()-1);
+		   
+	    }
+	   
+		//Log.i("torque2d", "Dump first dir: " + dirPath);
+		DumpDir2(context, dirPath);
+		
+		while (depth && dumpDirVec.size() > 0)
+		{
+			String newdir = dumpDirVec.remove(0);
+			//Log.i("torque2d", "Dump dir again: " + newdir);
+			DumpDir2(context,newdir);
+		}
+		
+		int size = dumpPathVec.size();
+		if (size > 500)
+			size = 500;
+		String[] retStringArray = new String[size];
+		int cnt = 0;
+		for(cnt = 0; cnt < size; cnt++)
+		{
+			String s = dumpPathVec.remove(0);
+			if (noBasePath)
+				s = s.replace(basePath + "/", "");
+			retStringArray[cnt] = "/" + s;
+		}
+		return retStringArray;
+	}
+	
+	public static void DumpDir2(Context context, String dir)
+	{
+		AssetManager assetMgr = context.getAssets();
+		try {
+			String[] assets = assetMgr.list(dir);
+			for (String asset : assets)
+			{
+				if (asset.equals(".") || asset.equals(".."))
+					continue;
+				
+				if (!asset.contains("."))
+				{
+					if (dir.equals(""))
+						dumpPathVec.add(asset);
+					else
+						dumpPathVec.add(dir + "/" + asset);
+					
+					String newdir = asset;
+					if (!dir.equals(""))
+						newdir = dir + "/" + asset;
+					
+					dumpDirVec.add(newdir);
+				}
+			}
+				
+		} catch (IOException e) {
+			
+		}
+	}
+	
+	public static String[] DumpPath(Context context, String dirPath, boolean depth)
+	{
+		dumpPathVec.clear();
+		dumpDirVec.clear();
+		
+		String dir = dirPath;
+		
+		if (dir.startsWith("/"))
+	    	dir = dir.substring(1);
+		
+		if (dir.endsWith("/"))
+	    	dir = dir.substring(0,dir.length()-1);
+	   
+		//Log.i("torque2d", "Dump first dir: " + dir);
+		DumpDir(context, dir);
+		
+		while (depth && dumpDirVec.size() > 0)
+		{
+			String newdir = dumpDirVec.remove(0);
+			//Log.i("torque2d", "Dump dir again: " + newdir);
+			DumpDir(context,newdir);
+		}
+		
+		int size = dumpPathVec.size();
+		if (size > 500)
+			size = 500;
+		String[] retStringArray = new String[size];
+		int cnt = 0;
+		for(cnt = 0; cnt < size; cnt++)
+		{
+			String s = dumpPathVec.remove(0);
+			retStringArray[cnt] = "/" + s;
+		}
+		return retStringArray;
+	}
+	
+	public static String[] getRestOfDump()
+	{
+		int size = dumpPathVec.size();
+		if (size > 500)
+			size = 500;
+		String[] retStringArray = new String[size];
+		int cnt = 0;
+		for(cnt = 0; cnt < size; cnt++)
+		{
+			String s = dumpPathVec.remove(0);
+			retStringArray[cnt] = "/" + s;
+		}
+		return retStringArray;
+	}
+	
+	public static void DumpDir(Context context, String dir)
+	{
+		AssetManager assetMgr = context.getAssets();
+		try {
+			String[] assets = assetMgr.list(dir);
+			for (String asset : assets)
+			{
+				if (asset.equals(".") || asset.equals(".."))
+					continue;
+				
+				if (asset.contains("."))
+				{
+					if (dir.equals(""))
+						dumpPathVec.add(asset);
+					else
+						dumpPathVec.add(dir + "/" + asset);
+				}
+				else
+				{
+					String newdir = asset;
+					if (!dir.equals(""))
+						newdir = dir + "/" + asset;
+					
+					dumpDirVec.add(newdir);
+						
+				}
+			}
+				
+		} catch (IOException e) {
+			
+		}
+	}
+	
 	public static String GetNextDir(String dir)
 	{
 		if (directories.get(dir).size() == 0)

+ 12 - 44
engine/source/platformAndroid/AndroidFileio.cpp

@@ -808,8 +808,13 @@ bool Platform::isFile(const char *path)
 	  return false;
    }
 
+   //Checking for . to avoid multiple JNI calls for performance.
+   if (strstr(path, ".") == NULL)
+	   return false;
+
+   return true;
 
-   return android_IsFile(path);
+   //return android_IsFile(path);
 }
 
 
@@ -938,7 +943,7 @@ bool Platform::hasSubDirectory(const char *path)
 }
 
 //-----------------------------------------------------------------------------
-bool recurseDumpDirectories(const char *basePath, const char *path, Vector<StringTableEntry> &directoryVector, S32 depth, bool noBasePath)
+/*bool recurseDumpDirectories(const char *basePath, const char *path, Vector<StringTableEntry> &directoryVector, S32 depth, bool noBasePath)
 {
 	char aPath[80];
    if (basePath[0] == '/')
@@ -1005,7 +1010,7 @@ bool recurseDumpDirectories(const char *basePath, const char *path, Vector<Strin
         android_GetNextDir(pathbuf, dir);
      }
      return true;
-}
+}*/
 
 //-----------------------------------------------------------------------------
 bool recurseDumpDirectoriesCache(const char *basePath, const char *path, Vector<StringTableEntry> &directoryVector, S32 depth, bool noBasePath)
@@ -1109,35 +1114,15 @@ bool Platform::dumpDirectories(const char *path, Vector<StringTableEntry> &direc
 	}
 
    PROFILE_START(dumpDirectories);
-
    ResourceManager->initExcludedDirectories();
-
-   const S32 len = dStrlen(path)+1;
-   char newpath[len];
-   if (path[0] == '/')
-   {
-	   dSprintf(newpath, len-1, "%s", path+1);
-   }
-   else
-   {
-	   dSprintf(newpath, len, "%s", path);
-   }
-
-   if(newpath[len - 1] == '/')
-      newpath[len - 1] = '\0'; // cut off the trailing slash, if there is one
-   
-    // Insert base path to follow what Windows does.
-    if ( !noBasePath )
-        directoryVector.push_back(StringTable->insert(newpath));
-   
-    bool ret = recurseDumpDirectories(newpath, "", directoryVector, depth, noBasePath);
+   bool ret = android_DumpDirectories(path, "", directoryVector, depth, noBasePath);
    PROFILE_END();
    
    return ret;
 }
 
 //-----------------------------------------------------------------------------
-static bool recurseDumpPath(const char* curPath, Vector<Platform::FileInfo>& fileVector, U32 depth)
+/*static bool recurseDumpPath(const char* curPath, Vector<Platform::FileInfo>& fileVector, U32 depth)
 {
    android_InitDirList(curPath);
    
@@ -1201,7 +1186,7 @@ static bool recurseDumpPath(const char* curPath, Vector<Platform::FileInfo>& fil
 
    return true;
    
-}
+}*/
 
 //-----------------------------------------------------------------------------
 static bool recurseDumpPathCache(const char* curPath, Vector<Platform::FileInfo>& fileVector, U32 depth)
@@ -1280,24 +1265,7 @@ bool Platform::dumpPath(const char *path, Vector<Platform::FileInfo>& fileVector
 	}
 
    PROFILE_START(dumpPath);
-   char apath[80];
-   if (path[0] == '/')
-   {
-	   strcpy(apath, path+1);
-   }
-   else
-   {
-	   strcpy(apath, path);
-   }
-    const S32 len = dStrlen(apath) + 1;
-   char newpath[len];
-   
-    dSprintf(newpath, len, "%s", apath);
-    
-   if(newpath[len - 2] == '/')
-      newpath[len - 2] = '\0'; // cut off the trailing slash, if there is one
-   
-   bool ret = recurseDumpPath( newpath, fileVector, depth);
+   bool ret = android_DumpPath( path, fileVector, depth);
    PROFILE_END();
    
    return ret;

+ 416 - 24
engine/source/platformAndroid/T2DActivity.cpp

@@ -76,7 +76,7 @@ void ChangeVolume(bool up) {
     // Attaches the current thread to the JVM.
     jint lResult;
     jint lFlags = 0;
-
+    adprintf("JVM ChangeVolume");
     JavaVM* lJavaVM = platState.engine->app->activity->vm;
     JNIEnv* lJNIEnv = platState.engine->app->activity->env;
 
@@ -521,7 +521,7 @@ void _AndroidGetDeviceIPAddress(char* address) {
 	 // Attaches the current thread to the JVM.
 	 jint lResult;
 	 jint lFlags = 0;
-
+	 adprintf("JVM GetDeviceIP");
 	 JavaVM* lJavaVM = platState.engine->app->activity->vm;
 	 JNIEnv* lJNIEnv = platState.engine->app->activity->env;
 
@@ -785,7 +785,7 @@ void keepScreenOn() {
     // Attaches the current thread to the JVM.
     jint lResult;
     jint lFlags = 0;
-
+    adprintf("JVM KeepScreenOn");
     JavaVM* lJavaVM = platState.engine->app->activity->vm;
     JNIEnv* lJNIEnv = platState.engine->app->activity->env;
 
@@ -831,7 +831,7 @@ void T2DActivity::loadCacheDir() {
     // Attaches the current thread to the JVM.
     jint lResult;
     jint lFlags = 0;
-
+    adprintf("JVM loadCacheDir");
     JavaVM* lJavaVM = platState.engine->app->activity->vm;
     JNIEnv* lJNIEnv = platState.engine->app->activity->env;
 
@@ -871,7 +871,7 @@ void T2DActivity::enumerateFonts() {
 	// Attaches the current thread to the JVM.
 	jint lResult;
 	jint lFlags = 0;
-
+	adprintf("JVM enumerateFonts");
 	JavaVM* lJavaVM = platState.engine->app->activity->vm;
 	JNIEnv* lJNIEnv = platState.engine->app->activity->env;
 
@@ -908,7 +908,7 @@ void T2DActivity::dumpFontList() {
 	// Attaches the current thread to the JVM.
 	jint lResult;
 	jint lFlags = 0;
-
+	adprintf("JVM dumpFontList");
 	JavaVM* lJavaVM = platState.engine->app->activity->vm;
 	JNIEnv* lJNIEnv = platState.engine->app->activity->env;
 
@@ -945,7 +945,7 @@ void T2DActivity::getFontPath(const char* fontName, char* fontPath) {
 	// Attaches the current thread to the JVM.
 	jint lResult;
 	jint lFlags = 0;
-
+	adprintf("JVM getFontPath");
 	JavaVM* lJavaVM = platState.engine->app->activity->vm;
 	JNIEnv* lJNIEnv = platState.engine->app->activity->env;
 
@@ -1168,12 +1168,404 @@ void android_main(struct android_app* state) {
     engine_term_display(&engine, true);
 }
 
-void android_InitDirList(const char* dir)
+struct MatchPathSeparator
+{
+    bool operator()( char ch ) const
+    {
+        return ch == '/';
+    }
+};
+
+bool android_DumpDirectoriesExtra(Vector<StringTableEntry> &directoryVector)
+{
+	// Attaches the current thread to the JVM.
+	jint lResult;
+	jint lFlags = 0;
+	adprintf("JNI dumpDirExtra");
+	JavaVM* lJavaVM = engine.app->activity->vm;
+	JNIEnv* lJNIEnv = engine.app->activity->env;
+
+	JavaVMAttachArgs lJavaVMAttachArgs;
+	lJavaVMAttachArgs.version = JNI_VERSION_1_6;
+	lJavaVMAttachArgs.name = "NativeThread";
+	lJavaVMAttachArgs.group = NULL;
+
+	lResult=lJavaVM->AttachCurrentThread(&lJNIEnv, &lJavaVMAttachArgs);
+	if (lResult == JNI_ERR) {
+		return false;
+	}
+
+	// Retrieves NativeActivity.
+	jobject lNativeActivity = engine.app->activity->clazz;
+	jclass ClassNativeActivity = lJNIEnv->GetObjectClass(lNativeActivity);
+
+	jmethodID getClassLoader = lJNIEnv->GetMethodID(ClassNativeActivity,"getClassLoader", "()Ljava/lang/ClassLoader;");
+	jobject cls = lJNIEnv->CallObjectMethod(lNativeActivity, getClassLoader);
+	jclass classLoader = lJNIEnv->FindClass("java/lang/ClassLoader");
+	jmethodID findClass = lJNIEnv->GetMethodID(classLoader, "loadClass", "(Ljava/lang/String;)Ljava/lang/Class;");
+	jstring strClassName = lJNIEnv->NewStringUTF("com/garagegames/torque2d/FileWalker");
+	jclass FileWalkerClass = (jclass)lJNIEnv->CallObjectMethod(cls, findClass, strClassName);
+	jmethodID MethodExtraPaths = lJNIEnv->GetStaticMethodID(FileWalkerClass, "getRestOfDump", "()[Ljava/lang/String;");
+	jobjectArray stringArray = (jobjectArray)lJNIEnv->CallStaticObjectMethod(FileWalkerClass, MethodExtraPaths);
+
+	bool ret = true;
+	if (stringArray)
+	{
+		int stringCount = lJNIEnv->GetArrayLength(stringArray);
+
+		if (stringCount < 500)
+			ret = false;
+
+		for (int i=0; i<stringCount; i++) {
+			jstring string = (jstring) lJNIEnv->GetObjectArrayElement(stringArray, i);
+			const char *rawString = lJNIEnv->GetStringUTFChars(string, 0);
+			char str[255];
+			strcpy(str, rawString);
+			lJNIEnv->ReleaseStringUTFChars(string, rawString);
+
+			if (!Platform::isExcludedDirectory(str))
+			{
+				directoryVector.push_back(StringTable->insert(str));
+			}
+		}
+		lJNIEnv->DeleteLocalRef(stringArray);
+	}
+	else
+	{
+		ret = false;
+	}
+
+	lJNIEnv->DeleteLocalRef(strClassName);
+
+	// Finished with the JVM.
+	lJavaVM->DetachCurrentThread();
+
+	return ret;
+}
+
+bool android_DumpDirectories(const char *basePath, const char *path, Vector<StringTableEntry> &directoryVector, S32 depth, bool noBasePath)
+{
+	// Attaches the current thread to the JVM.
+	jint lResult;
+	jint lFlags = 0;
+	adprintf("JNI dumpDir");
+	JavaVM* lJavaVM = engine.app->activity->vm;
+	JNIEnv* lJNIEnv = engine.app->activity->env;
+
+	JavaVMAttachArgs lJavaVMAttachArgs;
+	lJavaVMAttachArgs.version = JNI_VERSION_1_6;
+	lJavaVMAttachArgs.name = "NativeThread";
+	lJavaVMAttachArgs.group = NULL;
+
+	lResult=lJavaVM->AttachCurrentThread(&lJNIEnv, &lJavaVMAttachArgs);
+	if (lResult == JNI_ERR) {
+		return false;
+	}
+
+	// Retrieves NativeActivity.
+	jobject lNativeActivity = engine.app->activity->clazz;
+	jclass ClassNativeActivity = lJNIEnv->GetObjectClass(lNativeActivity);
+
+	jmethodID getClassLoader = lJNIEnv->GetMethodID(ClassNativeActivity,"getClassLoader", "()Ljava/lang/ClassLoader;");
+	jobject cls = lJNIEnv->CallObjectMethod(lNativeActivity, getClassLoader);
+	jclass classLoader = lJNIEnv->FindClass("java/lang/ClassLoader");
+	jmethodID findClass = lJNIEnv->GetMethodID(classLoader, "loadClass", "(Ljava/lang/String;)Ljava/lang/Class;");
+	jstring strClassName = lJNIEnv->NewStringUTF("com/garagegames/torque2d/FileWalker");
+	jclass FileWalkerClass = (jclass)lJNIEnv->CallObjectMethod(cls, findClass, strClassName);
+	jstring strDirName = lJNIEnv->NewStringUTF(basePath);
+	jstring strDirName2 = lJNIEnv->NewStringUTF(path);
+	jmethodID MethodFileWalker = lJNIEnv->GetStaticMethodID(FileWalkerClass, "DumpDirectories", "(Landroid/content/Context;Ljava/lang/String;Ljava/lang/String;ZZ)[Ljava/lang/String;");
+	jobjectArray stringArray = (jobjectArray)lJNIEnv->CallStaticObjectMethod(FileWalkerClass, MethodFileWalker, lNativeActivity, strDirName, strDirName2, depth != 0, noBasePath);
+
+	bool ret = false;
+
+	if (stringArray)
+	{
+		int stringCount = lJNIEnv->GetArrayLength(stringArray);
+
+		for (int i=0; i<stringCount; i++) {
+			jstring string = (jstring) lJNIEnv->GetObjectArrayElement(stringArray, i);
+			const char *rawString = lJNIEnv->GetStringUTFChars(string, 0);
+			char str[255];
+			strcpy(str, rawString);
+			lJNIEnv->ReleaseStringUTFChars(string, rawString);
+
+			if (!Platform::isExcludedDirectory(str))
+			{
+				directoryVector.push_back(StringTable->insert(str));
+			}
+
+
+		}
+
+		lJNIEnv->DeleteLocalRef(stringArray);
+
+		bool keepGoing = false;
+
+		if (stringCount == 500)
+		{
+			keepGoing = true;
+		}
+
+		lJNIEnv->DeleteLocalRef(strClassName);
+		lJNIEnv->DeleteLocalRef(strDirName);
+		lJNIEnv->DeleteLocalRef(strDirName2);
+
+		// Finished with the JVM.
+		lJavaVM->DetachCurrentThread();
+
+		while (keepGoing == true)
+			keepGoing = android_DumpDirectoriesExtra(directoryVector);
+
+		ret = true;
+	}
+	else
+	{
+		lJNIEnv->DeleteLocalRef(strClassName);
+		lJNIEnv->DeleteLocalRef(strDirName);
+		lJNIEnv->DeleteLocalRef(strDirName2);
+
+		// Finished with the JVM.
+		lJavaVM->DetachCurrentThread();
+
+		ret = false;
+	}
+
+	return ret;
+}
+
+static Vector<Platform::FileInfo> dumpPathBackup;
+
+bool android_DumpPathExtra(Vector<Platform::FileInfo>& fileVector)
+{
+	// Attaches the current thread to the JVM.
+	jint lResult;
+	jint lFlags = 0;
+	adprintf("JNI dumpPathExtra");
+	JavaVM* lJavaVM = engine.app->activity->vm;
+	JNIEnv* lJNIEnv = engine.app->activity->env;
+
+	JavaVMAttachArgs lJavaVMAttachArgs;
+	lJavaVMAttachArgs.version = JNI_VERSION_1_6;
+	lJavaVMAttachArgs.name = "NativeThread";
+	lJavaVMAttachArgs.group = NULL;
+
+	lResult=lJavaVM->AttachCurrentThread(&lJNIEnv, &lJavaVMAttachArgs);
+	if (lResult == JNI_ERR) {
+		return false;
+	}
+
+	// Retrieves NativeActivity.
+	jobject lNativeActivity = engine.app->activity->clazz;
+	jclass ClassNativeActivity = lJNIEnv->GetObjectClass(lNativeActivity);
+
+	jmethodID getClassLoader = lJNIEnv->GetMethodID(ClassNativeActivity,"getClassLoader", "()Ljava/lang/ClassLoader;");
+	jobject cls = lJNIEnv->CallObjectMethod(lNativeActivity, getClassLoader);
+	jclass classLoader = lJNIEnv->FindClass("java/lang/ClassLoader");
+	jmethodID findClass = lJNIEnv->GetMethodID(classLoader, "loadClass", "(Ljava/lang/String;)Ljava/lang/Class;");
+	jstring strClassName = lJNIEnv->NewStringUTF("com/garagegames/torque2d/FileWalker");
+	jclass FileWalkerClass = (jclass)lJNIEnv->CallObjectMethod(cls, findClass, strClassName);
+	jmethodID MethodExtraPaths = lJNIEnv->GetStaticMethodID(FileWalkerClass, "getRestOfDump", "()[Ljava/lang/String;");
+	jobjectArray stringArray = (jobjectArray)lJNIEnv->CallStaticObjectMethod(FileWalkerClass, MethodExtraPaths);
+
+	bool ret = true;
+	if (stringArray)
+	{
+		int stringCount = lJNIEnv->GetArrayLength(stringArray);
+
+		if (stringCount < 500)
+			ret = false;
+
+		for (int i=0; i<stringCount; i++) {
+			jstring string = (jstring) lJNIEnv->GetObjectArrayElement(stringArray, i);
+			const char *rawString = lJNIEnv->GetStringUTFChars(string, 0);
+			std::string str = rawString;
+			lJNIEnv->ReleaseStringUTFChars(string, rawString);
+
+			const U32 fileSize = Platform::getFileSize(str.c_str());
+			fileVector.increment();
+			Platform::FileInfo& rInfo = fileVector.last();
+			std::string fileName = std::string(
+					std::find_if( str.rbegin(), str.rend(),
+								  MatchPathSeparator() ).base(),
+					str.end() );
+			rInfo.pFullPath = StringTable->insert(str.substr(0,str.find(fileName)-1).c_str());
+			rInfo.pFileName = StringTable->insert(fileName.c_str());
+			rInfo.fileSize  = fileSize;
+
+			dumpPathBackup.increment();
+			Platform::FileInfo& rInfo2 = dumpPathBackup.last();
+			rInfo2.pFullPath = rInfo.pFullPath;
+			rInfo2.pFileName = rInfo.pFileName;
+			rInfo2.fileSize  = rInfo.fileSize;
+
+		}
+		lJNIEnv->DeleteLocalRef(stringArray);
+	}
+	else
+	{
+		ret = false;
+	}
+
+	lJNIEnv->DeleteLocalRef(strClassName);
+
+	// Finished with the JVM.
+	lJavaVM->DetachCurrentThread();
+
+	return ret;
+
+}
+
+bool loadDumpPathFromCache(const char* dir, Vector<Platform::FileInfo>& fileVector, U32 depth)
 {
+	bool foundPaths = false;
+	for (int i = 0; i < dumpPathBackup.size(); i++)
+	{
+		if (depth == 0)
+		{
+			Platform::FileInfo fi = dumpPathBackup[i];
+			if (strcmp(fi.pFullPath, dir) == 0)
+			{
+				fileVector.increment();
+				Platform::FileInfo& rInfo = fileVector.last();
+				rInfo.pFileName = fi.pFileName;
+				rInfo.pFullPath = fi.pFullPath;
+				rInfo.fileSize = fi.fileSize;
+				foundPaths = true;
+			}
+		}
+		else
+		{
+			Platform::FileInfo fi = dumpPathBackup[i];
+			std::string fullPath = fi.pFullPath;
+
+			if (fullPath.find(dir) == 0)
+			{
+				fileVector.increment();
+				Platform::FileInfo& rInfo = fileVector.last();
+				rInfo.pFileName = fi.pFileName;
+				rInfo.pFullPath = fi.pFullPath;
+				rInfo.fileSize = fi.fileSize;
+				foundPaths = true;
+			}
+		}
+	}
+
+	return true;
+}
+
+bool android_DumpPath(const char* dir, Vector<Platform::FileInfo>& fileVector, U32 depth)
+{
+	if (dumpPathBackup.size() > 0)
+	{
+		return loadDumpPathFromCache(dir, fileVector, depth);
+	}
+
 	// Attaches the current thread to the JVM.
 	jint lResult;
 	jint lFlags = 0;
+	adprintf("JNI dumpPath");
+	JavaVM* lJavaVM = engine.app->activity->vm;
+	JNIEnv* lJNIEnv = engine.app->activity->env;
+
+	JavaVMAttachArgs lJavaVMAttachArgs;
+	lJavaVMAttachArgs.version = JNI_VERSION_1_6;
+	lJavaVMAttachArgs.name = "NativeThread";
+	lJavaVMAttachArgs.group = NULL;
 
+	lResult=lJavaVM->AttachCurrentThread(&lJNIEnv, &lJavaVMAttachArgs);
+	if (lResult == JNI_ERR) {
+		return false;
+	}
+
+	// Retrieves NativeActivity.
+	jobject lNativeActivity = engine.app->activity->clazz;
+	jclass ClassNativeActivity = lJNIEnv->GetObjectClass(lNativeActivity);
+
+	jmethodID getClassLoader = lJNIEnv->GetMethodID(ClassNativeActivity,"getClassLoader", "()Ljava/lang/ClassLoader;");
+	jobject cls = lJNIEnv->CallObjectMethod(lNativeActivity, getClassLoader);
+	jclass classLoader = lJNIEnv->FindClass("java/lang/ClassLoader");
+	jmethodID findClass = lJNIEnv->GetMethodID(classLoader, "loadClass", "(Ljava/lang/String;)Ljava/lang/Class;");
+	jstring strClassName = lJNIEnv->NewStringUTF("com/garagegames/torque2d/FileWalker");
+	jclass FileWalkerClass = (jclass)lJNIEnv->CallObjectMethod(cls, findClass, strClassName);
+	jstring strDirName = lJNIEnv->NewStringUTF(dir);
+	jmethodID MethodFileWalker = lJNIEnv->GetStaticMethodID(FileWalkerClass, "DumpPath", "(Landroid/content/Context;Ljava/lang/String;Z)[Ljava/lang/String;");
+	jobjectArray stringArray = (jobjectArray)lJNIEnv->CallStaticObjectMethod(FileWalkerClass, MethodFileWalker, lNativeActivity, strDirName, depth != 0);
+
+	bool ret = false;
+
+	if (stringArray)
+	{
+		int stringCount = lJNIEnv->GetArrayLength(stringArray);
+
+		for (int i=0; i<stringCount; i++) {
+			jstring string = (jstring) lJNIEnv->GetObjectArrayElement(stringArray, i);
+			const char *rawString = lJNIEnv->GetStringUTFChars(string, 0);
+			std::string str = rawString;
+			lJNIEnv->ReleaseStringUTFChars(string, rawString);
+
+			const U32 fileSize = Platform::getFileSize(str.c_str());
+			fileVector.increment();
+			Platform::FileInfo& rInfo = fileVector.last();
+			std::string fileName = std::string(
+			        std::find_if( str.rbegin(), str.rend(),
+			                      MatchPathSeparator() ).base(),
+			        str.end() );
+			rInfo.pFullPath = StringTable->insert(str.substr(0,str.find(fileName)-1).c_str());
+			rInfo.pFileName = StringTable->insert(fileName.c_str());
+			rInfo.fileSize  = fileSize;
+
+			if (strcmp(dir, "") == 0)
+			{
+				dumpPathBackup.increment();
+				Platform::FileInfo& rInfo2 = dumpPathBackup.last();
+				rInfo2.pFullPath = rInfo.pFullPath;
+				rInfo2.pFileName = rInfo.pFileName;
+				rInfo2.fileSize  = rInfo.fileSize;
+
+			}
+		}
+		lJNIEnv->DeleteLocalRef(stringArray);
+		stringArray = NULL;
+
+		lJNIEnv->DeleteLocalRef(strClassName);
+		lJNIEnv->DeleteLocalRef(strDirName);
+
+		// Finished with the JVM.
+		lJavaVM->DetachCurrentThread();
+
+		bool keepGoing = false;
+
+		if (stringCount == 500)
+		{
+			keepGoing = true;
+		}
+
+		while (keepGoing == true)
+			keepGoing = android_DumpPathExtra(fileVector);
+
+		ret = true;
+	}
+	else
+	{
+		lJNIEnv->DeleteLocalRef(strClassName);
+		lJNIEnv->DeleteLocalRef(strDirName);
+
+		// Finished with the JVM.
+		lJavaVM->DetachCurrentThread();
+		ret = false;
+	}
+
+	return ret;
+
+}
+
+void android_InitDirList(const char* dir)
+{
+	// Attaches the current thread to the JVM.
+	jint lResult;
+	jint lFlags = 0;
+	adprintf("JNI InitDirList");
 	JavaVM* lJavaVM = engine.app->activity->vm;
 	JNIEnv* lJNIEnv = engine.app->activity->env;
 
@@ -1214,7 +1606,7 @@ void android_GetNextDir(const char* pdir, char *dir)
 	// Attaches the current thread to the JVM.
 	jint lResult;
 	jint lFlags = 0;
-
+	adprintf("JNI GetNextDir");
 	JavaVM* lJavaVM = engine.app->activity->vm;
 	JNIEnv* lJNIEnv = engine.app->activity->env;
 
@@ -1265,7 +1657,7 @@ void android_GetNextFile(const char* pdir, char *file)
 	// Attaches the current thread to the JVM.
 	jint lResult;
 	jint lFlags = 0;
-
+	adprintf("JNI GetNextFile");
 	JavaVM* lJavaVM = engine.app->activity->vm;
 	JNIEnv* lJNIEnv = engine.app->activity->env;
 
@@ -1316,7 +1708,7 @@ bool android_IsFile(const char* path)
 	// Attaches the current thread to the JVM.
 	jint lResult;
 	jint lFlags = 0;
-
+	adprintf("JNI ISFile");
 	JavaVM* lJavaVM = engine.app->activity->vm;
 	JNIEnv* lJNIEnv = engine.app->activity->env;
 
@@ -1368,7 +1760,7 @@ bool android_IsDir(const char* path)
 	// Attaches the current thread to the JVM.
 	jint lResult;
 	jint lFlags = 0;
-
+	adprintf("JNI ISDir");
 	JavaVM* lJavaVM = engine.app->activity->vm;
 	JNIEnv* lJNIEnv = engine.app->activity->env;
 
@@ -1484,7 +1876,7 @@ bool Platform::openWebBrowser(const char *webAddress)
 	// Attaches the current thread to the JVM.
 	jint lResult;
 	jint lFlags = 0;
-
+	adprintf("JNI openWeb");
 	JavaVM* lJavaVM = engine.app->activity->vm;
 	JNIEnv* lJNIEnv = engine.app->activity->env;
 
@@ -1525,7 +1917,7 @@ void android_AlertOK(const char *title, const char *message)
 	// Attaches the current thread to the JVM.
 	jint lResult;
 	jint lFlags = 0;
-
+	adprintf("JNI AlertOK");
 	JavaVM* lJavaVM = engine.app->activity->vm;
 	JNIEnv* lJNIEnv = engine.app->activity->env;
 
@@ -1566,7 +1958,7 @@ bool android_AlertOKCancel(const char *title, const char *message)
 	// Attaches the current thread to the JVM.
 	jint lResult;
 	jint lFlags = 0;
-
+	adprintf("JNI AlertOKCancel");
 	JavaVM* lJavaVM = engine.app->activity->vm;
 	JNIEnv* lJNIEnv = engine.app->activity->env;
 
@@ -1612,7 +2004,7 @@ bool android_AlertRetry(const char *title, const char *message)
 	// Attaches the current thread to the JVM.
 	jint lResult;
 	jint lFlags = 0;
-
+	adprintf("JNI alertRetry");
 	JavaVM* lJavaVM = engine.app->activity->vm;
 	JNIEnv* lJNIEnv = engine.app->activity->env;
 
@@ -1658,7 +2050,7 @@ bool android_AlertYesNo(const char *title, const char *message)
 	// Attaches the current thread to the JVM.
 	jint lResult;
 	jint lFlags = 0;
-
+	adprintf("JNI AlertYesNO");
 	JavaVM* lJavaVM = engine.app->activity->vm;
 	JNIEnv* lJNIEnv = engine.app->activity->env;
 
@@ -1704,7 +2096,7 @@ void android_LoadMusicTrack( const char *mFilename )
 	// Attaches the current thread to the JVM.
 	jint lResult;
 	jint lFlags = 0;
-
+	adprintf("JNI LoadMusic");
 	JavaVM* lJavaVM = engine.app->activity->vm;
 	JNIEnv* lJNIEnv = engine.app->activity->env;
 
@@ -1744,7 +2136,7 @@ void android_UnLoadMusicTrack()
 	// Attaches the current thread to the JVM.
 	jint lResult;
 	jint lFlags = 0;
-
+	adprintf("JNI UnloadMusic");
 	JavaVM* lJavaVM = engine.app->activity->vm;
 	JNIEnv* lJNIEnv = engine.app->activity->env;
 
@@ -1782,7 +2174,7 @@ bool android_isMusicTrackPlaying()
 	// Attaches the current thread to the JVM.
 	jint lResult;
 	jint lFlags = 0;
-
+	adprintf("JNI isMusicPLaying");
 	JavaVM* lJavaVM = engine.app->activity->vm;
 	JNIEnv* lJNIEnv = engine.app->activity->env;
 
@@ -1824,7 +2216,7 @@ void android_StartMusicTrack()
 	// Attaches the current thread to the JVM.
 	jint lResult;
 	jint lFlags = 0;
-
+	adprintf("JNI StartMusic");
 	JavaVM* lJavaVM = engine.app->activity->vm;
 	JNIEnv* lJNIEnv = engine.app->activity->env;
 
@@ -1862,7 +2254,7 @@ void android_StopMusicTrack()
 	// Attaches the current thread to the JVM.
 	jint lResult;
 	jint lFlags = 0;
-
+	adprintf("JNI stopMusic");
 	JavaVM* lJavaVM = engine.app->activity->vm;
 	JNIEnv* lJNIEnv = engine.app->activity->env;
 
@@ -1900,7 +2292,7 @@ void android_setMusicTrackVolume(F32 volume)
 	// Attaches the current thread to the JVM.
 	jint lResult;
 	jint lFlags = 0;
-
+	adprintf("JNI setMusicVol");
 	JavaVM* lJavaVM = engine.app->activity->vm;
 	JNIEnv* lJNIEnv = engine.app->activity->env;
 
@@ -1940,7 +2332,7 @@ ConsoleFunction(doDeviceVibrate, void, 1, 1, "Makes the device do a quick vibrat
 	// Attaches the current thread to the JVM.
 	jint lResult;
 	jint lFlags = 0;
-
+	adprintf("JVM DeviceVibrate");
 	JavaVM* lJavaVM = platState.engine->app->activity->vm;
 	JNIEnv* lJNIEnv = platState.engine->app->activity->env;
 

+ 3 - 0
engine/source/platformAndroid/T2DActivity.h

@@ -47,6 +47,9 @@ extern void android_GetNextFile(const char* pdir, char *file);
 extern bool android_IsDir(const char* path);
 extern bool android_IsFile(const char* path);
 extern U32 android_GetFileSize(const char* pFilePath);
+extern bool android_DumpPath(const char* dir, Vector<Platform::FileInfo>& fileVector, U32 depth);
+extern bool android_DumpDirectories(const char *basePath, const char *path, Vector<StringTableEntry> &directoryVector, S32 depth, bool noBasePath);
+
 
 /**
  * Our saved state data.