mirror of
https://github.com/hrydgard/ppsspp.git
synced 2025-04-02 11:01:50 -04:00
Assorted plumbing.
wip Buildfix
This commit is contained in:
parent
beb0b4e9f3
commit
b397e5c455
16 changed files with 195 additions and 120 deletions
|
@ -1156,6 +1156,7 @@ list(APPEND NativeAppSource
|
|||
UI/Store.cpp
|
||||
UI/CwCheatScreen.cpp
|
||||
UI/InstallZipScreen.cpp
|
||||
UI/MemStickScreen.cpp
|
||||
UI/ProfilerDraw.cpp
|
||||
UI/TextureUtil.cpp
|
||||
UI/ComboKeyMappingScreen.cpp
|
||||
|
|
|
@ -24,6 +24,8 @@
|
|||
|
||||
#include "ppsspp_config.h"
|
||||
|
||||
#include "android/jni/app-android.h"
|
||||
|
||||
#ifdef __MINGW32__
|
||||
#include <unistd.h>
|
||||
#ifndef _POSIX_THREAD_SAFE_FUNCTIONS
|
||||
|
@ -257,7 +259,9 @@ bool IsDirectory(const Path &filename) {
|
|||
WIN32_FILE_ATTRIBUTE_DATA data{};
|
||||
if (!GetFileAttributesEx(copy.c_str(), GetFileExInfoStandard, &data) || data.dwFileAttributes == INVALID_FILE_ATTRIBUTES) {
|
||||
auto err = GetLastError();
|
||||
WARN_LOG(COMMON, "GetFileAttributes failed on %s: %08x %s", fn.c_str(), (uint32_t)err, GetStringErrorMsg(err).c_str());
|
||||
if (err != ERROR_FILE_NOT_FOUND) {
|
||||
WARN_LOG(COMMON, "GetFileAttributes failed on %s: %08x %s", fn.c_str(), (uint32_t)err, GetStringErrorMsg(err).c_str());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
DWORD result = data.dwFileAttributes;
|
||||
|
|
|
@ -27,6 +27,8 @@
|
|||
#include "Common/Common.h"
|
||||
#include "Common/File/Path.h"
|
||||
|
||||
// Some functions here support Android content URIs. These are marked as such.
|
||||
|
||||
#ifdef _MSC_VER
|
||||
inline struct tm* localtime_r(const time_t *clock, struct tm *result) {
|
||||
if (localtime_s(result, clock) == 0)
|
||||
|
|
|
@ -121,8 +121,12 @@ bool AndroidDirectoryFileHandle::Open(const std::string &basePath, std::string &
|
|||
success = false;
|
||||
}
|
||||
|
||||
// Seek to end if append mode.
|
||||
Seek(0, FILEMOVE_END);
|
||||
// TODO: Experiment with fstat to see if we can extract more info.
|
||||
|
||||
// Seek to end to simulate append mode, if requested.
|
||||
if (access & FILEACCESS_APPEND) {
|
||||
Seek(0, FILEMOVE_END);
|
||||
}
|
||||
|
||||
// Try to detect reads/writes to PSP/GAME to avoid them in replays.
|
||||
if (basePath.find("/PSP/GAME/") != std::string::npos) {
|
||||
|
@ -439,10 +443,11 @@ std::vector<PSPFileInfo> AndroidStorageFileSystem::GetDirListing(std::string pat
|
|||
bool hideISOFiles = PSP_CoreParameter().compat.flags().HideISOFiles;
|
||||
for (auto &info : fileInfo) {
|
||||
PSPFileInfo entry;
|
||||
if (info.isDirectory)
|
||||
if (info.isDirectory) {
|
||||
entry.type = FILETYPE_DIRECTORY;
|
||||
else
|
||||
} else {
|
||||
entry.type = FILETYPE_NORMAL;
|
||||
}
|
||||
entry.access = info.isWritable ? 0777 : 0666;
|
||||
entry.name = info.name;
|
||||
if (Flags() & FileSystemFlags::SIMULATE_FAT32) {
|
||||
|
@ -466,8 +471,9 @@ std::vector<PSPFileInfo> AndroidStorageFileSystem::GetDirListing(std::string pat
|
|||
localtime_r((time_t*)&atime, &entry.atime);
|
||||
localtime_r((time_t*)&ctime, &entry.ctime);
|
||||
localtime_r((time_t*)&mtime, &entry.mtime);
|
||||
if (!hideFile && (!listingRoot || (strcmp(info.name.c_str(), "..") && strcmp(info.name.c_str(), "."))))
|
||||
if (!hideFile && (!listingRoot || (strcmp(info.name.c_str(), "..") && strcmp(info.name.c_str(), ".")))) {
|
||||
myVector.push_back(entry);
|
||||
}
|
||||
}
|
||||
|
||||
return ReplayApplyDiskListing(myVector, CoreTiming::GetGlobalTimeUs());
|
||||
|
|
|
@ -285,8 +285,7 @@ int VirtualDiscFileSystem::getFileListIndex(std::string &fileName)
|
|||
#endif
|
||||
}
|
||||
|
||||
FileType type = File::IsDirectory(fullName) ? FILETYPE_DIRECTORY : FILETYPE_NORMAL;
|
||||
if (type == FILETYPE_DIRECTORY)
|
||||
if (File::IsDirectory(fullName))
|
||||
return -1;
|
||||
|
||||
FileListEntry entry = {""};
|
||||
|
|
|
@ -51,6 +51,7 @@
|
|||
#include "UI/TiltEventProcessor.h"
|
||||
#include "UI/ComboKeyMappingScreen.h"
|
||||
#include "UI/GPUDriverTestScreen.h"
|
||||
#include "UI/MemStickScreen.h"
|
||||
|
||||
#include "Common/File/FileUtil.h"
|
||||
#include "Common/OSVersion.h"
|
||||
|
@ -931,6 +932,7 @@ void GameSettingsScreen::CreateViews() {
|
|||
#if defined(USING_WIN_UI) || defined(USING_QT_UI) || PPSSPP_PLATFORM(ANDROID)
|
||||
systemSettings->Add(new CheckBox(&g_Config.bBypassOSKWithKeyboard, sy->T("Use system native keyboard")));
|
||||
#endif
|
||||
|
||||
#if PPSSPP_PLATFORM(ANDROID)
|
||||
memstickDisplay_ = g_Config.memStickDirectory.ToVisualString();
|
||||
auto memstickPath = systemSettings->Add(new ChoiceWithValueDisplay(&memstickDisplay_, sy->T("Change Memory Stick folder"), (const char *)nullptr));
|
||||
|
@ -1098,40 +1100,12 @@ UI::EventReturn GameSettingsScreen::OnJitAffectingSetting(UI::EventParams &e) {
|
|||
return UI::EVENT_DONE;
|
||||
}
|
||||
|
||||
#if PPSSPP_PLATFORM(ANDROID)
|
||||
|
||||
UI::EventReturn GameSettingsScreen::OnChangeMemStickDir(UI::EventParams &e) {
|
||||
auto sy = GetI18NCategory("System");
|
||||
System_InputBoxGetString(sy->T("Memory Stick Folder"), g_Config.memStickDirectory.ToString(), [&](bool result, const std::string &value) {
|
||||
auto sy = GetI18NCategory("System");
|
||||
auto di = GetI18NCategory("Dialog");
|
||||
|
||||
if (result) {
|
||||
std::string newPath = value;
|
||||
size_t pos = newPath.find_last_not_of("/");
|
||||
// Gotta have at least something but a /, and also needs to start with a /.
|
||||
if (newPath.empty() || pos == newPath.npos || newPath[0] != '/') {
|
||||
settingInfo_->Show(sy->T("ChangingMemstickPathInvalid", "That path couldn't be used to save Memory Stick files."), nullptr);
|
||||
return;
|
||||
}
|
||||
if (pos != newPath.size() - 1) {
|
||||
newPath = newPath.substr(0, pos + 1);
|
||||
}
|
||||
|
||||
pendingMemstickFolder_ = newPath;
|
||||
std::string promptMessage = sy->T("ChangingMemstickPath", "Save games, save states, and other data will not be copied to this folder.\n\nChange the Memory Stick folder?");
|
||||
if (!File::Exists(Path(newPath))) {
|
||||
promptMessage = sy->T("ChangingMemstickPathNotExists", "That folder doesn't exist yet.\n\nSave games, save states, and other data will not be copied to this folder.\n\nCreate a new Memory Stick folder?");
|
||||
}
|
||||
// Add the path for clarity and proper confirmation.
|
||||
promptMessage += "\n\n" + newPath + "/";
|
||||
screenManager()->push(new PromptScreen(promptMessage, di->T("Yes"), di->T("No"), std::bind(&GameSettingsScreen::CallbackMemstickFolder, this, std::placeholders::_1)));
|
||||
}
|
||||
});
|
||||
screenManager()->push(new MemStickScreen());
|
||||
return UI::EVENT_DONE;
|
||||
}
|
||||
|
||||
#elif defined(_WIN32) && !PPSSPP_PLATFORM(UWP)
|
||||
#if defined(_WIN32) && !PPSSPP_PLATFORM(UWP)
|
||||
|
||||
UI::EventReturn GameSettingsScreen::OnSavePathMydoc(UI::EventParams &e) {
|
||||
const Path &PPSSPPpath = File::GetExeDirectory();
|
||||
|
@ -2006,52 +1980,3 @@ void HostnameSelectScreen::OnCompleted(DialogResult result) {
|
|||
if (result == DR_OK)
|
||||
*value_ = StripSpaces(addrView_->GetText());
|
||||
}
|
||||
|
||||
SettingInfoMessage::SettingInfoMessage(int align, UI::AnchorLayoutParams *lp)
|
||||
: UI::LinearLayout(UI::ORIENT_HORIZONTAL, lp) {
|
||||
using namespace UI;
|
||||
SetSpacing(0.0f);
|
||||
Add(new UI::Spacer(10.0f));
|
||||
text_ = Add(new UI::TextView("", align, false, new LinearLayoutParams(1.0, Margins(0, 10))));
|
||||
Add(new UI::Spacer(10.0f));
|
||||
}
|
||||
|
||||
void SettingInfoMessage::Show(const std::string &text, UI::View *refView) {
|
||||
if (refView) {
|
||||
Bounds b = refView->GetBounds();
|
||||
const UI::AnchorLayoutParams *lp = GetLayoutParams()->As<UI::AnchorLayoutParams>();
|
||||
if (b.y >= cutOffY_) {
|
||||
ReplaceLayoutParams(new UI::AnchorLayoutParams(lp->width, lp->height, lp->left, 80.0f, lp->right, lp->bottom, lp->center));
|
||||
} else {
|
||||
ReplaceLayoutParams(new UI::AnchorLayoutParams(lp->width, lp->height, lp->left, dp_yres - 80.0f - 40.0f, lp->right, lp->bottom, lp->center));
|
||||
}
|
||||
}
|
||||
text_->SetText(text);
|
||||
timeShown_ = time_now_d();
|
||||
}
|
||||
|
||||
void SettingInfoMessage::Draw(UIContext &dc) {
|
||||
static const double FADE_TIME = 1.0;
|
||||
static const float MAX_ALPHA = 0.9f;
|
||||
|
||||
// Let's show longer messages for more time (guesstimate at reading speed.)
|
||||
// Note: this will give multibyte characters more time, but they often have shorter words anyway.
|
||||
double timeToShow = std::max(1.5, text_->GetText().size() * 0.05);
|
||||
|
||||
double sinceShow = time_now_d() - timeShown_;
|
||||
float alpha = MAX_ALPHA;
|
||||
if (timeShown_ == 0.0 || sinceShow > timeToShow + FADE_TIME) {
|
||||
alpha = 0.0f;
|
||||
} else if (sinceShow > timeToShow) {
|
||||
alpha = MAX_ALPHA - MAX_ALPHA * (float)((sinceShow - timeToShow) / FADE_TIME);
|
||||
}
|
||||
|
||||
if (alpha >= 0.1f) {
|
||||
UI::Style style = dc.theme->popupTitle;
|
||||
style.background.color = colorAlpha(style.background.color, alpha - 0.1f);
|
||||
dc.FillRect(style.background, bounds_);
|
||||
}
|
||||
|
||||
text_->SetTextColor(whiteAlpha(alpha));
|
||||
ViewGroup::Draw(dc);
|
||||
}
|
||||
|
|
|
@ -24,8 +24,6 @@
|
|||
#include "Common/UI/UIScreen.h"
|
||||
#include "UI/MiscScreens.h"
|
||||
|
||||
class SettingInfoMessage;
|
||||
|
||||
// Per-game settings screen - enables you to configure graphic options, control options, etc
|
||||
// per game.
|
||||
class GameSettingsScreen : public UIDialogScreenWithGameBackground {
|
||||
|
@ -108,9 +106,8 @@ private:
|
|||
UI::EventReturn OnMicDeviceChange(UI::EventParams& e);
|
||||
UI::EventReturn OnAudioDevice(UI::EventParams &e);
|
||||
UI::EventReturn OnJitAffectingSetting(UI::EventParams &e);
|
||||
#if PPSSPP_PLATFORM(ANDROID)
|
||||
UI::EventReturn OnChangeMemStickDir(UI::EventParams &e);
|
||||
#elif defined(_WIN32) && !PPSSPP_PLATFORM(UWP)
|
||||
#if defined(_WIN32) && !PPSSPP_PLATFORM(UWP)
|
||||
UI::EventReturn OnSavePathMydoc(UI::EventParams &e);
|
||||
UI::EventReturn OnSavePathOther(UI::EventParams &e);
|
||||
#endif
|
||||
|
@ -141,23 +138,6 @@ private:
|
|||
std::string pendingMemstickFolder_;
|
||||
};
|
||||
|
||||
class SettingInfoMessage : public UI::LinearLayout {
|
||||
public:
|
||||
SettingInfoMessage(int align, UI::AnchorLayoutParams *lp);
|
||||
|
||||
void SetBottomCutoff(float y) {
|
||||
cutOffY_ = y;
|
||||
}
|
||||
void Show(const std::string &text, UI::View *refView = nullptr);
|
||||
|
||||
void Draw(UIContext &dc);
|
||||
|
||||
private:
|
||||
UI::TextView *text_ = nullptr;
|
||||
double timeShown_ = 0.0;
|
||||
float cutOffY_;
|
||||
};
|
||||
|
||||
class DeveloperToolsScreen : public UIDialogScreenWithBackground {
|
||||
public:
|
||||
DeveloperToolsScreen() {}
|
||||
|
|
|
@ -948,3 +948,52 @@ void CreditsScreen::render() {
|
|||
|
||||
dc.Flush();
|
||||
}
|
||||
|
||||
SettingInfoMessage::SettingInfoMessage(int align, UI::AnchorLayoutParams *lp)
|
||||
: UI::LinearLayout(UI::ORIENT_HORIZONTAL, lp) {
|
||||
using namespace UI;
|
||||
SetSpacing(0.0f);
|
||||
Add(new UI::Spacer(10.0f));
|
||||
text_ = Add(new UI::TextView("", align, false, new LinearLayoutParams(1.0, Margins(0, 10))));
|
||||
Add(new UI::Spacer(10.0f));
|
||||
}
|
||||
|
||||
void SettingInfoMessage::Show(const std::string &text, UI::View *refView) {
|
||||
if (refView) {
|
||||
Bounds b = refView->GetBounds();
|
||||
const UI::AnchorLayoutParams *lp = GetLayoutParams()->As<UI::AnchorLayoutParams>();
|
||||
if (b.y >= cutOffY_) {
|
||||
ReplaceLayoutParams(new UI::AnchorLayoutParams(lp->width, lp->height, lp->left, 80.0f, lp->right, lp->bottom, lp->center));
|
||||
} else {
|
||||
ReplaceLayoutParams(new UI::AnchorLayoutParams(lp->width, lp->height, lp->left, dp_yres - 80.0f - 40.0f, lp->right, lp->bottom, lp->center));
|
||||
}
|
||||
}
|
||||
text_->SetText(text);
|
||||
timeShown_ = time_now_d();
|
||||
}
|
||||
|
||||
void SettingInfoMessage::Draw(UIContext &dc) {
|
||||
static const double FADE_TIME = 1.0;
|
||||
static const float MAX_ALPHA = 0.9f;
|
||||
|
||||
// Let's show longer messages for more time (guesstimate at reading speed.)
|
||||
// Note: this will give multibyte characters more time, but they often have shorter words anyway.
|
||||
double timeToShow = std::max(1.5, text_->GetText().size() * 0.05);
|
||||
|
||||
double sinceShow = time_now_d() - timeShown_;
|
||||
float alpha = MAX_ALPHA;
|
||||
if (timeShown_ == 0.0 || sinceShow > timeToShow + FADE_TIME) {
|
||||
alpha = 0.0f;
|
||||
} else if (sinceShow > timeToShow) {
|
||||
alpha = MAX_ALPHA - MAX_ALPHA * (float)((sinceShow - timeToShow) / FADE_TIME);
|
||||
}
|
||||
|
||||
if (alpha >= 0.1f) {
|
||||
UI::Style style = dc.theme->popupTitle;
|
||||
style.background.color = colorAlpha(style.background.color, alpha - 0.1f);
|
||||
dc.FillRect(style.background, bounds_);
|
||||
}
|
||||
|
||||
text_->SetTextColor(whiteAlpha(alpha));
|
||||
ViewGroup::Draw(dc);
|
||||
}
|
||||
|
|
|
@ -164,3 +164,20 @@ private:
|
|||
|
||||
double startTime_ = 0.0;
|
||||
};
|
||||
|
||||
class SettingInfoMessage : public UI::LinearLayout {
|
||||
public:
|
||||
SettingInfoMessage(int align, UI::AnchorLayoutParams *lp);
|
||||
|
||||
void SetBottomCutoff(float y) {
|
||||
cutOffY_ = y;
|
||||
}
|
||||
void Show(const std::string &text, UI::View *refView = nullptr);
|
||||
|
||||
void Draw(UIContext &dc);
|
||||
|
||||
private:
|
||||
UI::TextView *text_ = nullptr;
|
||||
double timeShown_ = 0.0;
|
||||
float cutOffY_;
|
||||
};
|
||||
|
|
|
@ -511,10 +511,12 @@ void NativeInit(int argc, const char *argv[], const char *savegame_dir, const ch
|
|||
Path memstickPath(memstickDir);
|
||||
if (!memstickPath.empty() && File::Exists(memstickPath)) {
|
||||
g_Config.memStickDirectory = memstickPath;
|
||||
INFO_LOG(SYSTEM, "Memstick Directory from memstick_dir.txt: %s", g_Config.memStickDirectory.c_str());
|
||||
} else {
|
||||
ERROR_LOG(SYSTEM, "Couldn't read directory '%s' specified by memstick_dir.txt.", memstickDir.c_str());
|
||||
ERROR_LOG(SYSTEM, "Couldn't read directory '%s' specified by memstick_dir.txt.", memstickDir.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
#elif PPSSPP_PLATFORM(IOS)
|
||||
g_Config.defaultCurrentDirectory = g_Config.internalDataDirectory;
|
||||
g_Config.memStickDirectory = Path(user_data_path);
|
||||
|
|
|
@ -51,6 +51,7 @@
|
|||
<ClCompile Include="GameSettingsScreen.cpp" />
|
||||
<ClCompile Include="GPUDriverTestScreen.cpp" />
|
||||
<ClCompile Include="MainScreen.cpp" />
|
||||
<ClCompile Include="MemStickScreen.cpp" />
|
||||
<ClCompile Include="MiscScreens.cpp" />
|
||||
<ClCompile Include="NativeApp.cpp" />
|
||||
<ClCompile Include="OnScreenDisplay.cpp" />
|
||||
|
@ -85,6 +86,7 @@
|
|||
<ClInclude Include="GPUDriverTestScreen.h" />
|
||||
<ClInclude Include="HostTypes.h" />
|
||||
<ClInclude Include="MainScreen.h" />
|
||||
<ClInclude Include="MemStickScreen.h" />
|
||||
<ClInclude Include="MiscScreens.h" />
|
||||
<ClInclude Include="OnScreenDisplay.h" />
|
||||
<ClInclude Include="PauseScreen.h" />
|
||||
|
@ -394,4 +396,4 @@
|
|||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
</Project>
|
|
@ -78,6 +78,9 @@
|
|||
<ClCompile Include="Store.cpp">
|
||||
<Filter>Screens</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="MemStickScreen.cpp">
|
||||
<Filter>Screens</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="GameInfoCache.h" />
|
||||
|
@ -157,6 +160,9 @@
|
|||
<ClInclude Include="Store.h">
|
||||
<Filter>Screens</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="MemStickScreen.h">
|
||||
<Filter>Screens</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Filter Include="Screens">
|
||||
|
|
|
@ -9,9 +9,12 @@
|
|||
// content://com.android.externalstorage.documents/tree/primary%3APSP%20ISO
|
||||
// content://com.android.externalstorage.documents/tree/primary%3APSP%20ISO/document/primary%3APSP%20ISO
|
||||
|
||||
// This file compiles on all platforms, to reduce the need for ifdefs.
|
||||
|
||||
// I am not 100% sure it's OK to rely on the internal format of file content URIs.
|
||||
// On the other hand, I'm sure tons of apps would break if these changed, so I think we can
|
||||
// consider them pretty stable.
|
||||
// consider them pretty stable. Additionally, the official Document library just manipulates the URIs
|
||||
// in similar ways...
|
||||
class AndroidStorageContentURI {
|
||||
private:
|
||||
std::string provider;
|
||||
|
|
|
@ -177,6 +177,8 @@ static jmethodID contentUriCreateFile;
|
|||
static jmethodID contentUriCreateDirectory;
|
||||
static jmethodID contentUriRemoveFile;
|
||||
static jmethodID contentUriGetFileInfo;
|
||||
static jmethodID contentUriGetFreeStorageSpace;
|
||||
static jmethodID filePathGetFreeStorageSpace;
|
||||
|
||||
static jobject nativeActivity;
|
||||
static volatile bool exitRenderLoop;
|
||||
|
@ -342,6 +344,21 @@ std::vector<File::FileInfo> Android_ListContentUri(const std::string &path) {
|
|||
return items;
|
||||
}
|
||||
|
||||
int64_t Android_GetFreeSpaceByContentUri(const std::string &uri) {
|
||||
auto env = getEnv();
|
||||
|
||||
jstring param = env->NewStringUTF(uri.c_str());
|
||||
return env->CallLongMethod(nativeActivity, contentUriGetFreeStorageSpace, param);
|
||||
}
|
||||
|
||||
int64_t Android_GetFreeSpaceByFilePath(const std::string &filePath) {
|
||||
auto env = getEnv();
|
||||
|
||||
jstring param = env->NewStringUTF(filePath.c_str());
|
||||
return env->CallLongMethod(nativeActivity, filePathGetFreeStorageSpace, param);
|
||||
}
|
||||
|
||||
|
||||
class ContentURIFileLoader : public ProxiedFileLoader {
|
||||
public:
|
||||
ContentURIFileLoader(const Path &filename)
|
||||
|
@ -627,6 +644,10 @@ extern "C" void Java_org_ppsspp_ppsspp_NativeActivity_registerCallbacks(JNIEnv *
|
|||
_dbg_assert_(contentUriRemoveFile);
|
||||
contentUriGetFileInfo = env->GetMethodID(env->GetObjectClass(obj), "contentUriGetFileInfo", "(Ljava/lang/String;)Ljava/lang/String;");
|
||||
_dbg_assert_(contentUriGetFileInfo);
|
||||
contentUriGetFreeStorageSpace = env->GetMethodID(env->GetObjectClass(obj), "contentUriGetFreeStorageSpace", "(Ljava/lang/String;)J");
|
||||
_dbg_assert_(contentUriGetFreeStorageSpace);
|
||||
filePathGetFreeStorageSpace = env->GetMethodID(env->GetObjectClass(obj), "filePathGetFreeStorageSpace", "(Ljava/lang/String;)J");
|
||||
_dbg_assert_(filePathGetFreeStorageSpace);
|
||||
}
|
||||
|
||||
extern "C" void Java_org_ppsspp_ppsspp_NativeActivity_unregisterCallbacks(JNIEnv *env, jobject obj) {
|
||||
|
|
|
@ -4,10 +4,19 @@
|
|||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <cstdint>
|
||||
|
||||
#include "Common/LogManager.h"
|
||||
#include "Common/File/DirListing.h"
|
||||
|
||||
// To emphasize that Android storage mode strings are different, let's just use
|
||||
// an enum.
|
||||
enum class Android_OpenContentUriMode {
|
||||
READ = 0, // "r"
|
||||
READ_WRITE = 1, // "rw"
|
||||
READ_WRITE_TRUNCATE = 2, // "rwt"
|
||||
};
|
||||
|
||||
#if PPSSPP_PLATFORM(ANDROID)
|
||||
|
||||
#include <jni.h>
|
||||
|
@ -25,21 +34,30 @@ extern std::string g_extFilesDir;
|
|||
// Called from PathBrowser for example.
|
||||
|
||||
bool Android_IsContentUri(const std::string &uri);
|
||||
|
||||
// To emphasize that Android storage mode strings are different, let's just use
|
||||
// an enum.
|
||||
enum class Android_OpenContentUriMode {
|
||||
READ = 0, // "r"
|
||||
READ_WRITE = 1, // "rw"
|
||||
READ_WRITE_TRUNCATE = 2, // "rwt"
|
||||
};
|
||||
|
||||
int Android_OpenContentUriFd(const std::string &uri, const Android_OpenContentUriMode mode);
|
||||
bool Android_CreateDirectory(const std::string &parentTreeUri, const std::string &dirName);
|
||||
bool Android_CreateFile(const std::string &parentTreeUri, const std::string &fileName);
|
||||
bool Android_RemoveFile(const std::string &fileUri);
|
||||
bool Android_GetFileInfo(const std::string &fileUri, File::FileInfo *info);
|
||||
int64_t Android_GetFreeSpaceByContentUri(const std::string &uri);
|
||||
int64_t Android_GetFreeSpaceByFilePath(const std::string &filePath);
|
||||
|
||||
std::vector<File::FileInfo> Android_ListContentUri(const std::string &uri);
|
||||
|
||||
#else
|
||||
|
||||
// Stub out the Android Storage wrappers, so that we can avoid ifdefs everywhere.
|
||||
|
||||
inline bool Android_IsContentUri(const std::string &uri) { return false; }
|
||||
inline int Android_OpenContentUriFd(const std::string &uri, const Android_OpenContentUriMode mode) { return -1; }
|
||||
inline bool Android_CreateDirectory(const std::string &parentTreeUri, const std::string &dirName) { return false; }
|
||||
inline bool Android_CreateFile(const std::string &parentTreeUri, const std::string &fileName) { return false; }
|
||||
inline bool Android_RemoveFile(const std::string &fileUri) { return false; }
|
||||
inline bool Android_GetFileInfo(const std::string &fileUri, File::FileInfo *info) { return false; }
|
||||
inline int64_t Android_GetFreeSpaceByContentUri(const std::string &uri) { return -1; }
|
||||
inline int64_t Android_GetFreeSpaceByFilePath(const std::string &filePath) { return -1; }
|
||||
inline std::vector<File::FileInfo> Android_ListContentUri(const std::string &uri) {
|
||||
return std::vector<File::FileInfo>();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -8,8 +8,11 @@ import android.os.Bundle;
|
|||
import android.os.Looper;
|
||||
import android.os.ParcelFileDescriptor;
|
||||
import android.util.Log;
|
||||
import android.os.storage.StorageManager;
|
||||
import androidx.documentfile.provider.DocumentFile;
|
||||
import java.util.ArrayList;
|
||||
import java.util.UUID;
|
||||
import java.io.File;
|
||||
|
||||
public class PpssppActivity extends NativeActivity {
|
||||
private static final String TAG = "PpssppActivity";
|
||||
|
@ -223,4 +226,41 @@ public class PpssppActivity extends NativeActivity {
|
|||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// The example in Android documentation uses this.getFilesDir for path.
|
||||
// There's also a way to beg the OS for more space, which might clear caches, but
|
||||
// let's just not bother with that for now.
|
||||
public long contentUriGetFreeStorageSpace(String uriString) {
|
||||
try {
|
||||
StorageManager storageManager = getApplicationContext().getSystemService(StorageManager.class);
|
||||
|
||||
// In 29 and later, we can directly get the UUID for the storage volume
|
||||
// through the URI.
|
||||
UUID volumeUUID;
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||
Uri uri = Uri.parse(uriString);
|
||||
volumeUUID = UUID.fromString(storageManager.getStorageVolume(uri).getUuid());
|
||||
} else {
|
||||
volumeUUID = storageManager.getUuidForPath(this.getFilesDir());
|
||||
}
|
||||
long availableBytes = storageManager.getAllocatableBytes(volumeUUID);
|
||||
return availableBytes;
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Exception checking free space: " + e.toString());
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
public long filePathGetFreeStorageSpace(String filePath) {
|
||||
try {
|
||||
StorageManager storageManager = getApplicationContext().getSystemService(StorageManager.class);
|
||||
File file = new File(filePath);
|
||||
UUID volumeUUID = storageManager.getUuidForPath(file);
|
||||
long availableBytes = storageManager.getAllocatableBytes(volumeUUID);
|
||||
return availableBytes;
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Exception checking free space: " + e.toString());
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue