android: init user path

This commit is contained in:
BreadFish64 2019-01-15 19:12:43 -06:00
parent 28b2ee9cd7
commit 9848610ea2
10 changed files with 153 additions and 5 deletions

View File

@ -1,10 +1,13 @@
cmake_minimum_required(VERSION 3.8) cmake_minimum_required(VERSION 3.8)
add_library(citra-android SHARED add_library(citra-android SHARED
dummy.cpp native_interface.cpp
native_interface.h
ui/main/main_activity.cpp
) )
# find Android's log library # find Android's log library
find_library(log-lib log) find_library(log-lib log)
target_link_libraries(citra-android ${log-lib} core common inih) target_link_libraries(citra-android ${log-lib} core common inih)
target_include_directories(citra-android PRIVATE "../../../../../" "./")

View File

@ -1,3 +0,0 @@
int dummy(int a, int b) {
return a + b;
}

View File

@ -0,0 +1,22 @@
// Copyright 2019 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include "native_interface.h"
namespace CitraJNI {
jint JNI_OnLoad(JavaVM* vm, void* reserved) {
return JNI_VERSION_1_6;
}
std::string GetJString(JNIEnv* env, jstring jstr) {
std::string result = "";
if (!jstr)
return result;
const char* s = env->GetStringUTFChars(jstr, nullptr);
result = s;
env->ReleaseStringUTFChars(jstr, s);
return result;
}
} // namespace CitraJNI

View File

@ -0,0 +1,16 @@
// Copyright 2019 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <string>
#include <jni.h>
namespace CitraJNI {
extern "C" {
jint JNI_OnLoad(JavaVM* vm, void* reserved);
}
std::string GetJString(JNIEnv* env, jstring jstr);
} // namespace CitraJNI

View File

@ -0,0 +1,15 @@
// Copyright 2019 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include "common/file_util.h"
#include "native_interface.h"
namespace MainActivity {
extern "C" {
JNICALL void Java_org_citra_1emu_citra_ui_main_MainActivity_initUserPath(JNIEnv* env, jclass type,
jstring path) {
FileUtil::SetUserPath(CitraJNI::GetJString(env, path));
}
};
}; // namespace MainActivity

View File

@ -6,4 +6,8 @@ package org.citra_emu.citra;
import android.app.Application; import android.app.Application;
public class CitraApplication extends Application {} public class CitraApplication extends Application {
static {
System.loadLibrary("citra-android");
}
}

View File

@ -4,15 +4,53 @@
package org.citra_emu.citra.ui.main; package org.citra_emu.citra.ui.main;
import android.Manifest;
import android.content.pm.PackageManager;
import android.os.Bundle; import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity; import android.support.v7.app.AppCompatActivity;
import org.citra_emu.citra.R; import org.citra_emu.citra.R;
import org.citra_emu.citra.utils.FileUtil;
import org.citra_emu.citra.utils.PermissionUtil;
public final class MainActivity extends AppCompatActivity { public final class MainActivity extends AppCompatActivity {
// Java enums suck
private interface PermissionCodes { int INIT_USER_PATH = 0; }
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); setContentView(R.layout.activity_main);
PermissionUtil.verifyPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE,
PermissionCodes.INIT_USER_PATH);
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
@NonNull int[] grantResults) {
switch (requestCode) {
case PermissionCodes.INIT_USER_PATH:
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
initUserPath(FileUtil.getUserPath().toString());
} else {
AlertDialog.Builder dialog =
new AlertDialog.Builder(this)
.setTitle("Permission Error")
.setMessage("Citra requires storage permissions to function.")
.setCancelable(false)
.setPositiveButton("OK", (dialogInterface, which) -> {
PermissionUtil.verifyPermission(
MainActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE,
PermissionCodes.INIT_USER_PATH);
});
dialog.show();
} }
} }
}
private static native void initUserPath(String path);
}

View File

@ -0,0 +1,19 @@
// Copyright 2019 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
package org.citra_emu.citra.utils;
import android.os.Environment;
import java.io.File;
public class FileUtil {
public static File getUserPath() {
File storage = Environment.getExternalStorageDirectory();
File userPath = new File(storage, "citra");
if (!userPath.isDirectory())
userPath.mkdir();
return userPath;
}
}

View File

@ -0,0 +1,32 @@
// Copyright 2019 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
package org.citra_emu.citra.utils;
import android.app.Activity;
import android.content.pm.PackageManager;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
public class PermissionUtil {
/**
* Checks a permission, if needed shows a dialog to request it
*
* @param activity the activity requiring the permission
* @param permission the permission needed
* @param requestCode supplied to the callback to determine the next action
*/
public static void verifyPermission(Activity activity, String permission, int requestCode) {
if (ContextCompat.checkSelfPermission(activity, permission) ==
PackageManager.PERMISSION_GRANTED) {
// call the callback called by requestPermissions
activity.onRequestPermissionsResult(requestCode, new String[] {permission},
new int[] {PackageManager.PERMISSION_GRANTED});
return;
}
ActivityCompat.requestPermissions(activity, new String[] {permission}, requestCode);
}
}

View File

@ -695,6 +695,8 @@ void SetUserPath(const std::string& path) {
g_paths.emplace(UserPath::ConfigDir, user_path + CONFIG_DIR DIR_SEP); g_paths.emplace(UserPath::ConfigDir, user_path + CONFIG_DIR DIR_SEP);
g_paths.emplace(UserPath::CacheDir, user_path + CACHE_DIR DIR_SEP); g_paths.emplace(UserPath::CacheDir, user_path + CACHE_DIR DIR_SEP);
#elif ANDROID
ASSERT_MSG(false, "Specified path {} is not valid", path);
#else #else
if (FileUtil::Exists(ROOT_DIR DIR_SEP USERDATA_DIR)) { if (FileUtil::Exists(ROOT_DIR DIR_SEP USERDATA_DIR)) {
user_path = ROOT_DIR DIR_SEP USERDATA_DIR DIR_SEP; user_path = ROOT_DIR DIR_SEP USERDATA_DIR DIR_SEP;