summaryrefslogtreecommitdiff
path: root/src/android/app
diff options
context:
space:
mode:
Diffstat (limited to 'src/android/app')
-rw-r--r--src/android/app/src/main/AndroidManifest.xml1
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/NativeLibrary.java2
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/YuzuApplication.java3
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.java53
-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/GpuDriverHelper.java130
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/GpuDriverMetadata.java45
-rw-r--r--src/android/app/src/main/res/menu/menu_game_grid.xml5
-rw-r--r--src/android/app/src/main/res/values/strings.xml10
9 files changed, 251 insertions, 3 deletions
diff --git a/src/android/app/src/main/AndroidManifest.xml b/src/android/app/src/main/AndroidManifest.xml
index 88e1669cd..de4dbb948 100644
--- a/src/android/app/src/main/AndroidManifest.xml
+++ b/src/android/app/src/main/AndroidManifest.xml
@@ -27,6 +27,7 @@
27 android:supportsRtl="true" 27 android:supportsRtl="true"
28 android:isGame="true" 28 android:isGame="true"
29 android:banner="@mipmap/ic_launcher" 29 android:banner="@mipmap/ic_launcher"
30 android:extractNativeLibs="true"
30 android:requestLegacyExternalStorage="true"> 31 android:requestLegacyExternalStorage="true">
31 32
32 <activity 33 <activity
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/NativeLibrary.java b/src/android/app/src/main/java/org/yuzu/yuzu_emu/NativeLibrary.java
index e56196310..c09b711fd 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/NativeLibrary.java
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/NativeLibrary.java
@@ -181,7 +181,7 @@ public final class NativeLibrary {
181 181
182 public static native void SetAppDirectory(String directory); 182 public static native void SetAppDirectory(String directory);
183 183
184 public static native void SetGpuDriverParameters(String hookLibDir, String customDriverDir, String customDriverName, String fileRedirectDir); 184 public static native void InitializeGpuDriver(String hookLibDir, String customDriverDir, String customDriverName, String fileRedirectDir);
185 185
186 public static native boolean ReloadKeys(); 186 public static native boolean ReloadKeys();
187 187
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/YuzuApplication.java b/src/android/app/src/main/java/org/yuzu/yuzu_emu/YuzuApplication.java
index 9d4ed80b4..830d0b18c 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/YuzuApplication.java
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/YuzuApplication.java
@@ -13,6 +13,7 @@ import android.os.Build;
13import org.yuzu.yuzu_emu.model.GameDatabase; 13import org.yuzu.yuzu_emu.model.GameDatabase;
14import org.yuzu.yuzu_emu.utils.DocumentsTree; 14import org.yuzu.yuzu_emu.utils.DocumentsTree;
15import org.yuzu.yuzu_emu.utils.DirectoryInitialization; 15import org.yuzu.yuzu_emu.utils.DirectoryInitialization;
16import org.yuzu.yuzu_emu.utils.GpuDriverHelper;
16 17
17public class YuzuApplication extends Application { 18public class YuzuApplication extends Application {
18 public static GameDatabase databaseHelper; 19 public static GameDatabase databaseHelper;
@@ -43,7 +44,7 @@ public class YuzuApplication extends Application {
43 documentsTree = new DocumentsTree(); 44 documentsTree = new DocumentsTree();
44 45
45 DirectoryInitialization.start(getApplicationContext()); 46 DirectoryInitialization.start(getApplicationContext());
46 47 GpuDriverHelper.initializeDriverParameters(getApplicationContext());
47 NativeLibrary.LogDeviceInfo(); 48 NativeLibrary.LogDeviceInfo();
48 49
49 // TODO(bunnei): Disable notifications until we support app suspension. 50 // TODO(bunnei): Disable notifications until we support app suspension.
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 552232bd3..d5009bc60 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
@@ -9,6 +9,7 @@ import android.view.MenuItem;
9import android.widget.Toast; 9import android.widget.Toast;
10 10
11import androidx.annotation.NonNull; 11import androidx.annotation.NonNull;
12import androidx.appcompat.app.AlertDialog;
12import androidx.appcompat.app.AppCompatActivity; 13import androidx.appcompat.app.AppCompatActivity;
13import androidx.appcompat.widget.Toolbar; 14import androidx.appcompat.widget.Toolbar;
14 15
@@ -22,6 +23,7 @@ import org.yuzu.yuzu_emu.utils.AddDirectoryHelper;
22import org.yuzu.yuzu_emu.utils.DirectoryInitialization; 23import org.yuzu.yuzu_emu.utils.DirectoryInitialization;
23import org.yuzu.yuzu_emu.utils.FileBrowserHelper; 24import org.yuzu.yuzu_emu.utils.FileBrowserHelper;
24import org.yuzu.yuzu_emu.utils.FileUtil; 25import org.yuzu.yuzu_emu.utils.FileUtil;
26import org.yuzu.yuzu_emu.utils.GpuDriverHelper;
25import org.yuzu.yuzu_emu.utils.PicassoUtils; 27import org.yuzu.yuzu_emu.utils.PicassoUtils;
26import org.yuzu.yuzu_emu.utils.StartupHandler; 28import org.yuzu.yuzu_emu.utils.StartupHandler;
27import org.yuzu.yuzu_emu.utils.ThemeUtil; 29import org.yuzu.yuzu_emu.utils.ThemeUtil;
@@ -128,6 +130,41 @@ public final class MainActivity extends AppCompatActivity implements MainView {
128 MainPresenter.REQUEST_INSTALL_KEYS, 130 MainPresenter.REQUEST_INSTALL_KEYS,
129 R.string.install_keys); 131 R.string.install_keys);
130 break; 132 break;
133 case MainPresenter.REQUEST_SELECT_GPU_DRIVER:
134 AlertDialog.Builder builder = new AlertDialog.Builder(this);
135
136 // Get the driver name for the dialog message.
137 String driverName = GpuDriverHelper.getCustomDriverName();
138 if (driverName == null) {
139 driverName = getString(R.string.system_gpu_driver);
140 }
141
142 // Set the dialog message and title.
143 builder.setTitle(getString(R.string.select_gpu_driver_title));
144 builder.setMessage(driverName);
145
146 // Cancel button is a no-op.
147 builder.setNegativeButton(android.R.string.cancel, null);
148
149 // Select the default system driver.
150 builder.setPositiveButton(R.string.select_gpu_driver_default, (dialogInterface, i) ->
151 {
152 GpuDriverHelper.installDefaultDriver(this);
153 Toast.makeText(this, R.string.select_gpu_driver_use_default, Toast.LENGTH_SHORT).show();
154 });
155
156 // Use the file picker to install a custom driver.
157 builder.setNeutralButton(R.string.select_gpu_driver_install, (dialogInterface, i) -> {
158 FileBrowserHelper.openFilePicker(this,
159 MainPresenter.REQUEST_SELECT_GPU_DRIVER,
160 R.string.select_gpu_driver);
161 });
162
163 // Show the dialog.
164 AlertDialog alertDialog = builder.create();
165 alertDialog.show();
166
167 break;
131 } 168 }
132 } 169 }
133 170
@@ -163,12 +200,26 @@ public final class MainActivity extends AppCompatActivity implements MainView {
163 Toast.makeText(this, R.string.install_keys_success, Toast.LENGTH_SHORT).show(); 200 Toast.makeText(this, R.string.install_keys_success, Toast.LENGTH_SHORT).show();
164 refreshFragment(); 201 refreshFragment();
165 } else { 202 } else {
166 Toast.makeText(this, R.string.install_keys_failure, Toast.LENGTH_SHORT).show(); 203 Toast.makeText(this, R.string.install_keys_failure, Toast.LENGTH_LONG).show();
167 launchFileListActivity(MainPresenter.REQUEST_INSTALL_KEYS); 204 launchFileListActivity(MainPresenter.REQUEST_INSTALL_KEYS);
168 } 205 }
169 } 206 }
170 } 207 }
171 break; 208 break;
209
210 case MainPresenter.REQUEST_SELECT_GPU_DRIVER:
211 if (resultCode == MainActivity.RESULT_OK) {
212 int takeFlags = (Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION);
213 getContentResolver().takePersistableUriPermission(Uri.parse(result.getDataString()), takeFlags);
214 GpuDriverHelper.installCustomDriver(this, result.getData());
215 String driverName = GpuDriverHelper.getCustomDriverName();
216 if (driverName != null) {
217 Toast.makeText(this, getString(R.string.select_gpu_driver_install_success) + " " + driverName, Toast.LENGTH_SHORT).show();
218 } else {
219 Toast.makeText(this, R.string.select_gpu_driver_error, Toast.LENGTH_LONG).show();
220 }
221 }
222 break;
172 } 223 }
173 } 224 }
174 225
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 82667a98f..d2ef753bc 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
@@ -12,6 +12,7 @@ import org.yuzu.yuzu_emu.utils.AddDirectoryHelper;
12public final class MainPresenter { 12public final class MainPresenter {
13 public static final int REQUEST_ADD_DIRECTORY = 1; 13 public static final int REQUEST_ADD_DIRECTORY = 1;
14 public static final int REQUEST_INSTALL_KEYS = 2; 14 public static final int REQUEST_INSTALL_KEYS = 2;
15 public static final int REQUEST_SELECT_GPU_DRIVER = 3;
15 private final MainView mView; 16 private final MainView mView;
16 private String mDirToAdd; 17 private String mDirToAdd;
17 private long mLastClickTime = 0; 18 private long mLastClickTime = 0;
@@ -51,6 +52,10 @@ public final class MainPresenter {
51 case R.id.button_install_keys: 52 case R.id.button_install_keys:
52 launchFileListActivity(REQUEST_INSTALL_KEYS); 53 launchFileListActivity(REQUEST_INSTALL_KEYS);
53 return true; 54 return true;
55
56 case R.id.button_select_gpu_driver:
57 launchFileListActivity(REQUEST_SELECT_GPU_DRIVER);
58 return true;
54 } 59 }
55 60
56 return false; 61 return false;
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/GpuDriverHelper.java b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/GpuDriverHelper.java
new file mode 100644
index 000000000..822a3f1f9
--- /dev/null
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/GpuDriverHelper.java
@@ -0,0 +1,130 @@
1package org.yuzu.yuzu_emu.utils;
2
3import android.content.Context;
4import android.net.Uri;
5
6import org.yuzu.yuzu_emu.NativeLibrary;
7
8import java.io.File;
9import java.io.FileInputStream;
10import java.io.FileOutputStream;
11import java.io.IOException;
12import java.util.zip.ZipEntry;
13import java.util.zip.ZipInputStream;
14
15public class GpuDriverHelper {
16 private static final String META_JSON_FILENAME = "meta.json";
17 private static final String DRIVER_INTERNAL_FILENAME = "gpu_driver.zip";
18 private static String fileRedirectionPath;
19 private static String driverInstallationPath;
20 private static String hookLibPath;
21
22 private static void unzip(String zipFilePath, String destDir) throws IOException {
23 File dir = new File(destDir);
24
25 // Create output directory if it doesn't exist
26 if (!dir.exists()) dir.mkdirs();
27
28 // Unpack the files.
29 ZipInputStream zis = new ZipInputStream(new FileInputStream(zipFilePath));
30 byte[] buffer = new byte[1024];
31 ZipEntry ze = zis.getNextEntry();
32 while (ze != null) {
33 String fileName = ze.getName();
34 File newFile = new File(destDir + fileName);
35 newFile.getParentFile().mkdirs();
36 FileOutputStream fos = new FileOutputStream(newFile);
37 int len;
38 while ((len = zis.read(buffer)) > 0) {
39 fos.write(buffer, 0, len);
40 }
41 fos.close();
42 zis.closeEntry();
43 ze = zis.getNextEntry();
44 }
45 zis.closeEntry();
46 }
47
48 public static void initializeDriverParameters(Context context) {
49 try {
50 // Initialize the file redirection directory.
51 fileRedirectionPath = context.getExternalFilesDir(null).getCanonicalPath() + "/gpu/vk_file_redirect/";
52
53 // Initialize the driver installation directory.
54 driverInstallationPath = context.getFilesDir().getCanonicalPath() + "/gpu_driver/";
55 } catch (IOException e) {
56 throw new RuntimeException(e);
57 }
58
59 // Initialize directories.
60 initializeDirectories();
61
62 // Initialize hook libraries directory.
63 hookLibPath = context.getApplicationInfo().nativeLibraryDir + "/";
64
65 // Initialize GPU driver.
66 NativeLibrary.InitializeGpuDriver(hookLibPath, driverInstallationPath, getCustomDriverLibraryName(), fileRedirectionPath);
67 }
68
69 public static void installDefaultDriver(Context context) {
70 // Removing the installed driver will result in the backend using the default system driver.
71 File driverInstallationDir = new File(driverInstallationPath);
72 deleteRecursive(driverInstallationDir);
73 initializeDriverParameters(context);
74 }
75
76 public static void installCustomDriver(Context context, Uri driverPathUri) {
77 // Revert to system default in the event the specified driver is bad.
78 installDefaultDriver(context);
79
80 // Ensure we have directories.
81 initializeDirectories();
82
83 // Copy the zip file URI into our private storage.
84 FileUtil.copyUriToInternalStorage(context, driverPathUri, driverInstallationPath, DRIVER_INTERNAL_FILENAME);
85
86 // Unzip the driver.
87 try {
88 unzip(driverInstallationPath + DRIVER_INTERNAL_FILENAME, driverInstallationPath);
89 } catch (IOException e) {
90 throw new RuntimeException(e);
91 }
92
93 // Initialize the driver parameters.
94 initializeDriverParameters(context);
95 }
96
97 public static String getCustomDriverName() {
98 // Parse the custom driver metadata to retrieve the name.
99 GpuDriverMetadata metadata = new GpuDriverMetadata(driverInstallationPath + META_JSON_FILENAME);
100 return metadata.name;
101 }
102
103 private static String getCustomDriverLibraryName() {
104 // Parse the custom driver metadata to retrieve the library name.
105 GpuDriverMetadata metadata = new GpuDriverMetadata(driverInstallationPath + META_JSON_FILENAME);
106 return metadata.libraryName;
107 }
108
109 private static void initializeDirectories() {
110 // Ensure the file redirection directory exists.
111 File fileRedirectionDir = new File(fileRedirectionPath);
112 if (!fileRedirectionDir.exists()) {
113 fileRedirectionDir.mkdirs();
114 }
115 // Ensure the driver installation directory exists.
116 File driverInstallationDir = new File(driverInstallationPath);
117 if (!driverInstallationDir.exists()) {
118 driverInstallationDir.mkdirs();
119 }
120 }
121
122 private static void deleteRecursive(File fileOrDirectory) {
123 if (fileOrDirectory.isDirectory()) {
124 for (File child : fileOrDirectory.listFiles()) {
125 deleteRecursive(child);
126 }
127 }
128 fileOrDirectory.delete();
129 }
130}
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/GpuDriverMetadata.java b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/GpuDriverMetadata.java
new file mode 100644
index 000000000..d2bb2dd23
--- /dev/null
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/GpuDriverMetadata.java
@@ -0,0 +1,45 @@
1package org.yuzu.yuzu_emu.utils;
2
3import org.json.JSONException;
4import org.json.JSONObject;
5
6import java.io.IOException;
7import java.nio.charset.StandardCharsets;
8import java.nio.file.Files;
9import java.nio.file.Path;
10import java.nio.file.Paths;
11
12public class GpuDriverMetadata {
13
14 public String name;
15 public String description;
16 public String author;
17 public String vendor;
18 public String driverVersion;
19 public int minApi;
20 public String libraryName;
21
22 public GpuDriverMetadata(String metadataFilePath) {
23 try {
24 JSONObject json = new JSONObject(getStringFromFile(metadataFilePath));
25 name = json.getString("name");
26 description = json.getString("description");
27 author = json.getString("author");
28 vendor = json.getString("vendor");
29 driverVersion = json.getString("driverVersion");
30 minApi = json.getInt("minApi");
31 libraryName = json.getString("libraryName");
32 } catch (JSONException e) {
33 // JSON is malformed, ignore and treat as unsupported metadata.
34 } catch (IOException e) {
35 // File is inaccessible, ignore and treat as unsupported metadata.
36 }
37 }
38
39 private static String getStringFromFile(String filePath) throws IOException {
40 Path path = Paths.get(filePath);
41 byte[] bytes = Files.readAllBytes(path);
42 return new String(bytes, StandardCharsets.UTF_8);
43 }
44
45}
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 3eb8cf817..6211f5494 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
@@ -18,6 +18,11 @@
18 android:icon="@drawable/ic_install" 18 android:icon="@drawable/ic_install"
19 android:title="@string/install_keys" 19 android:title="@string/install_keys"
20 app:showAsAction="ifRoom" /> 20 app:showAsAction="ifRoom" />
21 <item
22 android:id="@+id/button_select_gpu_driver"
23 android:icon="@drawable/ic_settings_core"
24 android:title="@string/select_gpu_driver"
25 app:showAsAction="ifRoom" />
21 </menu> 26 </menu>
22 </item> 27 </item>
23 <item 28 <item
diff --git a/src/android/app/src/main/res/values/strings.xml b/src/android/app/src/main/res/values/strings.xml
index e450ee869..27749b287 100644
--- a/src/android/app/src/main/res/values/strings.xml
+++ b/src/android/app/src/main/res/values/strings.xml
@@ -53,6 +53,16 @@
53 <string name="install_keys_success">Keys successfully installed</string> 53 <string name="install_keys_success">Keys successfully installed</string>
54 <string name="install_keys_failure">Keys file (prod.keys) is invalid</string> 54 <string name="install_keys_failure">Keys file (prod.keys) is invalid</string>
55 55
56 <!-- GPU driver installation -->
57 <string name="select_gpu_driver">Select GPU driver</string>
58 <string name="select_gpu_driver_title">Would you like to replace your current GPU driver?</string>
59 <string name="select_gpu_driver_install">Install</string>
60 <string name="select_gpu_driver_default">Default</string>
61 <string name="select_gpu_driver_install_success">Installed</string>
62 <string name="select_gpu_driver_use_default">Using default GPU driver</string>
63 <string name="select_gpu_driver_error">Invalid driver selected, using system default!</string>
64 <string name="system_gpu_driver">System GPU driver</string>
65
56 <!-- Preferences Screen --> 66 <!-- Preferences Screen -->
57 <string name="preferences_settings">Settings</string> 67 <string name="preferences_settings">Settings</string>
58 <string name="preferences_general">General</string> 68 <string name="preferences_general">General</string>