mirror of
https://github.com/hrydgard/ppsspp.git
synced 2025-04-02 11:01:50 -04:00
Android: Implement opening ISOs through a file picker and Storage Access Framework
Has issues with the recent list - fails to open during shutdown due to no activity, there's a little race to fix.
This commit is contained in:
parent
35ad3106ff
commit
54c9e28444
10 changed files with 100 additions and 13 deletions
|
@ -1529,6 +1529,8 @@ void Config::RemoveRecent(const std::string &file) {
|
|||
}
|
||||
}
|
||||
|
||||
// TODO: This can be called during shutdown at a point where we have no NativeActivity object.
|
||||
// That causes us to drop all content URI isos since they fail to open.
|
||||
void Config::CleanRecent() {
|
||||
std::vector<std::string> cleanedRecent;
|
||||
for (size_t i = 0; i < recentIsos.size(); i++) {
|
||||
|
|
|
@ -31,8 +31,28 @@
|
|||
#include <fcntl.h>
|
||||
#endif
|
||||
|
||||
#ifndef _WIN32
|
||||
LocalFileLoader::LocalFileLoader(int fd, const std::string &filename) : fd_(fd), filename_(filename), isOpenedByFd_(fd != -1) {
|
||||
if (fd != -1) {
|
||||
DetectSizeFd();
|
||||
}
|
||||
}
|
||||
|
||||
void LocalFileLoader::DetectSizeFd() {
|
||||
#if PPSSPP_PLATFORM(ANDROID) || (defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS < 64)
|
||||
off64_t off = lseek64(fd_, 0, SEEK_END);
|
||||
filesize_ = off;
|
||||
lseek64(fd_, 0, SEEK_SET);
|
||||
#else
|
||||
off_t off = lseek(fd_, 0, SEEK_END);
|
||||
filesize_ = off;
|
||||
lseek(fd_, 0, SEEK_SET);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
LocalFileLoader::LocalFileLoader(const std::string &filename)
|
||||
: filesize_(0), filename_(filename) {
|
||||
: filesize_(0), filename_(filename), isOpenedByFd_(false) {
|
||||
if (filename.empty()) {
|
||||
ERROR_LOG(FILESYS, "LocalFileLoader can't load empty filenames");
|
||||
return;
|
||||
|
@ -43,15 +63,8 @@ LocalFileLoader::LocalFileLoader(const std::string &filename)
|
|||
if (fd_ == -1) {
|
||||
return;
|
||||
}
|
||||
#if PPSSPP_PLATFORM(ANDROID) || (defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS < 64)
|
||||
off64_t off = lseek64(fd_, 0, SEEK_END);
|
||||
filesize_ = off;
|
||||
lseek64(fd_, 0, SEEK_SET);
|
||||
#else
|
||||
off_t off = lseek(fd_, 0, SEEK_END);
|
||||
filesize_ = off;
|
||||
lseek(fd_, 0, SEEK_SET);
|
||||
#endif
|
||||
|
||||
DetectSizeFd();
|
||||
|
||||
#else // _WIN32
|
||||
|
||||
|
@ -92,6 +105,9 @@ LocalFileLoader::~LocalFileLoader() {
|
|||
bool LocalFileLoader::Exists() {
|
||||
// If we couldn't open it for reading, we say it does not exist.
|
||||
#ifndef _WIN32
|
||||
if (isOpenedByFd_) {
|
||||
return true;
|
||||
}
|
||||
if (fd_ != -1 || IsDirectory()) {
|
||||
#else
|
||||
if (handle_ != INVALID_HANDLE_VALUE || IsDirectory()) {
|
||||
|
|
|
@ -27,6 +27,7 @@ typedef void *HANDLE;
|
|||
class LocalFileLoader : public FileLoader {
|
||||
public:
|
||||
LocalFileLoader(const std::string &filename);
|
||||
LocalFileLoader(const int fd, const std::string &filename);
|
||||
virtual ~LocalFileLoader();
|
||||
|
||||
virtual bool Exists() override;
|
||||
|
@ -37,6 +38,7 @@ public:
|
|||
|
||||
private:
|
||||
#ifndef _WIN32
|
||||
void DetectSizeFd();
|
||||
int fd_;
|
||||
#else
|
||||
HANDLE handle_;
|
||||
|
@ -44,4 +46,5 @@ private:
|
|||
u64 filesize_;
|
||||
std::string filename_;
|
||||
std::mutex readLock_;
|
||||
bool isOpenedByFd_;
|
||||
};
|
||||
|
|
|
@ -50,7 +50,7 @@ FileLoader *ConstructFileLoader(const std::string &filename) {
|
|||
}
|
||||
|
||||
for (auto &iter : factories) {
|
||||
if (startsWith(iter.first, filename)) {
|
||||
if (startsWith(filename, iter.first)) {
|
||||
return iter.second->ConstructFileLoader(filename);
|
||||
}
|
||||
}
|
||||
|
@ -126,6 +126,7 @@ IdentifiedFileType Identify_File(FileLoader *fileLoader) {
|
|||
|
||||
size_t readSize = fileLoader->ReadAt(0, 4, 1, &id);
|
||||
if (readSize != 1) {
|
||||
ERROR_LOG(LOADER, "Failed to read identification bytes");
|
||||
return IdentifiedFileType::ERROR_IDENTIFYING;
|
||||
}
|
||||
|
||||
|
@ -293,7 +294,7 @@ bool LoadFile(FileLoader **fileLoaderPtr, std::string *error_string) {
|
|||
break;
|
||||
|
||||
case IdentifiedFileType::ERROR_IDENTIFYING:
|
||||
ERROR_LOG(LOADER, "Could not read file");
|
||||
ERROR_LOG(LOADER, "Could not read file enough to identify it");
|
||||
*error_string = fileLoader ? fileLoader->LatestError() : "";
|
||||
if (error_string->empty())
|
||||
*error_string = "Error reading file";
|
||||
|
|
|
@ -596,6 +596,9 @@ void SystemInfoScreen::CreateViews() {
|
|||
|
||||
#if PPSSPP_PLATFORM(ANDROID)
|
||||
storage->Add(new InfoItem("ExtFilesDir", g_extFilesDir));
|
||||
if (System_GetPropertyBool(SYSPROP_ANDROID_SCOPED_STORAGE)) {
|
||||
storage->Add(new InfoItem("Scoped Storage", di->T("Yes")));
|
||||
}
|
||||
#endif
|
||||
|
||||
ViewGroup *buildConfigScroll = new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(FILL_PARENT, FILL_PARENT));
|
||||
|
|
|
@ -1183,6 +1183,10 @@ void MainScreen::sendMessage(const char *message, const char *value) {
|
|||
if (!strcmp(message, "boot")) {
|
||||
LaunchFile(screenManager(), std::string(value));
|
||||
}
|
||||
if (!strcmp(message, "browse_fileSelect")) {
|
||||
INFO_LOG(SYSTEM, "Attempting to launch: '%s'", value);
|
||||
LaunchFile(screenManager(), std::string(value));
|
||||
}
|
||||
if (!strcmp(message, "browse_folderSelect")) {
|
||||
std::string filename;
|
||||
#if PPSSPP_PLATFORM(ANDROID)
|
||||
|
|
|
@ -81,6 +81,7 @@ struct JNIEnv {};
|
|||
#include "Core/Config.h"
|
||||
#include "Core/ConfigValues.h"
|
||||
#include "Core/Loaders.h"
|
||||
#include "Core/FileLoaders/LocalFileLoader.h"
|
||||
#include "Core/System.h"
|
||||
#include "Core/HLE/sceUsbCam.h"
|
||||
#include "Core/HLE/sceUsbGps.h"
|
||||
|
@ -168,6 +169,10 @@ static float g_safeInsetTop = 0.0;
|
|||
static float g_safeInsetBottom = 0.0;
|
||||
|
||||
static jmethodID postCommand;
|
||||
|
||||
static jmethodID openContentUri;
|
||||
static jmethodID closeContentUri;
|
||||
|
||||
static jobject nativeActivity;
|
||||
static volatile bool exitRenderLoop;
|
||||
static bool renderLoopRunning;
|
||||
|
@ -227,6 +232,36 @@ void AndroidLogger::Log(const LogMessage &message) {
|
|||
}
|
||||
}
|
||||
|
||||
bool Android_IsContentUri(const std::string &filename) {
|
||||
return startsWith(filename, "content://");
|
||||
}
|
||||
|
||||
int Android_OpenContentUriFd(const std::string &filename) {
|
||||
if (!nativeActivity) {
|
||||
return -1;
|
||||
}
|
||||
auto env = getEnv();
|
||||
jstring param = env->NewStringUTF(filename.c_str());
|
||||
int fd = env->CallIntMethod(nativeActivity, openContentUri, param);
|
||||
return fd;
|
||||
}
|
||||
|
||||
void Android_CloseContentUriFd(int fd) {
|
||||
if (!fd) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
class AndroidContentLoaderFactory : public FileLoaderFactory {
|
||||
public:
|
||||
AndroidContentLoaderFactory() {}
|
||||
FileLoader *ConstructFileLoader(const std::string &filename) override {
|
||||
int fd = Android_OpenContentUriFd(filename);
|
||||
INFO_LOG(SYSTEM, "Fd %d for content URI: '%s'", fd, filename.c_str());
|
||||
return new LocalFileLoader(fd, filename);
|
||||
}
|
||||
};
|
||||
|
||||
JNIEnv* getEnv() {
|
||||
JNIEnv *env;
|
||||
int status = gJvm->GetEnv((void**)&env, JNI_VERSION_1_6);
|
||||
|
@ -438,7 +473,8 @@ bool System_GetPropertyBool(SystemProperty prop) {
|
|||
case SYSPROP_HAS_IMAGE_BROWSER:
|
||||
return true;
|
||||
case SYSPROP_HAS_FILE_BROWSER:
|
||||
return false; // We kind of have but needs more work.
|
||||
// return System_GetPropertyBool(SYSPROP_ANDROID_SCOPED_STORAGE);
|
||||
return androidVersion >= 21;
|
||||
case SYSPROP_HAS_FOLDER_BROWSER:
|
||||
// Uses OPEN_DOCUMENT_TREE to let you select a folder.
|
||||
return androidVersion >= 21;
|
||||
|
@ -470,6 +506,7 @@ std::string GetJavaString(JNIEnv *env, jstring jstr) {
|
|||
extern "C" void Java_org_ppsspp_ppsspp_NativeActivity_registerCallbacks(JNIEnv *env, jobject obj) {
|
||||
nativeActivity = env->NewGlobalRef(obj);
|
||||
postCommand = env->GetMethodID(env->GetObjectClass(obj), "postCommand", "(Ljava/lang/String;Ljava/lang/String;)V");
|
||||
openContentUri = env->GetMethodID(env->GetObjectClass(obj), "openContentUri", "(Ljava/lang/String;)I");
|
||||
}
|
||||
|
||||
extern "C" void Java_org_ppsspp_ppsspp_NativeActivity_unregisterCallbacks(JNIEnv *env, jobject obj) {
|
||||
|
@ -651,6 +688,12 @@ extern "C" void Java_org_ppsspp_ppsspp_NativeApp_init
|
|||
|
||||
NativeInit((int)args.size(), &args[0], user_data_path.c_str(), externalStorageDir.c_str(), cacheDir.c_str());
|
||||
|
||||
|
||||
std::unique_ptr<FileLoaderFactory> factory(new AndroidContentLoaderFactory());
|
||||
|
||||
// Register a content URI file loader.
|
||||
RegisterFileLoaderFactory("content://", std::move(factory));
|
||||
|
||||
// No need to use EARLY_LOG anymore.
|
||||
|
||||
retry:
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
#include "ppsspp_config.h"
|
||||
|
||||
#include <string>
|
||||
#include "Common/LogManager.h"
|
||||
|
||||
#if PPSSPP_PLATFORM(ANDROID)
|
||||
|
|
|
@ -1146,6 +1146,7 @@ public abstract class NativeActivity extends Activity {
|
|||
if (selectedFile != null) {
|
||||
// NativeApp.sendMessage("br");
|
||||
Log.i(TAG, "Browse file finished:" + selectedFile.toString());
|
||||
NativeApp.sendMessage("browse_fileSelect", selectedFile.toString());
|
||||
}
|
||||
} else if (requestCode == RESULT_OPEN_DOCUMENT_TREE) {
|
||||
Uri selectedFile = data.getData();
|
||||
|
|
|
@ -6,6 +6,7 @@ import android.net.Uri;
|
|||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.Looper;
|
||||
import android.os.ParcelFileDescriptor;
|
||||
import android.util.Log;
|
||||
|
||||
public class PpssppActivity extends NativeActivity {
|
||||
|
@ -112,4 +113,16 @@ public class PpssppActivity extends NativeActivity {
|
|||
}
|
||||
});
|
||||
}
|
||||
|
||||
public int openContentUri(String uriString) {
|
||||
try {
|
||||
Uri uri = Uri.parse(uriString);
|
||||
ParcelFileDescriptor filePfd = getContentResolver().openFileDescriptor(uri, "r");
|
||||
int fd = filePfd.detachFd(); // Take ownership of the fd.
|
||||
return fd;
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Exception opening content uri: " + e.toString());
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue