aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorbunnei <[email protected]>2023-02-04 00:55:02 -0800
committerbunnei <[email protected]>2023-06-03 00:05:29 -0700
commit93cf8c3090889e1228b94df4d171601d8f7dd7f0 (patch)
tree50dea0d1b7e2c9ecd668ad3e33c912df5b3e5f0a
parent63a98e3e1cc9dfb306bb3f063a6c89acaf1f55ad (diff)
downloadyuzu-android-93cf8c3090889e1228b94df4d171601d8f7dd7f0.tar.gz
yuzu-android-93cf8c3090889e1228b94df4d171601d8f7dd7f0.zip
android: frontend: Integrate key installation for SAF.
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.java30
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainPresenter.java5
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/FileBrowserHelper.java9
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/FileUtil.java37
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/StartupHandler.java24
-rw-r--r--src/android/app/src/main/jni/native.cpp2
-rw-r--r--src/android/app/src/main/res/drawable-hdpi/ic_install.png (renamed from src/android/app/src/main/res/drawable-hdpi/ic_cia_install.png)bin514 -> 514 bytes
-rw-r--r--src/android/app/src/main/res/drawable-mdpi/ic_install.png (renamed from src/android/app/src/main/res/drawable-mdpi/ic_cia_install.png)bin364 -> 364 bytes
-rw-r--r--src/android/app/src/main/res/drawable-night-hdpi/ic_install.png (renamed from src/android/app/src/main/res/drawable-night-hdpi/ic_cia_install.png)bin556 -> 556 bytes
-rw-r--r--src/android/app/src/main/res/drawable-night-mdpi/ic_install.png (renamed from src/android/app/src/main/res/drawable-night-mdpi/ic_cia_install.png)bin405 -> 405 bytes
-rw-r--r--src/android/app/src/main/res/drawable-night-xhdpi/ic_install.png (renamed from src/android/app/src/main/res/drawable-night-xhdpi/ic_cia_install.png)bin729 -> 729 bytes
-rw-r--r--src/android/app/src/main/res/drawable-night-xxhdpi/ic_install.png (renamed from src/android/app/src/main/res/drawable-night-xxhdpi/ic_cia_install.png)bin1168 -> 1168 bytes
-rw-r--r--src/android/app/src/main/res/drawable-night-xxxhdpi/ic_install.png (renamed from src/android/app/src/main/res/drawable-night-xxxhdpi/ic_cia_install.png)bin1433 -> 1433 bytes
-rw-r--r--src/android/app/src/main/res/drawable-xhdpi/ic_install.png (renamed from src/android/app/src/main/res/drawable-xhdpi/ic_cia_install.png)bin656 -> 656 bytes
-rw-r--r--src/android/app/src/main/res/drawable-xxhdpi/ic_install.png (renamed from src/android/app/src/main/res/drawable-xxhdpi/ic_cia_install.png)bin967 -> 967 bytes
-rw-r--r--src/android/app/src/main/res/drawable-xxxhdpi/ic_install.png (renamed from src/android/app/src/main/res/drawable-xxxhdpi/ic_cia_install.png)bin1244 -> 1244 bytes
-rw-r--r--src/android/app/src/main/res/menu/menu_game_grid.xml6
-rw-r--r--src/android/app/src/main/res/values/strings.xml6
-rw-r--r--src/core/crypto/key_manager.cpp2
-rw-r--r--src/core/crypto/key_manager.h2
20 files changed, 102 insertions, 21 deletions
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.java b/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.java
index 26ff14914..7fdd692c2 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.java
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.java
@@ -6,18 +6,22 @@ import android.os.Bundle;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
+import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
+import org.yuzu.yuzu_emu.NativeLibrary;
import org.yuzu.yuzu_emu.R;
import org.yuzu.yuzu_emu.activities.EmulationActivity;
import org.yuzu.yuzu_emu.features.settings.ui.SettingsActivity;
import org.yuzu.yuzu_emu.model.GameProvider;
import org.yuzu.yuzu_emu.ui.platform.PlatformGamesFragment;
import org.yuzu.yuzu_emu.utils.AddDirectoryHelper;
+import org.yuzu.yuzu_emu.utils.DirectoryInitialization;
import org.yuzu.yuzu_emu.utils.FileBrowserHelper;
+import org.yuzu.yuzu_emu.utils.FileUtil;
import org.yuzu.yuzu_emu.utils.PicassoUtils;
import org.yuzu.yuzu_emu.utils.StartupHandler;
import org.yuzu.yuzu_emu.utils.ThemeUtil;
@@ -116,8 +120,13 @@ public final class MainActivity extends AppCompatActivity implements MainView {
switch (request) {
case MainPresenter.REQUEST_ADD_DIRECTORY:
FileBrowserHelper.openDirectoryPicker(this,
- MainPresenter.REQUEST_ADD_DIRECTORY,
- R.string.select_game_folder);
+ MainPresenter.REQUEST_ADD_DIRECTORY,
+ R.string.select_game_folder);
+ break;
+ case MainPresenter.REQUEST_INSTALL_KEYS:
+ FileBrowserHelper.openFilePicker(this,
+ MainPresenter.REQUEST_INSTALL_KEYS,
+ R.string.install_keys);
break;
}
}
@@ -132,7 +141,6 @@ public final class MainActivity extends AppCompatActivity implements MainView {
super.onActivityResult(requestCode, resultCode, result);
switch (requestCode) {
case MainPresenter.REQUEST_ADD_DIRECTORY:
- // If the user picked a file, as opposed to just backing out.
if (resultCode == MainActivity.RESULT_OK) {
int takeFlags = (Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION);
getContentResolver().takePersistableUriPermission(Uri.parse(result.getDataString()), takeFlags);
@@ -144,6 +152,22 @@ public final class MainActivity extends AppCompatActivity implements MainView {
mPresenter.onDirectorySelected(FileBrowserHelper.getSelectedDirectory(result));
}
break;
+
+ case MainPresenter.REQUEST_INSTALL_KEYS:
+ if (resultCode == MainActivity.RESULT_OK) {
+ int takeFlags = (Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION);
+ getContentResolver().takePersistableUriPermission(Uri.parse(result.getDataString()), takeFlags);
+ String dstPath = DirectoryInitialization.getUserDirectory() + "/keys/";
+ if (FileUtil.copyUriToInternalStorage(this, result.getData(), dstPath, "prod.keys")) {
+ if (NativeLibrary.ReloadKeys()) {
+ Toast.makeText(this, R.string.install_keys_success, Toast.LENGTH_SHORT).show();
+ } else {
+ Toast.makeText(this, R.string.install_keys_failure, Toast.LENGTH_SHORT).show();
+ launchFileListActivity(MainPresenter.REQUEST_INSTALL_KEYS);
+ }
+ }
+ }
+ break;
}
}
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainPresenter.java b/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainPresenter.java
index 01f577600..82667a98f 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainPresenter.java
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainPresenter.java
@@ -11,6 +11,7 @@ import org.yuzu.yuzu_emu.utils.AddDirectoryHelper;
public final class MainPresenter {
public static final int REQUEST_ADD_DIRECTORY = 1;
+ public static final int REQUEST_INSTALL_KEYS = 2;
private final MainView mView;
private String mDirToAdd;
private long mLastClickTime = 0;
@@ -46,6 +47,10 @@ public final class MainPresenter {
case R.id.button_add_directory:
launchFileListActivity(REQUEST_ADD_DIRECTORY);
return true;
+
+ case R.id.button_install_keys:
+ launchFileListActivity(REQUEST_INSTALL_KEYS);
+ return true;
}
return false;
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/FileBrowserHelper.java b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/FileBrowserHelper.java
index 6175f39c4..4dab914c7 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/FileBrowserHelper.java
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/FileBrowserHelper.java
@@ -10,6 +10,15 @@ public final class FileBrowserHelper {
activity.startActivityForResult(i, requestCode);
}
+ public static void openFilePicker(FragmentActivity activity, int requestCode, int title) {
+ Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
+ intent.addCategory(Intent.CATEGORY_OPENABLE);
+ intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION);
+ intent.putExtra(Intent.EXTRA_TITLE, title);
+ intent.setType("*/*");
+ activity.startActivityForResult(intent, requestCode);
+ }
+
public static String getSelectedDirectory(Intent result) {
return result.getDataString();
}
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/FileUtil.java b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/FileUtil.java
index 624fd4a88..8665704cc 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/FileUtil.java
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/FileUtil.java
@@ -12,8 +12,9 @@ import androidx.documentfile.provider.DocumentFile;
import org.yuzu.yuzu_emu.model.MinimalDocumentFile;
+import java.io.FileOutputStream;
+import java.io.IOException;
import java.io.InputStream;
-import java.io.OutputStream;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.List;
@@ -243,6 +244,40 @@ public class FileUtil {
return size;
}
+ public static boolean copyUriToInternalStorage(Context context, Uri sourceUri, String destinationParentPath, String destinationFilename) {
+ InputStream input = null;
+ FileOutputStream output = null;
+ try {
+ input = context.getContentResolver().openInputStream(sourceUri);
+ output = new FileOutputStream(destinationParentPath + "/" + destinationFilename);
+ byte[] buffer = new byte[1024];
+ int len;
+ while ((len = input.read(buffer)) != -1) {
+ output.write(buffer, 0, len);
+ }
+ output.flush();
+ return true;
+ } catch (Exception e) {
+ Log.error("[FileUtil]: Cannot copy file, error: " + e.getMessage());
+ } finally {
+ if (input != null) {
+ try {
+ input.close();
+ } catch (IOException e) {
+ Log.error("[FileUtil]: Cannot close input file, error: " + e.getMessage());
+ }
+ }
+ if (output != null) {
+ try {
+ output.close();
+ } catch (IOException e) {
+ Log.error("[FileUtil]: Cannot close output file, error: " + e.getMessage());
+ }
+ }
+ }
+ return false;
+ }
+
public static boolean isRootTreeUri(Uri uri) {
final List<String> paths = uri.getPathSegments();
return paths.size() == 2 && PATH_TREE.equals(paths.get(0));
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/StartupHandler.java b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/StartupHandler.java
index 6d3e58e18..749a06b32 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/StartupHandler.java
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/StartupHandler.java
@@ -2,6 +2,10 @@ package org.yuzu.yuzu_emu.utils;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
+import android.text.Html;
+import android.text.method.LinkMovementMethod;
+import android.widget.TextView;
+
import androidx.appcompat.app.AlertDialog;
import org.yuzu.yuzu_emu.R;
@@ -13,7 +17,7 @@ public final class StartupHandler {
private static SharedPreferences mPreferences = PreferenceManager.getDefaultSharedPreferences(YuzuApplication.getAppContext());
private static void handleStartupPromptDismiss(MainActivity parent) {
- parent.launchFileListActivity(MainPresenter.REQUEST_ADD_DIRECTORY);
+ parent.launchFileListActivity(MainPresenter.REQUEST_INSTALL_KEYS);
}
private static void markFirstBoot() {
@@ -26,14 +30,16 @@ public final class StartupHandler {
if (mPreferences.getBoolean("FirstApplicationLaunch", true)) {
markFirstBoot();
- // Prompt user with standard first boot disclaimer
- new AlertDialog.Builder(parent)
- .setTitle(R.string.app_name)
- .setIcon(R.mipmap.ic_launcher)
- .setMessage(parent.getResources().getString(R.string.app_disclaimer))
- .setPositiveButton(android.R.string.ok, null)
- .setOnDismissListener(dialogInterface -> handleStartupPromptDismiss(parent))
- .show();
+ AlertDialog.Builder builder = new AlertDialog.Builder(parent);
+ builder.setMessage(Html.fromHtml(parent.getResources().getString(R.string.app_disclaimer)));
+ builder.setTitle(R.string.app_name);
+ builder.setIcon(R.mipmap.ic_launcher);
+ builder.setPositiveButton(android.R.string.ok, null);
+ builder.setOnDismissListener(dialogInterface -> handleStartupPromptDismiss(parent));
+
+ AlertDialog alert = builder.create();
+ alert.show();
+ ((TextView) alert.findViewById(android.R.id.message)).setMovementMethod(LinkMovementMethod.getInstance());
}
}
}
diff --git a/src/android/app/src/main/jni/native.cpp b/src/android/app/src/main/jni/native.cpp
index 358316c48..6d1e75c40 100644
--- a/src/android/app/src/main/jni/native.cpp
+++ b/src/android/app/src/main/jni/native.cpp
@@ -271,7 +271,7 @@ void Java_org_yuzu_yuzu_1emu_NativeLibrary_SetAppDirectory(JNIEnv* env,
jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_ReloadKeys(JNIEnv* env,
[[maybe_unused]] jclass clazz) {
Core::Crypto::KeyManager::Instance().ReloadKeys();
- return static_cast<jboolean>(Core::Crypto::KeyManager::Instance().IsKeysLoaded());
+ return static_cast<jboolean>(Core::Crypto::KeyManager::Instance().AreKeysLoaded());
}
void Java_org_yuzu_yuzu_1emu_NativeLibrary_UnPauseEmulation([[maybe_unused]] JNIEnv* env,
diff --git a/src/android/app/src/main/res/drawable-hdpi/ic_cia_install.png b/src/android/app/src/main/res/drawable-hdpi/ic_install.png
index 8c00d8c34..8c00d8c34 100644
--- a/src/android/app/src/main/res/drawable-hdpi/ic_cia_install.png
+++ b/src/android/app/src/main/res/drawable-hdpi/ic_install.png
Binary files differ
diff --git a/src/android/app/src/main/res/drawable-mdpi/ic_cia_install.png b/src/android/app/src/main/res/drawable-mdpi/ic_install.png
index c6dc232b4..c6dc232b4 100644
--- a/src/android/app/src/main/res/drawable-mdpi/ic_cia_install.png
+++ b/src/android/app/src/main/res/drawable-mdpi/ic_install.png
Binary files differ
diff --git a/src/android/app/src/main/res/drawable-night-hdpi/ic_cia_install.png b/src/android/app/src/main/res/drawable-night-hdpi/ic_install.png
index cc986c8ac..cc986c8ac 100644
--- a/src/android/app/src/main/res/drawable-night-hdpi/ic_cia_install.png
+++ b/src/android/app/src/main/res/drawable-night-hdpi/ic_install.png
Binary files differ
diff --git a/src/android/app/src/main/res/drawable-night-mdpi/ic_cia_install.png b/src/android/app/src/main/res/drawable-night-mdpi/ic_install.png
index f61d84961..f61d84961 100644
--- a/src/android/app/src/main/res/drawable-night-mdpi/ic_cia_install.png
+++ b/src/android/app/src/main/res/drawable-night-mdpi/ic_install.png
Binary files differ
diff --git a/src/android/app/src/main/res/drawable-night-xhdpi/ic_cia_install.png b/src/android/app/src/main/res/drawable-night-xhdpi/ic_install.png
index 1eccbe68d..1eccbe68d 100644
--- a/src/android/app/src/main/res/drawable-night-xhdpi/ic_cia_install.png
+++ b/src/android/app/src/main/res/drawable-night-xhdpi/ic_install.png
Binary files differ
diff --git a/src/android/app/src/main/res/drawable-night-xxhdpi/ic_cia_install.png b/src/android/app/src/main/res/drawable-night-xxhdpi/ic_install.png
index fc3c434b0..fc3c434b0 100644
--- a/src/android/app/src/main/res/drawable-night-xxhdpi/ic_cia_install.png
+++ b/src/android/app/src/main/res/drawable-night-xxhdpi/ic_install.png
Binary files differ
diff --git a/src/android/app/src/main/res/drawable-night-xxxhdpi/ic_cia_install.png b/src/android/app/src/main/res/drawable-night-xxxhdpi/ic_install.png
index b4d1b92b7..b4d1b92b7 100644
--- a/src/android/app/src/main/res/drawable-night-xxxhdpi/ic_cia_install.png
+++ b/src/android/app/src/main/res/drawable-night-xxxhdpi/ic_install.png
Binary files differ
diff --git a/src/android/app/src/main/res/drawable-xhdpi/ic_cia_install.png b/src/android/app/src/main/res/drawable-xhdpi/ic_install.png
index 839869401..839869401 100644
--- a/src/android/app/src/main/res/drawable-xhdpi/ic_cia_install.png
+++ b/src/android/app/src/main/res/drawable-xhdpi/ic_install.png
Binary files differ
diff --git a/src/android/app/src/main/res/drawable-xxhdpi/ic_cia_install.png b/src/android/app/src/main/res/drawable-xxhdpi/ic_install.png
index e6812f0d4..e6812f0d4 100644
--- a/src/android/app/src/main/res/drawable-xxhdpi/ic_cia_install.png
+++ b/src/android/app/src/main/res/drawable-xxhdpi/ic_install.png
Binary files differ
diff --git a/src/android/app/src/main/res/drawable-xxxhdpi/ic_cia_install.png b/src/android/app/src/main/res/drawable-xxxhdpi/ic_install.png
index 69ae32dc3..69ae32dc3 100644
--- a/src/android/app/src/main/res/drawable-xxxhdpi/ic_cia_install.png
+++ b/src/android/app/src/main/res/drawable-xxxhdpi/ic_install.png
Binary files differ
diff --git a/src/android/app/src/main/res/menu/menu_game_grid.xml b/src/android/app/src/main/res/menu/menu_game_grid.xml
index cd515afbf..3eb8cf817 100644
--- a/src/android/app/src/main/res/menu/menu_game_grid.xml
+++ b/src/android/app/src/main/res/menu/menu_game_grid.xml
@@ -14,9 +14,9 @@
android:title="@string/select_game_folder"
app:showAsAction="ifRoom" />
<item
- android:id="@+id/button_install_cia"
- android:icon="@drawable/ic_cia_install"
- android:title="@string/install_cia_title"
+ android:id="@+id/button_install_keys"
+ android:icon="@drawable/ic_install"
+ android:title="@string/install_keys"
app:showAsAction="ifRoom" />
</menu>
</item>
diff --git a/src/android/app/src/main/res/values/strings.xml b/src/android/app/src/main/res/values/strings.xml
index 893f6aa1a..1c6858a60 100644
--- a/src/android/app/src/main/res/values/strings.xml
+++ b/src/android/app/src/main/res/values/strings.xml
@@ -3,7 +3,7 @@
<!-- General application strings -->
<string name="app_name" translatable="false">yuzu</string>
- <string name="app_disclaimer">This software will run games for the Nintendo Switch game console. No game titles are included.\n\nBefore you run, please place your rightfully owned Switch game files onto your device storage.</string>
+ <string name="app_disclaimer">This software will run games for the Nintendo Switch game console. No game titles or keys are included.&lt;br /&gt;&lt;br /&gt;Before you begin, please locate your <![CDATA[<b> prod.keys </b>]]> file on your device storage.&lt;br /&gt;&lt;br /&gt;<![CDATA[<a href="https://yuzu-emu.org/wiki/dumping-decryption-keys-from-a-switch-console/">Learn more</a>]]></string>
<string name="app_notification_channel_name" translatable="false">yuzu</string>
<string name="app_notification_channel_id" translatable="false">yuzu</string>
<string name="app_notification_channel_description">yuzu Switch emulator notifications</string>
@@ -49,7 +49,9 @@
<!-- Add Directory Screen-->
<string name="select_game_folder">Select game folder</string>
- <string name="install_cia_title">Install CIA</string>
+ <string name="install_keys">Install keys</string>
+ <string name="install_keys_success">Keys successfully installed</string>
+ <string name="install_keys_failure">Keys file (prod.keys) is invalid</string>
<!-- Preferences Screen -->
<string name="preferences_settings">Settings</string>
diff --git a/src/core/crypto/key_manager.cpp b/src/core/crypto/key_manager.cpp
index 0bd5859d0..4ff2c50e5 100644
--- a/src/core/crypto/key_manager.cpp
+++ b/src/core/crypto/key_manager.cpp
@@ -706,7 +706,7 @@ void KeyManager::LoadFromFile(const std::filesystem::path& file_path, bool is_ti
}
}
-bool KeyManager::IsKeysLoaded() const {
+bool KeyManager::AreKeysLoaded() const {
return !s128_keys.empty() && !s256_keys.empty();
}
diff --git a/src/core/crypto/key_manager.h b/src/core/crypto/key_manager.h
index fb991ae54..8c864503b 100644
--- a/src/core/crypto/key_manager.h
+++ b/src/core/crypto/key_manager.h
@@ -268,7 +268,7 @@ public:
bool AddTicketPersonalized(Ticket raw);
void ReloadKeys();
- bool IsKeysLoaded() const;
+ bool AreKeysLoaded() const;
private:
KeyManager();