[android] move the key processor to firmware_manager
All checks were successful
eden-license / license-header (pull_request) Successful in 13s

Signed-off-by: Aleksandr Popovich <popovich@eden-emu.dev>
This commit is contained in:
Aleksandr Popovich 2025-07-12 00:04:58 -04:00
parent 67edb897bf
commit a360f67fad
Signed by: AleksandrPopovich
GPG key ID: B2008BBDA7954884
8 changed files with 616 additions and 555 deletions

View file

@ -15,6 +15,7 @@ import android.view.Surface
import android.view.View import android.view.View
import android.widget.TextView import android.widget.TextView
import androidx.annotation.Keep import androidx.annotation.Keep
import androidx.core.net.toUri
import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.dialog.MaterialAlertDialogBuilder
import net.swiftzer.semver.SemVer import net.swiftzer.semver.SemVer
import java.lang.ref.WeakReference import java.lang.ref.WeakReference
@ -27,6 +28,7 @@ import org.yuzu.yuzu_emu.model.InstallResult
import org.yuzu.yuzu_emu.model.Patch import org.yuzu.yuzu_emu.model.Patch
import org.yuzu.yuzu_emu.model.GameVerificationResult import org.yuzu.yuzu_emu.model.GameVerificationResult
import org.yuzu.yuzu_emu.network.NetPlayManager import org.yuzu.yuzu_emu.network.NetPlayManager
import java.io.File
/** /**
* Class which contains methods that interact * Class which contains methods that interact
@ -102,6 +104,21 @@ object NativeLibrary {
FileUtil.getFilename(Uri.parse(path)) FileUtil.getFilename(Uri.parse(path))
} }
@Keep
@JvmStatic
fun copyFileToStorage(source: String, destdir: String): Boolean {
return FileUtil.copyUriToInternalStorage(
source.toUri(),
destdir
) != null
}
@Keep
@JvmStatic
fun getFileExtension(source: String): String {
return FileUtil.getExtension(source.toUri())
}
external fun setAppDirectory(directory: String) external fun setAppDirectory(directory: String)
/** /**

View file

@ -264,8 +264,6 @@ class DriverFetcherFragment : Fragment() {
} }
releases.add(release) releases.add(release)
println(release.publishTime)
} }
} }

View file

@ -478,7 +478,6 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
} }
private fun startEmulation(programIndex: Int = 0) { private fun startEmulation(programIndex: Int = 0) {
println("PROGRAM INDEX: $programIndex")
if (!NativeLibrary.isRunning() && !NativeLibrary.isPaused()) { if (!NativeLibrary.isRunning() && !NativeLibrary.isPaused()) {
if (!DirectoryInitialization.areDirectoriesReady) { if (!DirectoryInitialization.areDirectoriesReady) {
DirectoryInitialization.start() DirectoryInitialization.start()

View file

@ -337,59 +337,35 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
val getAmiiboKey = registerForActivityResult(ActivityResultContracts.OpenDocument()) { result -> val getAmiiboKey = registerForActivityResult(ActivityResultContracts.OpenDocument()) { result ->
if (result != null) { if (result != null) {
processKey(result, "bin", false) processKey(result, "bin")
} }
} }
fun processKey(result: Uri, extension: String = "keys", check: Boolean = true): Boolean { fun processKey(result: Uri, extension: String = "keys") {
if (FileUtil.getExtension(result) != extension) {
MessageDialogFragment.newInstance(
this,
titleId = R.string.keys_failed,
descriptionId = R.string.error_keys_invalid_filename
).show(supportFragmentManager, MessageDialogFragment.TAG)
return false
}
contentResolver.takePersistableUriPermission( contentResolver.takePersistableUriPermission(
result, Intent.FLAG_GRANT_READ_URI_PERMISSION result, Intent.FLAG_GRANT_READ_URI_PERMISSION
) )
val dstPath = DirectoryInitialization.userDirectory + "/keys/" val resultCode: Int = NativeLibrary.installKeys(result.toString(), extension);
if (FileUtil.copyUriToInternalStorage(
result, dstPath, "" if (resultCode == 0) {
) != null
) {
if (NativeLibrary.reloadKeys()) {
Toast.makeText( Toast.makeText(
applicationContext, R.string.keys_install_success, Toast.LENGTH_SHORT applicationContext, R.string.keys_install_success, Toast.LENGTH_SHORT
).show() ).show()
if (check) {
homeViewModel.setCheckKeys(true)
val firstTimeSetup =
PreferenceManager.getDefaultSharedPreferences(applicationContext)
.getBoolean(Settings.PREF_FIRST_APP_LAUNCH, true)
if (!firstTimeSetup) {
homeViewModel.setCheckFirmware(true)
}
gamesViewModel.reloadGames(true) gamesViewModel.reloadGames(true)
}
return true return
} else {
MessageDialogFragment.newInstance(
this,
titleId = R.string.keys_failed,
descriptionId = R.string.error_keys_failed_init,
helpLinkId = R.string.dumping_keys_quickstart_link
).show(supportFragmentManager, MessageDialogFragment.TAG)
return false
}
} }
return true val resultString: String =
resources.getStringArray(R.array.installKeysResults)[resultCode]
MessageDialogFragment.newInstance(
titleId = R.string.keys_failed,
descriptionString = resultString,
helpLinkId = R.string.keys_missing_help
).show(supportFragmentManager, MessageDialogFragment.TAG)
} }
val getFirmware = registerForActivityResult(ActivityResultContracts.OpenDocument()) { result -> val getFirmware = registerForActivityResult(ActivityResultContracts.OpenDocument()) { result ->
@ -542,7 +518,7 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
addonViewModel.refreshAddons() addonViewModel.refreshAddons()
val separator = System.getProperty("line.separator") ?: "\n" val separator = System.lineSeparator() ?: "\n"
val installResult = StringBuilder() val installResult = StringBuilder()
if (installSuccess > 0) { if (installSuccess > 0) {
installResult.append( installResult.append(

View file

@ -504,6 +504,7 @@
</string-array> </string-array>
<string-array name="installKeysResults"> <string-array name="installKeysResults">
<item>""</item>
<item>""</item> <item>""</item>
<item>@string/error_keys_copy_failed</item> <item>@string/error_keys_copy_failed</item>
<item>@string/error_keys_invalid_filename</item> <item>@string/error_keys_invalid_filename</item>

View file

@ -15,7 +15,7 @@
#include <network/network.h> #include <network/network.h>
static JavaVM* s_java_vm; static JavaVM *s_java_vm;
static jclass s_native_library_class; static jclass s_native_library_class;
static jclass s_disk_cache_progress_class; static jclass s_disk_cache_progress_class;
static jclass s_load_callback_stage_class; static jclass s_load_callback_stage_class;
@ -26,6 +26,9 @@ static jmethodID s_disk_cache_load_progress;
static jmethodID s_on_emulation_started; static jmethodID s_on_emulation_started;
static jmethodID s_on_emulation_stopped; static jmethodID s_on_emulation_stopped;
static jmethodID s_on_program_changed; static jmethodID s_on_program_changed;
static jmethodID s_copy_to_storage;
static jmethodID s_file_exists;
static jmethodID s_file_extension;
static jclass s_game_class; static jclass s_game_class;
static jmethodID s_game_constructor; static jmethodID s_game_constructor;
@ -102,10 +105,10 @@ static constexpr jint JNI_VERSION = JNI_VERSION_1_6;
namespace Common::Android { namespace Common::Android {
JNIEnv* GetEnvForThread() { JNIEnv *GetEnvForThread() {
thread_local static struct OwnedEnv { thread_local static struct OwnedEnv {
OwnedEnv() { OwnedEnv() {
status = s_java_vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6); status = s_java_vm->GetEnv(reinterpret_cast<void **>(&env), JNI_VERSION_1_6);
if (status == JNI_EDETACHED) if (status == JNI_EDETACHED)
s_java_vm->AttachCurrentThread(&env, nullptr); s_java_vm->AttachCurrentThread(&env, nullptr);
} }
@ -116,304 +119,316 @@ JNIEnv* GetEnvForThread() {
} }
int status; int status;
JNIEnv* env = nullptr; JNIEnv *env = nullptr;
} owned; } owned;
return owned.env; return owned.env;
} }
jclass GetNativeLibraryClass() { jclass GetNativeLibraryClass() {
return s_native_library_class; return s_native_library_class;
} }
jclass GetDiskCacheProgressClass() { jclass GetDiskCacheProgressClass() {
return s_disk_cache_progress_class; return s_disk_cache_progress_class;
} }
jclass GetDiskCacheLoadCallbackStageClass() { jclass GetDiskCacheLoadCallbackStageClass() {
return s_load_callback_stage_class; return s_load_callback_stage_class;
} }
jclass GetGameDirClass() { jclass GetGameDirClass() {
return s_game_dir_class; return s_game_dir_class;
} }
jmethodID GetGameDirConstructor() { jmethodID GetGameDirConstructor() {
return s_game_dir_constructor; return s_game_dir_constructor;
} }
jmethodID GetExitEmulationActivity() { jmethodID GetExitEmulationActivity() {
return s_exit_emulation_activity; return s_exit_emulation_activity;
} }
jmethodID GetDiskCacheLoadProgress() { jmethodID GetDiskCacheLoadProgress() {
return s_disk_cache_load_progress; return s_disk_cache_load_progress;
} }
jmethodID GetOnEmulationStarted() { jmethodID GetCopyToStorage() {
return s_copy_to_storage;
}
jmethodID GetFileExists() {
return s_file_exists;
}
jmethodID GetFileExtension() {
return s_file_extension;
}
jmethodID GetOnEmulationStarted() {
return s_on_emulation_started; return s_on_emulation_started;
} }
jmethodID GetOnEmulationStopped() { jmethodID GetOnEmulationStopped() {
return s_on_emulation_stopped; return s_on_emulation_stopped;
} }
jmethodID GetOnProgramChanged() { jmethodID GetOnProgramChanged() {
return s_on_program_changed; return s_on_program_changed;
} }
jclass GetGameClass() { jclass GetGameClass() {
return s_game_class; return s_game_class;
} }
jmethodID GetGameConstructor() { jmethodID GetGameConstructor() {
return s_game_constructor; return s_game_constructor;
} }
jfieldID GetGameTitleField() { jfieldID GetGameTitleField() {
return s_game_title_field; return s_game_title_field;
} }
jfieldID GetGamePathField() { jfieldID GetGamePathField() {
return s_game_path_field; return s_game_path_field;
} }
jfieldID GetGameProgramIdField() { jfieldID GetGameProgramIdField() {
return s_game_program_id_field; return s_game_program_id_field;
} }
jfieldID GetGameDeveloperField() { jfieldID GetGameDeveloperField() {
return s_game_developer_field; return s_game_developer_field;
} }
jfieldID GetGameVersionField() { jfieldID GetGameVersionField() {
return s_game_version_field; return s_game_version_field;
} }
jfieldID GetGameIsHomebrewField() { jfieldID GetGameIsHomebrewField() {
return s_game_is_homebrew_field; return s_game_is_homebrew_field;
} }
jclass GetStringClass() { jclass GetStringClass() {
return s_string_class; return s_string_class;
} }
jclass GetPairClass() { jclass GetPairClass() {
return s_pair_class; return s_pair_class;
} }
jmethodID GetPairConstructor() { jmethodID GetPairConstructor() {
return s_pair_constructor; return s_pair_constructor;
} }
jfieldID GetPairFirstField() { jfieldID GetPairFirstField() {
return s_pair_first_field; return s_pair_first_field;
} }
jfieldID GetPairSecondField() { jfieldID GetPairSecondField() {
return s_pair_second_field; return s_pair_second_field;
} }
jclass GetOverlayControlDataClass() { jclass GetOverlayControlDataClass() {
return s_overlay_control_data_class; return s_overlay_control_data_class;
} }
jmethodID GetOverlayControlDataConstructor() { jmethodID GetOverlayControlDataConstructor() {
return s_overlay_control_data_constructor; return s_overlay_control_data_constructor;
} }
jfieldID GetOverlayControlDataIdField() { jfieldID GetOverlayControlDataIdField() {
return s_overlay_control_data_id_field; return s_overlay_control_data_id_field;
} }
jfieldID GetOverlayControlDataEnabledField() { jfieldID GetOverlayControlDataEnabledField() {
return s_overlay_control_data_enabled_field; return s_overlay_control_data_enabled_field;
} }
jfieldID GetOverlayControlDataLandscapePositionField() { jfieldID GetOverlayControlDataLandscapePositionField() {
return s_overlay_control_data_landscape_position_field; return s_overlay_control_data_landscape_position_field;
} }
jfieldID GetOverlayControlDataPortraitPositionField() { jfieldID GetOverlayControlDataPortraitPositionField() {
return s_overlay_control_data_portrait_position_field; return s_overlay_control_data_portrait_position_field;
} }
jfieldID GetOverlayControlDataFoldablePositionField() { jfieldID GetOverlayControlDataFoldablePositionField() {
return s_overlay_control_data_foldable_position_field; return s_overlay_control_data_foldable_position_field;
} }
jclass GetPatchClass() { jclass GetPatchClass() {
return s_patch_class; return s_patch_class;
} }
jmethodID GetPatchConstructor() { jmethodID GetPatchConstructor() {
return s_patch_constructor; return s_patch_constructor;
} }
jfieldID GetPatchEnabledField() { jfieldID GetPatchEnabledField() {
return s_patch_enabled_field; return s_patch_enabled_field;
} }
jfieldID GetPatchNameField() { jfieldID GetPatchNameField() {
return s_patch_name_field; return s_patch_name_field;
} }
jfieldID GetPatchVersionField() { jfieldID GetPatchVersionField() {
return s_patch_version_field; return s_patch_version_field;
} }
jfieldID GetPatchTypeField() { jfieldID GetPatchTypeField() {
return s_patch_type_field; return s_patch_type_field;
} }
jfieldID GetPatchProgramIdField() { jfieldID GetPatchProgramIdField() {
return s_patch_program_id_field; return s_patch_program_id_field;
} }
jfieldID GetPatchTitleIdField() { jfieldID GetPatchTitleIdField() {
return s_patch_title_id_field; return s_patch_title_id_field;
} }
jclass GetDoubleClass() { jclass GetDoubleClass() {
return s_double_class; return s_double_class;
} }
jmethodID GetDoubleConstructor() { jmethodID GetDoubleConstructor() {
return s_double_constructor; return s_double_constructor;
} }
jfieldID GetDoubleValueField() { jfieldID GetDoubleValueField() {
return s_double_value_field; return s_double_value_field;
} }
jclass GetIntegerClass() { jclass GetIntegerClass() {
return s_integer_class; return s_integer_class;
} }
jmethodID GetIntegerConstructor() { jmethodID GetIntegerConstructor() {
return s_integer_constructor; return s_integer_constructor;
} }
jfieldID GetIntegerValueField() { jfieldID GetIntegerValueField() {
return s_integer_value_field; return s_integer_value_field;
} }
jclass GetBooleanClass() { jclass GetBooleanClass() {
return s_boolean_class; return s_boolean_class;
} }
jmethodID GetBooleanConstructor() { jmethodID GetBooleanConstructor() {
return s_boolean_constructor; return s_boolean_constructor;
} }
jfieldID GetBooleanValueField() { jfieldID GetBooleanValueField() {
return s_boolean_value_field; return s_boolean_value_field;
} }
jclass GetPlayerInputClass() { jclass GetPlayerInputClass() {
return s_player_input_class; return s_player_input_class;
} }
jmethodID GetPlayerInputConstructor() { jmethodID GetPlayerInputConstructor() {
return s_player_input_constructor; return s_player_input_constructor;
} }
jfieldID GetPlayerInputConnectedField() { jfieldID GetPlayerInputConnectedField() {
return s_player_input_connected_field; return s_player_input_connected_field;
} }
jfieldID GetPlayerInputButtonsField() { jfieldID GetPlayerInputButtonsField() {
return s_player_input_buttons_field; return s_player_input_buttons_field;
} }
jfieldID GetPlayerInputAnalogsField() { jfieldID GetPlayerInputAnalogsField() {
return s_player_input_analogs_field; return s_player_input_analogs_field;
} }
jfieldID GetPlayerInputMotionsField() { jfieldID GetPlayerInputMotionsField() {
return s_player_input_motions_field; return s_player_input_motions_field;
} }
jfieldID GetPlayerInputVibrationEnabledField() { jfieldID GetPlayerInputVibrationEnabledField() {
return s_player_input_vibration_enabled_field; return s_player_input_vibration_enabled_field;
} }
jfieldID GetPlayerInputVibrationStrengthField() { jfieldID GetPlayerInputVibrationStrengthField() {
return s_player_input_vibration_strength_field; return s_player_input_vibration_strength_field;
} }
jfieldID GetPlayerInputBodyColorLeftField() { jfieldID GetPlayerInputBodyColorLeftField() {
return s_player_input_body_color_left_field; return s_player_input_body_color_left_field;
} }
jfieldID GetPlayerInputBodyColorRightField() { jfieldID GetPlayerInputBodyColorRightField() {
return s_player_input_body_color_right_field; return s_player_input_body_color_right_field;
} }
jfieldID GetPlayerInputButtonColorLeftField() { jfieldID GetPlayerInputButtonColorLeftField() {
return s_player_input_button_color_left_field; return s_player_input_button_color_left_field;
} }
jfieldID GetPlayerInputButtonColorRightField() { jfieldID GetPlayerInputButtonColorRightField() {
return s_player_input_button_color_right_field; return s_player_input_button_color_right_field;
} }
jfieldID GetPlayerInputProfileNameField() { jfieldID GetPlayerInputProfileNameField() {
return s_player_input_profile_name_field; return s_player_input_profile_name_field;
} }
jfieldID GetPlayerInputUseSystemVibratorField() { jfieldID GetPlayerInputUseSystemVibratorField() {
return s_player_input_use_system_vibrator_field; return s_player_input_use_system_vibrator_field;
} }
jclass GetYuzuInputDeviceInterface() { jclass GetYuzuInputDeviceInterface() {
return s_yuzu_input_device_interface; return s_yuzu_input_device_interface;
} }
jmethodID GetYuzuDeviceGetName() { jmethodID GetYuzuDeviceGetName() {
return s_yuzu_input_device_get_name; return s_yuzu_input_device_get_name;
} }
jmethodID GetYuzuDeviceGetGUID() { jmethodID GetYuzuDeviceGetGUID() {
return s_yuzu_input_device_get_guid; return s_yuzu_input_device_get_guid;
} }
jmethodID GetYuzuDeviceGetPort() { jmethodID GetYuzuDeviceGetPort() {
return s_yuzu_input_device_get_port; return s_yuzu_input_device_get_port;
} }
jmethodID GetYuzuDeviceGetSupportsVibration() { jmethodID GetYuzuDeviceGetSupportsVibration() {
return s_yuzu_input_device_get_supports_vibration; return s_yuzu_input_device_get_supports_vibration;
} }
jmethodID GetYuzuDeviceVibrate() { jmethodID GetYuzuDeviceVibrate() {
return s_yuzu_input_device_vibrate; return s_yuzu_input_device_vibrate;
} }
jmethodID GetYuzuDeviceGetAxes() { jmethodID GetYuzuDeviceGetAxes() {
return s_yuzu_input_device_get_axes; return s_yuzu_input_device_get_axes;
} }
jmethodID GetYuzuDeviceHasKeys() { jmethodID GetYuzuDeviceHasKeys() {
return s_yuzu_input_device_has_keys; return s_yuzu_input_device_has_keys;
} }
jmethodID GetAddNetPlayMessage() { jmethodID GetAddNetPlayMessage() {
return s_add_netplay_message; return s_add_netplay_message;
} }
jmethodID ClearChat() { jmethodID ClearChat() {
return s_clear_chat; return s_clear_chat;
} }
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
jint JNI_OnLoad(JavaVM* vm, void* reserved) { jint JNI_OnLoad(JavaVM *vm, void *reserved) {
s_java_vm = vm; s_java_vm = vm;
JNIEnv* env; JNIEnv *env;
if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION) != JNI_OK) if (vm->GetEnv(reinterpret_cast<void **>(&env), JNI_VERSION) != JNI_OK)
return JNI_ERR; return JNI_ERR;
// Initialize Java classes // Initialize Java classes
@ -426,7 +441,8 @@ jint JNI_OnLoad(JavaVM* vm, void* reserved) {
const jclass game_dir_class = env->FindClass("org/yuzu/yuzu_emu/model/GameDir"); const jclass game_dir_class = env->FindClass("org/yuzu/yuzu_emu/model/GameDir");
s_game_dir_class = reinterpret_cast<jclass>(env->NewGlobalRef(game_dir_class)); s_game_dir_class = reinterpret_cast<jclass>(env->NewGlobalRef(game_dir_class));
s_game_dir_constructor = env->GetMethodID(game_dir_class, "<init>", "(Ljava/lang/String;Z)V"); s_game_dir_constructor = env->GetMethodID(game_dir_class, "<init>",
"(Ljava/lang/String;Z)V");
env->DeleteLocalRef(game_dir_class); env->DeleteLocalRef(game_dir_class);
// Initialize methods // Initialize methods
@ -434,6 +450,12 @@ jint JNI_OnLoad(JavaVM* vm, void* reserved) {
env->GetStaticMethodID(s_native_library_class, "exitEmulationActivity", "(I)V"); env->GetStaticMethodID(s_native_library_class, "exitEmulationActivity", "(I)V");
s_disk_cache_load_progress = s_disk_cache_load_progress =
env->GetStaticMethodID(s_disk_cache_progress_class, "loadProgress", "(III)V"); env->GetStaticMethodID(s_disk_cache_progress_class, "loadProgress", "(III)V");
s_copy_to_storage = env->GetStaticMethodID(s_native_library_class, "copyFileToStorage",
"(Ljava/lang/String;Ljava/lang/String;)Z");
s_file_exists = env->GetStaticMethodID(s_native_library_class, "exists",
"(Ljava/lang/String;)Z");
s_file_extension = env->GetStaticMethodID(s_native_library_class, "getFileExtension",
"(Ljava/lang/String;)Ljava/lang/String;");
s_on_emulation_started = s_on_emulation_started =
env->GetStaticMethodID(s_native_library_class, "onEmulationStarted", "()V"); env->GetStaticMethodID(s_native_library_class, "onEmulationStarted", "()V");
s_on_emulation_stopped = s_on_emulation_stopped =
@ -555,10 +577,12 @@ jint JNI_OnLoad(JavaVM* vm, void* reserved) {
env->GetMethodID(yuzu_input_device_interface, "getName", "()Ljava/lang/String;"); env->GetMethodID(yuzu_input_device_interface, "getName", "()Ljava/lang/String;");
s_yuzu_input_device_get_guid = s_yuzu_input_device_get_guid =
env->GetMethodID(yuzu_input_device_interface, "getGUID", "()Ljava/lang/String;"); env->GetMethodID(yuzu_input_device_interface, "getGUID", "()Ljava/lang/String;");
s_yuzu_input_device_get_port = env->GetMethodID(yuzu_input_device_interface, "getPort", "()I"); s_yuzu_input_device_get_port = env->GetMethodID(yuzu_input_device_interface, "getPort",
"()I");
s_yuzu_input_device_get_supports_vibration = s_yuzu_input_device_get_supports_vibration =
env->GetMethodID(yuzu_input_device_interface, "getSupportsVibration", "()Z"); env->GetMethodID(yuzu_input_device_interface, "getSupportsVibration", "()Z");
s_yuzu_input_device_vibrate = env->GetMethodID(yuzu_input_device_interface, "vibrate", "(F)V"); s_yuzu_input_device_vibrate = env->GetMethodID(yuzu_input_device_interface, "vibrate",
"(F)V");
s_yuzu_input_device_get_axes = s_yuzu_input_device_get_axes =
env->GetMethodID(yuzu_input_device_interface, "getAxes", "()[Ljava/lang/Integer;"); env->GetMethodID(yuzu_input_device_interface, "getAxes", "()[Ljava/lang/Integer;");
s_yuzu_input_device_has_keys = s_yuzu_input_device_has_keys =
@ -576,11 +600,11 @@ jint JNI_OnLoad(JavaVM* vm, void* reserved) {
Common::Android::SoftwareKeyboard::InitJNI(env); Common::Android::SoftwareKeyboard::InitJNI(env);
return JNI_VERSION; return JNI_VERSION;
} }
void JNI_OnUnload(JavaVM* vm, void* reserved) { void JNI_OnUnload(JavaVM *vm, void *reserved) {
JNIEnv* env; JNIEnv *env;
if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION) != JNI_OK) { if (vm->GetEnv(reinterpret_cast<void **>(&env), JNI_VERSION) != JNI_OK) {
return; return;
} }
@ -605,10 +629,10 @@ void JNI_OnUnload(JavaVM* vm, void* reserved) {
SoftwareKeyboard::CleanupJNI(env); SoftwareKeyboard::CleanupJNI(env);
AndroidMultiplayer::NetworkShutdown(); AndroidMultiplayer::NetworkShutdown();
} }
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif
} // namespace Common::Android } // namespace Common::Android

View file

@ -39,6 +39,9 @@ jclass GetDiskCacheLoadCallbackStageClass();
jclass GetGameDirClass(); jclass GetGameDirClass();
jmethodID GetGameDirConstructor(); jmethodID GetGameDirConstructor();
jmethodID GetDiskCacheLoadProgress(); jmethodID GetDiskCacheLoadProgress();
jmethodID GetCopyToStorage();
jmethodID GetFileExists();
jmethodID GetFileExtension();
jmethodID GetExitEmulationActivity(); jmethodID GetExitEmulationActivity();
jmethodID GetOnEmulationStarted(); jmethodID GetOnEmulationStarted();

View file

@ -3,6 +3,10 @@
#include "firmware_manager.h" #include "firmware_manager.h"
#include <filesystem> #include <filesystem>
#include <jni.h>
#include <common/android/id_cache.h>
#include <common/android/android_common.h>
#include <common/fs/fs_paths.h>
#include "common/fs/fs.h" #include "common/fs/fs.h"
#include "common/fs/path_util.h" #include "common/fs/path_util.h"
@ -12,12 +16,52 @@
#include "core/crypto/key_manager.h" #include "core/crypto/key_manager.h"
#include "frontend_common/content_manager.h" #include "frontend_common/content_manager.h"
FirmwareManager::KeyInstallResult FirmwareManager::InstallKeys(std::string location, std::string extension) FirmwareManager::KeyInstallResult
{ FirmwareManager::InstallKeys(std::string location, std::string extension) {
LOG_INFO(Frontend, "Installing key files from {}", location); LOG_INFO(Frontend, "Installing key files from {}", location);
const auto keys_dir = Common::FS::GetEdenPath(Common::FS::EdenPath::KeysDir); const auto keys_dir = Common::FS::GetEdenPath(Common::FS::EdenPath::KeysDir);
#ifdef ANDROID
JNIEnv *env = Common::Android::GetEnvForThread();
jstring jsrc = Common::Android::ToJString(env, location);
jclass native = Common::Android::GetNativeLibraryClass();
jmethodID getExtension = Common::Android::GetFileExtension();
jstring jext = static_cast<jstring>(env->CallStaticObjectMethod(
native,
getExtension,
jsrc
));
std::string ext = Common::Android::GetJString(env, jext);
if (ext != extension) {
return ErrorWrongFilename;
}
jmethodID copyToStorage = Common::Android::GetCopyToStorage();
jstring jdest = Common::Android::ToJString(env, keys_dir.string());
jboolean copyResult = env->CallStaticBooleanMethod(
native,
copyToStorage,
jsrc,
jdest
);
if (!copyResult) {
return ErrorFailedCopy;
}
#else
if (!location.ends_with(extension)) {
return ErrorWrongFilename;
}
bool prod_keys_found = false;
const std::filesystem::path prod_key_path = location; const std::filesystem::path prod_key_path = location;
const std::filesystem::path key_source_path = prod_key_path.parent_path(); const std::filesystem::path key_source_path = prod_key_path.parent_path();
@ -25,7 +69,6 @@ FirmwareManager::KeyInstallResult FirmwareManager::InstallKeys(std::string locat
return InvalidDir; return InvalidDir;
} }
bool prod_keys_found = false;
std::vector<std::filesystem::path> source_key_files; std::vector<std::filesystem::path> source_key_files;
if (Common::FS::Exists(prod_key_path)) { if (Common::FS::Exists(prod_key_path)) {
@ -57,6 +100,7 @@ FirmwareManager::KeyInstallResult FirmwareManager::InstallKeys(std::string locat
return ErrorFailedCopy; return ErrorFailedCopy;
} }
} }
#endif
// Reinitialize the key manager // Reinitialize the key manager
Core::Crypto::KeyManager::Instance().ReloadKeys(); Core::Crypto::KeyManager::Instance().ReloadKeys();
@ -65,12 +109,11 @@ FirmwareManager::KeyInstallResult FirmwareManager::InstallKeys(std::string locat
return Success; return Success;
} }
// let the frontend handle checking everything else // Let the frontend handle everything else
return ErrorFailedInit; return ErrorFailedInit;
} }
FirmwareManager::FirmwareCheckResult FirmwareManager::VerifyFirmware(Core::System &system) FirmwareManager::FirmwareCheckResult FirmwareManager::VerifyFirmware(Core::System &system) {
{
if (!CheckFirmwarePresence(system)) { if (!CheckFirmwarePresence(system)) {
return ErrorFirmwareMissing; return ErrorFirmwareMissing;
} else { } else {