Skip to content

Commit fe39323

Browse files
authored
[Android] FileUtils::listFiles implementation that works with empty folders (#2463)
* Use Android Java method for listing files and folders * Update comment * Figure out if paths are files or folders * Rename method to better reflect its purpose
1 parent 1bcbcc5 commit fe39323

File tree

3 files changed

+93
-22
lines changed

3 files changed

+93
-22
lines changed

core/platform/android/FileUtils-android.cpp

Lines changed: 22 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -242,15 +242,32 @@ int64_t FileUtilsAndroid::getFileSize(std::string_view filepath) const
242242

243243
std::vector<std::string> FileUtilsAndroid::listFiles(std::string_view dirPath) const
244244
{
245-
246245
if (!dirPath.empty() && dirPath[0] == '/')
247246
return FileUtils::listFiles(dirPath);
248247

249248
std::vector<std::string> fileList;
250-
std::string fullPath = fullPathForDirectory(dirPath);
251-
252249
static const std::string apkprefix("assets/");
253250
std::string relativePath;
251+
252+
if (obbfile)
253+
{
254+
std::string fullPath = fullPathForDirectory(dirPath);
255+
256+
size_t position = fullPath.find(apkprefix);
257+
if (0 == position)
258+
{
259+
// "assets/" is at the beginning of the path and we don't want it
260+
relativePath += fullPath.substr(apkprefix.size());
261+
}
262+
else
263+
{
264+
relativePath = fullPath;
265+
}
266+
267+
return obbfile->listFiles(relativePath);
268+
}
269+
270+
std::string fullPath = std::string(dirPath); // don't call fullPathForDirectory(dirPath), since empty folders will not return a valid result
254271
size_t position = fullPath.find(apkprefix);
255272
if (0 == position)
256273
{
@@ -262,9 +279,6 @@ std::vector<std::string> FileUtilsAndroid::listFiles(std::string_view dirPath) c
262279
relativePath = fullPath;
263280
}
264281

265-
if (obbfile)
266-
return obbfile->listFiles(relativePath);
267-
268282
if (nullptr == assetmanager)
269283
{
270284
LOGD("... FileUtilsAndroid::assetmanager is nullptr");
@@ -276,22 +290,8 @@ std::vector<std::string> FileUtilsAndroid::listFiles(std::string_view dirPath) c
276290
relativePath.erase(relativePath.length() - 1);
277291
}
278292

279-
auto* dir = AAssetManager_openDir(assetmanager, relativePath.c_str());
280-
if (nullptr == dir)
281-
{
282-
LOGD("... FileUtilsAndroid::failed to open dir %s", relativePath.c_str());
283-
AAssetDir_close(dir);
284-
return fileList;
285-
}
286-
const char* tmpDir = nullptr;
287-
while ((tmpDir = AAssetDir_getNextFileName(dir)) != nullptr)
288-
{
289-
std::string filepath(tmpDir);
290-
if (isDirectoryExistInternal(filepath))
291-
filepath += "/";
292-
fileList.emplace_back(fullPath + filepath);
293-
}
294-
AAssetDir_close(dir);
293+
fileList = JniHelper::callStaticStringArrayMethod("dev/axmol/lib/AxmolEngine", "getAssetsList", relativePath);
294+
295295
return fileList;
296296
}
297297

core/platform/android/java/src/dev/axmol/lib/AxmolEngine.java

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -746,4 +746,31 @@ private static AxmolAccelerometer getAccelerometer() {
746746

747747
return sAccelerometer;
748748
}
749+
750+
public static String[] getAssetsList(String path) {
751+
try {
752+
String basePath;
753+
if (!path.isEmpty()) {
754+
basePath = path + "/";
755+
} else {
756+
basePath = path;
757+
}
758+
759+
AssetManager assetManager = getAssetManager();
760+
String[] list = assetManager.list(path);
761+
for (int i = 0; i < list.length; i++) {
762+
try {
763+
list[i] = basePath + list[i];
764+
java.io.InputStream stream = assetManager.open(list[i]);
765+
stream.close(); // if we got to here, then it is a file
766+
} catch (IOException e) {
767+
list[i] += "/";
768+
}
769+
}
770+
return list;
771+
} catch (IOException e) {
772+
e.printStackTrace();
773+
}
774+
return null;
775+
}
749776
}

core/platform/android/jni/JniHelper.h

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,50 @@ class AX_DLL JniHelper
220220
return ret;
221221
}
222222

223+
/**
224+
@brief Call of Java static method
225+
@return std::vector<std::string>
226+
*/
227+
template <typename... Ts>
228+
static std::vector<std::string> callStaticStringArrayMethod(const char* className, const char* methodName, Ts&&... xs)
229+
{
230+
ax::JniMethodInfo t;
231+
const auto signature = "(Ljava/lang/String;)[Ljava/lang/String;";
232+
if (ax::JniHelper::getStaticMethodInfo(t, className, methodName, signature))
233+
{
234+
LocalRefMapType localRefs;
235+
jobjectArray array =
236+
(jobjectArray)t.env->CallStaticObjectMethod(t.classID, t.methodID, convert(localRefs, t, xs)...);
237+
238+
if (array == nullptr)
239+
{
240+
t.env->DeleteLocalRef(t.classID);
241+
deleteLocalRefs(t.env, localRefs);
242+
return {};
243+
}
244+
245+
jsize len = t.env->GetArrayLength(array);
246+
std::vector<std::string> result(len);
247+
for (int i=0; i < len; ++i)
248+
{
249+
jstring string = (jstring)t.env->GetObjectArrayElement(array, i);
250+
const char* arrayItem = t.env->GetStringUTFChars(string, 0);
251+
result[i] = std::move((std::string(arrayItem)));
252+
t.env->ReleaseStringUTFChars(string, arrayItem);
253+
t.env->DeleteLocalRef(string);
254+
}
255+
256+
t.env->DeleteLocalRef(t.classID);
257+
deleteLocalRefs(t.env, localRefs);
258+
return result;
259+
}
260+
else
261+
{
262+
reportError(className, methodName, signature);
263+
}
264+
return {};
265+
}
266+
223267
/**
224268
@brief Call of Java static float* method
225269
@return axstd::pod_vector

0 commit comments

Comments
 (0)