Merge pull request #6051 from JosJuice/android-sys

Android: Extract Sys to a different folder than the User folder
This commit is contained in:
JosJuice 2017-12-27 17:34:24 +01:00 committed by GitHub
commit 1df69c5750
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 149 additions and 90 deletions

View File

@ -283,6 +283,8 @@ public final class NativeLibrary
*/ */
public static native String GetVersionString(); public static native String GetVersionString();
public static native String GetGitRevision();
/** /**
* Saves a screen capture of the game * Saves a screen capture of the game
*/ */
@ -302,11 +304,6 @@ public final class NativeLibrary
*/ */
public static native void LoadState(int slot); public static native void LoadState(int slot);
/**
* Creates the initial folder structure in /sdcard/dolphin-emu/
*/
public static native void CreateUserFolders();
/** /**
* Sets the current working user directory * Sets the current working user directory
* If not set, it auto-detects a location * If not set, it auto-detects a location

View File

@ -9,6 +9,8 @@ package org.dolphinemu.dolphinemu.services;
import android.app.IntentService; import android.app.IntentService;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import android.support.v4.content.LocalBroadcastManager; import android.support.v4.content.LocalBroadcastManager;
import org.dolphinemu.dolphinemu.NativeLibrary; import org.dolphinemu.dolphinemu.NativeLibrary;
@ -59,7 +61,8 @@ public final class DirectoryInitializationService extends IntentService
} }
else if (PermissionsHandler.hasWriteAccess(this)) else if (PermissionsHandler.hasWriteAccess(this))
{ {
initDolphinDirectories(); initializeInternalStorage();
initializeExternalStorage();
directoryState = DirectoryInitializationState.DOLPHIN_DIRECTORIES_INITIALIZED; directoryState = DirectoryInitializationState.DOLPHIN_DIRECTORIES_INITIALIZED;
sendBroadcastState(directoryState); sendBroadcastState(directoryState);
} }
@ -69,21 +72,55 @@ public final class DirectoryInitializationService extends IntentService
} }
} }
private void initDolphinDirectories() private void initializeInternalStorage()
{ {
String BaseDir = NativeLibrary.GetUserDirectory(); File sysDirectory = new File(getFilesDir(), "Sys");
String ConfigDir = BaseDir + File.separator + "Config";
// Copy assets if needed SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
NativeLibrary.CreateUserFolders(); String revision = NativeLibrary.GetGitRevision();
copyAssetFolder("GC", BaseDir + File.separator + "GC", false); if (!preferences.getString("sysDirectoryVersion", "").equals(revision))
copyAssetFolder("Shaders", BaseDir + File.separator + "Shaders", false); {
copyAssetFolder("Wii", BaseDir + File.separator + "Wii", false); // There is no extracted Sys directory, or there is a Sys directory from another
// version of Dolphin that might contain outdated files. Let's (re-)extract Sys.
deleteDirectoryRecursively(sysDirectory);
copyAssetFolder("Sys", sysDirectory, true);
// Always copy over the GCPad config in case of change or corruption. SharedPreferences.Editor editor = preferences.edit();
// Not a user configurable file. editor.putString("sysDirectoryVersion", revision);
copyAsset("GCPadNew.ini", ConfigDir + File.separator + "GCPadNew.ini", true); editor.apply();
copyAsset("WiimoteNew.ini", ConfigDir + File.separator + "WiimoteNew.ini", false); }
// Let the native code know where the Sys directory is.
SetSysDirectory(sysDirectory.getPath());
}
private void initializeExternalStorage()
{
// Create User directory structure and copy some NAND files from the extracted Sys directory.
CreateUserDirectories();
// GCPadNew.ini and WiimoteNew.ini must contain specific values in order for controller
// input to work as intended (they aren't user configurable), so we overwrite them just
// in case the user has tried to modify them manually.
//
// ...Except WiimoteNew.ini contains the user configurable settings for Wii Remote
// extensions in addition to all of its lines that aren't user configurable, so since we
// don't want to lose the selected extensions, we don't overwrite that file if it exists.
//
// TODO: Redo the Android controller system so that we don't have to extract these INIs.
String configDirectory = NativeLibrary.GetUserDirectory() + File.separator + "Config";
copyAsset("GCPadNew.ini", new File(configDirectory, "GCPadNew.ini"), true);
copyAsset("WiimoteNew.ini", new File(configDirectory,"WiimoteNew.ini"), false);
}
private static void deleteDirectoryRecursively(File file)
{
if (file.isDirectory())
{
for (File child : file.listFiles())
deleteDirectoryRecursively(child);
}
file.delete();
} }
public static boolean areDolphinDirectoriesReady() public static boolean areDolphinDirectoriesReady()
@ -99,19 +136,16 @@ public final class DirectoryInitializationService extends IntentService
LocalBroadcastManager.getInstance(this).sendBroadcast(localIntent); LocalBroadcastManager.getInstance(this).sendBroadcast(localIntent);
} }
private void copyAsset(String asset, String output, Boolean overwrite) private void copyAsset(String asset, File output, Boolean overwrite)
{ {
Log.verbose("[DirectoryInitializationService] Copying File " + asset + " to " + output); Log.verbose("[DirectoryInitializationService] Copying File " + asset + " to " + output);
InputStream in;
OutputStream out;
try try
{ {
File file = new File(output); if (!output.exists() || overwrite)
if (!file.exists() || overwrite)
{ {
in = getAssets().open(asset); InputStream in = getAssets().open(asset);
out = new FileOutputStream(output); OutputStream out = new FileOutputStream(output);
copyFile(in, out); copyFile(in, out);
in.close(); in.close();
out.close(); out.close();
@ -123,16 +157,22 @@ public final class DirectoryInitializationService extends IntentService
} }
} }
private void copyAssetFolder(String assetFolder, String outputFolder, Boolean overwrite) private void copyAssetFolder(String assetFolder, File outputFolder, Boolean overwrite)
{ {
Log.verbose("[DirectoryInitializationService] Copying Folder " + assetFolder + " to " + outputFolder); Log.verbose("[DirectoryInitializationService] Copying Folder " + assetFolder + " to " + outputFolder);
try try
{ {
boolean createdFolder = false;
for (String file : getAssets().list(assetFolder)) for (String file : getAssets().list(assetFolder))
{ {
copyAssetFolder(assetFolder + File.separator + file, outputFolder + File.separator + file, overwrite); if (!createdFolder)
copyAsset(assetFolder + File.separator + file, outputFolder + File.separator + file, overwrite); {
outputFolder.mkdir();
createdFolder = true;
}
copyAssetFolder(assetFolder + File.separator + file, new File(outputFolder, file), overwrite);
copyAsset(assetFolder + File.separator + file, new File(outputFolder, file), overwrite);
} }
} }
catch (IOException e) catch (IOException e)
@ -151,4 +191,7 @@ public final class DirectoryInitializationService extends IntentService
out.write(buffer, 0, read); out.write(buffer, 0, read);
} }
} }
private static native void CreateUserDirectories();
private static native void SetSysDirectory(String path);
} }

View File

@ -13,33 +13,31 @@ public final class StartupHandler
{ {
public static boolean HandleInit(FragmentActivity parent) public static boolean HandleInit(FragmentActivity parent)
{ {
NativeLibrary.SetUserDirectory(""); // Auto-Detect String user_dir = "";
String start_file = "";
if (PermissionsHandler.checkWritePermission(parent)) {
DirectoryInitializationService.startService(parent);
}
Intent intent = parent.getIntent();
Bundle extras = intent.getExtras();
Bundle extras = parent.getIntent().getExtras();
if (extras != null) if (extras != null)
{ {
String user_dir = extras.getString("UserDir"); user_dir = extras.getString("UserDir");
String start_file = extras.getString("AutoStartFile"); start_file = extras.getString("AutoStartFile");
if (!TextUtils.isEmpty(user_dir))
NativeLibrary.SetUserDirectory(user_dir);
if (!TextUtils.isEmpty(start_file))
{
// Start the emulation activity, send the ISO passed in and finish the main activity
Intent emulation_intent = new Intent(parent, EmulationActivity.class);
emulation_intent.putExtra("SelectedGame", start_file);
parent.startActivity(emulation_intent);
parent.finish();
return false;
}
} }
NativeLibrary.SetUserDirectory(user_dir); // Uses default path if user_dir equals ""
if (PermissionsHandler.checkWritePermission(parent))
DirectoryInitializationService.startService(parent);
if (!TextUtils.isEmpty(start_file))
{
// Start the emulation activity, send the ISO passed in and finish the main activity
Intent emulation_intent = new Intent(parent, EmulationActivity.class);
emulation_intent.putExtra("SelectedGame", start_file);
parent.startActivity(emulation_intent);
parent.finish();
return false;
}
return false; return false;
} }
} }

View File

@ -15,6 +15,8 @@ ${LIBS}
) )
file(MAKE_DIRECTORY ${CMAKE_SOURCE_DIR}/Source/Android/app/src/main/assets/) file(MAKE_DIRECTORY ${CMAKE_SOURCE_DIR}/Source/Android/app/src/main/assets/)
file(COPY ${CMAKE_SOURCE_DIR}/Data/Sys/GameSettings ${CMAKE_SOURCE_DIR}/Data/Sys/GC ${CMAKE_SOURCE_DIR}/Data/Sys/Wii ${CMAKE_SOURCE_DIR}/Data/Sys/Shaders DESTINATION ${CMAKE_SOURCE_DIR}/Source/Android/app/src/main/assets/) file(REMOVE_RECURSE ${CMAKE_SOURCE_DIR}/Source/Android/app/src/main/assets/Sys/)
file(COPY ${CMAKE_SOURCE_DIR}/Data/Sys DESTINATION ${CMAKE_SOURCE_DIR}/Source/Android/app/src/main/assets/)
file(REMOVE_RECURSE ${CMAKE_SOURCE_DIR}/Source/Android/app/src/main/assets/Sys/Resources/) # not used on Android
set(CPACK_PACKAGE_EXECUTABLES ${CPACK_PACKAGE_EXECUTABLES} ${SHARED_LIB}) set(CPACK_PACKAGE_EXECUTABLES ${CPACK_PACKAGE_EXECUTABLES} ${SHARED_LIB})

View File

@ -432,6 +432,8 @@ JNIEXPORT jint JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_GetPlatform(
jstring jFilename); jstring jFilename);
JNIEXPORT jstring JNICALL JNIEXPORT jstring JNICALL
Java_org_dolphinemu_dolphinemu_NativeLibrary_GetVersionString(JNIEnv* env, jobject obj); Java_org_dolphinemu_dolphinemu_NativeLibrary_GetVersionString(JNIEnv* env, jobject obj);
JNIEXPORT jstring JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_GetGitRevision(JNIEnv* env,
jobject obj);
JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_SaveScreenShot(JNIEnv* env, JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_SaveScreenShot(JNIEnv* env,
jobject obj); jobject obj);
JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_eglBindAPI(JNIEnv* env, JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_eglBindAPI(JNIEnv* env,
@ -450,8 +452,9 @@ JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_SaveState(JN
JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_LoadState(JNIEnv* env, JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_LoadState(JNIEnv* env,
jobject obj, jobject obj,
jint slot); jint slot);
JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_CreateUserFolders(JNIEnv* env, JNIEXPORT void JNICALL
jobject obj); Java_org_dolphinemu_dolphinemu_services_DirectoryInitializationService_CreateUserDirectories(
JNIEnv* env, jobject obj);
JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_SetUserDirectory( JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_SetUserDirectory(
JNIEnv* env, jobject obj, jstring jDirectory); JNIEnv* env, jobject obj, jstring jDirectory);
JNIEXPORT jstring JNICALL JNIEXPORT jstring JNICALL
@ -588,6 +591,12 @@ JNIEXPORT jstring JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_GetVersio
return env->NewStringUTF(Common::scm_rev_str.c_str()); return env->NewStringUTF(Common::scm_rev_str.c_str());
} }
JNIEXPORT jstring JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_GetGitRevision(JNIEnv* env,
jobject obj)
{
return env->NewStringUTF(Common::scm_rev_git_str.c_str());
}
JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_SaveScreenShot(JNIEnv* env, JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_SaveScreenShot(JNIEnv* env,
jobject obj) jobject obj)
{ {
@ -649,28 +658,19 @@ JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_LoadState(JN
State::Load(slot); State::Load(slot);
} }
JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_CreateUserFolders(JNIEnv* env, JNIEXPORT void JNICALL
jobject obj) Java_org_dolphinemu_dolphinemu_services_DirectoryInitializationService_SetSysDirectory(
JNIEnv* env, jobject obj, jstring jPath)
{ {
File::CreateFullPath(File::GetUserPath(D_CONFIG_IDX)); const std::string path = GetJString(env, jPath);
File::CreateFullPath(File::GetUserPath(D_GCUSER_IDX)); File::SetSysDirectory(path);
File::CreateFullPath(File::GetUserPath(D_WIIROOT_IDX) + DIR_SEP WII_WC24CONF_DIR DIR_SEP }
"mbox" DIR_SEP);
File::CreateFullPath(File::GetUserPath(D_WIIROOT_IDX) + DIR_SEP "shared2" DIR_SEP JNIEXPORT void JNICALL
"succession" DIR_SEP); Java_org_dolphinemu_dolphinemu_services_DirectoryInitializationService_CreateUserDirectories(
File::CreateFullPath(File::GetUserPath(D_WIIROOT_IDX) + DIR_SEP "shared2" DIR_SEP "ec" DIR_SEP); JNIEnv* env, jobject obj)
File::CreateFullPath(File::GetUserPath(D_WIIROOT_IDX) + DIR_SEP WII_SYSCONF_DIR DIR_SEP); {
File::CreateFullPath(File::GetUserPath(D_CACHE_IDX)); UICommon::CreateDirectories();
File::CreateFullPath(File::GetUserPath(D_DUMPDSP_IDX));
File::CreateFullPath(File::GetUserPath(D_DUMPTEXTURES_IDX));
File::CreateFullPath(File::GetUserPath(D_HIRESTEXTURES_IDX));
File::CreateFullPath(File::GetUserPath(D_SCREENSHOTS_IDX));
File::CreateFullPath(File::GetUserPath(D_STATESAVES_IDX));
File::CreateFullPath(File::GetUserPath(D_MAILLOGS_IDX));
File::CreateFullPath(File::GetUserPath(D_SHADERS_IDX) + "Anaglyph" DIR_SEP);
File::CreateFullPath(File::GetUserPath(D_GCUSER_IDX) + USA_DIR DIR_SEP);
File::CreateFullPath(File::GetUserPath(D_GCUSER_IDX) + EUR_DIR DIR_SEP);
File::CreateFullPath(File::GetUserPath(D_GCUSER_IDX) + JAP_DIR DIR_SEP);
} }
JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_SetUserDirectory( JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_SetUserDirectory(

View File

@ -27,21 +27,6 @@
#define DOLPHIN_DATA_DIR "dolphin-emu" #define DOLPHIN_DATA_DIR "dolphin-emu"
#endif #endif
// Shared data dirs (Sys and shared User for Linux)
#if defined(_WIN32) || defined(LINUX_LOCAL_DEV)
#define SYSDATA_DIR "Sys"
#elif defined __APPLE__
#define SYSDATA_DIR "Contents/Resources/Sys"
#elif defined ANDROID
#define SYSDATA_DIR "/sdcard/dolphin-emu"
#else
#ifdef DATA_DIR
#define SYSDATA_DIR DATA_DIR "sys"
#else
#define SYSDATA_DIR "sys"
#endif
#endif
// Dirs in both User and Sys // Dirs in both User and Sys
#define EUR_DIR "EUR" #define EUR_DIR "EUR"
#define USA_DIR "USA" #define USA_DIR "USA"

View File

@ -13,6 +13,7 @@
#include <sys/stat.h> #include <sys/stat.h>
#include <vector> #include <vector>
#include "Common/Assert.h"
#include "Common/Common.h" #include "Common/Common.h"
#include "Common/CommonFuncs.h" #include "Common/CommonFuncs.h"
#include "Common/CommonPaths.h" #include "Common/CommonPaths.h"
@ -52,6 +53,10 @@
// REMEMBER: strdup considered harmful! // REMEMBER: strdup considered harmful!
namespace File namespace File
{ {
#ifdef ANDROID
static std::string s_android_sys_directory;
#endif
#ifdef _WIN32 #ifdef _WIN32
FileInfo::FileInfo(const std::string& path) FileInfo::FileInfo(const std::string& path)
{ {
@ -692,10 +697,25 @@ std::string GetSysDirectory()
{ {
std::string sysDir; std::string sysDir;
#if defined(_WIN32) || defined(LINUX_LOCAL_DEV)
#define SYSDATA_DIR "Sys"
#elif defined __APPLE__
#define SYSDATA_DIR "Contents/Resources/Sys"
#else
#ifdef DATA_DIR
#define SYSDATA_DIR DATA_DIR "sys"
#else
#define SYSDATA_DIR "sys"
#endif
#endif
#if defined(__APPLE__) #if defined(__APPLE__)
sysDir = GetBundleDirectory() + DIR_SEP + SYSDATA_DIR; sysDir = GetBundleDirectory() + DIR_SEP + SYSDATA_DIR;
#elif defined(_WIN32) || defined(LINUX_LOCAL_DEV) #elif defined(_WIN32) || defined(LINUX_LOCAL_DEV)
sysDir = GetExeDirectory() + DIR_SEP + SYSDATA_DIR; sysDir = GetExeDirectory() + DIR_SEP + SYSDATA_DIR;
#elif defined ANDROID
sysDir = s_android_sys_directory;
_assert_msg_(COMMON, !sysDir.empty(), "Sys directory has not been set");
#else #else
sysDir = SYSDATA_DIR; sysDir = SYSDATA_DIR;
#endif #endif
@ -705,6 +725,14 @@ std::string GetSysDirectory()
return sysDir; return sysDir;
} }
#ifdef ANDROID
void SetSysDirectory(const std::string& path)
{
INFO_LOG(COMMON, "Setting Sys directory to %s", path.c_str());
s_android_sys_directory = path;
}
#endif
static std::string s_user_paths[NUM_PATH_INDICES]; static std::string s_user_paths[NUM_PATH_INDICES];
static void RebuildUserDirectories(unsigned int dir_index) static void RebuildUserDirectories(unsigned int dir_index)
{ {

View File

@ -183,6 +183,10 @@ std::string GetThemeDir(const std::string& theme_name);
// Returns the path to where the sys file are // Returns the path to where the sys file are
std::string GetSysDirectory(); std::string GetSysDirectory();
#ifdef ANDROID
void SetSysDirectory(const std::string& path);
#endif
#ifdef __APPLE__ #ifdef __APPLE__
std::string GetBundleDirectory(); std::string GetBundleDirectory();
#endif #endif

View File

@ -77,7 +77,9 @@ void CreateDirectories()
File::CreateFullPath(File::GetUserPath(D_SHADERS_IDX)); File::CreateFullPath(File::GetUserPath(D_SHADERS_IDX));
File::CreateFullPath(File::GetUserPath(D_SHADERS_IDX) + ANAGLYPH_DIR DIR_SEP); File::CreateFullPath(File::GetUserPath(D_SHADERS_IDX) + ANAGLYPH_DIR DIR_SEP);
File::CreateFullPath(File::GetUserPath(D_STATESAVES_IDX)); File::CreateFullPath(File::GetUserPath(D_STATESAVES_IDX));
#ifndef ANDROID
File::CreateFullPath(File::GetUserPath(D_THEMES_IDX)); File::CreateFullPath(File::GetUserPath(D_THEMES_IDX));
#endif
} }
void SetUserDirectory(const std::string& custom_path) void SetUserDirectory(const std::string& custom_path)