diff --git a/android/.gitignore b/android/.gitignore
deleted file mode 100644
index 603b14077..000000000
--- a/android/.gitignore
+++ /dev/null
@@ -1,14 +0,0 @@
-*.iml
-.gradle
-/local.properties
-/.idea/caches
-/.idea/libraries
-/.idea/modules.xml
-/.idea/workspace.xml
-/.idea/navEditor.xml
-/.idea/assetWizardSettings.xml
-.DS_Store
-/build
-/captures
-.externalNativeBuild
-.cxx
diff --git a/android/.idea/.name b/android/.idea/.name
deleted file mode 100644
index eea1d2e85..000000000
--- a/android/.idea/.name
+++ /dev/null
@@ -1 +0,0 @@
-DuckStation
\ No newline at end of file
diff --git a/android/.idea/codeStyles/Project.xml b/android/.idea/codeStyles/Project.xml
deleted file mode 100644
index 681f41ae2..000000000
--- a/android/.idea/codeStyles/Project.xml
+++ /dev/null
@@ -1,116 +0,0 @@
-<component name="ProjectCodeStyleConfiguration">
-  <code_scheme name="Project" version="173">
-    <codeStyleSettings language="XML">
-      <indentOptions>
-        <option name="CONTINUATION_INDENT_SIZE" value="4" />
-      </indentOptions>
-      <arrangement>
-        <rules>
-          <section>
-            <rule>
-              <match>
-                <AND>
-                  <NAME>xmlns:android</NAME>
-                  <XML_ATTRIBUTE />
-                  <XML_NAMESPACE>^$</XML_NAMESPACE>
-                </AND>
-              </match>
-            </rule>
-          </section>
-          <section>
-            <rule>
-              <match>
-                <AND>
-                  <NAME>xmlns:.*</NAME>
-                  <XML_ATTRIBUTE />
-                  <XML_NAMESPACE>^$</XML_NAMESPACE>
-                </AND>
-              </match>
-              <order>BY_NAME</order>
-            </rule>
-          </section>
-          <section>
-            <rule>
-              <match>
-                <AND>
-                  <NAME>.*:id</NAME>
-                  <XML_ATTRIBUTE />
-                  <XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
-                </AND>
-              </match>
-            </rule>
-          </section>
-          <section>
-            <rule>
-              <match>
-                <AND>
-                  <NAME>.*:name</NAME>
-                  <XML_ATTRIBUTE />
-                  <XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
-                </AND>
-              </match>
-            </rule>
-          </section>
-          <section>
-            <rule>
-              <match>
-                <AND>
-                  <NAME>name</NAME>
-                  <XML_ATTRIBUTE />
-                  <XML_NAMESPACE>^$</XML_NAMESPACE>
-                </AND>
-              </match>
-            </rule>
-          </section>
-          <section>
-            <rule>
-              <match>
-                <AND>
-                  <NAME>style</NAME>
-                  <XML_ATTRIBUTE />
-                  <XML_NAMESPACE>^$</XML_NAMESPACE>
-                </AND>
-              </match>
-            </rule>
-          </section>
-          <section>
-            <rule>
-              <match>
-                <AND>
-                  <NAME>.*</NAME>
-                  <XML_ATTRIBUTE />
-                  <XML_NAMESPACE>^$</XML_NAMESPACE>
-                </AND>
-              </match>
-              <order>BY_NAME</order>
-            </rule>
-          </section>
-          <section>
-            <rule>
-              <match>
-                <AND>
-                  <NAME>.*</NAME>
-                  <XML_ATTRIBUTE />
-                  <XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
-                </AND>
-              </match>
-              <order>ANDROID_ATTRIBUTE_ORDER</order>
-            </rule>
-          </section>
-          <section>
-            <rule>
-              <match>
-                <AND>
-                  <NAME>.*</NAME>
-                  <XML_ATTRIBUTE />
-                  <XML_NAMESPACE>.*</XML_NAMESPACE>
-                </AND>
-              </match>
-              <order>BY_NAME</order>
-            </rule>
-          </section>
-        </rules>
-      </arrangement>
-    </codeStyleSettings>
-  </code_scheme>
-</component>
\ No newline at end of file
diff --git a/android/.idea/codeStyles/codeStyleConfig.xml b/android/.idea/codeStyles/codeStyleConfig.xml
deleted file mode 100644
index a55e7a179..000000000
--- a/android/.idea/codeStyles/codeStyleConfig.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<component name="ProjectCodeStyleConfiguration">
-  <state>
-    <option name="PREFERRED_PROJECT_CODE_STYLE" value="Default" />
-  </state>
-</component>
\ No newline at end of file
diff --git a/android/.idea/compiler.xml b/android/.idea/compiler.xml
deleted file mode 100644
index fb7f4a8a4..000000000
--- a/android/.idea/compiler.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project version="4">
-  <component name="CompilerConfiguration">
-    <bytecodeTargetLevel target="11" />
-  </component>
-</project>
\ No newline at end of file
diff --git a/android/.idea/gradle.xml b/android/.idea/gradle.xml
deleted file mode 100644
index 9bba60dad..000000000
--- a/android/.idea/gradle.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project version="4">
-  <component name="GradleMigrationSettings" migrationVersion="1" />
-  <component name="GradleSettings">
-    <option name="linkedExternalProjectsSettings">
-      <GradleProjectSettings>
-        <option name="testRunner" value="PLATFORM" />
-        <option name="distributionType" value="DEFAULT_WRAPPED" />
-        <option name="externalProjectPath" value="$PROJECT_DIR$" />
-        <option name="modules">
-          <set>
-            <option value="$PROJECT_DIR$" />
-            <option value="$PROJECT_DIR$/app" />
-          </set>
-        </option>
-        <option name="resolveModulePerSourceSet" value="false" />
-        <option name="useQualifiedModuleNames" value="true" />
-      </GradleProjectSettings>
-    </option>
-  </component>
-</project>
\ No newline at end of file
diff --git a/android/.idea/jarRepositories.xml b/android/.idea/jarRepositories.xml
deleted file mode 100644
index e34606ccd..000000000
--- a/android/.idea/jarRepositories.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project version="4">
-  <component name="RemoteRepositoriesConfiguration">
-    <remote-repository>
-      <option name="id" value="central" />
-      <option name="name" value="Maven Central repository" />
-      <option name="url" value="https://repo1.maven.org/maven2" />
-    </remote-repository>
-    <remote-repository>
-      <option name="id" value="jboss.community" />
-      <option name="name" value="JBoss Community repository" />
-      <option name="url" value="https://repository.jboss.org/nexus/content/repositories/public/" />
-    </remote-repository>
-    <remote-repository>
-      <option name="id" value="BintrayJCenter" />
-      <option name="name" value="BintrayJCenter" />
-      <option name="url" value="https://jcenter.bintray.com/" />
-    </remote-repository>
-    <remote-repository>
-      <option name="id" value="Google" />
-      <option name="name" value="Google" />
-      <option name="url" value="https://dl.google.com/dl/android/maven2/" />
-    </remote-repository>
-    <remote-repository>
-      <option name="id" value="MavenRepo" />
-      <option name="name" value="MavenRepo" />
-      <option name="url" value="https://repo.maven.apache.org/maven2/" />
-    </remote-repository>
-  </component>
-</project>
\ No newline at end of file
diff --git a/android/.idea/misc.xml b/android/.idea/misc.xml
deleted file mode 100644
index 860da66a5..000000000
--- a/android/.idea/misc.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project version="4">
-  <component name="ProjectRootManager" version="2" languageLevel="JDK_11" default="true" project-jdk-name="1.8" project-jdk-type="JavaSDK">
-    <output url="file://$PROJECT_DIR$/build/classes" />
-  </component>
-  <component name="ProjectType">
-    <option name="id" value="Android" />
-  </component>
-</project>
\ No newline at end of file
diff --git a/android/.idea/runConfigurations.xml b/android/.idea/runConfigurations.xml
deleted file mode 100644
index e497da999..000000000
--- a/android/.idea/runConfigurations.xml
+++ /dev/null
@@ -1,13 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project version="4">
-  <component name="RunConfigurationProducerService">
-    <option name="ignoredProducers">
-      <set>
-        <option value="com.android.tools.idea.compose.preview.runconfiguration.ComposePreviewRunConfigurationProducer" />
-        <option value="org.jetbrains.plugins.gradle.execution.test.runner.AllInPackageGradleConfigurationProducer" />
-        <option value="org.jetbrains.plugins.gradle.execution.test.runner.TestClassGradleConfigurationProducer" />
-        <option value="org.jetbrains.plugins.gradle.execution.test.runner.TestMethodGradleConfigurationProducer" />
-      </set>
-    </option>
-  </component>
-</project>
\ No newline at end of file
diff --git a/android/.idea/vcs.xml b/android/.idea/vcs.xml
deleted file mode 100644
index 6c0b86358..000000000
--- a/android/.idea/vcs.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project version="4">
-  <component name="VcsDirectoryMappings">
-    <mapping directory="$PROJECT_DIR$/.." vcs="Git" />
-  </component>
-</project>
\ No newline at end of file
diff --git a/android/app/.gitignore b/android/app/.gitignore
deleted file mode 100644
index 796b96d1c..000000000
--- a/android/app/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-/build
diff --git a/android/app/build.gradle b/android/app/build.gradle
deleted file mode 100644
index 38ec9c8df..000000000
--- a/android/app/build.gradle
+++ /dev/null
@@ -1,90 +0,0 @@
-apply plugin: 'com.android.application'
-
-android {
-    compileSdkVersion 29
-    buildToolsVersion "30.0.2"
-    defaultConfig {
-        applicationId "com.github.stenzek.duckstation"
-        minSdkVersion 23
-        targetSdkVersion 29
-        versionCode(getBuildVersionCode())
-        versionName "${getVersion()}"
-    }
-    buildTypes {
-        release {
-            minifyEnabled false
-            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
-
-            ndk {
-                debugSymbolLevel "FULL"
-            }
-        }
-    }
-
-    externalNativeBuild {
-        cmake {
-            path "../../CMakeLists.txt"
-            version "3.10.2"
-        }
-    }
-    compileOptions {
-        sourceCompatibility JavaVersion.VERSION_1_8
-        targetCompatibility JavaVersion.VERSION_1_8
-    }
-    defaultConfig {
-        externalNativeBuild {
-            cmake {
-                arguments "-DCMAKE_BUILD_TYPE=Release"
-                abiFilters "arm64-v8a", "armeabi-v7a", "x86_64"
-            }
-        }
-    }
-    sourceSets {
-        main.assets.srcDirs += "../../data"
-    }
-
-    // Blocked on R21 until CMake is updated to 3.19 or later.
-    ndkVersion '21.4.7075529'
-}
-
-dependencies {
-    implementation fileTree(dir: 'libs', include: ['*.jar'])
-    implementation 'androidx.appcompat:appcompat:1.3.0'
-    implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
-    implementation 'com.google.android.material:material:1.3.0'
-    implementation 'androidx.preference:preference:1.1.1'
-    implementation 'androidx.legacy:legacy-support-v4:1.0.0'
-    implementation "androidx.viewpager2:viewpager2:1.0.0"
-    testImplementation 'junit:junit:4.13.2'
-    androidTestImplementation 'androidx.test.ext:junit:1.1.2'
-    androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
-}
-
-// Adapted from Dolphin.
-
-def getVersion() {
-    def versionNumber = '0.0-unknown'
-
-    try {
-        versionNumber = 'git describe --tags --exclude latest --exclude preview'.execute([], project.rootDir).text
-                .trim()
-                .replaceAll(/(-0)?-[^-]+$/, "")
-    } catch (Exception e) {
-        logger.error('Cannot find git, defaulting to dummy version number')
-    }
-
-    return versionNumber
-}
-
-
-def getBuildVersionCode() {
-    try {
-        def versionNumber = 'git rev-list --first-parent --count HEAD'.execute([], project.rootDir).text
-                .trim()
-        return Integer.valueOf(versionNumber);
-    } catch (Exception e) {
-        logger.error('Cannot find git, defaulting to dummy version number')
-    }
-
-    return 1;
-}
diff --git a/android/app/proguard-rules.pro b/android/app/proguard-rules.pro
deleted file mode 100644
index f1b424510..000000000
--- a/android/app/proguard-rules.pro
+++ /dev/null
@@ -1,21 +0,0 @@
-# Add project specific ProGuard rules here.
-# You can control the set of applied configuration files using the
-# proguardFiles setting in build.gradle.
-#
-# For more details, see
-#   http://developer.android.com/guide/developing/tools/proguard.html
-
-# If your project uses WebView with JS, uncomment the following
-# and specify the fully qualified class name to the JavaScript interface
-# class:
-#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
-#   public *;
-#}
-
-# Uncomment this to preserve the line number information for
-# debugging stack traces.
-#-keepattributes SourceFile,LineNumberTable
-
-# If you keep the line number information, uncomment this to
-# hide the original source file name.
-#-renamesourcefileattribute SourceFile
diff --git a/android/app/src/androidTest/java/com/github/stenzek/duckstation/ExampleInstrumentedTest.java b/android/app/src/androidTest/java/com/github/stenzek/duckstation/ExampleInstrumentedTest.java
deleted file mode 100644
index 71cc603ed..000000000
--- a/android/app/src/androidTest/java/com/github/stenzek/duckstation/ExampleInstrumentedTest.java
+++ /dev/null
@@ -1,27 +0,0 @@
-package com.github.stenzek.duckstation;
-
-import android.content.Context;
-
-import androidx.test.platform.app.InstrumentationRegistry;
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import static org.junit.Assert.*;
-
-/**
- * Instrumented test, which will execute on an Android device.
- *
- * @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
- */
-@RunWith(AndroidJUnit4.class)
-public class ExampleInstrumentedTest {
-    @Test
-    public void useAppContext() {
-        // Context of the app under test.
-        Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
-
-        assertEquals("com.github.stenzek.duckstation", appContext.getPackageName());
-    }
-}
diff --git a/android/app/src/cpp/CMakeLists.txt b/android/app/src/cpp/CMakeLists.txt
deleted file mode 100644
index 2e3fb11ed..000000000
--- a/android/app/src/cpp/CMakeLists.txt
+++ /dev/null
@@ -1,25 +0,0 @@
-set(SRCS
-  android_controller_interface.cpp
-  android_controller_interface.h
-  android_host_interface.cpp
-  android_host_interface.h
-  android_http_downloader.cpp
-  android_http_downloader.h
-  android_progress_callback.cpp
-  android_progress_callback.h
-  android_settings_interface.cpp
-  android_settings_interface.h
-)
-
-add_library(duckstation-native SHARED ${SRCS})
-target_link_libraries(duckstation-native PRIVATE android frontend-common core common glad imgui)
-
-find_package(OpenSLES)
-if(OPENSLES_FOUND)
-  message("Enabling OpenSL ES audio stream")
-  target_sources(duckstation-native PRIVATE
-    opensles_audio_stream.cpp
-    opensles_audio_stream.h)
-  target_link_libraries(duckstation-native PRIVATE OpenSLES::OpenSLES)
-  target_compile_definitions(duckstation-native PRIVATE "-DUSE_OPENSLES=1")
-endif()
diff --git a/android/app/src/cpp/android_controller_interface.cpp b/android/app/src/cpp/android_controller_interface.cpp
deleted file mode 100644
index 7fea10ecd..000000000
--- a/android/app/src/cpp/android_controller_interface.cpp
+++ /dev/null
@@ -1,249 +0,0 @@
-#include "android_controller_interface.h"
-#include "android_host_interface.h"
-#include "common/assert.h"
-#include "common/file_system.h"
-#include "common/log.h"
-#include "core/controller.h"
-#include "core/host_interface.h"
-#include "core/system.h"
-#include <cmath>
-Log_SetChannel(AndroidControllerInterface);
-
-AndroidControllerInterface::AndroidControllerInterface() = default;
-
-AndroidControllerInterface::~AndroidControllerInterface() = default;
-
-ControllerInterface::Backend AndroidControllerInterface::GetBackend() const
-{
-  return ControllerInterface::Backend::Android;
-}
-
-bool AndroidControllerInterface::Initialize(CommonHostInterface* host_interface)
-{
-  if (!ControllerInterface::Initialize(host_interface))
-    return false;
-
-  return true;
-}
-
-void AndroidControllerInterface::Shutdown()
-{
-  ControllerInterface::Shutdown();
-}
-
-void AndroidControllerInterface::PollEvents() {}
-
-void AndroidControllerInterface::ClearBindings()
-{
-  std::unique_lock<std::mutex> lock(m_controllers_mutex);
-  for (ControllerData& cd : m_controllers)
-  {
-    cd.axis_mapping.clear();
-    cd.button_mapping.clear();
-    cd.axis_button_mapping.clear();
-    cd.button_axis_mapping.clear();
-  }
-}
-
-std::optional<int> AndroidControllerInterface::GetControllerIndex(const std::string_view& device)
-{
-  std::unique_lock<std::mutex> lock(m_controllers_mutex);
-  for (u32 i = 0; i < static_cast<u32>(m_device_names.size()); i++)
-  {
-    if (device == m_device_names[i])
-      return static_cast<int>(i);
-  }
-
-  return std::nullopt;
-}
-
-bool AndroidControllerInterface::BindControllerAxis(int controller_index, int axis_number, AxisSide axis_side,
-                                                    AxisCallback callback)
-{
-  std::unique_lock<std::mutex> lock(m_controllers_mutex);
-  if (static_cast<u32>(controller_index) >= m_controllers.size())
-    return false;
-
-  m_controllers[controller_index].axis_mapping[axis_number][axis_side] = std::move(callback);
-  Log_DevPrintf("Bound controller %d axis %d side %u", controller_index, axis_number, static_cast<unsigned>(axis_side));
-  return true;
-}
-
-bool AndroidControllerInterface::BindControllerButton(int controller_index, int button_number, ButtonCallback callback)
-{
-  std::unique_lock<std::mutex> lock(m_controllers_mutex);
-  if (static_cast<u32>(controller_index) >= m_controllers.size())
-    return false;
-
-  m_controllers[controller_index].button_mapping[button_number] = std::move(callback);
-  Log_DevPrintf("Bound controller %d button %d", controller_index, button_number);
-  return true;
-}
-
-bool AndroidControllerInterface::BindControllerAxisToButton(int controller_index, int axis_number, bool direction,
-                                                            ButtonCallback callback)
-{
-  std::unique_lock<std::mutex> lock(m_controllers_mutex);
-  if (static_cast<u32>(controller_index) >= m_controllers.size())
-    return false;
-
-  m_controllers[controller_index].axis_button_mapping[axis_number][BoolToUInt8(direction)] = std::move(callback);
-  Log_DevPrintf("Bound controller %d axis %d to button", controller_index, axis_number);
-  return true;
-}
-
-bool AndroidControllerInterface::BindControllerHatToButton(int controller_index, int hat_number,
-                                                           std::string_view hat_position, ButtonCallback callback)
-{
-  return false;
-}
-
-bool AndroidControllerInterface::BindControllerButtonToAxis(int controller_index, int button_number,
-                                                            AxisCallback callback)
-{
-  std::unique_lock<std::mutex> lock(m_controllers_mutex);
-  if (static_cast<u32>(controller_index) >= m_controllers.size())
-    return false;
-
-  m_controllers[controller_index].button_axis_mapping[button_number] = std::move(callback);
-  Log_DevPrintf("Bound controller %d button %d to axis", controller_index, button_number);
-  return true;
-}
-
-void AndroidControllerInterface::SetDeviceNames(std::vector<std::string> device_names)
-{
-  std::unique_lock<std::mutex> lock(m_controllers_mutex);
-  m_device_names = std::move(device_names);
-  m_controllers.resize(m_device_names.size());
-
-  for (u32 i = 0; i < static_cast<u32>(m_device_names.size()); i++)
-    Log_DevPrintf("Controller %u: %s", i, m_device_names[i].c_str());
-}
-
-void AndroidControllerInterface::SetDeviceRumble(u32 index, bool has_vibrator)
-{
-  std::unique_lock<std::mutex> lock(m_controllers_mutex);
-  if (index >= m_controllers.size())
-    return;
-
-  m_controllers[index].has_rumble = has_vibrator;
-}
-
-void AndroidControllerInterface::HandleAxisEvent(u32 index, u32 axis, float value)
-{
-  std::unique_lock<std::mutex> lock(m_controllers_mutex);
-  if (index >= m_controllers.size())
-    return;
-
-  Log_DevPrintf("controller %u axis %u %f", index, axis, value);
-  if (DoEventHook(Hook::Type::Axis, index, axis, value))
-    return;
-
-  const ControllerData& cd = m_controllers[index];
-  const auto am_iter = cd.axis_mapping.find(axis);
-  if (am_iter != cd.axis_mapping.end())
-  {
-    const AxisCallback& cb = am_iter->second[AxisSide::Full];
-    if (cb)
-    {
-      cb(value);
-      return;
-    }
-  }
-
-  // set the other direction to false so large movements don't leave the opposite on
-  const bool outside_deadzone = (std::abs(value) >= cd.deadzone);
-  const bool positive = (value >= 0.0f);
-  const auto bm_iter = cd.axis_button_mapping.find(axis);
-  if (bm_iter != cd.axis_button_mapping.end())
-  {
-    const ButtonCallback& other_button_cb = bm_iter->second[BoolToUInt8(!positive)];
-    const ButtonCallback& button_cb = bm_iter->second[BoolToUInt8(positive)];
-    if (button_cb)
-    {
-      button_cb(outside_deadzone);
-      if (other_button_cb)
-        other_button_cb(false);
-      return;
-    }
-    else if (other_button_cb)
-    {
-      other_button_cb(false);
-      return;
-    }
-  }
-}
-
-void AndroidControllerInterface::HandleButtonEvent(u32 index, u32 button, bool pressed)
-{
-  Log_DevPrintf("controller %u button %u %s", index, button, pressed ? "pressed" : "released");
-
-  std::unique_lock<std::mutex> lock(m_controllers_mutex);
-  if (index >= m_controllers.size())
-    return;
-
-  if (DoEventHook(Hook::Type::Button, index, button, pressed ? 1.0f : 0.0f))
-    return;
-
-  const ControllerData& cd = m_controllers[index];
-  const auto button_iter = cd.button_mapping.find(button);
-  if (button_iter != cd.button_mapping.end() && button_iter->second)
-  {
-    button_iter->second(pressed);
-    return;
-  }
-
-  const auto axis_iter = cd.button_axis_mapping.find(button);
-  if (axis_iter != cd.button_axis_mapping.end() && axis_iter->second)
-  {
-    axis_iter->second(pressed ? 1.0f : -1.0f);
-    return;
-  }
-
-  Log_DevPrintf("controller %u button %u has no binding", index, button);
-}
-
-bool AndroidControllerInterface::HasButtonBinding(u32 index, u32 button)
-{
-  std::unique_lock<std::mutex> lock(m_controllers_mutex);
-  if (index >= m_controllers.size())
-    return false;
-
-  const ControllerData& cd = m_controllers[index];
-  return (cd.button_mapping.find(button) != cd.button_mapping.end() ||
-          cd.button_axis_mapping.find(button) != cd.button_axis_mapping.end());
-}
-
-u32 AndroidControllerInterface::GetControllerRumbleMotorCount(int controller_index)
-{
-  std::unique_lock<std::mutex> lock(m_controllers_mutex);
-  if (static_cast<u32>(controller_index) >= m_controllers.size())
-    return false;
-
-  return m_controllers[static_cast<u32>(controller_index)].has_rumble ? NUM_RUMBLE_MOTORS : 0;
-}
-
-void AndroidControllerInterface::SetControllerRumbleStrength(int controller_index, const float* strengths,
-                                                             u32 num_motors)
-{
-  std::unique_lock<std::mutex> lock(m_controllers_mutex);
-  if (static_cast<u32>(controller_index) >= m_controllers.size())
-    return;
-
-  const float small_motor = strengths[0];
-  const float large_motor = strengths[1];
-  static_cast<AndroidHostInterface*>(m_host_interface)
-    ->SetControllerVibration(static_cast<u32>(controller_index), small_motor, large_motor);
-}
-
-bool AndroidControllerInterface::SetControllerDeadzone(int controller_index, float size /* = 0.25f */)
-{
-  std::unique_lock<std::mutex> lock(m_controllers_mutex);
-  if (static_cast<u32>(controller_index) >= m_controllers.size())
-    return false;
-
-  m_controllers[static_cast<u32>(controller_index)].deadzone = std::clamp(std::abs(size), 0.01f, 0.99f);
-  Log_InfoPrintf("Controller %d deadzone size set to %f", controller_index,
-                 m_controllers[static_cast<u32>(controller_index)].deadzone);
-  return true;
-}
diff --git a/android/app/src/cpp/android_controller_interface.h b/android/app/src/cpp/android_controller_interface.h
deleted file mode 100644
index a22b81f50..000000000
--- a/android/app/src/cpp/android_controller_interface.h
+++ /dev/null
@@ -1,73 +0,0 @@
-#pragma once
-#include "core/types.h"
-#include "frontend-common/controller_interface.h"
-#include <array>
-#include <functional>
-#include <map>
-#include <mutex>
-#include <vector>
-
-class AndroidControllerInterface final : public ControllerInterface
-{
-public:
-  AndroidControllerInterface();
-  ~AndroidControllerInterface() override;
-
-  ALWAYS_INLINE u32 GetControllerCount() const { return static_cast<u32>(m_controllers.size()); }
-
-  Backend GetBackend() const override;
-  bool Initialize(CommonHostInterface* host_interface) override;
-  void Shutdown() override;
-
-  // Removes all bindings. Call before setting new bindings.
-  void ClearBindings() override;
-
-  // Binding to events. If a binding for this axis/button already exists, returns false.
-  std::optional<int> GetControllerIndex(const std::string_view& device) override;
-  bool BindControllerAxis(int controller_index, int axis_number, AxisSide axis_side, AxisCallback callback) override;
-  bool BindControllerButton(int controller_index, int button_number, ButtonCallback callback) override;
-  bool BindControllerAxisToButton(int controller_index, int axis_number, bool direction,
-                                  ButtonCallback callback) override;
-  bool BindControllerHatToButton(int controller_index, int hat_number, std::string_view hat_position,
-                                 ButtonCallback callback) override;
-  bool BindControllerButtonToAxis(int controller_index, int button_number, AxisCallback callback) override;
-
-  // Changing rumble strength.
-  u32 GetControllerRumbleMotorCount(int controller_index) override;
-  void SetControllerRumbleStrength(int controller_index, const float* strengths, u32 num_motors) override;
-
-  // Set deadzone that will be applied on axis-to-button mappings
-  bool SetControllerDeadzone(int controller_index, float size = 0.25f) override;
-
-  void PollEvents() override;
-
-  void SetDeviceNames(std::vector<std::string> device_names);
-  void SetDeviceRumble(u32 index, bool has_vibrator);
-  void HandleAxisEvent(u32 index, u32 axis, float value);
-  void HandleButtonEvent(u32 index, u32 button, bool pressed);
-  bool HasButtonBinding(u32 index, u32 button);
-
-private:
-  enum : u32
-  {
-    NUM_RUMBLE_MOTORS = 2
-  };
-
-  struct ControllerData
-  {
-    float deadzone = 0.25f;
-
-    std::map<u32, std::array<AxisCallback, 3>> axis_mapping;
-    std::map<u32, ButtonCallback> button_mapping;
-    std::map<u32, std::array<ButtonCallback, 2>> axis_button_mapping;
-    std::map<u32, AxisCallback> button_axis_mapping;
-    bool has_rumble = false;
-  };
-
-  std::vector<std::string> m_device_names;
-  std::vector<ControllerData> m_controllers;
-  std::mutex m_controllers_mutex;
-
-  std::mutex m_event_intercept_mutex;
-  Hook::Callback m_event_intercept_callback;
-};
diff --git a/android/app/src/cpp/android_host_interface.cpp b/android/app/src/cpp/android_host_interface.cpp
deleted file mode 100644
index ea4ec3dd0..000000000
--- a/android/app/src/cpp/android_host_interface.cpp
+++ /dev/null
@@ -1,2198 +0,0 @@
-#include "android_host_interface.h"
-#include "android_controller_interface.h"
-#include "android_progress_callback.h"
-#include "common/assert.h"
-#include "common/audio_stream.h"
-#include "common/file_system.h"
-#include "common/log.h"
-#include "common/string.h"
-#include "common/string_util.h"
-#include "common/timer.h"
-#include "common/timestamp.h"
-#include "core/bios.h"
-#include "core/cheats.h"
-#include "core/controller.h"
-#include "core/gpu.h"
-#include "core/host_display.h"
-#include "core/memory_card_image.h"
-#include "core/system.h"
-#include "frontend-common/cheevos.h"
-#include "frontend-common/game_list.h"
-#include "frontend-common/imgui_fullscreen.h"
-#include "frontend-common/imgui_styles.h"
-#include "frontend-common/opengl_host_display.h"
-#include "frontend-common/vulkan_host_display.h"
-#include "scmversion/scmversion.h"
-#include <android/native_window_jni.h>
-#include <cmath>
-#include <imgui.h>
-#include <sched.h>
-#include <unistd.h>
-Log_SetChannel(AndroidHostInterface);
-
-#ifdef USE_OPENSLES
-#include "opensles_audio_stream.h"
-#endif
-
-static JavaVM* s_jvm;
-static jclass s_String_class;
-static jclass s_AndroidHostInterface_class;
-static jmethodID s_AndroidHostInterface_constructor;
-static jfieldID s_AndroidHostInterface_field_mNativePointer;
-static jfieldID s_AndroidHostInterface_field_mEmulationActivity;
-static jmethodID s_AndroidHostInterface_method_reportError;
-static jmethodID s_AndroidHostInterface_method_reportMessage;
-static jmethodID s_AndroidHostInterface_method_openAssetStream;
-static jclass s_EmulationActivity_class;
-static jmethodID s_EmulationActivity_method_reportError;
-static jmethodID s_EmulationActivity_method_onEmulationStarted;
-static jmethodID s_EmulationActivity_method_onEmulationStopped;
-static jmethodID s_EmulationActivity_method_onRunningGameChanged;
-static jmethodID s_EmulationActivity_method_setVibration;
-static jmethodID s_EmulationActivity_method_getRefreshRate;
-static jmethodID s_EmulationActivity_method_openPauseMenu;
-static jmethodID s_EmulationActivity_method_getInputDeviceNames;
-static jmethodID s_EmulationActivity_method_hasInputDeviceVibration;
-static jmethodID s_EmulationActivity_method_setInputDeviceVibration;
-static jclass s_PatchCode_class;
-static jmethodID s_PatchCode_constructor;
-static jclass s_GameListEntry_class;
-static jmethodID s_GameListEntry_constructor;
-static jclass s_SaveStateInfo_class;
-static jmethodID s_SaveStateInfo_constructor;
-static jclass s_Achievement_class;
-static jmethodID s_Achievement_constructor;
-static jclass s_MemoryCardFileInfo_class;
-static jmethodID s_MemoryCardFileInfo_constructor;
-
-namespace AndroidHelpers {
-JavaVM* GetJavaVM()
-{
-  return s_jvm;
-}
-
-// helper for retrieving the current per-thread jni environment
-JNIEnv* GetJNIEnv()
-{
-  JNIEnv* env;
-  if (s_jvm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK)
-    return nullptr;
-  else
-    return env;
-}
-
-AndroidHostInterface* GetNativeClass(JNIEnv* env, jobject obj)
-{
-  return reinterpret_cast<AndroidHostInterface*>(
-    static_cast<uintptr_t>(env->GetLongField(obj, s_AndroidHostInterface_field_mNativePointer)));
-}
-
-std::string JStringToString(JNIEnv* env, jstring str)
-{
-  if (str == nullptr)
-    return {};
-
-  jsize length = env->GetStringUTFLength(str);
-  if (length == 0)
-    return {};
-
-  const char* data = env->GetStringUTFChars(str, nullptr);
-  Assert(data != nullptr);
-
-  std::string ret(data, length);
-  env->ReleaseStringUTFChars(str, data);
-
-  return ret;
-}
-
-jclass GetStringClass()
-{
-  return s_String_class;
-}
-
-std::unique_ptr<GrowableMemoryByteStream> ReadInputStreamToMemory(JNIEnv* env, jobject obj, u32 chunk_size /* = 65536*/)
-{
-  std::unique_ptr<GrowableMemoryByteStream> bs = std::make_unique<GrowableMemoryByteStream>(nullptr, 0);
-  u32 position = 0;
-
-  jclass cls = env->GetObjectClass(obj);
-  jmethodID read_method = env->GetMethodID(cls, "read", "([B)I");
-  Assert(read_method);
-
-  jbyteArray temp = env->NewByteArray(chunk_size);
-  for (;;)
-  {
-    int bytes_read = env->CallIntMethod(obj, read_method, temp);
-    if (bytes_read <= 0)
-      break;
-
-    if ((position + static_cast<u32>(bytes_read)) > bs->GetMemorySize())
-    {
-      const u32 new_size = std::max<u32>(bs->GetMemorySize() * 2, position + static_cast<u32>(bytes_read));
-      bs->ResizeMemory(new_size);
-    }
-
-    env->GetByteArrayRegion(temp, 0, bytes_read, reinterpret_cast<jbyte*>(bs->GetMemoryPointer() + position));
-    position += static_cast<u32>(bytes_read);
-  }
-
-  bs->Resize(position);
-  env->DeleteLocalRef(temp);
-  env->DeleteLocalRef(cls);
-  return bs;
-}
-
-std::vector<u8> ByteArrayToVector(JNIEnv* env, jbyteArray obj)
-{
-  std::vector<u8> ret;
-  const jsize size = obj ? env->GetArrayLength(obj) : 0;
-  if (size > 0)
-  {
-    jbyte* data = env->GetByteArrayElements(obj, nullptr);
-    ret.resize(static_cast<size_t>(size));
-    std::memcpy(ret.data(), data, ret.size());
-    env->ReleaseByteArrayElements(obj, data, 0);
-  }
-
-  return ret;
-}
-
-jbyteArray NewByteArray(JNIEnv* env, const void* data, size_t size)
-{
-  if (!data || size == 0)
-    return nullptr;
-
-  jbyteArray obj = env->NewByteArray(static_cast<jsize>(size));
-  jbyte* obj_data = env->GetByteArrayElements(obj, nullptr);
-  std::memcpy(obj_data, data, static_cast<size_t>(static_cast<jsize>(size)));
-  env->ReleaseByteArrayElements(obj, obj_data, 0);
-  return obj;
-}
-
-jbyteArray VectorToByteArray(JNIEnv* env, const std::vector<u8>& data)
-{
-  if (data.empty())
-    return nullptr;
-
-  return NewByteArray(env, data.data(), data.size());
-}
-
-jobjectArray CreateObjectArray(JNIEnv* env, jclass object_class, const jobject* objects, size_t num_objects,
-                               bool release_refs /* = false*/)
-{
-  if (!objects || num_objects == 0)
-    return nullptr;
-
-  jobjectArray arr = env->NewObjectArray(static_cast<jsize>(num_objects), object_class, nullptr);
-  for (jsize i = 0; i < static_cast<jsize>(num_objects); i++)
-  {
-    env->SetObjectArrayElement(arr, i, objects[i]);
-    if (release_refs && objects[i])
-      env->DeleteLocalRef(objects[i]);
-  }
-
-  return arr;
-}
-} // namespace AndroidHelpers
-
-AndroidHostInterface::AndroidHostInterface(jobject java_object, jobject context_object, std::string user_directory)
-  : m_java_object(java_object)
-{
-  m_user_directory = std::move(user_directory);
-  m_settings_interface = std::make_unique<AndroidSettingsInterface>(context_object);
-}
-
-AndroidHostInterface::~AndroidHostInterface()
-{
-  ImGui::DestroyContext();
-  AndroidHelpers::GetJNIEnv()->DeleteGlobalRef(m_java_object);
-}
-
-bool AndroidHostInterface::Initialize()
-{
-  if (!CommonHostInterface::Initialize())
-    return false;
-
-  return true;
-}
-
-void AndroidHostInterface::Shutdown()
-{
-  HostInterface::Shutdown();
-}
-
-const char* AndroidHostInterface::GetFrontendName() const
-{
-  return "DuckStation Android";
-}
-
-void AndroidHostInterface::RequestExit()
-{
-  ReportError("Ignoring RequestExit()");
-}
-
-void AndroidHostInterface::ReportError(const char* message)
-{
-  CommonHostInterface::ReportError(message);
-
-  JNIEnv* env = AndroidHelpers::GetJNIEnv();
-  jstring message_jstr = env->NewStringUTF(message);
-  if (m_emulation_activity_object)
-    env->CallVoidMethod(m_emulation_activity_object, s_EmulationActivity_method_reportError, message_jstr);
-  else
-    env->CallVoidMethod(m_java_object, s_AndroidHostInterface_method_reportError, message_jstr);
-  env->DeleteLocalRef(message_jstr);
-}
-
-void AndroidHostInterface::ReportMessage(const char* message)
-{
-  CommonHostInterface::ReportMessage(message);
-
-  if (IsOnEmulationThread())
-  {
-    // The toasts are not visible when the emulation activity is running anyway.
-    AddOSDMessage(message, 5.0f);
-  }
-  else
-  {
-    JNIEnv* env = AndroidHelpers::GetJNIEnv();
-    LocalRefHolder<jstring> message_jstr(env, env->NewStringUTF(message));
-    env->CallVoidMethod(m_java_object, s_AndroidHostInterface_method_reportMessage, message_jstr.Get());
-  }
-}
-
-std::unique_ptr<ByteStream> AndroidHostInterface::OpenPackageFile(const char* path, u32 flags)
-{
-  Log_DevPrintf("OpenPackageFile(%s, %x)", path, flags);
-  if (flags & (BYTESTREAM_OPEN_CREATE | BYTESTREAM_OPEN_WRITE))
-    return {};
-
-  JNIEnv* env = AndroidHelpers::GetJNIEnv();
-  jobject stream =
-    env->CallObjectMethod(m_java_object, s_AndroidHostInterface_method_openAssetStream, env->NewStringUTF(path));
-  if (!stream)
-  {
-    Log_ErrorPrintf("Package file '%s' not found", path);
-    return {};
-  }
-
-  std::unique_ptr<ByteStream> ret(AndroidHelpers::ReadInputStreamToMemory(env, stream, 65536));
-  env->DeleteLocalRef(stream);
-  return ret;
-}
-
-void AndroidHostInterface::RegisterHotkeys()
-{
-  RegisterHotkey(StaticString(TRANSLATABLE("Hotkeys", "General")), StaticString("OpenPauseMenu"),
-                 StaticString(TRANSLATABLE("Hotkeys", "Open Pause Menu")), [this](bool pressed) {
-                   if (pressed)
-                   {
-                     AndroidHelpers::GetJNIEnv()->CallVoidMethod(m_emulation_activity_object,
-                                                                 s_EmulationActivity_method_openPauseMenu);
-                   }
-                 });
-
-  CommonHostInterface::RegisterHotkeys();
-}
-
-float AndroidHostInterface::GetRefreshRate() const
-{
-  if (!m_emulation_activity_object)
-    return 0.0f;
-
-  const float value = AndroidHelpers::GetJNIEnv()->CallFloatMethod(m_emulation_activity_object,
-                                                                   s_EmulationActivity_method_getRefreshRate);
-  return (value > 0.0f) ? value : 0.0f;
-}
-
-float AndroidHostInterface::GetSurfaceScale(int width, int height) const
-{
-  if (width <= 0 || height <= 0)
-    return 1.0f;
-
-  // TODO: Really need a better way of determining this.
-  return (width > height) ? (static_cast<float>(width) / 1280.0f) : (static_cast<float>(height) / 1280.0f);
-}
-
-void AndroidHostInterface::SetUserDirectory()
-{
-  // Already set in constructor.
-  Assert(!m_user_directory.empty());
-}
-
-void AndroidHostInterface::LoadSettings(SettingsInterface& si)
-{
-  const GPURenderer old_renderer = g_settings.gpu_renderer;
-  CommonHostInterface::LoadSettings(si);
-
-  const std::string msaa_str = si.GetStringValue("GPU", "MSAA", "1");
-  g_settings.gpu_multisamples = std::max<u32>(StringUtil::FromChars<u32>(msaa_str).value_or(1), 1);
-  g_settings.gpu_per_sample_shading = StringUtil::EndsWith(msaa_str, "-ssaa");
-
-  // turn percentage into fraction for overclock
-  const u32 overclock_percent = static_cast<u32>(std::max(si.GetIntValue("CPU", "Overclock", 100), 1));
-  Settings::CPUOverclockPercentToFraction(overclock_percent, &g_settings.cpu_overclock_numerator,
-                                          &g_settings.cpu_overclock_denominator);
-  g_settings.cpu_overclock_enable = (overclock_percent != 100);
-  g_settings.UpdateOverclockActive();
-
-  m_vibration_enabled = si.GetBoolValue("Controller1", "Vibration", false);
-
-  // Defer renderer changes, the app really doesn't like it.
-  if (System::IsValid() && g_settings.gpu_renderer != old_renderer)
-  {
-    AddFormattedOSDMessage(5.0f,
-                           TranslateString("OSDMessage", "Change to %s GPU renderer will take effect on restart."),
-                           Settings::GetRendererName(g_settings.gpu_renderer));
-    g_settings.gpu_renderer = old_renderer;
-  }
-}
-
-void AndroidHostInterface::UpdateInputMap(SettingsInterface& si)
-{
-  if (m_emulation_activity_object)
-  {
-    JNIEnv* env = AndroidHelpers::GetJNIEnv();
-    DebugAssert(env);
-
-    std::vector<std::string> device_names;
-
-    jobjectArray const java_names = reinterpret_cast<jobjectArray>(
-      env->CallObjectMethod(m_emulation_activity_object, s_EmulationActivity_method_getInputDeviceNames));
-    if (java_names)
-    {
-      const u32 count = static_cast<u32>(env->GetArrayLength(java_names));
-      for (u32 i = 0; i < count; i++)
-      {
-        device_names.push_back(
-          AndroidHelpers::JStringToString(env, reinterpret_cast<jstring>(env->GetObjectArrayElement(java_names, i))));
-      }
-
-      env->DeleteLocalRef(java_names);
-    }
-
-    if (m_controller_interface)
-    {
-      AndroidControllerInterface* ci = static_cast<AndroidControllerInterface*>(m_controller_interface.get());
-      if (ci)
-      {
-        ci->SetDeviceNames(std::move(device_names));
-        for (u32 i = 0; i < ci->GetControllerCount(); i++)
-        {
-          const bool has_vibration = env->CallBooleanMethod(
-            m_emulation_activity_object, s_EmulationActivity_method_hasInputDeviceVibration, static_cast<jint>(i));
-          ci->SetDeviceRumble(i, has_vibration);
-        }
-      }
-    }
-  }
-
-  CommonHostInterface::UpdateInputMap(si);
-}
-
-bool AndroidHostInterface::IsEmulationThreadPaused() const
-{
-  return System::IsValid() && System::IsPaused();
-}
-
-void AndroidHostInterface::PauseEmulationThread(bool paused)
-{
-  Assert(IsEmulationThreadRunning());
-  RunOnEmulationThread([this, paused]() { PauseSystem(paused); });
-}
-
-void AndroidHostInterface::StopEmulationThreadLoop()
-{
-  if (!IsEmulationThreadRunning())
-    return;
-
-  std::unique_lock<std::mutex> lock(m_mutex);
-  m_emulation_thread_stop_request.store(true);
-  m_sleep_cv.notify_one();
-}
-
-bool AndroidHostInterface::IsOnEmulationThread() const
-{
-  return std::this_thread::get_id() == m_emulation_thread_id;
-}
-
-void AndroidHostInterface::RunOnEmulationThread(std::function<void()> function, bool blocking)
-{
-  if (!IsEmulationThreadRunning())
-  {
-    function();
-    return;
-  }
-
-  m_mutex.lock();
-  m_callback_queue.push_back(std::move(function));
-  m_callbacks_outstanding.store(true);
-  m_sleep_cv.notify_one();
-
-  if (blocking)
-  {
-    // TODO: Don't spin
-    for (;;)
-    {
-      if (!m_callbacks_outstanding.load())
-        break;
-
-      m_mutex.unlock();
-      m_mutex.lock();
-    }
-  }
-
-  m_mutex.unlock();
-}
-
-void AndroidHostInterface::RunLater(std::function<void()> func)
-{
-  std::unique_lock<std::mutex> lock(m_mutex);
-  m_callback_queue.push_back(std::move(func));
-  m_callbacks_outstanding.store(true);
-}
-
-void AndroidHostInterface::EmulationThreadEntryPoint(JNIEnv* env, jobject emulation_activity,
-                                                     SystemBootParameters boot_params, bool resume_state)
-{
-  if (!m_surface)
-  {
-    Log_ErrorPrint("Emulation thread started without surface set.");
-    env->CallVoidMethod(emulation_activity, s_EmulationActivity_method_onEmulationStopped);
-    return;
-  }
-
-  emulation_activity = env->NewGlobalRef(emulation_activity);
-  Assert(emulation_activity != nullptr);
-
-  {
-    std::unique_lock<std::mutex> lock(m_mutex);
-    m_emulation_thread_running.store(true);
-    m_emulation_activity_object = emulation_activity;
-    m_emulation_thread_id = std::this_thread::get_id();
-    env->SetObjectField(m_java_object, s_AndroidHostInterface_field_mEmulationActivity, emulation_activity);
-  }
-
-  ApplySettings(true);
-
-  // Boot system.
-  bool boot_result = false;
-  if (resume_state && boot_params.filename.empty())
-    boot_result = ResumeSystemFromMostRecentState();
-  else if (resume_state && CanResumeSystemFromFile(boot_params.filename.c_str()))
-    boot_result = ResumeSystemFromState(boot_params.filename.c_str(), true);
-  else
-    boot_result = BootSystem(boot_params);
-
-  if (boot_result)
-  {
-    // System is ready to go.
-    EmulationThreadLoop(env);
-    PowerOffSystem(ShouldSaveResumeState());
-  }
-
-  // Drain any callbacks so we don't leave things in a screwed-up state for next boot.
-  {
-    std::unique_lock<std::mutex> lock(m_mutex);
-    while (!m_callback_queue.empty())
-    {
-      auto callback = std::move(m_callback_queue.front());
-      m_callback_queue.pop_front();
-      lock.unlock();
-      callback();
-      lock.lock();
-    }
-    env->SetObjectField(m_java_object, s_AndroidHostInterface_field_mEmulationActivity, nullptr);
-    m_emulation_thread_running.store(false);
-    m_emulation_thread_id = {};
-    m_emulation_activity_object = {};
-    m_callbacks_outstanding.store(false);
-  }
-
-  env->CallVoidMethod(emulation_activity, s_EmulationActivity_method_onEmulationStopped);
-  env->DeleteGlobalRef(emulation_activity);
-}
-
-void AndroidHostInterface::EmulationThreadLoop(JNIEnv* env)
-{
-  env->CallVoidMethod(m_emulation_activity_object, s_EmulationActivity_method_onEmulationStarted);
-
-  for (;;)
-  {
-    // run any events
-    {
-      std::unique_lock<std::mutex> lock(m_mutex);
-      for (;;)
-      {
-        if (!m_callback_queue.empty())
-        {
-          do
-          {
-            auto callback = std::move(m_callback_queue.front());
-            m_callback_queue.pop_front();
-            lock.unlock();
-            callback();
-            lock.lock();
-          } while (!m_callback_queue.empty());
-          m_callbacks_outstanding.store(false);
-        }
-
-        if (m_emulation_thread_stop_request.load())
-        {
-          m_emulation_thread_stop_request.store(false);
-          return;
-        }
-
-        if (System::IsPaused())
-        {
-          // paused, wait for us to resume
-          m_sleep_cv.wait(lock);
-        }
-        else
-        {
-          // done with callbacks, run the frame
-          break;
-        }
-      }
-    }
-
-    // we don't do a full PollAndUpdate() here
-    if (Cheevos::IsActive())
-      Cheevos::Update();
-
-    // simulate the system if not paused
-    if (System::IsRunning())
-    {
-      if (m_throttler_enabled)
-        System::RunFrames();
-      else
-        System::RunFrame();
-
-      UpdateControllerMetaState();
-      if (m_vibration_enabled)
-        UpdateVibration();
-    }
-
-    // rendering
-    {
-      ImGui::NewFrame();
-      DrawImGuiWindows();
-
-      m_display->Render();
-      ImGui::EndFrame();
-
-      if (System::IsRunning())
-      {
-        System::UpdatePerformanceCounters();
-
-        if (m_throttler_enabled)
-          System::Throttle();
-      }
-    }
-  }
-}
-
-bool AndroidHostInterface::AcquireHostDisplay()
-{
-  WindowInfo wi;
-  wi.type = WindowInfo::Type::Android;
-  wi.window_handle = m_surface;
-  wi.surface_width = ANativeWindow_getWidth(m_surface);
-  wi.surface_height = ANativeWindow_getHeight(m_surface);
-  wi.surface_refresh_rate = GetRefreshRate();
-  wi.surface_scale = GetSurfaceScale(wi.surface_width, wi.surface_height);
-
-  switch (g_settings.gpu_renderer)
-  {
-    case GPURenderer::HardwareVulkan:
-      m_display = std::make_unique<FrontendCommon::VulkanHostDisplay>();
-      break;
-
-    case GPURenderer::HardwareOpenGL:
-    default:
-      m_display = std::make_unique<FrontendCommon::OpenGLHostDisplay>();
-      break;
-  }
-
-  if (!m_display->CreateRenderDevice(wi, {}, g_settings.gpu_use_debug_device, g_settings.gpu_threaded_presentation) ||
-      !m_display->InitializeRenderDevice(GetShaderCacheBasePath(), g_settings.gpu_use_debug_device,
-                                         g_settings.gpu_threaded_presentation))
-  {
-    m_display->DestroyRenderDevice();
-    m_display.reset();
-    return false;
-  }
-
-  // The alignment was set prior to booting.
-  m_display->SetDisplayAlignment(m_display_alignment);
-
-  if (!CreateHostDisplayResources())
-  {
-    ReportError("Failed to create host display resources");
-    ReleaseHostDisplay();
-    return false;
-  }
-
-  return true;
-}
-
-void AndroidHostInterface::ReleaseHostDisplay()
-{
-  ReleaseHostDisplayResources();
-  if (m_display)
-  {
-    m_display->DestroyRenderDevice();
-    m_display.reset();
-  }
-}
-
-std::unique_ptr<AudioStream> AndroidHostInterface::CreateAudioStream(AudioBackend backend)
-{
-#ifdef USE_OPENSLES
-  if (backend == AudioBackend::OpenSLES)
-    return OpenSLESAudioStream::Create();
-#endif
-
-  return CommonHostInterface::CreateAudioStream(backend);
-}
-
-void AndroidHostInterface::UpdateControllerInterface()
-{
-  if (m_controller_interface)
-  {
-    m_controller_interface->Shutdown();
-    m_controller_interface.reset();
-  }
-
-  m_controller_interface = std::make_unique<AndroidControllerInterface>();
-  if (!m_controller_interface || !m_controller_interface->Initialize(this))
-  {
-    Log_WarningPrintf("Failed to initialize controller interface, bindings are not possible.");
-    if (m_controller_interface)
-    {
-      m_controller_interface->Shutdown();
-      m_controller_interface.reset();
-    }
-  }
-}
-
-void AndroidHostInterface::OnSystemPaused(bool paused)
-{
-  CommonHostInterface::OnSystemPaused(paused);
-
-  if (m_vibration_enabled)
-    SetVibration(false);
-}
-
-void AndroidHostInterface::OnSystemDestroyed()
-{
-  CommonHostInterface::OnSystemDestroyed();
-  ClearOSDMessages();
-
-  if (m_vibration_enabled)
-    SetVibration(false);
-}
-
-void AndroidHostInterface::OnRunningGameChanged(const std::string& path, CDImage* image, const std::string& game_code,
-                                                const std::string& game_title)
-{
-  CommonHostInterface::OnRunningGameChanged(path, image, game_code, game_title);
-
-  if (m_emulation_activity_object)
-  {
-    JNIEnv* env = AndroidHelpers::GetJNIEnv();
-
-    jstring path_string = env->NewStringUTF(path.c_str());
-    jstring code_string = env->NewStringUTF(game_code.c_str());
-    jstring title_string = env->NewStringUTF(game_title.c_str());
-
-    const GameListEntry* game_list_entry = m_game_list->GetEntryForPath(path.c_str());
-    std::string cover_path_str;
-    if (game_list_entry)
-      cover_path_str = m_game_list->GetCoverImagePathForEntry(game_list_entry);
-    else
-      cover_path_str = m_game_list->GetCoverImagePath(path, game_code, game_title);
-
-    jstring cover_path = nullptr;
-    if (!cover_path_str.empty())
-      cover_path = env->NewStringUTF(cover_path_str.c_str());
-
-    env->CallVoidMethod(m_emulation_activity_object, s_EmulationActivity_method_onRunningGameChanged, path_string,
-                        code_string, title_string, cover_path);
-
-    if (cover_path)
-      env->DeleteLocalRef(cover_path);
-    env->DeleteLocalRef(title_string);
-    env->DeleteLocalRef(code_string);
-    env->DeleteLocalRef(path_string);
-  }
-}
-
-void AndroidHostInterface::SurfaceChanged(ANativeWindow* surface, int format, int width, int height)
-{
-  Log_InfoPrintf("SurfaceChanged %p %d %d %d", surface, format, width, height);
-  if (m_surface == surface)
-  {
-    if (m_display && (width != m_display->GetWindowWidth() || height != m_display->GetWindowHeight()))
-    {
-      m_display->ResizeRenderWindow(width, height);
-      OnHostDisplayResized();
-    }
-
-    return;
-  }
-
-  m_surface = surface;
-
-  if (m_display)
-  {
-    WindowInfo wi;
-    wi.type = surface ? WindowInfo::Type::Android : WindowInfo::Type::Surfaceless;
-    wi.window_handle = surface;
-    wi.surface_width = width;
-    wi.surface_height = height;
-    wi.surface_refresh_rate = GetRefreshRate();
-    wi.surface_scale = GetSurfaceScale(width, height);
-
-    const bool surface_valid = m_display->ChangeRenderWindow(wi) && surface;
-    if (surface_valid)
-      OnHostDisplayResized();
-
-    if (surface_valid && System::GetState() == System::State::Paused)
-      PauseSystem(false);
-    else if (!surface_valid && System::IsRunning())
-      PauseSystem(true);
-  }
-}
-
-void AndroidHostInterface::SetDisplayAlignment(HostDisplay::Alignment alignment)
-{
-  m_display_alignment = alignment;
-  if (m_display)
-    m_display->SetDisplayAlignment(alignment);
-}
-
-void AndroidHostInterface::SetControllerButtonState(u32 index, s32 button_code, bool pressed)
-{
-  if (!IsEmulationThreadRunning())
-    return;
-
-  RunOnEmulationThread(
-    [index, button_code, pressed]() {
-      Controller* controller = System::GetController(index);
-      if (!controller)
-        return;
-
-      controller->SetButtonState(button_code, pressed);
-    },
-    false);
-}
-
-void AndroidHostInterface::SetControllerAxisState(u32 index, s32 button_code, float value)
-{
-  if (!IsEmulationThreadRunning())
-    return;
-
-  RunOnEmulationThread(
-    [index, button_code, value]() {
-      Controller* controller = System::GetController(index);
-      if (!controller)
-        return;
-
-      controller->SetAxisState(button_code, value);
-    },
-    false);
-}
-
-void AndroidHostInterface::HandleControllerButtonEvent(u32 controller_index, u32 button_index, bool pressed)
-{
-  if (!IsEmulationThreadRunning())
-    return;
-
-  RunOnEmulationThread([this, controller_index, button_index, pressed]() {
-    AndroidControllerInterface* ci = static_cast<AndroidControllerInterface*>(m_controller_interface.get());
-    if (ci)
-      ci->HandleButtonEvent(controller_index, button_index, pressed);
-  });
-}
-
-void AndroidHostInterface::HandleControllerAxisEvent(u32 controller_index, u32 axis_index, float value)
-{
-  if (!IsEmulationThreadRunning())
-    return;
-
-  RunOnEmulationThread([this, controller_index, axis_index, value]() {
-    AndroidControllerInterface* ci = static_cast<AndroidControllerInterface*>(m_controller_interface.get());
-    if (ci)
-      ci->HandleAxisEvent(controller_index, axis_index, value);
-  });
-}
-
-bool AndroidHostInterface::HasControllerButtonBinding(u32 controller_index, u32 button)
-{
-  AndroidControllerInterface* ci = static_cast<AndroidControllerInterface*>(m_controller_interface.get());
-  if (!ci)
-    return false;
-
-  return ci->HasButtonBinding(controller_index, button);
-}
-
-void AndroidHostInterface::SetControllerVibration(u32 controller_index, float small_motor, float large_motor)
-{
-  if (!m_emulation_activity_object)
-    return;
-
-  JNIEnv* env = AndroidHelpers::GetJNIEnv();
-  DebugAssert(env);
-
-  env->CallVoidMethod(m_emulation_activity_object, s_EmulationActivity_method_setInputDeviceVibration,
-                      static_cast<jint>(controller_index), static_cast<jfloat>(small_motor),
-                      static_cast<jfloat>(large_motor));
-}
-
-void AndroidHostInterface::SetFastForwardEnabled(bool enabled)
-{
-  m_fast_forward_enabled = enabled;
-  UpdateSpeedLimiterState();
-}
-
-void AndroidHostInterface::RefreshGameList(bool invalidate_cache, bool invalidate_database,
-                                           ProgressCallback* progress_callback)
-{
-  m_game_list->SetSearchDirectoriesFromSettings(*m_settings_interface);
-  m_game_list->Refresh(invalidate_cache, invalidate_database, progress_callback);
-}
-
-bool AndroidHostInterface::ImportPatchCodesFromString(const std::string& str)
-{
-  CheatList* cl = new CheatList();
-  if (!cl->LoadFromString(str, CheatList::Format::Autodetect) || cl->GetCodeCount() == 0)
-    return false;
-
-  RunOnEmulationThread([this, cl]() {
-    u32 imported_count;
-    if (!System::HasCheatList())
-    {
-      imported_count = cl->GetCodeCount();
-      System::SetCheatList(std::unique_ptr<CheatList>(cl));
-    }
-    else
-    {
-      const u32 old_count = System::GetCheatList()->GetCodeCount();
-      System::GetCheatList()->MergeList(*cl);
-      imported_count = System::GetCheatList()->GetCodeCount() - old_count;
-      delete cl;
-    }
-
-    AddFormattedOSDMessage(20.0f, "Imported %u patch codes.", imported_count);
-    CommonHostInterface::SaveCheatList();
-  });
-
-  return true;
-}
-
-void AndroidHostInterface::SetVibration(bool enabled)
-{
-  const u64 current_time = Common::Timer::GetValue();
-  if (Common::Timer::ConvertValueToSeconds(current_time - m_last_vibration_update_time) < 0.1f &&
-      m_last_vibration_state == enabled)
-  {
-    return;
-  }
-
-  m_last_vibration_state = enabled;
-  m_last_vibration_update_time = current_time;
-
-  JNIEnv* env = AndroidHelpers::GetJNIEnv();
-  if (m_emulation_activity_object)
-  {
-    env->CallVoidMethod(m_emulation_activity_object, s_EmulationActivity_method_setVibration,
-                        static_cast<jboolean>(enabled));
-  }
-}
-
-void AndroidHostInterface::UpdateVibration()
-{
-  static constexpr float THRESHOLD = 0.5f;
-
-  bool vibration_state = false;
-
-  for (u32 i = 0; i < NUM_CONTROLLER_AND_CARD_PORTS; i++)
-  {
-    Controller* controller = System::GetController(i);
-    if (!controller)
-      continue;
-
-    const u32 motors = controller->GetVibrationMotorCount();
-    for (u32 j = 0; j < motors; j++)
-    {
-      if (controller->GetVibrationMotorStrength(j) >= THRESHOLD)
-      {
-        vibration_state = true;
-        break;
-      }
-    }
-  }
-
-  SetVibration(vibration_state);
-}
-
-jobjectArray AndroidHostInterface::GetInputProfileNames(JNIEnv* env) const
-{
-  const InputProfileList profile_list(GetInputProfileList());
-  if (profile_list.empty())
-    return nullptr;
-
-  jobjectArray name_array = env->NewObjectArray(static_cast<u32>(profile_list.size()), s_String_class, nullptr);
-  u32 name_array_index = 0;
-  Assert(name_array != nullptr);
-  for (const InputProfileEntry& e : profile_list)
-  {
-    jstring axis_name_jstr = env->NewStringUTF(e.name.c_str());
-    env->SetObjectArrayElement(name_array, name_array_index++, axis_name_jstr);
-    env->DeleteLocalRef(axis_name_jstr);
-  }
-
-  return name_array;
-}
-
-extern "C" jint JNI_OnLoad(JavaVM* vm, void* reserved)
-{
-  Log::SetDebugOutputParams(true, nullptr, LOGLEVEL_DEV);
-  s_jvm = vm;
-
-  // Create global reference so it doesn't get cleaned up.
-  JNIEnv* env = AndroidHelpers::GetJNIEnv();
-  jclass string_class, host_interface_class, patch_code_class, game_list_entry_class, save_state_info_class,
-    achievement_class, memory_card_file_info_class;
-  if ((string_class = env->FindClass("java/lang/String")) == nullptr ||
-      (s_String_class = static_cast<jclass>(env->NewGlobalRef(string_class))) == nullptr ||
-      (host_interface_class = env->FindClass("com/github/stenzek/duckstation/AndroidHostInterface")) == nullptr ||
-      (s_AndroidHostInterface_class = static_cast<jclass>(env->NewGlobalRef(host_interface_class))) == nullptr ||
-      (patch_code_class = env->FindClass("com/github/stenzek/duckstation/PatchCode")) == nullptr ||
-      (s_PatchCode_class = static_cast<jclass>(env->NewGlobalRef(patch_code_class))) == nullptr ||
-      (game_list_entry_class = env->FindClass("com/github/stenzek/duckstation/GameListEntry")) == nullptr ||
-      (s_GameListEntry_class = static_cast<jclass>(env->NewGlobalRef(game_list_entry_class))) == nullptr ||
-      (save_state_info_class = env->FindClass("com/github/stenzek/duckstation/SaveStateInfo")) == nullptr ||
-      (s_SaveStateInfo_class = static_cast<jclass>(env->NewGlobalRef(save_state_info_class))) == nullptr ||
-      (achievement_class = env->FindClass("com/github/stenzek/duckstation/Achievement")) == nullptr ||
-      (s_Achievement_class = static_cast<jclass>(env->NewGlobalRef(achievement_class))) == nullptr ||
-      (memory_card_file_info_class = env->FindClass("com/github/stenzek/duckstation/MemoryCardFileInfo")) == nullptr ||
-      (s_MemoryCardFileInfo_class = static_cast<jclass>(env->NewGlobalRef(memory_card_file_info_class))) == nullptr)
-  {
-    Log_ErrorPrint("AndroidHostInterface class lookup failed");
-    return -1;
-  }
-
-  env->DeleteLocalRef(string_class);
-  env->DeleteLocalRef(host_interface_class);
-  env->DeleteLocalRef(patch_code_class);
-  env->DeleteLocalRef(game_list_entry_class);
-  env->DeleteLocalRef(achievement_class);
-  env->DeleteLocalRef(memory_card_file_info_class);
-
-  jclass emulation_activity_class;
-  if ((s_AndroidHostInterface_constructor =
-         env->GetMethodID(s_AndroidHostInterface_class, "<init>",
-                          "(Landroid/content/Context;Lcom/github/stenzek/duckstation/FileHelper;)V")) == nullptr ||
-      (s_AndroidHostInterface_field_mNativePointer =
-         env->GetFieldID(s_AndroidHostInterface_class, "mNativePointer", "J")) == nullptr ||
-      (s_AndroidHostInterface_field_mEmulationActivity =
-         env->GetFieldID(s_AndroidHostInterface_class, "mEmulationActivity",
-                         "Lcom/github/stenzek/duckstation/EmulationActivity;")) == nullptr ||
-      (s_AndroidHostInterface_method_reportError =
-         env->GetMethodID(s_AndroidHostInterface_class, "reportError", "(Ljava/lang/String;)V")) == nullptr ||
-      (s_AndroidHostInterface_method_reportMessage =
-         env->GetMethodID(s_AndroidHostInterface_class, "reportMessage", "(Ljava/lang/String;)V")) == nullptr ||
-      (s_AndroidHostInterface_method_openAssetStream = env->GetMethodID(
-         s_AndroidHostInterface_class, "openAssetStream", "(Ljava/lang/String;)Ljava/io/InputStream;")) == nullptr ||
-      (emulation_activity_class = env->FindClass("com/github/stenzek/duckstation/EmulationActivity")) == nullptr ||
-      (s_EmulationActivity_class = static_cast<jclass>(env->NewGlobalRef(emulation_activity_class))) == nullptr ||
-      (s_EmulationActivity_method_reportError =
-         env->GetMethodID(s_EmulationActivity_class, "reportError", "(Ljava/lang/String;)V")) == nullptr ||
-      (s_EmulationActivity_method_onEmulationStarted =
-         env->GetMethodID(s_EmulationActivity_class, "onEmulationStarted", "()V")) == nullptr ||
-      (s_EmulationActivity_method_onEmulationStopped =
-         env->GetMethodID(s_EmulationActivity_class, "onEmulationStopped", "()V")) == nullptr ||
-      (s_EmulationActivity_method_onRunningGameChanged =
-         env->GetMethodID(s_EmulationActivity_class, "onRunningGameChanged",
-                          "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V")) == nullptr ||
-      (s_EmulationActivity_method_setVibration = env->GetMethodID(emulation_activity_class, "setVibration", "(Z)V")) ==
-        nullptr ||
-      (s_EmulationActivity_method_getRefreshRate =
-         env->GetMethodID(emulation_activity_class, "getRefreshRate", "()F")) == nullptr ||
-      (s_EmulationActivity_method_openPauseMenu = env->GetMethodID(emulation_activity_class, "openPauseMenu", "()V")) ==
-        nullptr ||
-      (s_EmulationActivity_method_getInputDeviceNames =
-         env->GetMethodID(s_EmulationActivity_class, "getInputDeviceNames", "()[Ljava/lang/String;")) == nullptr ||
-      (s_EmulationActivity_method_hasInputDeviceVibration =
-         env->GetMethodID(s_EmulationActivity_class, "hasInputDeviceVibration", "(I)Z")) == nullptr ||
-      (s_EmulationActivity_method_setInputDeviceVibration =
-         env->GetMethodID(s_EmulationActivity_class, "setInputDeviceVibration", "(IFF)V")) == nullptr ||
-      (s_PatchCode_constructor =
-         env->GetMethodID(s_PatchCode_class, "<init>", "(ILjava/lang/String;Ljava/lang/String;Z)V")) == nullptr ||
-      (s_GameListEntry_constructor =
-         env->GetMethodID(s_GameListEntry_class, "<init>",
-                          "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;JLjava/lang/String;Ljava/lang/"
-                          "String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V")) == nullptr ||
-      (s_SaveStateInfo_constructor = env->GetMethodID(
-         s_SaveStateInfo_class, "<init>",
-         "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;IZII[B)V")) ==
-        nullptr ||
-      (s_Achievement_constructor = env->GetMethodID(
-         s_Achievement_class, "<init>",
-         "(ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;IZ)V")) == nullptr ||
-      (s_MemoryCardFileInfo_constructor = env->GetMethodID(s_MemoryCardFileInfo_class, "<init>",
-                                                           "(Ljava/lang/String;Ljava/lang/String;III[[B)V")) == nullptr)
-  {
-    Log_ErrorPrint("AndroidHostInterface lookups failed");
-    return -1;
-  }
-
-  env->DeleteLocalRef(emulation_activity_class);
-
-  return JNI_VERSION_1_6;
-}
-
-#define DEFINE_JNI_METHOD(return_type, name)                                                                           \
-  extern "C" JNIEXPORT return_type JNICALL Java_com_github_stenzek_duckstation_##name(JNIEnv* env)
-
-#define DEFINE_JNI_ARGS_METHOD(return_type, name, ...)                                                                 \
-  extern "C" JNIEXPORT return_type JNICALL Java_com_github_stenzek_duckstation_##name(JNIEnv* env, __VA_ARGS__)
-
-DEFINE_JNI_ARGS_METHOD(jstring, AndroidHostInterface_getScmVersion, jobject unused)
-{
-  return env->NewStringUTF(g_scm_tag_str);
-}
-
-DEFINE_JNI_ARGS_METHOD(jstring, AndroidHostInterface_getFullScmVersion, jobject unused)
-{
-  return env->NewStringUTF(SmallString::FromFormat("DuckStation for Android %s (%s)\nBuilt %s %s", g_scm_tag_str,
-                                                   g_scm_branch_str, __DATE__, __TIME__));
-}
-
-DEFINE_JNI_ARGS_METHOD(void, AndroidHostInterface_setThreadAffinity, jobject unused, jintArray cores)
-{
-  // https://github.com/googlearchive/android-audio-high-performance/blob/c232c21bf35d3bfea16537b781c526b8abdcc3cf/SimpleSynth/app/src/main/cpp/audio_player.cc
-  int length = env->GetArrayLength(cores);
-  int* p_cores = env->GetIntArrayElements(cores, nullptr);
-
-  pid_t current_thread_id = gettid();
-  cpu_set_t cpu_set;
-  CPU_ZERO(&cpu_set);
-  for (int i = 0; i < length; i++)
-  {
-    Log_InfoPrintf("Binding to CPU %d", p_cores[i]);
-    CPU_SET(p_cores[i], &cpu_set);
-  }
-
-  int result = sched_setaffinity(current_thread_id, sizeof(cpu_set_t), &cpu_set);
-  if (result != 0)
-    Log_InfoPrintf("Thread affinity set.");
-  else
-    Log_ErrorPrintf("Error setting thread affinity: %d", result);
-
-  env->ReleaseIntArrayElements(cores, p_cores, 0);
-}
-
-DEFINE_JNI_ARGS_METHOD(jobject, AndroidHostInterface_create, jobject unused, jobject context_object,
-                       jobject file_helper_object, jstring user_directory)
-{
-  Log::SetDebugOutputParams(true, nullptr, LOGLEVEL_DEBUG);
-
-  // initialize the java side
-  jobject java_obj = env->NewObject(s_AndroidHostInterface_class, s_AndroidHostInterface_constructor, context_object,
-                                    file_helper_object);
-  if (!java_obj)
-  {
-    Log_ErrorPrint("Failed to create Java AndroidHostInterface");
-    return nullptr;
-  }
-
-  jobject java_obj_ref = env->NewGlobalRef(java_obj);
-  Assert(java_obj_ref != nullptr);
-
-  // initialize the C++ side
-  std::string user_directory_str = AndroidHelpers::JStringToString(env, user_directory);
-  AndroidHostInterface* cpp_obj = new AndroidHostInterface(java_obj_ref, context_object, std::move(user_directory_str));
-  if (!cpp_obj->Initialize())
-  {
-    // TODO: Do we need to release the original java object reference?
-    Log_ErrorPrint("Failed to create C++ AndroidHostInterface");
-    env->DeleteGlobalRef(java_obj_ref);
-    return nullptr;
-  }
-
-  env->SetLongField(java_obj, s_AndroidHostInterface_field_mNativePointer,
-                    static_cast<long>(reinterpret_cast<uintptr_t>(cpp_obj)));
-
-  FileSystem::SetAndroidFileHelper(s_jvm, env, file_helper_object);
-  return java_obj;
-}
-
-DEFINE_JNI_ARGS_METHOD(jboolean, AndroidHostInterface_isEmulationThreadRunning, jobject obj)
-{
-  return AndroidHelpers::GetNativeClass(env, obj)->IsEmulationThreadRunning();
-}
-
-DEFINE_JNI_ARGS_METHOD(void, AndroidHostInterface_runEmulationThread, jobject obj, jobject emulationActivity,
-                       jstring filename, jboolean resume_state, jstring state_filename)
-{
-  std::string state_filename_str = AndroidHelpers::JStringToString(env, state_filename);
-
-  SystemBootParameters boot_params;
-  boot_params.filename = AndroidHelpers::JStringToString(env, filename);
-
-  AndroidHelpers::GetNativeClass(env, obj)->EmulationThreadEntryPoint(env, emulationActivity, std::move(boot_params),
-                                                                      resume_state);
-}
-
-DEFINE_JNI_ARGS_METHOD(void, AndroidHostInterface_stopEmulationThreadLoop, jobject obj)
-{
-  AndroidHelpers::GetNativeClass(env, obj)->StopEmulationThreadLoop();
-}
-
-DEFINE_JNI_ARGS_METHOD(void, AndroidHostInterface_surfaceChanged, jobject obj, jobject surface, jint format, jint width,
-                       jint height)
-{
-  ANativeWindow* native_surface = surface ? ANativeWindow_fromSurface(env, surface) : nullptr;
-  if (surface && !native_surface)
-    Log_ErrorPrint("ANativeWindow_fromSurface() returned null");
-
-  if (!surface && System::GetState() == System::State::Starting)
-  {
-    // User switched away from the app while it was compiling shaders.
-    Log_ErrorPrintf("Surface destroyed while starting, cancelling");
-    System::CancelPendingStartup();
-  }
-
-  // We should wait for the emu to finish if the surface is being destroyed or changed.
-  AndroidHostInterface* hi = AndroidHelpers::GetNativeClass(env, obj);
-  const bool block = (!native_surface || native_surface != hi->GetSurface());
-  hi->RunOnEmulationThread(
-    [hi, native_surface, format, width, height]() { hi->SurfaceChanged(native_surface, format, width, height); },
-    block);
-}
-
-DEFINE_JNI_ARGS_METHOD(void, AndroidHostInterface_setMousePosition, jobject obj, jint positionX, jint positionY)
-{
-  HostDisplay* display = AndroidHelpers::GetNativeClass(env, obj)->GetDisplay();
-  if (!display)
-    return;
-
-  // Technically a race, but shouldn't cause any issues.
-  display->SetMousePosition(positionX, positionY);
-}
-
-DEFINE_JNI_ARGS_METHOD(void, AndroidHostInterface_setControllerButtonState, jobject obj, jint index, jint button_code,
-                       jboolean pressed)
-{
-  AndroidHelpers::GetNativeClass(env, obj)->SetControllerButtonState(index, button_code, pressed);
-}
-
-DEFINE_JNI_ARGS_METHOD(void, AndroidHostInterface_setControllerAutoFireState, jobject obj, jint controller_index,
-                       jint autofire_index, jboolean active)
-{
-  AndroidHostInterface* hi = AndroidHelpers::GetNativeClass(env, obj);
-  if (!hi->IsEmulationThreadRunning())
-    return;
-
-  hi->RunOnEmulationThread([hi, controller_index, autofire_index, active]() {
-    hi->SetControllerAutoFireSlotState(controller_index, autofire_index, active);
-  });
-}
-
-DEFINE_JNI_ARGS_METHOD(jint, AndroidHostInterface_getControllerButtonCode, jobject unused, jstring controller_type,
-                       jstring button_name)
-{
-  std::optional<ControllerType> type =
-    Settings::ParseControllerTypeName(AndroidHelpers::JStringToString(env, controller_type).c_str());
-  if (!type)
-    return -1;
-
-  std::optional<s32> code =
-    Controller::GetButtonCodeByName(type.value(), AndroidHelpers::JStringToString(env, button_name));
-  return code.value_or(-1);
-}
-
-DEFINE_JNI_ARGS_METHOD(void, AndroidHostInterface_setControllerAxisState, jobject obj, jint index, jint button_code,
-                       jfloat value)
-{
-  AndroidHelpers::GetNativeClass(env, obj)->SetControllerAxisState(index, button_code, value);
-}
-
-DEFINE_JNI_ARGS_METHOD(jint, AndroidHostInterface_getControllerAxisCode, jobject unused, jstring controller_type,
-                       jstring axis_name)
-{
-  std::optional<ControllerType> type =
-    Settings::ParseControllerTypeName(AndroidHelpers::JStringToString(env, controller_type).c_str());
-  if (!type)
-    return -1;
-
-  std::optional<s32> code =
-    Controller::GetAxisCodeByName(type.value(), AndroidHelpers::JStringToString(env, axis_name));
-  return code.value_or(-1);
-}
-
-DEFINE_JNI_ARGS_METHOD(jint, AndroidHostInterface_getControllerAxisType, jobject unused, jstring controller_type,
-                       jstring axis_name)
-{
-  std::optional<ControllerType> type =
-    Settings::ParseControllerTypeName(AndroidHelpers::JStringToString(env, controller_type).c_str());
-  if (!type)
-    return -1;
-
-  const std::string axis_name_str(AndroidHelpers::JStringToString(env, axis_name));
-  for (const auto& [name, code, type] : Controller::GetAxisNames(type.value()))
-  {
-    if (name == axis_name_str)
-      return static_cast<jint>(type);
-  }
-
-  return -1;
-}
-
-DEFINE_JNI_ARGS_METHOD(jobjectArray, AndroidHostInterface_getControllerButtonNames, jobject unused,
-                       jstring controller_type)
-{
-  std::optional<ControllerType> type =
-    Settings::ParseControllerTypeName(AndroidHelpers::JStringToString(env, controller_type).c_str());
-  if (!type)
-    return nullptr;
-
-  const Controller::ButtonList buttons(Controller::GetButtonNames(type.value()));
-  if (buttons.empty())
-    return nullptr;
-
-  jobjectArray name_array = env->NewObjectArray(static_cast<u32>(buttons.size()), s_String_class, nullptr);
-  u32 name_array_index = 0;
-  Assert(name_array != nullptr);
-  for (const auto& [button_name, button_code] : buttons)
-  {
-    jstring button_name_jstr = env->NewStringUTF(button_name.c_str());
-    env->SetObjectArrayElement(name_array, name_array_index++, button_name_jstr);
-    env->DeleteLocalRef(button_name_jstr);
-  }
-
-  return name_array;
-}
-
-DEFINE_JNI_ARGS_METHOD(jobjectArray, AndroidHostInterface_getControllerAxisNames, jobject unused,
-                       jstring controller_type)
-{
-  std::optional<ControllerType> type =
-    Settings::ParseControllerTypeName(AndroidHelpers::JStringToString(env, controller_type).c_str());
-  if (!type)
-    return nullptr;
-
-  const Controller::AxisList axes(Controller::GetAxisNames(type.value()));
-  if (axes.empty())
-    return nullptr;
-
-  jobjectArray name_array = env->NewObjectArray(static_cast<u32>(axes.size()), s_String_class, nullptr);
-  u32 name_array_index = 0;
-  Assert(name_array != nullptr);
-  for (const auto& [axis_name, axis_code, axis_type] : axes)
-  {
-    jstring axis_name_jstr = env->NewStringUTF(axis_name.c_str());
-    env->SetObjectArrayElement(name_array, name_array_index++, axis_name_jstr);
-    env->DeleteLocalRef(axis_name_jstr);
-  }
-
-  return name_array;
-}
-
-DEFINE_JNI_ARGS_METHOD(jint, AndroidHostInterface_getControllerVibrationMotorCount, jobject unused,
-                       jstring controller_type)
-{
-  std::optional<ControllerType> type =
-    Settings::ParseControllerTypeName(AndroidHelpers::JStringToString(env, controller_type).c_str());
-  if (!type)
-    return 0;
-
-  return static_cast<jint>(Controller::GetVibrationMotorCount(type.value()));
-}
-
-DEFINE_JNI_ARGS_METHOD(void, AndroidHostInterface_handleControllerButtonEvent, jobject obj, jint controller_index,
-                       jint button_index, jboolean pressed)
-{
-  AndroidHelpers::GetNativeClass(env, obj)->HandleControllerButtonEvent(static_cast<u32>(controller_index),
-                                                                        static_cast<u32>(button_index), pressed);
-}
-
-DEFINE_JNI_ARGS_METHOD(void, AndroidHostInterface_handleControllerAxisEvent, jobject obj, jint controller_index,
-                       jint axis_index, jfloat value)
-{
-  AndroidHelpers::GetNativeClass(env, obj)->HandleControllerAxisEvent(static_cast<u32>(controller_index),
-                                                                      static_cast<u32>(axis_index), value);
-}
-
-DEFINE_JNI_ARGS_METHOD(jboolean, AndroidHostInterface_hasControllerButtonBinding, jobject obj, jint controller_index,
-                       jint button_index)
-{
-  return AndroidHelpers::GetNativeClass(env, obj)->HasControllerButtonBinding(static_cast<u32>(controller_index),
-                                                                              static_cast<u32>(button_index));
-}
-
-DEFINE_JNI_ARGS_METHOD(jobjectArray, AndroidHostInterface_getInputProfileNames, jobject obj)
-{
-  AndroidHostInterface* hi = AndroidHelpers::GetNativeClass(env, obj);
-  return hi->GetInputProfileNames(env);
-}
-
-DEFINE_JNI_ARGS_METHOD(jboolean, AndroidHostInterface_loadInputProfile, jobject obj, jstring name)
-{
-  AndroidHostInterface* hi = AndroidHelpers::GetNativeClass(env, obj);
-  const std::string profile_name(AndroidHelpers::JStringToString(env, name));
-  if (profile_name.empty())
-    return false;
-
-  const std::string profile_path(hi->GetInputProfilePath(profile_name.c_str()));
-  if (profile_path.empty())
-    return false;
-
-  return hi->ApplyInputProfile(profile_path.c_str());
-}
-
-DEFINE_JNI_ARGS_METHOD(jboolean, AndroidHostInterface_saveInputProfile, jobject obj, jstring name)
-{
-  AndroidHostInterface* hi = AndroidHelpers::GetNativeClass(env, obj);
-  const std::string profile_name(AndroidHelpers::JStringToString(env, name));
-  if (profile_name.empty())
-    return false;
-
-  const std::string profile_path(hi->GetSavePathForInputProfile(profile_name.c_str()));
-  if (profile_path.empty())
-    return false;
-
-  return hi->SaveInputProfile(profile_path.c_str());
-}
-
-DEFINE_JNI_ARGS_METHOD(void, AndroidHostInterface_refreshGameList, jobject obj, jboolean invalidate_cache,
-                       jboolean invalidate_database, jobject progress_callback)
-{
-  AndroidProgressCallback cb(env, progress_callback);
-  AndroidHelpers::GetNativeClass(env, obj)->RefreshGameList(invalidate_cache, invalidate_database, &cb);
-}
-
-static const char* DiscRegionToString(DiscRegion region)
-{
-  static std::array<const char*, 4> names = {{"NTSC_J", "NTSC_U", "PAL", "Other"}};
-  return names[static_cast<int>(region)];
-}
-
-static jobject CreateGameListEntry(JNIEnv* env, AndroidHostInterface* hi, const GameListEntry& entry)
-{
-  const Timestamp modified_ts(
-    Timestamp::FromUnixTimestamp(static_cast<Timestamp::UnixTimestampValue>(entry.last_modified_time)));
-  const std::string cover_path_str(hi->GetGameList()->GetCoverImagePathForEntry(&entry));
-
-  jstring path = env->NewStringUTF(entry.path.c_str());
-  jstring code = env->NewStringUTF(entry.code.c_str());
-  jstring title = env->NewStringUTF(entry.title.c_str());
-  jstring region = env->NewStringUTF(DiscRegionToString(entry.region));
-  jstring type = env->NewStringUTF(GameList::EntryTypeToString(entry.type));
-  jstring compatibility_rating =
-    env->NewStringUTF(GameList::EntryCompatibilityRatingToString(entry.compatibility_rating));
-  jstring cover_path = (cover_path_str.empty()) ? nullptr : env->NewStringUTF(cover_path_str.c_str());
-  jstring modified_time = env->NewStringUTF(modified_ts.ToString("%Y/%m/%d, %H:%M:%S"));
-  jlong size = entry.total_size;
-
-  jobject entry_jobject = env->NewObject(s_GameListEntry_class, s_GameListEntry_constructor, path, code, title, size,
-                                         modified_time, region, type, compatibility_rating, cover_path);
-
-  env->DeleteLocalRef(modified_time);
-  if (cover_path)
-    env->DeleteLocalRef(cover_path);
-  env->DeleteLocalRef(compatibility_rating);
-  env->DeleteLocalRef(type);
-  env->DeleteLocalRef(region);
-  env->DeleteLocalRef(title);
-  env->DeleteLocalRef(code);
-  env->DeleteLocalRef(path);
-
-  return entry_jobject;
-}
-
-DEFINE_JNI_ARGS_METHOD(jarray, AndroidHostInterface_getGameListEntries, jobject obj)
-{
-  AndroidHostInterface* hi = AndroidHelpers::GetNativeClass(env, obj);
-  jobjectArray entry_array = env->NewObjectArray(hi->GetGameList()->GetEntryCount(), s_GameListEntry_class, nullptr);
-  Assert(entry_array != nullptr);
-
-  u32 counter = 0;
-  for (const GameListEntry& entry : hi->GetGameList()->GetEntries())
-  {
-    jobject entry_jobject = CreateGameListEntry(env, hi, entry);
-    env->SetObjectArrayElement(entry_array, counter++, entry_jobject);
-    env->DeleteLocalRef(entry_jobject);
-  }
-
-  return entry_array;
-}
-
-DEFINE_JNI_ARGS_METHOD(jobject, AndroidHostInterface_getGameListEntry, jobject obj, jstring path)
-{
-  AndroidHostInterface* hi = AndroidHelpers::GetNativeClass(env, obj);
-  const std::string path_str(AndroidHelpers::JStringToString(env, path));
-  const GameListEntry* entry = hi->GetGameList()->GetEntryForPath(path_str.c_str());
-  if (!entry)
-    return nullptr;
-
-  return CreateGameListEntry(env, hi, *entry);
-}
-
-DEFINE_JNI_ARGS_METHOD(jstring, AndroidHostInterface_getGameSettingValue, jobject obj, jstring path, jstring key)
-{
-  AndroidHostInterface* hi = AndroidHelpers::GetNativeClass(env, obj);
-  const std::string path_str(AndroidHelpers::JStringToString(env, path));
-  const std::string key_str(AndroidHelpers::JStringToString(env, key));
-
-  const GameListEntry* entry = hi->GetGameList()->GetEntryForPath(path_str.c_str());
-  if (!entry)
-    return nullptr;
-
-  std::optional<std::string> value = entry->settings.GetValueForKey(key_str);
-  if (!value.has_value())
-    return nullptr;
-  else
-    return env->NewStringUTF(value->c_str());
-}
-
-DEFINE_JNI_ARGS_METHOD(void, AndroidHostInterface_setGameSettingValue, jobject obj, jstring path, jstring key,
-                       jstring value)
-{
-  AndroidHostInterface* hi = AndroidHelpers::GetNativeClass(env, obj);
-  const std::string path_str(AndroidHelpers::JStringToString(env, path));
-  const std::string key_str(AndroidHelpers::JStringToString(env, key));
-
-  const GameListEntry* entry = hi->GetGameList()->GetEntryForPath(path_str.c_str());
-  if (!entry)
-    return;
-
-  GameSettings::Entry new_entry(entry->settings);
-
-  std::optional<std::string> value_str;
-  if (value)
-    value_str = AndroidHelpers::JStringToString(env, value);
-
-  new_entry.SetValueForKey(key_str, value_str);
-  hi->GetGameList()->UpdateGameSettings(path_str, entry->code, entry->title, new_entry, true);
-}
-
-DEFINE_JNI_ARGS_METHOD(jobjectArray, AndroidHostInterface_getHotkeyInfoList, jobject obj)
-{
-  jclass entry_class = env->FindClass("com/github/stenzek/duckstation/HotkeyInfo");
-  Assert(entry_class != nullptr);
-
-  jmethodID entry_constructor =
-    env->GetMethodID(entry_class, "<init>", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V");
-  Assert(entry_constructor != nullptr);
-
-  AndroidHostInterface* hi = AndroidHelpers::GetNativeClass(env, obj);
-  const CommonHostInterface::HotkeyInfoList& hotkeys = hi->GetHotkeyInfoList();
-  if (hotkeys.empty())
-    return nullptr;
-
-  jobjectArray entry_array = env->NewObjectArray(static_cast<jsize>(hotkeys.size()), entry_class, nullptr);
-  Assert(entry_array != nullptr);
-
-  u32 counter = 0;
-  for (const CommonHostInterface::HotkeyInfo& hk : hotkeys)
-  {
-    jstring category = env->NewStringUTF(hk.category.GetCharArray());
-    jstring name = env->NewStringUTF(hk.name.GetCharArray());
-    jstring display_name = env->NewStringUTF(hk.display_name.GetCharArray());
-
-    jobject entry_jobject = env->NewObject(entry_class, entry_constructor, category, name, display_name);
-
-    env->SetObjectArrayElement(entry_array, counter++, entry_jobject);
-    env->DeleteLocalRef(entry_jobject);
-    env->DeleteLocalRef(display_name);
-    env->DeleteLocalRef(name);
-    env->DeleteLocalRef(category);
-  }
-
-  return entry_array;
-}
-
-DEFINE_JNI_ARGS_METHOD(void, AndroidHostInterface_applySettings, jobject obj)
-{
-  AndroidHostInterface* hi = AndroidHelpers::GetNativeClass(env, obj);
-  if (hi->IsEmulationThreadRunning())
-  {
-    hi->RunOnEmulationThread([hi]() { hi->ApplySettings(false); });
-  }
-  else
-  {
-    hi->ApplySettings(false);
-  }
-}
-
-DEFINE_JNI_ARGS_METHOD(void, AndroidHostInterface_updateInputMap, jobject obj)
-{
-  AndroidHostInterface* hi = AndroidHelpers::GetNativeClass(env, obj);
-  if (hi->IsEmulationThreadRunning())
-  {
-    hi->RunOnEmulationThread([hi]() { hi->UpdateInputMap(); });
-  }
-  else
-  {
-    hi->UpdateInputMap();
-  }
-}
-
-DEFINE_JNI_ARGS_METHOD(void, AndroidHostInterface_resetSystem, jobject obj, jboolean global, jint slot)
-{
-  AndroidHostInterface* hi = AndroidHelpers::GetNativeClass(env, obj);
-  hi->RunOnEmulationThread([hi]() { hi->ResetSystem(); });
-}
-
-DEFINE_JNI_ARGS_METHOD(void, AndroidHostInterface_loadState, jobject obj, jboolean global, jint slot)
-{
-  AndroidHostInterface* hi = AndroidHelpers::GetNativeClass(env, obj);
-  hi->RunOnEmulationThread([hi, global, slot]() { hi->LoadState(global, slot); });
-}
-
-DEFINE_JNI_ARGS_METHOD(void, AndroidHostInterface_saveState, jobject obj, jboolean global, jint slot)
-{
-  AndroidHostInterface* hi = AndroidHelpers::GetNativeClass(env, obj);
-  hi->RunOnEmulationThread([hi, global, slot]() { hi->SaveState(global, slot); });
-}
-
-DEFINE_JNI_ARGS_METHOD(void, AndroidHostInterface_saveResumeState, jobject obj, jboolean wait_for_completion)
-{
-  if (!System::IsValid() || System::GetState() == System::State::Starting)
-  {
-    // This gets called when the surface is destroyed, which can happen while starting.
-    return;
-  }
-
-  AndroidHostInterface* hi = AndroidHelpers::GetNativeClass(env, obj);
-  hi->RunOnEmulationThread([hi]() { hi->SaveResumeSaveState(); }, wait_for_completion);
-}
-
-DEFINE_JNI_ARGS_METHOD(void, AndroidHostInterface_setDisplayAlignment, jobject obj, jint alignment)
-{
-  AndroidHostInterface* hi = AndroidHelpers::GetNativeClass(env, obj);
-  hi->RunOnEmulationThread(
-    [hi, alignment]() { hi->SetDisplayAlignment(static_cast<HostDisplay::Alignment>(alignment)); }, false);
-}
-
-DEFINE_JNI_ARGS_METHOD(bool, AndroidHostInterface_hasSurface, jobject obj)
-{
-  AndroidHostInterface* hi = AndroidHelpers::GetNativeClass(env, obj);
-  HostDisplay* display = hi->GetDisplay();
-  if (display)
-    return display->HasRenderSurface();
-  else
-    return false;
-}
-
-DEFINE_JNI_ARGS_METHOD(bool, AndroidHostInterface_isEmulationThreadPaused, jobject obj)
-{
-  AndroidHostInterface* hi = AndroidHelpers::GetNativeClass(env, obj);
-  return hi->IsEmulationThreadPaused();
-}
-
-DEFINE_JNI_ARGS_METHOD(void, AndroidHostInterface_pauseEmulationThread, jobject obj, jboolean paused)
-{
-  AndroidHostInterface* hi = AndroidHelpers::GetNativeClass(env, obj);
-  hi->PauseEmulationThread(paused);
-}
-
-DEFINE_JNI_ARGS_METHOD(jobject, AndroidHostInterface_getPatchCodeList, jobject obj)
-{
-  if (!System::IsValid())
-    return nullptr;
-
-  AndroidHostInterface* hi = AndroidHelpers::GetNativeClass(env, obj);
-  if (!System::HasCheatList())
-  {
-    // Hopefully this won't deadlock...
-    hi->RunOnEmulationThread(
-      [hi]() {
-        if (!hi->LoadCheatListFromGameTitle())
-          hi->LoadCheatListFromDatabase();
-      },
-      true);
-  }
-
-  if (!System::HasCheatList())
-    return nullptr;
-
-  CheatList* cl = System::GetCheatList();
-  const u32 count = cl->GetCodeCount();
-
-  jobjectArray arr = env->NewObjectArray(count, s_PatchCode_class, nullptr);
-  for (u32 i = 0; i < count; i++)
-  {
-    const CheatCode& cc = cl->GetCode(i);
-
-    jstring group_str = cc.group.empty() ? nullptr : env->NewStringUTF(cc.group.c_str());
-    jstring desc_str = env->NewStringUTF(cc.description.c_str());
-    jobject java_cc =
-      env->NewObject(s_PatchCode_class, s_PatchCode_constructor, static_cast<jint>(i), group_str, desc_str, cc.enabled);
-    env->SetObjectArrayElement(arr, i, java_cc);
-    env->DeleteLocalRef(java_cc);
-    env->DeleteLocalRef(desc_str);
-    env->DeleteLocalRef(group_str);
-  }
-
-  return arr;
-}
-
-DEFINE_JNI_ARGS_METHOD(jboolean, AndroidHostInterface_importPatchCodesFromString, jobject obj, jstring str)
-{
-  if (!System::IsValid())
-    return false;
-
-  AndroidHostInterface* hi = AndroidHelpers::GetNativeClass(env, obj);
-  return hi->ImportPatchCodesFromString(AndroidHelpers::JStringToString(env, str));
-}
-
-DEFINE_JNI_ARGS_METHOD(void, AndroidHostInterface_setPatchCodeEnabled, jobject obj, jint index, jboolean enabled)
-{
-  if (!System::IsValid() || !System::HasCheatList())
-    return;
-
-  AndroidHostInterface* hi = AndroidHelpers::GetNativeClass(env, obj);
-  hi->RunOnEmulationThread([index, enabled, hi]() { hi->SetCheatCodeState(static_cast<u32>(index), enabled, true); });
-}
-
-DEFINE_JNI_ARGS_METHOD(void, AndroidHostInterface_addOSDMessage, jobject obj, jstring message, jfloat duration)
-{
-  AndroidHostInterface* hi = AndroidHelpers::GetNativeClass(env, obj);
-  hi->AddOSDMessage(AndroidHelpers::JStringToString(env, message), duration);
-}
-
-DEFINE_JNI_ARGS_METHOD(jboolean, AndroidHostInterface_hasAnyBIOSImages, jobject obj)
-{
-  AndroidHostInterface* hi = AndroidHelpers::GetNativeClass(env, obj);
-  return hi->HasAnyBIOSImages();
-}
-
-DEFINE_JNI_ARGS_METHOD(jboolean, AndroidHostInterface_isFastForwardEnabled, jobject obj)
-{
-  return AndroidHelpers::GetNativeClass(env, obj)->IsRunningAtNonStandardSpeed();
-}
-
-DEFINE_JNI_ARGS_METHOD(void, AndroidHostInterface_setFastForwardEnabled, jobject obj, jboolean enabled)
-{
-  if (!System::IsValid())
-    return;
-
-  AndroidHostInterface* hi = AndroidHelpers::GetNativeClass(env, obj);
-  hi->RunOnEmulationThread([enabled, hi]() { hi->SetFastForwardEnabled(enabled); });
-}
-
-DEFINE_JNI_ARGS_METHOD(jstring, AndroidHostInterface_importBIOSImage, jobject obj, jbyteArray data)
-{
-  AndroidHostInterface* hi = AndroidHelpers::GetNativeClass(env, obj);
-
-  const jsize len = env->GetArrayLength(data);
-  if (len != BIOS::BIOS_SIZE)
-    return nullptr;
-
-  BIOS::Image image;
-  image.resize(static_cast<size_t>(len));
-  env->GetByteArrayRegion(data, 0, len, reinterpret_cast<jbyte*>(image.data()));
-
-  const BIOS::Hash hash = BIOS::GetHash(image);
-  const BIOS::ImageInfo* ii = BIOS::GetImageInfoForHash(hash);
-
-  const std::string dest_path(hi->GetUserDirectoryRelativePath("bios/%s.bin", hash.ToString().c_str()));
-  if (FileSystem::FileExists(dest_path.c_str()) ||
-      !FileSystem::WriteBinaryFile(dest_path.c_str(), image.data(), image.size()))
-  {
-    return nullptr;
-  }
-
-  if (ii)
-    return env->NewStringUTF(ii->description);
-  else
-    return env->NewStringUTF(hash.ToString().c_str());
-}
-
-DEFINE_JNI_ARGS_METHOD(jboolean, AndroidHostInterface_hasMediaSubImages, jobject obj)
-{
-  if (!System::IsValid())
-    return false;
-
-  return System::HasMediaSubImages();
-}
-
-DEFINE_JNI_ARGS_METHOD(jobjectArray, AndroidHostInterface_getMediaSubImageTitles, jobject obj)
-{
-  if (!System::IsValid())
-    return nullptr;
-
-  const u32 count = System::GetMediaSubImageCount();
-  if (count == 0)
-    return nullptr;
-
-  jobjectArray arr = env->NewObjectArray(static_cast<jsize>(count), s_String_class, nullptr);
-  for (u32 i = 0; i < count; i++)
-  {
-    jstring str = env->NewStringUTF(System::GetMediaSubImageTitle(i).c_str());
-    env->SetObjectArrayElement(arr, static_cast<jsize>(i), str);
-    env->DeleteLocalRef(str);
-  }
-
-  return arr;
-}
-
-DEFINE_JNI_ARGS_METHOD(jint, AndroidHostInterface_getMediaSubImageIndex, jobject obj)
-{
-  if (!System::IsValid())
-    return -1;
-
-  return System::GetMediaSubImageIndex();
-}
-
-DEFINE_JNI_ARGS_METHOD(jboolean, AndroidHostInterface_switchMediaSubImage, jobject obj, jint index)
-{
-  if (!System::IsValid() || index < 0 || static_cast<u32>(index) >= System::GetMediaSubImageCount())
-    return false;
-
-  AndroidHostInterface* hi = AndroidHelpers::GetNativeClass(env, obj);
-  hi->RunOnEmulationThread([index, hi]() {
-    if (System::IsValid())
-    {
-      if (!System::SwitchMediaSubImage(static_cast<u32>(index)))
-        hi->AddOSDMessage("Disc switch failed. Please make sure the file exists.");
-    }
-  });
-
-  return true;
-}
-
-DEFINE_JNI_ARGS_METHOD(jboolean, AndroidHostInterface_setMediaFilename, jstring obj, jstring filename)
-{
-  if (!System::IsValid() || !filename)
-    return false;
-
-  std::string filename_str(AndroidHelpers::JStringToString(env, filename));
-  AndroidHostInterface* hi = AndroidHelpers::GetNativeClass(env, obj);
-  hi->RunOnEmulationThread([filename_str, hi]() {
-    if (System::IsValid())
-    {
-      if (!System::InsertMedia(filename_str.c_str()))
-        hi->AddOSDMessage("Disc switch failed. Please make sure the file exists and is a supported disc image.");
-    }
-  });
-
-  return true;
-}
-
-static jobject CreateSaveStateInfo(JNIEnv* env, const CommonHostInterface::ExtendedSaveStateInfo& ssi)
-{
-  LocalRefHolder<jstring> path(env, env->NewStringUTF(ssi.path.c_str()));
-  LocalRefHolder<jstring> title(env, env->NewStringUTF(ssi.title.c_str()));
-  LocalRefHolder<jstring> code(env, env->NewStringUTF(ssi.game_code.c_str()));
-  LocalRefHolder<jstring> media_path(env, env->NewStringUTF(ssi.media_path.c_str()));
-  LocalRefHolder<jstring> timestamp(env, env->NewStringUTF(Timestamp::FromUnixTimestamp(ssi.timestamp).ToString("%c")));
-  LocalRefHolder<jbyteArray> screenshot_data;
-  if (!ssi.screenshot_data.empty())
-  {
-    const jsize data_size = static_cast<jsize>(ssi.screenshot_data.size() * sizeof(u32));
-    screenshot_data = LocalRefHolder<jbyteArray>(env, env->NewByteArray(data_size));
-    env->SetByteArrayRegion(screenshot_data.Get(), 0, data_size,
-                            reinterpret_cast<const jbyte*>(ssi.screenshot_data.data()));
-  }
-
-  return env->NewObject(s_SaveStateInfo_class, s_SaveStateInfo_constructor, path.Get(), title.Get(), code.Get(),
-                        media_path.Get(), timestamp.Get(), static_cast<jint>(ssi.slot),
-                        static_cast<jboolean>(ssi.global), static_cast<jint>(ssi.screenshot_width),
-                        static_cast<jint>(ssi.screenshot_height), screenshot_data.Get());
-}
-
-static jobject CreateEmptySaveStateInfo(JNIEnv* env, s32 slot, bool global)
-{
-  return env->NewObject(s_SaveStateInfo_class, s_SaveStateInfo_constructor, nullptr, nullptr, nullptr, nullptr, nullptr,
-                        static_cast<jint>(slot), static_cast<jboolean>(global), static_cast<jint>(0),
-                        static_cast<jint>(0), nullptr);
-}
-
-DEFINE_JNI_ARGS_METHOD(jobjectArray, AndroidHostInterface_getSaveStateInfo, jobject obj, jboolean includeEmpty)
-{
-  if (!System::IsValid())
-    return nullptr;
-
-  AndroidHostInterface* hi = AndroidHelpers::GetNativeClass(env, obj);
-  std::vector<jobject> infos;
-
-  // +1 for the quick save only in android.
-  infos.reserve(1 + CommonHostInterface::PER_GAME_SAVE_STATE_SLOTS + CommonHostInterface::GLOBAL_SAVE_STATE_SLOTS);
-
-  const std::string& game_code = System::GetRunningCode();
-  if (!game_code.empty())
-  {
-    for (u32 i = 0; i <= CommonHostInterface::PER_GAME_SAVE_STATE_SLOTS; i++)
-    {
-      std::optional<CommonHostInterface::ExtendedSaveStateInfo> esi =
-        hi->GetExtendedSaveStateInfo(game_code.c_str(), static_cast<s32>(i));
-      if (esi.has_value())
-      {
-        jobject obj = CreateSaveStateInfo(env, esi.value());
-        if (obj)
-          infos.push_back(obj);
-      }
-      else if (includeEmpty)
-      {
-        jobject obj = CreateEmptySaveStateInfo(env, static_cast<s32>(i), false);
-        if (obj)
-          infos.push_back(obj);
-      }
-    }
-  }
-
-  for (u32 i = 1; i <= CommonHostInterface::GLOBAL_SAVE_STATE_SLOTS; i++)
-  {
-    std::optional<CommonHostInterface::ExtendedSaveStateInfo> esi =
-      hi->GetExtendedSaveStateInfo(nullptr, static_cast<s32>(i));
-    if (esi.has_value())
-    {
-      jobject obj = CreateSaveStateInfo(env, esi.value());
-      if (obj)
-        infos.push_back(obj);
-    }
-    else if (includeEmpty)
-    {
-      jobject obj = CreateEmptySaveStateInfo(env, static_cast<s32>(i), true);
-      if (obj)
-        infos.push_back(obj);
-    }
-  }
-
-  if (infos.empty())
-    return nullptr;
-
-  jobjectArray ret = env->NewObjectArray(static_cast<jsize>(infos.size()), s_SaveStateInfo_class, nullptr);
-  for (size_t i = 0; i < infos.size(); i++)
-  {
-    env->SetObjectArrayElement(ret, static_cast<jsize>(i), infos[i]);
-    env->DeleteLocalRef(infos[i]);
-  }
-
-  return ret;
-}
-
-DEFINE_JNI_ARGS_METHOD(void, AndroidHostInterface_toggleControllerAnalogMode, jobject obj)
-{
-  // hacky way to toggle analog mode
-  for (u32 i = 0; i < NUM_CONTROLLER_AND_CARD_PORTS; i++)
-  {
-    Controller* ctrl = System::GetController(i);
-    if (!ctrl)
-      continue;
-
-    std::optional<s32> code = Controller::GetButtonCodeByName(ctrl->GetType(), "Analog");
-    if (!code.has_value())
-      continue;
-
-    ctrl->SetButtonState(code.value(), true);
-    ctrl->SetButtonState(code.value(), false);
-  }
-}
-
-DEFINE_JNI_ARGS_METHOD(void, AndroidHostInterface_setFullscreenUINotificationVerticalPosition, jobject obj,
-                       jfloat position, jfloat direction)
-{
-  AndroidHostInterface* hi = AndroidHelpers::GetNativeClass(env, obj);
-  hi->RunOnEmulationThread(
-    [position, direction]() { ImGuiFullscreen::SetNotificationVerticalPosition(position, direction); });
-}
-
-DEFINE_JNI_ARGS_METHOD(jboolean, AndroidHostInterface_isCheevosActive, jobject obj)
-{
-  return Cheevos::IsActive();
-}
-
-DEFINE_JNI_ARGS_METHOD(jboolean, AndroidHostInterface_isCheevosChallengeModeActive, jobject obj)
-{
-  return Cheevos::IsChallengeModeActive();
-}
-
-DEFINE_JNI_ARGS_METHOD(jobjectArray, AndroidHostInterface_getCheevoList, jobject obj)
-{
-  if (!Cheevos::IsActive())
-    return nullptr;
-
-  std::vector<jobject> cheevos;
-  Cheevos::EnumerateAchievements([env, &cheevos](const Cheevos::Achievement& cheevo) {
-    jstring title = env->NewStringUTF(cheevo.title.c_str());
-    jstring description = env->NewStringUTF(cheevo.description.c_str());
-    jstring locked_badge_path =
-      cheevo.locked_badge_path.empty() ? nullptr : env->NewStringUTF(cheevo.locked_badge_path.c_str());
-    jstring unlocked_badge_path =
-      cheevo.unlocked_badge_path.empty() ? nullptr : env->NewStringUTF(cheevo.unlocked_badge_path.c_str());
-
-    jobject object = env->NewObject(s_Achievement_class, s_Achievement_constructor, static_cast<jint>(cheevo.id), title,
-                                    description, locked_badge_path, unlocked_badge_path,
-                                    static_cast<jint>(cheevo.points), static_cast<jboolean>(cheevo.locked));
-    cheevos.push_back(object);
-
-    if (unlocked_badge_path)
-      env->DeleteLocalRef(unlocked_badge_path);
-    if (locked_badge_path)
-      env->DeleteLocalRef(locked_badge_path);
-    env->DeleteLocalRef(description);
-    env->DeleteLocalRef(title);
-    return true;
-  });
-
-  if (cheevos.empty())
-    return nullptr;
-
-  jobjectArray ret = env->NewObjectArray(static_cast<jsize>(cheevos.size()), s_Achievement_class, nullptr);
-  for (size_t i = 0; i < cheevos.size(); i++)
-  {
-    env->SetObjectArrayElement(ret, static_cast<jsize>(i), cheevos[i]);
-    env->DeleteLocalRef(cheevos[i]);
-  }
-
-  return ret;
-}
-
-DEFINE_JNI_ARGS_METHOD(jint, AndroidHostInterface_getCheevoCount, jobject obj)
-{
-  return Cheevos::GetAchievementCount();
-}
-
-DEFINE_JNI_ARGS_METHOD(jint, AndroidHostInterface_getUnlockedCheevoCount, jobject obj)
-{
-  return Cheevos::GetUnlockedAchiementCount();
-}
-
-DEFINE_JNI_ARGS_METHOD(jint, AndroidHostInterface_getCheevoPointsForGame, jobject obj)
-{
-  return Cheevos::GetCurrentPointsForGame();
-}
-
-DEFINE_JNI_ARGS_METHOD(jint, AndroidHostInterface_getCheevoMaximumPointsForGame, jobject obj)
-{
-  return Cheevos::GetMaximumPointsForGame();
-}
-
-DEFINE_JNI_ARGS_METHOD(jstring, AndroidHostInterface_getCheevoGameTitle, jobject obj)
-{
-  const std::string& title = Cheevos::GetGameTitle();
-  return title.empty() ? nullptr : env->NewStringUTF(title.c_str());
-}
-
-DEFINE_JNI_ARGS_METHOD(jstring, AndroidHostInterface_getCheevoGameIconPath, jobject obj)
-{
-  const std::string& path = Cheevos::GetGameIcon();
-  return path.empty() ? nullptr : env->NewStringUTF(path.c_str());
-}
-
-DEFINE_JNI_ARGS_METHOD(jboolean, AndroidHostInterface_cheevosLogin, jobject obj, jstring username, jstring password)
-{
-  const std::string username_str(AndroidHelpers::JStringToString(env, username));
-  const std::string password_str(AndroidHelpers::JStringToString(env, password));
-  return Cheevos::Login(username_str.c_str(), password_str.c_str());
-}
-
-DEFINE_JNI_ARGS_METHOD(void, AndroidHostInterface_cheevosLogout, jobject obj)
-{
-  return Cheevos::Logout();
-}
-
-static_assert(sizeof(MemoryCardImage::DataArray) == MemoryCardImage::DATA_SIZE);
-
-static MemoryCardImage::DataArray* GetMemoryCardData(JNIEnv* env, jbyteArray obj)
-{
-  if (!obj || env->GetArrayLength(obj) != MemoryCardImage::DATA_SIZE)
-    return nullptr;
-
-  return reinterpret_cast<MemoryCardImage::DataArray*>(env->GetByteArrayElements(obj, nullptr));
-}
-
-static void ReleaseMemoryCardData(JNIEnv* env, jbyteArray obj, MemoryCardImage::DataArray* data)
-{
-  env->ReleaseByteArrayElements(obj, reinterpret_cast<jbyte*>(data), 0);
-}
-
-DEFINE_JNI_ARGS_METHOD(jboolean, MemoryCardImage_isValid, jclass clazz, jbyteArray obj)
-{
-  MemoryCardImage::DataArray* data = GetMemoryCardData(env, obj);
-  if (!data)
-    return false;
-
-  const bool res = MemoryCardImage::IsValid(*data);
-  ReleaseMemoryCardData(env, obj, data);
-  return res;
-}
-
-DEFINE_JNI_ARGS_METHOD(void, MemoryCardImage_format, jclass clazz, jbyteArray obj)
-{
-  MemoryCardImage::DataArray* data = GetMemoryCardData(env, obj);
-  if (!data)
-    return;
-
-  MemoryCardImage::Format(data);
-  ReleaseMemoryCardData(env, obj, data);
-}
-
-DEFINE_JNI_ARGS_METHOD(jint, MemoryCardImage_getFreeBlocks, jclass clazz, jbyteArray obj)
-{
-  MemoryCardImage::DataArray* data = GetMemoryCardData(env, obj);
-  if (!data)
-    return 0;
-
-  const u32 free_blocks = MemoryCardImage::GetFreeBlockCount(*data);
-  ReleaseMemoryCardData(env, obj, data);
-  return free_blocks;
-}
-
-DEFINE_JNI_ARGS_METHOD(jobjectArray, MemoryCardImage_getFiles, jclass clazz, jbyteArray obj)
-{
-  MemoryCardImage::DataArray* data = GetMemoryCardData(env, obj);
-  if (!data)
-    return nullptr;
-
-  const std::vector<MemoryCardImage::FileInfo> files(MemoryCardImage::EnumerateFiles(*data));
-
-  std::vector<jobject> file_objects;
-  file_objects.reserve(files.size());
-
-  jclass byteArrayClass = env->FindClass("[B");
-
-  for (const MemoryCardImage::FileInfo& file : files)
-  {
-    jobject filename = env->NewStringUTF(file.filename.c_str());
-    jobject title = env->NewStringUTF(file.title.c_str());
-    jobjectArray frames = nullptr;
-    if (!file.icon_frames.empty())
-    {
-      frames = env->NewObjectArray(static_cast<jint>(file.icon_frames.size()), byteArrayClass, nullptr);
-      for (jsize i = 0; i < static_cast<jsize>(file.icon_frames.size()); i++)
-      {
-        static constexpr jsize frame_size = MemoryCardImage::ICON_WIDTH * MemoryCardImage::ICON_HEIGHT * sizeof(u32);
-        jbyteArray frame_data = env->NewByteArray(frame_size);
-        jbyte* frame_data_ptr = env->GetByteArrayElements(frame_data, nullptr);
-        std::memcpy(frame_data_ptr, file.icon_frames[i].pixels, frame_size);
-        env->ReleaseByteArrayElements(frame_data, frame_data_ptr, 0);
-        env->SetObjectArrayElement(frames, i, frame_data);
-        env->DeleteLocalRef(frame_data);
-      }
-    }
-
-    file_objects.push_back(env->NewObject(s_MemoryCardFileInfo_class, s_MemoryCardFileInfo_constructor, filename, title,
-                                          static_cast<jint>(file.size), static_cast<jint>(file.first_block),
-                                          static_cast<int>(file.num_blocks), frames));
-
-    env->DeleteLocalRef(frames);
-    env->DeleteLocalRef(title);
-    env->DeleteLocalRef(filename);
-  }
-
-  jobjectArray file_object_array =
-    AndroidHelpers::CreateObjectArray(env, s_MemoryCardFileInfo_class, file_objects.data(), file_objects.size(), true);
-  ReleaseMemoryCardData(env, obj, data);
-  return file_object_array;
-}
-
-DEFINE_JNI_ARGS_METHOD(jboolean, MemoryCardImage_hasFile, jclass clazz, jbyteArray obj, jstring filename)
-{
-  MemoryCardImage::DataArray* data = GetMemoryCardData(env, obj);
-  if (!data)
-    return false;
-
-  const std::string filename_str(AndroidHelpers::JStringToString(env, filename));
-  bool result = false;
-  if (!filename_str.empty())
-  {
-    const std::vector<MemoryCardImage::FileInfo> files(MemoryCardImage::EnumerateFiles(*data));
-    result = std::any_of(files.begin(), files.end(),
-                         [&filename_str](const MemoryCardImage::FileInfo& fi) { return fi.filename == filename_str; });
-  }
-
-  ReleaseMemoryCardData(env, obj, data);
-  return result;
-}
-
-DEFINE_JNI_ARGS_METHOD(jbyteArray, MemoryCardImage_readFile, jclass clazz, jbyteArray obj, jstring filename)
-{
-  MemoryCardImage::DataArray* data = GetMemoryCardData(env, obj);
-  if (!data)
-    return nullptr;
-
-  const std::string filename_str(AndroidHelpers::JStringToString(env, filename));
-  jbyteArray ret = nullptr;
-  if (!filename_str.empty())
-  {
-    const std::vector<MemoryCardImage::FileInfo> files(MemoryCardImage::EnumerateFiles(*data));
-    auto iter = std::find_if(files.begin(), files.end(), [&filename_str](const MemoryCardImage::FileInfo& fi) {
-      return fi.filename == filename_str;
-    });
-    if (iter != files.end())
-    {
-      std::vector<u8> file_data;
-      if (MemoryCardImage::ReadFile(*data, *iter, &file_data))
-        ret = AndroidHelpers::VectorToByteArray(env, file_data);
-    }
-  }
-
-  ReleaseMemoryCardData(env, obj, data);
-  return ret;
-}
-
-DEFINE_JNI_ARGS_METHOD(jboolean, MemoryCardImage_writeFile, jclass clazz, jbyteArray obj, jstring filename,
-                       jbyteArray file_data)
-{
-  MemoryCardImage::DataArray* data = GetMemoryCardData(env, obj);
-  if (!data)
-    return false;
-
-  const std::string filename_str(AndroidHelpers::JStringToString(env, filename));
-  const std::vector<u8> file_data_vec(AndroidHelpers::ByteArrayToVector(env, file_data));
-  bool ret = false;
-  if (!filename_str.empty())
-    ret = MemoryCardImage::WriteFile(data, filename_str, file_data_vec);
-
-  ReleaseMemoryCardData(env, obj, data);
-  return ret;
-}
-
-DEFINE_JNI_ARGS_METHOD(jboolean, MemoryCardImage_deleteFile, jclass clazz, jbyteArray obj, jstring filename)
-{
-  MemoryCardImage::DataArray* data = GetMemoryCardData(env, obj);
-  if (!data)
-    return false;
-
-  const std::string filename_str(AndroidHelpers::JStringToString(env, filename));
-  bool ret = false;
-
-  if (!filename_str.empty())
-  {
-    const std::vector<MemoryCardImage::FileInfo> files(MemoryCardImage::EnumerateFiles(*data));
-    auto iter = std::find_if(files.begin(), files.end(), [&filename_str](const MemoryCardImage::FileInfo& fi) {
-      return fi.filename == filename_str;
-    });
-
-    if (iter != files.end())
-      ret = MemoryCardImage::DeleteFile(data, *iter);
-  }
-
-  ReleaseMemoryCardData(env, obj, data);
-  return ret;
-}
-
-DEFINE_JNI_ARGS_METHOD(jboolean, MemoryCardImage_importCard, jclass clazz, jbyteArray obj, jstring filename,
-                       jbyteArray import_data)
-{
-  MemoryCardImage::DataArray* data = GetMemoryCardData(env, obj);
-  if (!data)
-    return false;
-
-  const std::string filename_str(AndroidHelpers::JStringToString(env, filename));
-  std::vector<u8> import_data_vec(AndroidHelpers::ByteArrayToVector(env, import_data));
-  bool ret = false;
-  if (!filename_str.empty() && !import_data_vec.empty())
-    ret = MemoryCardImage::ImportCard(data, filename_str.c_str(), std::move(import_data_vec));
-
-  ReleaseMemoryCardData(env, obj, data);
-  return ret;
-}
\ No newline at end of file
diff --git a/android/app/src/cpp/android_host_interface.h b/android/app/src/cpp/android_host_interface.h
deleted file mode 100644
index 99f91b5f2..000000000
--- a/android/app/src/cpp/android_host_interface.h
+++ /dev/null
@@ -1,171 +0,0 @@
-#pragma once
-#include "android_settings_interface.h"
-#include "common/byte_stream.h"
-#include "common/event.h"
-#include "common/progress_callback.h"
-#include "core/host_display.h"
-#include "frontend-common/common_host_interface.h"
-#include <array>
-#include <atomic>
-#include <condition_variable>
-#include <functional>
-#include <jni.h>
-#include <memory>
-#include <string>
-#include <thread>
-
-struct ANativeWindow;
-
-class Controller;
-
-class AndroidHostInterface final : public CommonHostInterface
-{
-public:
-  using CommonHostInterface::UpdateInputMap;
-
-  AndroidHostInterface(jobject java_object, jobject context_object, std::string user_directory);
-  ~AndroidHostInterface() override;
-
-  ALWAYS_INLINE ANativeWindow* GetSurface() const { return m_surface; }
-
-  bool Initialize() override;
-  void Shutdown() override;
-
-  const char* GetFrontendName() const override;
-  void RequestExit() override;
-  void RunLater(std::function<void()> func) override;
-
-  void ReportError(const char* message) override;
-  void ReportMessage(const char* message) override;
-
-  std::unique_ptr<ByteStream> OpenPackageFile(const char* path, u32 flags) override;
-
-  bool IsEmulationThreadRunning() const { return m_emulation_thread_running.load(); }
-  bool IsEmulationThreadPaused() const;
-  bool IsOnEmulationThread() const;
-  void RunOnEmulationThread(std::function<void()> function, bool blocking = false);
-  void PauseEmulationThread(bool paused);
-  void StopEmulationThreadLoop();
-
-  void EmulationThreadEntryPoint(JNIEnv* env, jobject emulation_activity, SystemBootParameters boot_params,
-                                 bool resume_state);
-
-  void SurfaceChanged(ANativeWindow* surface, int format, int width, int height);
-  void SetDisplayAlignment(HostDisplay::Alignment alignment);
-
-  void SetControllerButtonState(u32 index, s32 button_code, bool pressed);
-  void SetControllerAxisState(u32 index, s32 button_code, float value);
-  void HandleControllerButtonEvent(u32 controller_index, u32 button_index, bool pressed);
-  void HandleControllerAxisEvent(u32 controller_index, u32 axis_index, float value);
-  bool HasControllerButtonBinding(u32 controller_index, u32 button);
-  void SetControllerVibration(u32 controller_index, float small_motor, float large_motor);
-  void SetFastForwardEnabled(bool enabled);
-
-  void RefreshGameList(bool invalidate_cache, bool invalidate_database, ProgressCallback* progress_callback);
-
-  bool ImportPatchCodesFromString(const std::string& str);
-
-  jobjectArray GetInputProfileNames(JNIEnv* env) const;
-
-protected:
-  void SetUserDirectory() override;
-  void RegisterHotkeys() override;
-
-  bool AcquireHostDisplay() override;
-  void ReleaseHostDisplay() override;
-  std::unique_ptr<AudioStream> CreateAudioStream(AudioBackend backend) override;
-  void UpdateControllerInterface() override;
-
-  void OnSystemPaused(bool paused) override;
-  void OnSystemDestroyed() override;
-  void OnRunningGameChanged(const std::string& path, CDImage* image, const std::string& game_code,
-                            const std::string& game_title) override;
-
-private:
-  void EmulationThreadLoop(JNIEnv* env);
-
-  void LoadSettings(SettingsInterface& si) override;
-  void UpdateInputMap(SettingsInterface& si) override;
-  void SetVibration(bool enabled);
-  void UpdateVibration();
-  float GetRefreshRate() const;
-  float GetSurfaceScale(int width, int height) const;
-
-  jobject m_java_object = {};
-  jobject m_emulation_activity_object = {};
-
-  ANativeWindow* m_surface = nullptr;
-
-  std::mutex m_mutex;
-  std::condition_variable m_sleep_cv;
-  std::deque<std::function<void()>> m_callback_queue;
-  std::atomic_bool m_callbacks_outstanding{false};
-
-  std::atomic_bool m_emulation_thread_stop_request{false};
-  std::atomic_bool m_emulation_thread_running{false};
-  std::thread::id m_emulation_thread_id{};
-
-  HostDisplay::Alignment m_display_alignment = HostDisplay::Alignment::Center;
-
-  u64 m_last_vibration_update_time = 0;
-  bool m_last_vibration_state = false;
-  bool m_vibration_enabled = false;
-};
-
-namespace AndroidHelpers {
-
-JavaVM* GetJavaVM();
-JNIEnv* GetJNIEnv();
-AndroidHostInterface* GetNativeClass(JNIEnv* env, jobject obj);
-std::string JStringToString(JNIEnv* env, jstring str);
-std::unique_ptr<GrowableMemoryByteStream> ReadInputStreamToMemory(JNIEnv* env, jobject obj, u32 chunk_size = 65536);
-jclass GetStringClass();
-std::vector<u8> ByteArrayToVector(JNIEnv* env, jbyteArray obj);
-jbyteArray NewByteArray(JNIEnv* env, const void* data, size_t size);
-jbyteArray VectorToByteArray(JNIEnv* env, const std::vector<u8>& data);
-jobjectArray CreateObjectArray(JNIEnv* env, jclass object_class, const jobject* objects, size_t num_objects,
-                               bool release_refs = false);
-} // namespace AndroidHelpers
-
-template<typename T>
-class LocalRefHolder
-{
-public:
-  LocalRefHolder() : m_env(nullptr), m_object(nullptr) {}
-
-  LocalRefHolder(JNIEnv* env, T object) : m_env(env), m_object(object) {}
-
-  LocalRefHolder(const LocalRefHolder<T>&) = delete;
-  LocalRefHolder(LocalRefHolder&& move) : m_env(move.m_env), m_object(move.m_object)
-  {
-    move.m_env = nullptr;
-    move.m_object = {};
-  }
-
-  ~LocalRefHolder()
-  {
-    if (m_object)
-      m_env->DeleteLocalRef(m_object);
-  }
-
-  operator T() const { return m_object; }
-  T operator*() const { return m_object; }
-
-  LocalRefHolder& operator=(const LocalRefHolder&) = delete;
-  LocalRefHolder& operator=(LocalRefHolder&& move)
-  {
-    if (m_object)
-      m_env->DeleteLocalRef(m_object);
-    m_env = move.m_env;
-    m_object = move.m_object;
-    move.m_env = nullptr;
-    move.m_object = {};
-    return *this;
-  }
-
-  T Get() const { return m_object; }
-
-private:
-  JNIEnv* m_env;
-  T m_object;
-};
diff --git a/android/app/src/cpp/android_http_downloader.cpp b/android/app/src/cpp/android_http_downloader.cpp
deleted file mode 100644
index d1f462641..000000000
--- a/android/app/src/cpp/android_http_downloader.cpp
+++ /dev/null
@@ -1,167 +0,0 @@
-#include "android_http_downloader.h"
-#include "android_host_interface.h"
-#include "common/assert.h"
-#include "common/log.h"
-#include "common/string_util.h"
-#include "common/timer.h"
-#include <algorithm>
-#include <functional>
-Log_SetChannel(AndroidHTTPDownloader);
-
-namespace FrontendCommon {
-
-AndroidHTTPDownloader::AndroidHTTPDownloader() : HTTPDownloader() {}
-
-AndroidHTTPDownloader::~AndroidHTTPDownloader()
-{
-  JNIEnv* env = AndroidHelpers::GetJNIEnv();
-  if (m_URLDownloader_class)
-    env->DeleteGlobalRef(m_URLDownloader_class);
-}
-
-std::unique_ptr<HTTPDownloader> HTTPDownloader::Create(const char* user_agent)
-{
-  std::unique_ptr<AndroidHTTPDownloader> instance(std::make_unique<AndroidHTTPDownloader>());
-  if (!instance->Initialize(user_agent))
-    return {};
-
-  return instance;
-}
-
-bool AndroidHTTPDownloader::Initialize(const char* user_agent)
-{
-  JNIEnv* env = AndroidHelpers::GetJNIEnv();
-  jclass klass = env->FindClass("com/github/stenzek/duckstation/URLDownloader");
-  if (!klass)
-    return false;
-
-  m_URLDownloader_class = static_cast<jclass>(env->NewGlobalRef(klass));
-  if (!m_URLDownloader_class)
-    return false;
-
-  m_URLDownloader_constructor = env->GetMethodID(klass, "<init>", "(Ljava/lang/String;)V");
-  m_URLDownloader_get = env->GetMethodID(klass, "get", "(Ljava/lang/String;)Z");
-  m_URLDownloader_post = env->GetMethodID(klass, "post", "(Ljava/lang/String;[B)Z");
-  m_URLDownloader_getStatusCode = env->GetMethodID(klass, "getStatusCode", "()I");
-  m_URLDownloader_getData = env->GetMethodID(klass, "getData", "()[B");
-  if (!m_URLDownloader_constructor || !m_URLDownloader_get || !m_URLDownloader_post || !m_URLDownloader_getStatusCode ||
-      !m_URLDownloader_getData)
-  {
-    return false;
-  }
-
-  m_user_agent = user_agent;
-  m_thread_pool = std::make_unique<cb::ThreadPool>(m_max_active_requests);
-  return true;
-}
-
-void AndroidHTTPDownloader::ProcessRequest(Request* req)
-{
-  std::unique_lock<std::mutex> cancel_lock(m_cancel_mutex);
-  if (req->closed.load())
-    return;
-
-  cancel_lock.unlock();
-  req->status_code = -1;
-  req->start_time = Common::Timer::GetValue();
-
-  // TODO: Move to Java side...
-  JNIEnv* env;
-  if (AndroidHelpers::GetJavaVM()->AttachCurrentThread(&env, nullptr) == JNI_OK)
-  {
-    jstring url_string = env->NewStringUTF(req->url.c_str());
-    jstring user_agent_string = env->NewStringUTF(m_user_agent.c_str());
-
-    jobject obj = env->NewObject(m_URLDownloader_class, m_URLDownloader_constructor, user_agent_string);
-    jboolean result;
-    if (req->post_data.empty())
-    {
-      result = env->CallBooleanMethod(obj, m_URLDownloader_get, url_string);
-    }
-    else
-    {
-      jbyteArray post_data = env->NewByteArray(static_cast<jsize>(req->post_data.size()));
-      env->SetByteArrayRegion(post_data, 0, static_cast<jsize>(req->post_data.size()),
-                              reinterpret_cast<const jbyte*>(req->post_data.data()));
-      result = env->CallBooleanMethod(obj, m_URLDownloader_post, url_string, post_data);
-      env->DeleteLocalRef(post_data);
-    }
-
-    env->DeleteLocalRef(url_string);
-    env->DeleteLocalRef(user_agent_string);
-
-    if (result)
-    {
-      req->status_code = env->CallIntMethod(obj, m_URLDownloader_getStatusCode);
-
-      jbyteArray data = reinterpret_cast<jbyteArray>(env->CallObjectMethod(obj, m_URLDownloader_getData));
-      if (data)
-      {
-        const u32 size = static_cast<u32>(env->GetArrayLength(data));
-        req->data.resize(size);
-        if (size > 0)
-        {
-          jbyte* data_ptr = env->GetByteArrayElements(data, nullptr);
-          std::memcpy(req->data.data(), data_ptr, size);
-          env->ReleaseByteArrayElements(data, data_ptr, 0);
-        }
-
-        env->DeleteLocalRef(data);
-      }
-
-      Log_DevPrintf("Request for '%s' returned status code %d and %zu bytes", req->url.c_str(), req->status_code,
-                    req->data.size());
-    }
-    else
-    {
-      Log_ErrorPrintf("Request for '%s' failed", req->url.c_str());
-    }
-
-    env->DeleteLocalRef(obj);
-    AndroidHelpers::GetJavaVM()->DetachCurrentThread();
-  }
-  else
-  {
-    Log_ErrorPrintf("AttachCurrentThread() failed");
-  }
-
-  cancel_lock.lock();
-  req->state = Request::State::Complete;
-  if (req->closed.load())
-    delete req;
-  else
-    req->closed.store(true);
-}
-
-HTTPDownloader::Request* AndroidHTTPDownloader::InternalCreateRequest()
-{
-  Request* req = new Request();
-  return req;
-}
-
-void AndroidHTTPDownloader::InternalPollRequests()
-{
-  // noop - uses thread pool
-}
-
-bool AndroidHTTPDownloader::StartRequest(HTTPDownloader::Request* request)
-{
-  Request* req = static_cast<Request*>(request);
-  Log_DevPrintf("Started HTTP request for '%s'", req->url.c_str());
-  req->state = Request::State::Started;
-  req->start_time = Common::Timer::GetValue();
-  m_thread_pool->Schedule(std::bind(&AndroidHTTPDownloader::ProcessRequest, this, req));
-  return true;
-}
-
-void AndroidHTTPDownloader::CloseRequest(HTTPDownloader::Request* request)
-{
-  std::unique_lock<std::mutex> cancel_lock(m_cancel_mutex);
-  Request* req = static_cast<Request*>(request);
-  if (req->closed.load())
-    delete req;
-  else
-    req->closed.store(true);
-}
-
-} // namespace FrontendCommon
diff --git a/android/app/src/cpp/android_http_downloader.h b/android/app/src/cpp/android_http_downloader.h
deleted file mode 100644
index b5774846b..000000000
--- a/android/app/src/cpp/android_http_downloader.h
+++ /dev/null
@@ -1,45 +0,0 @@
-#pragma once
-#include "common/thirdparty/thread_pool.h"
-#include "frontend-common/http_downloader.h"
-#include <atomic>
-#include <jni.h>
-#include <memory>
-#include <mutex>
-
-namespace FrontendCommon {
-
-class AndroidHTTPDownloader final : public HTTPDownloader
-{
-public:
-  AndroidHTTPDownloader();
-  ~AndroidHTTPDownloader() override;
-
-  bool Initialize(const char* user_agent);
-
-protected:
-  Request* InternalCreateRequest() override;
-  void InternalPollRequests() override;
-  bool StartRequest(HTTPDownloader::Request* request) override;
-  void CloseRequest(HTTPDownloader::Request* request) override;
-
-private:
-  struct Request : HTTPDownloader::Request
-  {
-    std::atomic_bool closed{false};
-  };
-
-  void ProcessRequest(Request* req);
-
-  std::string m_user_agent;
-  std::unique_ptr<cb::ThreadPool> m_thread_pool;
-  std::mutex m_cancel_mutex;
-
-  jclass m_URLDownloader_class = nullptr;
-  jmethodID m_URLDownloader_constructor = nullptr;
-  jmethodID m_URLDownloader_get = nullptr;
-  jmethodID m_URLDownloader_post = nullptr;
-  jmethodID m_URLDownloader_getStatusCode = nullptr;
-  jmethodID m_URLDownloader_getData = nullptr;
-};
-
-} // namespace FrontendCommon
diff --git a/android/app/src/cpp/android_progress_callback.cpp b/android/app/src/cpp/android_progress_callback.cpp
deleted file mode 100644
index a25d02624..000000000
--- a/android/app/src/cpp/android_progress_callback.cpp
+++ /dev/null
@@ -1,113 +0,0 @@
-#include "android_progress_callback.h"
-#include "android_host_interface.h"
-#include "common/assert.h"
-#include "common/log.h"
-Log_SetChannel(AndroidProgressCallback);
-
-AndroidProgressCallback::AndroidProgressCallback(JNIEnv* env, jobject java_object) : m_java_object(java_object)
-{
-  jclass cls = env->GetObjectClass(java_object);
-  m_set_title_method = env->GetMethodID(cls, "setTitle", "(Ljava/lang/String;)V");
-  m_set_status_text_method = env->GetMethodID(cls, "setStatusText", "(Ljava/lang/String;)V");
-  m_set_progress_range_method = env->GetMethodID(cls, "setProgressRange", "(I)V");
-  m_set_progress_value_method = env->GetMethodID(cls, "setProgressValue", "(I)V");
-  m_modal_error_method = env->GetMethodID(cls, "modalError", "(Ljava/lang/String;)V");
-  m_modal_information_method = env->GetMethodID(cls, "modalInformation", "(Ljava/lang/String;)V");
-  m_modal_confirmation_method = env->GetMethodID(cls, "modalConfirmation", "(Ljava/lang/String;)Z");
-  Assert(m_set_status_text_method && m_set_progress_range_method && m_set_progress_value_method &&
-         m_modal_error_method && m_modal_information_method && m_modal_confirmation_method);
-}
-
-AndroidProgressCallback::~AndroidProgressCallback() = default;
-
-bool AndroidProgressCallback::IsCancelled() const
-{
-  return false;
-}
-
-void AndroidProgressCallback::SetCancellable(bool cancellable)
-{
-  if (m_cancellable == cancellable)
-    return;
-
-  BaseProgressCallback::SetCancellable(cancellable);
-}
-
-void AndroidProgressCallback::SetTitle(const char* title)
-{
-  Assert(title);
-  JNIEnv* env = AndroidHelpers::GetJNIEnv();
-  LocalRefHolder<jstring> text_jstr(env, env->NewStringUTF(title));
-  env->CallVoidMethod(m_java_object, m_set_title_method, text_jstr.Get());
-}
-
-void AndroidProgressCallback::SetStatusText(const char* text)
-{
-  Assert(text);
-  JNIEnv* env = AndroidHelpers::GetJNIEnv();
-  LocalRefHolder<jstring> text_jstr(env, env->NewStringUTF(text));
-  env->CallVoidMethod(m_java_object, m_set_status_text_method, text_jstr.Get());
-}
-
-void AndroidProgressCallback::SetProgressRange(u32 range)
-{
-  BaseProgressCallback::SetProgressRange(range);
-
-  JNIEnv* env = AndroidHelpers::GetJNIEnv();
-  env->CallVoidMethod(m_java_object, m_set_progress_range_method, static_cast<jint>(range));
-}
-
-void AndroidProgressCallback::SetProgressValue(u32 value)
-{
-  const u32 old_value = m_progress_value;
-  BaseProgressCallback::SetProgressValue(value);
-  if (old_value == m_progress_value)
-    return;
-
-  JNIEnv* env = AndroidHelpers::GetJNIEnv();
-  env->CallVoidMethod(m_java_object, m_set_progress_value_method, static_cast<jint>(value));
-}
-
-void AndroidProgressCallback::DisplayError(const char* message)
-{
-  Log_ErrorPrintf("%s", message);
-}
-
-void AndroidProgressCallback::DisplayWarning(const char* message)
-{
-  Log_WarningPrintf("%s", message);
-}
-
-void AndroidProgressCallback::DisplayInformation(const char* message)
-{
-  Log_InfoPrintf("%s", message);
-}
-
-void AndroidProgressCallback::DisplayDebugMessage(const char* message)
-{
-  Log_DevPrintf("%s", message);
-}
-
-void AndroidProgressCallback::ModalError(const char* message)
-{
-  Assert(message);
-  JNIEnv* env = AndroidHelpers::GetJNIEnv();
-  LocalRefHolder<jstring> message_jstr(env, env->NewStringUTF(message));
-  env->CallVoidMethod(m_java_object, m_modal_error_method, message_jstr.Get());
-}
-
-bool AndroidProgressCallback::ModalConfirmation(const char* message)
-{
-  Assert(message);
-  JNIEnv* env = AndroidHelpers::GetJNIEnv();
-  LocalRefHolder<jstring> message_jstr(env, env->NewStringUTF(message));
-  return env->CallBooleanMethod(m_java_object, m_modal_confirmation_method, message_jstr.Get());
-}
-
-void AndroidProgressCallback::ModalInformation(const char* message)
-{
-  Assert(message);
-  JNIEnv* env = AndroidHelpers::GetJNIEnv();
-  LocalRefHolder<jstring> message_jstr(env, env->NewStringUTF(message));
-  env->CallVoidMethod(m_java_object, m_modal_information_method, message_jstr.Get());
-}
diff --git a/android/app/src/cpp/android_progress_callback.h b/android/app/src/cpp/android_progress_callback.h
deleted file mode 100644
index 8b15bca18..000000000
--- a/android/app/src/cpp/android_progress_callback.h
+++ /dev/null
@@ -1,38 +0,0 @@
-#pragma once
-#include "common/progress_callback.h"
-#include <jni.h>
-
-class AndroidProgressCallback final : public BaseProgressCallback
-{
-public:
-  AndroidProgressCallback(JNIEnv* env, jobject java_object);
-  ~AndroidProgressCallback();
-
-  bool IsCancelled() const override;
-
-  void SetCancellable(bool cancellable) override;
-  void SetTitle(const char* title) override;
-  void SetStatusText(const char* text) override;
-  void SetProgressRange(u32 range) override;
-  void SetProgressValue(u32 value) override;
-
-  void DisplayError(const char* message) override;
-  void DisplayWarning(const char* message) override;
-  void DisplayInformation(const char* message) override;
-  void DisplayDebugMessage(const char* message) override;
-
-  void ModalError(const char* message) override;
-  bool ModalConfirmation(const char* message) override;
-  void ModalInformation(const char* message) override;
-
-private:
-  jobject m_java_object;
-
-  jmethodID m_set_title_method;
-  jmethodID m_set_status_text_method;
-  jmethodID m_set_progress_range_method;
-  jmethodID m_set_progress_value_method;
-  jmethodID m_modal_error_method;
-  jmethodID m_modal_confirmation_method;
-  jmethodID m_modal_information_method;
-};
diff --git a/android/app/src/cpp/android_settings_interface.cpp b/android/app/src/cpp/android_settings_interface.cpp
deleted file mode 100644
index 52af477c8..000000000
--- a/android/app/src/cpp/android_settings_interface.cpp
+++ /dev/null
@@ -1,425 +0,0 @@
-#include "android_settings_interface.h"
-#include "android_host_interface.h"
-#include "common/assert.h"
-#include "common/log.h"
-#include "common/string.h"
-#include "common/string_util.h"
-#include <algorithm>
-Log_SetChannel(AndroidSettingsInterface);
-
-ALWAYS_INLINE TinyString GetSettingKey(const char* section, const char* key)
-{
-  return TinyString::FromFormat("%s/%s", section, key);
-}
-
-AndroidSettingsInterface::AndroidSettingsInterface(jobject java_context)
-{
-  JNIEnv* env = AndroidHelpers::GetJNIEnv();
-  jclass c_preference_manager = env->FindClass("androidx/preference/PreferenceManager");
-  jclass c_preference_editor = env->FindClass("android/content/SharedPreferences$Editor");
-  jclass c_set = env->FindClass("java/util/Set");
-  jclass c_helper = env->FindClass("com/github/stenzek/duckstation/PreferenceHelpers");
-  jmethodID m_get_default_shared_preferences =
-    env->GetStaticMethodID(c_preference_manager, "getDefaultSharedPreferences",
-                           "(Landroid/content/Context;)Landroid/content/SharedPreferences;");
-  Assert(c_preference_manager && c_preference_editor && c_set && c_helper && m_get_default_shared_preferences);
-  m_set_class = reinterpret_cast<jclass>(env->NewGlobalRef(c_set));
-  m_shared_preferences_editor_class = reinterpret_cast<jclass>(env->NewGlobalRef(c_preference_editor));
-  m_helper_class = reinterpret_cast<jclass>(env->NewGlobalRef(c_helper));
-  Assert(m_set_class && m_shared_preferences_editor_class && m_helper_class);
-
-  env->DeleteLocalRef(c_set);
-  env->DeleteLocalRef(c_preference_editor);
-  env->DeleteLocalRef(c_helper);
-
-  jobject shared_preferences =
-    env->CallStaticObjectMethod(c_preference_manager, m_get_default_shared_preferences, java_context);
-  Assert(shared_preferences);
-  m_java_shared_preferences = env->NewGlobalRef(shared_preferences);
-  Assert(m_java_shared_preferences);
-  env->DeleteLocalRef(c_preference_manager);
-  env->DeleteLocalRef(shared_preferences);
-
-  jclass c_shared_preferences = env->GetObjectClass(m_java_shared_preferences);
-  m_shared_preferences_class = reinterpret_cast<jclass>(env->NewGlobalRef(c_shared_preferences));
-  Assert(m_shared_preferences_class);
-  env->DeleteLocalRef(c_shared_preferences);
-
-  m_get_boolean = env->GetMethodID(m_shared_preferences_class, "getBoolean", "(Ljava/lang/String;Z)Z");
-  m_get_int = env->GetMethodID(m_shared_preferences_class, "getInt", "(Ljava/lang/String;I)I");
-  m_get_float = env->GetMethodID(m_shared_preferences_class, "getFloat", "(Ljava/lang/String;F)F");
-  m_get_string = env->GetMethodID(m_shared_preferences_class, "getString",
-                                  "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;");
-  m_get_string_set =
-    env->GetMethodID(m_shared_preferences_class, "getStringSet", "(Ljava/lang/String;Ljava/util/Set;)Ljava/util/Set;");
-  m_set_to_array = env->GetMethodID(m_set_class, "toArray", "()[Ljava/lang/Object;");
-  Assert(m_get_boolean && m_get_int && m_get_float && m_get_string && m_get_string_set && m_set_to_array);
-
-  m_edit = env->GetMethodID(m_shared_preferences_class, "edit", "()Landroid/content/SharedPreferences$Editor;");
-  m_edit_set_string =
-    env->GetMethodID(m_shared_preferences_editor_class, "putString",
-                     "(Ljava/lang/String;Ljava/lang/String;)Landroid/content/SharedPreferences$Editor;");
-  m_edit_commit = env->GetMethodID(m_shared_preferences_editor_class, "commit", "()Z");
-  m_edit_remove = env->GetMethodID(m_shared_preferences_editor_class, "remove",
-                                   "(Ljava/lang/String;)Landroid/content/SharedPreferences$Editor;");
-  Assert(m_edit && m_edit_set_string && m_edit_commit && m_edit_remove);
-
-  m_helper_clear_section =
-    env->GetStaticMethodID(m_helper_class, "clearSection", "(Landroid/content/SharedPreferences;Ljava/lang/String;)V");
-  m_helper_add_to_string_list = env->GetStaticMethodID(
-    m_helper_class, "addToStringList", "(Landroid/content/SharedPreferences;Ljava/lang/String;Ljava/lang/String;)Z");
-  m_helper_remove_from_string_list =
-    env->GetStaticMethodID(m_helper_class, "removeFromStringList",
-                           "(Landroid/content/SharedPreferences;Ljava/lang/String;Ljava/lang/String;)Z");
-  m_helper_set_string_list = env->GetStaticMethodID(
-    m_helper_class, "setStringList", "(Landroid/content/SharedPreferences;Ljava/lang/String;[Ljava/lang/String;)V");
-  Assert(m_helper_clear_section && m_helper_add_to_string_list && m_helper_remove_from_string_list &&
-         m_helper_set_string_list);
-}
-
-AndroidSettingsInterface::~AndroidSettingsInterface()
-{
-  JNIEnv* env = AndroidHelpers::GetJNIEnv();
-  if (m_java_shared_preferences)
-    env->DeleteGlobalRef(m_java_shared_preferences);
-  if (m_shared_preferences_editor_class)
-    env->DeleteGlobalRef(m_shared_preferences_editor_class);
-  if (m_shared_preferences_class)
-    env->DeleteGlobalRef(m_shared_preferences_class);
-  if (m_set_class)
-    env->DeleteGlobalRef(m_set_class);
-  if (m_helper_class)
-    env->DeleteGlobalRef(m_helper_class);
-}
-
-bool AndroidSettingsInterface::Save()
-{
-  return true;
-}
-
-void AndroidSettingsInterface::Clear()
-{
-  Log_ErrorPrint("Not implemented");
-}
-
-int AndroidSettingsInterface::GetIntValue(const char* section, const char* key, int default_value /*= 0*/)
-{
-  // Some of these settings are string lists...
-  JNIEnv* env = AndroidHelpers::GetJNIEnv();
-  LocalRefHolder<jstring> key_string(env, env->NewStringUTF(GetSettingKey(section, key)));
-  LocalRefHolder<jstring> default_value_string(env, env->NewStringUTF(TinyString::FromFormat("%d", default_value)));
-  LocalRefHolder<jstring> string_object(
-    env, reinterpret_cast<jstring>(env->CallObjectMethod(m_java_shared_preferences, m_get_string, key_string.Get(),
-                                                         default_value_string.Get())));
-  if (env->ExceptionCheck())
-  {
-    env->ExceptionClear();
-
-    // it might actually be an int (e.g. seek bar preference)
-    const int int_value =
-      static_cast<int>(env->CallIntMethod(m_java_shared_preferences, m_get_int, key_string.Get(), default_value));
-    if (env->ExceptionCheck())
-    {
-      env->ExceptionClear();
-      Log_DevPrintf("GetIntValue(%s, %s) -> %d (exception)", section, key, default_value);
-      return default_value;
-    }
-
-    Log_DevPrintf("GetIntValue(%s, %s) -> %d (int)", section, key, int_value);
-    return int_value;
-  }
-
-  if (!string_object)
-    return default_value;
-
-  const char* data = env->GetStringUTFChars(string_object, nullptr);
-  Assert(data != nullptr);
-  Log_DevPrintf("GetIntValue(%s, %s) -> %s", section, key, data);
-
-  std::optional<int> value = StringUtil::FromChars<int>(data);
-  env->ReleaseStringUTFChars(string_object, data);
-  return value.value_or(default_value);
-}
-
-float AndroidSettingsInterface::GetFloatValue(const char* section, const char* key, float default_value /*= 0.0f*/)
-{
-  JNIEnv* env = AndroidHelpers::GetJNIEnv();
-  LocalRefHolder<jstring> key_string(env, env->NewStringUTF(GetSettingKey(section, key)));
-  LocalRefHolder<jstring> default_value_string(env, env->NewStringUTF(TinyString::FromFormat("%f", default_value)));
-  LocalRefHolder<jstring> string_object(
-    env, reinterpret_cast<jstring>(env->CallObjectMethod(m_java_shared_preferences, m_get_string, key_string.Get(),
-                                                         default_value_string.Get())));
-  if (env->ExceptionCheck())
-  {
-    env->ExceptionClear();
-    Log_DevPrintf("GetFloatValue(%s, %s) -> %f (exception)", section, key, default_value);
-    return default_value;
-  }
-
-  if (!string_object)
-  {
-    Log_DevPrintf("GetFloatValue(%s, %s) -> %f (null)", section, key, default_value);
-    return default_value;
-  }
-
-  const char* data = env->GetStringUTFChars(string_object, nullptr);
-  Assert(data != nullptr);
-  Log_DevPrintf("GetFloatValue(%s, %s) -> %s", section, key, data);
-
-  std::optional<float> value = StringUtil::FromChars<float>(data);
-  env->ReleaseStringUTFChars(string_object, data);
-  return value.value_or(default_value);
-}
-
-bool AndroidSettingsInterface::GetBoolValue(const char* section, const char* key, bool default_value /*= false*/)
-{
-  JNIEnv* env = AndroidHelpers::GetJNIEnv();
-  LocalRefHolder<jstring> key_string(env, env->NewStringUTF(GetSettingKey(section, key)));
-  jboolean bool_value = static_cast<bool>(
-    env->CallBooleanMethod(m_java_shared_preferences, m_get_boolean, key_string.Get(), default_value));
-  if (env->ExceptionCheck())
-  {
-    Log_DevPrintf("GetBoolValue(%s, %s) -> %u (exception)", section, key, static_cast<unsigned>(default_value));
-    env->ExceptionClear();
-    return default_value;
-  }
-
-  Log_DevPrintf("GetBoolValue(%s, %s) -> %u", section, key, static_cast<unsigned>(bool_value));
-  return bool_value;
-}
-
-std::string AndroidSettingsInterface::GetStringValue(const char* section, const char* key,
-                                                     const char* default_value /*= ""*/)
-{
-  JNIEnv* env = AndroidHelpers::GetJNIEnv();
-  LocalRefHolder<jstring> key_string(env, env->NewStringUTF(GetSettingKey(section, key)));
-  LocalRefHolder<jstring> default_value_string(env, env->NewStringUTF(default_value));
-  LocalRefHolder<jstring> string_object(
-    env, reinterpret_cast<jstring>(env->CallObjectMethod(m_java_shared_preferences, m_get_string, key_string.Get(),
-                                                         default_value_string.Get())));
-
-  if (env->ExceptionCheck())
-  {
-    env->ExceptionClear();
-    Log_DevPrintf("GetStringValue(%s, %s) -> %s (exception)", section, key, default_value);
-    return default_value;
-  }
-
-  if (!string_object)
-  {
-    Log_DevPrintf("GetStringValue(%s, %s) -> %s (null)", section, key, default_value);
-    return default_value;
-  }
-
-  const std::string ret(AndroidHelpers::JStringToString(env, string_object));
-  Log_DevPrintf("GetStringValue(%s, %s) -> %s", section, key, ret.c_str());
-  return ret;
-}
-
-jobject AndroidSettingsInterface::GetPreferencesEditor(JNIEnv* env)
-{
-  return env->CallObjectMethod(m_java_shared_preferences, m_edit);
-}
-
-void AndroidSettingsInterface::CheckForException(JNIEnv* env, const char* task)
-{
-  if (!env->ExceptionCheck())
-    return;
-
-  Log_ErrorPrintf("JNI exception during %s", task);
-  env->ExceptionClear();
-}
-
-void AndroidSettingsInterface::SetIntValue(const char* section, const char* key, int value)
-{
-  Log_DevPrintf("SetIntValue(\"%s\", \"%s\", %d)", section, key, value);
-
-  JNIEnv* env = AndroidHelpers::GetJNIEnv();
-  LocalRefHolder<jobject> editor(env, GetPreferencesEditor(env));
-  LocalRefHolder<jstring> key_string(env, env->NewStringUTF(GetSettingKey(section, key)));
-  LocalRefHolder<jstring> str_value(env, env->NewStringUTF(TinyString::FromFormat("%d", value)));
-
-  LocalRefHolder<jobject> dummy(env,
-                                env->CallObjectMethod(editor, m_edit_set_string, key_string.Get(), str_value.Get()));
-  env->CallBooleanMethod(editor, m_edit_commit);
-
-  CheckForException(env, "SetIntValue");
-}
-
-void AndroidSettingsInterface::SetFloatValue(const char* section, const char* key, float value)
-{
-  Log_DevPrintf("SetFloatValue(\"%s\", \"%s\", %f)", section, key, value);
-
-  JNIEnv* env = AndroidHelpers::GetJNIEnv();
-  LocalRefHolder<jobject> editor(env, GetPreferencesEditor(env));
-  LocalRefHolder<jstring> key_string(env, env->NewStringUTF(GetSettingKey(section, key)));
-  LocalRefHolder<jstring> str_value(env, env->NewStringUTF(TinyString::FromFormat("%f", value)));
-
-  LocalRefHolder<jobject> dummy(env,
-                                env->CallObjectMethod(editor, m_edit_set_string, key_string.Get(), str_value.Get()));
-  env->CallBooleanMethod(editor, m_edit_commit);
-
-  CheckForException(env, "SetFloatValue");
-}
-
-void AndroidSettingsInterface::SetBoolValue(const char* section, const char* key, bool value)
-{
-  Log_DevPrintf("SetBoolValue(\"%s\", \"%s\", %u)", section, key, static_cast<unsigned>(value));
-
-  JNIEnv* env = AndroidHelpers::GetJNIEnv();
-  LocalRefHolder<jobject> editor(env, GetPreferencesEditor(env));
-  LocalRefHolder<jstring> key_string(env, env->NewStringUTF(GetSettingKey(section, key)));
-  LocalRefHolder<jstring> str_value(env, env->NewStringUTF(value ? "true" : "false"));
-
-  LocalRefHolder<jobject> dummy(env,
-                                env->CallObjectMethod(editor, m_edit_set_string, key_string.Get(), str_value.Get()));
-  env->CallBooleanMethod(editor, m_edit_commit);
-
-  CheckForException(env, "SetBoolValue");
-}
-
-void AndroidSettingsInterface::SetStringValue(const char* section, const char* key, const char* value)
-{
-  Log_DevPrintf("SetStringValue(\"%s\", \"%s\", \"%s\")", section, key, value);
-
-  JNIEnv* env = AndroidHelpers::GetJNIEnv();
-  LocalRefHolder<jobject> editor(env, GetPreferencesEditor(env));
-  LocalRefHolder<jstring> key_string(env, env->NewStringUTF(GetSettingKey(section, key)));
-  LocalRefHolder<jstring> str_value(env, env->NewStringUTF(value));
-
-  LocalRefHolder<jobject> dummy(env,
-                                env->CallObjectMethod(editor, m_edit_set_string, key_string.Get(), str_value.Get()));
-  env->CallBooleanMethod(editor, m_edit_commit);
-
-  CheckForException(env, "SetStringValue");
-}
-
-void AndroidSettingsInterface::DeleteValue(const char* section, const char* key)
-{
-  Log_DevPrintf("DeleteValue(\"%s\", \"%s\")", section, key);
-
-  JNIEnv* env = AndroidHelpers::GetJNIEnv();
-  LocalRefHolder<jobject> editor(env, GetPreferencesEditor(env));
-  LocalRefHolder<jstring> key_string(env, env->NewStringUTF(GetSettingKey(section, key)));
-  LocalRefHolder<jobject> dummy(env, env->CallObjectMethod(editor, m_edit_remove, key_string.Get()));
-  env->CallBooleanMethod(editor, m_edit_commit);
-
-  CheckForException(env, "DeleteValue");
-}
-
-void AndroidSettingsInterface::ClearSection(const char* section)
-{
-  Log_DevPrintf("ClearSection(\"%s\")", section);
-
-  JNIEnv* env = AndroidHelpers::GetJNIEnv();
-  LocalRefHolder<jstring> str_section(env, env->NewStringUTF(section));
-  env->CallStaticVoidMethod(m_helper_class, m_helper_clear_section, m_java_shared_preferences, str_section.Get());
-
-  CheckForException(env, "ClearSection");
-}
-
-std::vector<std::string> AndroidSettingsInterface::GetStringList(const char* section, const char* key)
-{
-  JNIEnv* env = AndroidHelpers::GetJNIEnv();
-  LocalRefHolder<jstring> key_string(env, env->NewStringUTF(GetSettingKey(section, key)));
-  LocalRefHolder<jobject> values_set(
-    env, env->CallObjectMethod(m_java_shared_preferences, m_get_string_set, key_string.Get(), nullptr));
-  if (env->ExceptionCheck())
-  {
-    env->ExceptionClear();
-
-    // this might just be a string, not a string set
-    LocalRefHolder<jstring> string_object(env, reinterpret_cast<jstring>(env->CallObjectMethod(
-                                                 m_java_shared_preferences, m_get_string, key_string.Get(), nullptr)));
-
-    if (!env->ExceptionCheck())
-    {
-      std::vector<std::string> ret;
-      if (string_object)
-        ret.push_back(AndroidHelpers::JStringToString(env, string_object));
-
-      return ret;
-    }
-
-    env->ExceptionClear();
-    return {};
-  }
-
-  if (!values_set)
-    return {};
-
-  LocalRefHolder<jobjectArray> values_array(
-    env, reinterpret_cast<jobjectArray>(env->CallObjectMethod(values_set, m_set_to_array)));
-  if (env->ExceptionCheck())
-  {
-    env->ExceptionClear();
-    return {};
-  }
-
-  if (!values_array)
-    return {};
-
-  jsize size = env->GetArrayLength(values_array);
-  std::vector<std::string> values;
-  values.reserve(size);
-  for (jsize i = 0; i < size; i++)
-  {
-    jstring str = reinterpret_cast<jstring>(env->GetObjectArrayElement(values_array, i));
-    values.push_back(AndroidHelpers::JStringToString(env, str));
-    env->DeleteLocalRef(str);
-  }
-
-  return values;
-}
-
-void AndroidSettingsInterface::SetStringList(const char* section, const char* key,
-                                             const std::vector<std::string>& items)
-{
-  Log_DevPrintf("SetStringList(\"%s\", \"%s\")", section, key);
-  if (items.empty())
-  {
-    DeleteValue(section, key);
-    return;
-  }
-
-  JNIEnv* env = AndroidHelpers::GetJNIEnv();
-  LocalRefHolder<jobjectArray> items_array(
-    env, env->NewObjectArray(static_cast<jsize>(items.size()), AndroidHelpers::GetStringClass(), nullptr));
-  for (size_t i = 0; i < items.size(); i++)
-  {
-    LocalRefHolder<jstring> item_jstr(env, env->NewStringUTF(items[i].c_str()));
-    env->SetObjectArrayElement(items_array, static_cast<jsize>(i), item_jstr);
-  }
-
-  LocalRefHolder<jstring> key_string(env, env->NewStringUTF(GetSettingKey(section, key)));
-  env->CallStaticVoidMethod(m_helper_class, m_helper_set_string_list, m_java_shared_preferences, key_string.Get(),
-                            items_array.Get());
-
-  CheckForException(env, "SetStringList");
-}
-
-bool AndroidSettingsInterface::RemoveFromStringList(const char* section, const char* key, const char* item)
-{
-  Log_DevPrintf("RemoveFromStringList(\"%s\", \"%s\", \"%s\")", section, key, item);
-
-  JNIEnv* env = AndroidHelpers::GetJNIEnv();
-  LocalRefHolder<jstring> key_string(env, env->NewStringUTF(GetSettingKey(section, key)));
-  LocalRefHolder<jstring> item_string(env, env->NewStringUTF(item));
-  const bool result = env->CallStaticBooleanMethod(m_helper_class, m_helper_remove_from_string_list,
-                                                   m_java_shared_preferences, key_string.Get(), item_string.Get());
-  CheckForException(env, "RemoveFromStringList");
-  return result;
-}
-
-bool AndroidSettingsInterface::AddToStringList(const char* section, const char* key, const char* item)
-{
-  Log_DevPrintf("AddToStringList(\"%s\", \"%s\", \"%s\")", section, key, item);
-
-  JNIEnv* env = AndroidHelpers::GetJNIEnv();
-  LocalRefHolder<jstring> key_string(env, env->NewStringUTF(GetSettingKey(section, key)));
-  LocalRefHolder<jstring> item_string(env, env->NewStringUTF(item));
-  const bool result = env->CallStaticBooleanMethod(m_helper_class, m_helper_add_to_string_list,
-                                                   m_java_shared_preferences, key_string.Get(), item_string.Get());
-  CheckForException(env, "AddToStringList");
-  return result;
-}
diff --git a/android/app/src/cpp/android_settings_interface.h b/android/app/src/cpp/android_settings_interface.h
deleted file mode 100644
index 542a2f90e..000000000
--- a/android/app/src/cpp/android_settings_interface.h
+++ /dev/null
@@ -1,54 +0,0 @@
-#pragma once
-#include "core/settings.h"
-#include <jni.h>
-
-class AndroidSettingsInterface : public SettingsInterface
-{
-public:
-  AndroidSettingsInterface(jobject java_context);
-  ~AndroidSettingsInterface();
-
-  bool Save() override;
-  void Clear() override;
-
-  int GetIntValue(const char* section, const char* key, int default_value = 0) override;
-  float GetFloatValue(const char* section, const char* key, float default_value = 0.0f) override;
-  bool GetBoolValue(const char* section, const char* key, bool default_value = false) override;
-  std::string GetStringValue(const char* section, const char* key, const char* default_value = "") override;
-
-  void SetIntValue(const char* section, const char* key, int value) override;
-  void SetFloatValue(const char* section, const char* key, float value) override;
-  void SetBoolValue(const char* section, const char* key, bool value) override;
-  void SetStringValue(const char* section, const char* key, const char* value) override;
-  void DeleteValue(const char* section, const char* key) override;
-  void ClearSection(const char* section) override;
-
-  std::vector<std::string> GetStringList(const char* section, const char* key) override;
-  void SetStringList(const char* section, const char* key, const std::vector<std::string>& items) override;
-  bool RemoveFromStringList(const char* section, const char* key, const char* item) override;
-  bool AddToStringList(const char* section, const char* key, const char* item) override;
-
-private:
-  jobject GetPreferencesEditor(JNIEnv* env);
-  void CheckForException(JNIEnv* env, const char* task);
-
-  jclass m_set_class{};
-  jclass m_shared_preferences_class{};
-  jclass m_shared_preferences_editor_class{};
-  jclass m_helper_class{};
-  jobject m_java_shared_preferences{};
-  jmethodID m_get_boolean{};
-  jmethodID m_get_int{};
-  jmethodID m_get_float{};
-  jmethodID m_get_string{};
-  jmethodID m_get_string_set{};
-  jmethodID m_edit{};
-  jmethodID m_edit_set_string{};
-  jmethodID m_edit_commit{};
-  jmethodID m_edit_remove{};
-  jmethodID m_set_to_array{};
-  jmethodID m_helper_clear_section{};
-  jmethodID m_helper_add_to_string_list{};
-  jmethodID m_helper_remove_from_string_list{};
-  jmethodID m_helper_set_string_list{};
-};
diff --git a/android/app/src/cpp/opensles_audio_stream.cpp b/android/app/src/cpp/opensles_audio_stream.cpp
deleted file mode 100644
index 70f2c207c..000000000
--- a/android/app/src/cpp/opensles_audio_stream.cpp
+++ /dev/null
@@ -1,210 +0,0 @@
-#include "opensles_audio_stream.h"
-#include "common/assert.h"
-#include "common/log.h"
-#include <cmath>
-Log_SetChannel(OpenSLESAudioStream);
-
-// Based off Dolphin's OpenSLESStream class.
-
-OpenSLESAudioStream::OpenSLESAudioStream() = default;
-
-OpenSLESAudioStream::~OpenSLESAudioStream()
-{
-  if (IsOpen())
-    OpenSLESAudioStream::CloseDevice();
-}
-
-std::unique_ptr<AudioStream> OpenSLESAudioStream::Create()
-{
-  return std::make_unique<OpenSLESAudioStream>();
-}
-
-bool OpenSLESAudioStream::OpenDevice()
-{
-  DebugAssert(!IsOpen());
-
-  SLresult res = slCreateEngine(&m_engine, 0, nullptr, 0, nullptr, nullptr);
-  if (res != SL_RESULT_SUCCESS)
-  {
-    Log_ErrorPrintf("slCreateEngine failed: %d", res);
-    return false;
-  }
-
-  res = (*m_engine)->Realize(m_engine, SL_BOOLEAN_FALSE);
-  if (res != SL_RESULT_SUCCESS)
-  {
-    Log_ErrorPrintf("Realize(Engine) failed: %d", res);
-    CloseDevice();
-    return false;
-  }
-
-  res = (*m_engine)->GetInterface(m_engine, SL_IID_ENGINE, &m_engine_engine);
-  if (res != SL_RESULT_SUCCESS)
-  {
-    Log_ErrorPrintf("GetInterface(SL_IID_ENGINE) failed: %d", res);
-    CloseDevice();
-    return false;
-  }
-
-  res = (*m_engine_engine)->CreateOutputMix(m_engine_engine, &m_output_mix, 0, 0, 0);
-  if (res != SL_RESULT_SUCCESS)
-  {
-    Log_ErrorPrintf("CreateOutputMix failed: %d", res);
-    CloseDevice();
-    return false;
-  }
-
-  res = (*m_output_mix)->Realize(m_output_mix, SL_BOOLEAN_FALSE);
-  if (res != SL_RESULT_SUCCESS)
-  {
-    Log_ErrorPrintf("Realize(OutputMix) mix failed: %d", res);
-    CloseDevice();
-    return false;
-  }
-
-  SLDataLocator_AndroidSimpleBufferQueue dloc_bq{SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, NUM_BUFFERS};
-  SLDataFormat_PCM format = {SL_DATAFORMAT_PCM,
-                             m_channels,
-                             m_output_sample_rate * 1000u,
-                             SL_PCMSAMPLEFORMAT_FIXED_16,
-                             SL_PCMSAMPLEFORMAT_FIXED_16,
-                             SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT,
-                             SL_BYTEORDER_LITTLEENDIAN};
-  SLDataSource dsrc{&dloc_bq, &format};
-  SLDataLocator_OutputMix dloc_outputmix{SL_DATALOCATOR_OUTPUTMIX, m_output_mix};
-  SLDataSink dsink{&dloc_outputmix, nullptr};
-
-  const std::array<SLInterfaceID, 2> ap_interfaces = {{SL_IID_BUFFERQUEUE, SL_IID_VOLUME}};
-  const std::array<SLboolean, 2> ap_interfaces_req = {{true, true}};
-  res = (*m_engine_engine)
-          ->CreateAudioPlayer(m_engine_engine, &m_player, &dsrc, &dsink, static_cast<u32>(ap_interfaces.size()),
-                              ap_interfaces.data(), ap_interfaces_req.data());
-  if (res != SL_RESULT_SUCCESS)
-  {
-    Log_ErrorPrintf("CreateAudioPlayer failed: %d", res);
-    CloseDevice();
-    return false;
-  }
-
-  res = (*m_player)->Realize(m_player, SL_BOOLEAN_FALSE);
-  if (res != SL_RESULT_SUCCESS)
-  {
-    Log_ErrorPrintf("Realize(AudioPlayer) failed: %d", res);
-    CloseDevice();
-    return false;
-  }
-
-  res = (*m_player)->GetInterface(m_player, SL_IID_PLAY, &m_play_interface);
-  if (res != SL_RESULT_SUCCESS)
-  {
-    Log_ErrorPrintf("GetInterface(SL_IID_PLAY) failed: %d", res);
-    CloseDevice();
-    return false;
-  }
-
-  res = (*m_player)->GetInterface(m_player, SL_IID_BUFFERQUEUE, &m_buffer_queue_interface);
-  if (res != SL_RESULT_SUCCESS)
-  {
-    Log_ErrorPrintf("GetInterface(SL_IID_BUFFERQUEUE) failed: %d", res);
-    CloseDevice();
-    return false;
-  }
-
-  res = (*m_player)->GetInterface(m_player, SL_IID_VOLUME, &m_volume_interface);
-  if (res != SL_RESULT_SUCCESS)
-  {
-    Log_ErrorPrintf("GetInterface(SL_IID_VOLUME) failed: %d", res);
-    CloseDevice();
-    return false;
-  }
-
-  res = (*m_buffer_queue_interface)->RegisterCallback(m_buffer_queue_interface, BufferCallback, this);
-  if (res != SL_RESULT_SUCCESS)
-  {
-    Log_ErrorPrintf("Failed to register callback: %d", res);
-    CloseDevice();
-    return false;
-  }
-
-  for (u32 i = 0; i < NUM_BUFFERS; i++)
-    m_buffers[i] = std::make_unique<SampleType[]>(m_buffer_size * m_channels);
-
-  Log_InfoPrintf("OpenSL ES device opened: %uhz, %u channels, %u buffer size, %u buffers", m_output_sample_rate,
-                 m_channels, m_buffer_size, NUM_BUFFERS);
-  return true;
-}
-
-void OpenSLESAudioStream::PauseDevice(bool paused)
-{
-  if (m_paused == paused)
-    return;
-
-  SLresult res =
-    (*m_play_interface)->SetPlayState(m_play_interface, paused ? SL_PLAYSTATE_PAUSED : SL_PLAYSTATE_PLAYING);
-  if (res != SL_RESULT_SUCCESS)
-    Log_ErrorPrintf("SetPlayState failed: %d", res);
-
-  if (!paused && !m_buffer_enqueued)
-  {
-    m_buffer_enqueued = true;
-    EnqueueBuffer();
-  }
-
-  m_paused = paused;
-}
-
-void OpenSLESAudioStream::CloseDevice()
-{
-  m_buffers = {};
-  m_current_buffer = 0;
-  m_paused = true;
-  m_buffer_enqueued = false;
-
-  if (m_player)
-  {
-    (*m_player)->Destroy(m_player);
-    m_volume_interface = {};
-    m_buffer_queue_interface = {};
-    m_play_interface = {};
-    m_player = {};
-  }
-  if (m_output_mix)
-  {
-    (*m_output_mix)->Destroy(m_output_mix);
-    m_output_mix = {};
-  }
-  (*m_engine)->Destroy(m_engine);
-  m_engine_engine = {};
-  m_engine = {};
-}
-
-void OpenSLESAudioStream::SetOutputVolume(u32 volume)
-{
-  const SLmillibel attenuation = (volume == 0) ?
-                                   SL_MILLIBEL_MIN :
-                                   static_cast<SLmillibel>(2000.0f * std::log10(static_cast<float>(volume) / 100.0f));
-  SLresult res = (*m_volume_interface)->SetVolumeLevel(m_volume_interface, attenuation);
-  if (res != SL_RESULT_SUCCESS)
-    Log_ErrorPrintf("SetVolumeLevel failed: %d", res);
-}
-
-void OpenSLESAudioStream::EnqueueBuffer()
-{
-  SampleType* samples = m_buffers[m_current_buffer].get();
-  ReadFrames(samples, m_buffer_size, false);
-
-  SLresult res = (*m_buffer_queue_interface)
-                   ->Enqueue(m_buffer_queue_interface, samples, m_buffer_size * m_channels * sizeof(SampleType));
-  if (res != SL_RESULT_SUCCESS)
-    Log_ErrorPrintf("Enqueue buffer failed: %d", res);
-
-  m_current_buffer = (m_current_buffer + 1) % NUM_BUFFERS;
-}
-
-void OpenSLESAudioStream::BufferCallback(SLAndroidSimpleBufferQueueItf buffer_queue, void* context)
-{
-  OpenSLESAudioStream* const this_ptr = static_cast<OpenSLESAudioStream*>(context);
-  this_ptr->EnqueueBuffer();
-}
-
-void OpenSLESAudioStream::FramesAvailable() {}
diff --git a/android/app/src/cpp/opensles_audio_stream.h b/android/app/src/cpp/opensles_audio_stream.h
deleted file mode 100644
index 83c54aa6e..000000000
--- a/android/app/src/cpp/opensles_audio_stream.h
+++ /dev/null
@@ -1,48 +0,0 @@
-#pragma once
-#include "common/audio_stream.h"
-#include <SLES/OpenSLES.h>
-#include <SLES/OpenSLES_Android.h>
-#include <array>
-#include <memory>
-
-class OpenSLESAudioStream final : public AudioStream
-{
-public:
-  OpenSLESAudioStream();
-  ~OpenSLESAudioStream();
-
-  static std::unique_ptr<AudioStream> Create();
-
-  void SetOutputVolume(u32 volume) override;
-
-protected:
-  enum : u32
-  {
-    NUM_BUFFERS = 2
-  };
-
-  ALWAYS_INLINE bool IsOpen() const { return (m_engine != nullptr); }
-
-  bool OpenDevice() override;
-  void PauseDevice(bool paused) override;
-  void CloseDevice() override;
-  void FramesAvailable() override;
-
-  void EnqueueBuffer();
-
-  static void BufferCallback(SLAndroidSimpleBufferQueueItf buffer_queue, void* context);
-
-  SLObjectItf m_engine{};
-  SLEngineItf m_engine_engine{};
-  SLObjectItf m_output_mix{};
-
-  SLObjectItf m_player{};
-  SLPlayItf m_play_interface{};
-  SLAndroidSimpleBufferQueueItf m_buffer_queue_interface{};
-  SLVolumeItf m_volume_interface{};
-
-  std::array<std::unique_ptr<SampleType[]>, NUM_BUFFERS> m_buffers;
-  u32 m_current_buffer = 0;
-  bool m_paused = true;
-  bool m_buffer_enqueued = false;
-};
diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml
deleted file mode 100644
index d1181b437..000000000
--- a/android/app/src/main/AndroidManifest.xml
+++ /dev/null
@@ -1,80 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.github.stenzek.duckstation">
-
-    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
-    <uses-permission android:name="android.permission.VIBRATE" />
-    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
-    <uses-permission android:name="android.permission.INTERNET" />
-
-    <application
-        android:allowBackup="true"
-        android:icon="@mipmap/ic_launcher"
-        android:label="@string/app_name"
-        android:networkSecurityConfig="@xml/network_security_config"
-        android:requestLegacyExternalStorage="true"
-        android:roundIcon="@mipmap/ic_launcher_round"
-        android:supportsRtl="true"
-        android:theme="@style/AppTheme"
-        android:usesCleartextTraffic="true">
-        <activity
-            android:name=".MemoryCardEditorActivity"
-            android:label="@string/title_activity_memory_card_editor"
-            android:theme="@style/AppTheme.NoActionBar"></activity>
-        <activity
-            android:name=".GameDirectoriesActivity"
-            android:label="@string/title_activity_game_directories"
-            android:theme="@style/AppTheme.NoActionBar" />
-        <activity
-            android:name=".EmulationActivity"
-            android:configChanges="orientation|keyboard|keyboardHidden|screenSize"
-            android:exported="true"
-            android:immersive="true"
-            android:label="@string/title_activity_emulation"
-            android:parentActivityName=".MainActivity"
-            android:theme="@style/Theme.AppCompat.DayNight.NoActionBar">
-            <meta-data
-                android:name="android.support.PARENT_ACTIVITY"
-                android:value="com.github.stenzek.duckstation.MainActivity" />
-        </activity>
-        <activity
-            android:name=".SettingsActivity"
-            android:configChanges="orientation|keyboard|keyboardHidden|screenSize"
-            android:label="@string/title_activity_settings"
-            android:parentActivityName=".MainActivity">
-            <meta-data
-                android:name="android.support.PARENT_ACTIVITY"
-                android:value="com.github.stenzek.duckstation.MainActivity" />
-        </activity>
-        <activity
-            android:name=".ControllerSettingsActivity"
-            android:configChanges="orientation|keyboard|keyboardHidden|screenSize"
-            android:label="@string/controller_mapping_activity_title"
-            android:parentActivityName=".MainActivity">
-            <meta-data
-                android:name="android.support.PARENT_ACTIVITY"
-                android:value="com.github.stenzek.duckstation.MainActivity" />
-        </activity>
-        <activity
-            android:name=".GamePropertiesActivity"
-            android:configChanges="orientation|keyboard|keyboardHidden|screenSize"
-            android:label="@string/activity_game_properties"
-            android:parentActivityName=".MainActivity">
-            <meta-data
-                android:name="android.support.PARENT_ACTIVITY"
-                android:value="com.github.stenzek.duckstation.MainActivity" />
-        </activity>
-        <activity
-            android:name=".MainActivity"
-            android:configChanges="orientation|keyboard|keyboardHidden|screenSize"
-            android:label="@string/app_name"
-            android:theme="@style/AppTheme.NoActionBar">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-
-                <category android:name="android.intent.category.LAUNCHER" />
-            </intent-filter>
-        </activity>
-    </application>
-
-</manifest>
\ No newline at end of file
diff --git a/android/app/src/main/ic_launcher-web.png b/android/app/src/main/ic_launcher-web.png
deleted file mode 100644
index 353ac1fe7..000000000
Binary files a/android/app/src/main/ic_launcher-web.png and /dev/null differ
diff --git a/android/app/src/main/java/com/github/stenzek/duckstation/Achievement.java b/android/app/src/main/java/com/github/stenzek/duckstation/Achievement.java
deleted file mode 100644
index ee4477c83..000000000
--- a/android/app/src/main/java/com/github/stenzek/duckstation/Achievement.java
+++ /dev/null
@@ -1,76 +0,0 @@
-package com.github.stenzek.duckstation;
-
-import android.content.Context;
-import android.content.SharedPreferences;
-
-import androidx.preference.PreferenceManager;
-
-public final class Achievement {
-    public static final int CATEGORY_LOCAL = 0;
-    public static final int CATEGORY_CORE = 3;
-    public static final int CATEGORY_UNOFFICIAL = 5;
-
-    private final int id;
-    private final String name;
-    private final String description;
-    private final String lockedBadgePath;
-    private final String unlockedBadgePath;
-    private final int points;
-    private final boolean locked;
-
-    public Achievement(int id, String name, String description, String lockedBadgePath,
-                       String unlockedBadgePath, int points, boolean locked) {
-        this.id = id;
-        this.name = name;
-        this.description = description;
-        this.lockedBadgePath = lockedBadgePath;
-        this.unlockedBadgePath = unlockedBadgePath;
-        this.points = points;
-        this.locked = locked;
-    }
-
-    /**
-     * Returns true if challenge mode will be enabled when a game is started.
-     * Does not depend on the emulation running.
-     *
-     * @param context context to pull settings from
-     * @return true if challenge mode will be used, false otherwise
-     */
-    public static boolean willChallengeModeBeEnabled(Context context) {
-        final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
-        return prefs.getBoolean("Cheevos/Enabled", false) &&
-               prefs.getBoolean("Cheevos/ChallengeMode", false);
-    }
-
-    public int getId() {
-        return id;
-    }
-
-    public String getName() {
-        return name;
-    }
-
-    public String getDescription() {
-        return description;
-    }
-
-    public String getLockedBadgePath() {
-        return lockedBadgePath;
-    }
-
-    public String getUnlockedBadgePath() {
-        return unlockedBadgePath;
-    }
-
-    public int getPoints() {
-        return points;
-    }
-
-    public boolean isLocked() {
-        return locked;
-    }
-
-    public String getBadgePath() {
-        return locked ? lockedBadgePath : unlockedBadgePath;
-    }
-}
diff --git a/android/app/src/main/java/com/github/stenzek/duckstation/AchievementListFragment.java b/android/app/src/main/java/com/github/stenzek/duckstation/AchievementListFragment.java
deleted file mode 100644
index 04b229ad4..000000000
--- a/android/app/src/main/java/com/github/stenzek/duckstation/AchievementListFragment.java
+++ /dev/null
@@ -1,193 +0,0 @@
-package com.github.stenzek.duckstation;
-
-import android.content.Context;
-import android.content.DialogInterface;
-import android.content.res.Configuration;
-import android.os.AsyncTask;
-import android.os.Bundle;
-import android.util.DisplayMetrics;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.ImageView;
-import android.widget.ProgressBar;
-import android.widget.TextView;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.fragment.app.DialogFragment;
-import androidx.recyclerview.widget.DividerItemDecoration;
-import androidx.recyclerview.widget.LinearLayoutManager;
-import androidx.recyclerview.widget.RecyclerView;
-
-import java.util.Arrays;
-import java.util.Comparator;
-
-public class AchievementListFragment extends DialogFragment {
-
-    private RecyclerView mRecyclerView;
-    private AchievementListFragment.ViewAdapter mAdapter;
-    private final Achievement[] mAchievements;
-    private DialogInterface.OnDismissListener mOnDismissListener;
-
-    public AchievementListFragment(Achievement[] achievements) {
-        mAchievements = achievements;
-        sortAchievements();
-    }
-
-    public void setOnDismissListener(DialogInterface.OnDismissListener l) {
-        mOnDismissListener = l;
-    }
-
-    @Override
-    public void onDismiss(@NonNull DialogInterface dialog) {
-        if (mOnDismissListener != null)
-            mOnDismissListener.onDismiss(dialog);
-
-        super.onDismiss(dialog);
-    }
-
-    @Override
-    public void onResume() {
-        super.onResume();
-
-        if (getDialog() == null)
-            return;
-
-        final boolean isLandscape = (getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE);
-        final float scale = (float) getContext().getResources().getDisplayMetrics().densityDpi / DisplayMetrics.DENSITY_DEFAULT;
-        final int width = Math.round((isLandscape ? 700.0f : 400.0f) * scale);
-        final int height = Math.round((isLandscape ? 400.0f : 700.0f) * scale);
-        getDialog().getWindow().setLayout(width, height);
-    }
-
-    @Nullable
-    @Override
-    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
-        return inflater.inflate(R.layout.fragment_achievement_list, container, false);
-    }
-
-    @Override
-    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
-        super.onViewCreated(view, savedInstanceState);
-
-        mAdapter = new AchievementListFragment.ViewAdapter(getContext(), mAchievements);
-
-        mRecyclerView = view.findViewById(R.id.recyclerView);
-        mRecyclerView.setAdapter(mAdapter);
-        mRecyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
-        mRecyclerView.addItemDecoration(new DividerItemDecoration(mRecyclerView.getContext(),
-                DividerItemDecoration.VERTICAL));
-
-        fillHeading(view);
-    }
-
-    private void fillHeading(@NonNull View view) {
-        final AndroidHostInterface hi = AndroidHostInterface.getInstance();
-        final String gameTitle = hi.getCheevoGameTitle();
-        if (gameTitle != null) {
-            final String formattedTitle = hi.isCheevosChallengeModeActive() ?
-                    String.format(getString(R.string.achievement_title_challenge_mode_format_string), gameTitle) :
-                    gameTitle;
-            ((TextView) view.findViewById(R.id.title)).setText(formattedTitle);
-        }
-
-        final int cheevoCount = hi.getCheevoCount();
-        final int unlockedCheevoCount = hi.getUnlockedCheevoCount();
-        final String summary = String.format(getString(R.string.achievement_summary_format_string),
-                unlockedCheevoCount, cheevoCount, hi.getCheevoPointsForGame(), hi.getCheevoMaximumPointsForGame());
-        ((TextView) view.findViewById(R.id.summary)).setText(summary);
-
-        ProgressBar pb = ((ProgressBar) view.findViewById(R.id.progressBar));
-        pb.setMax(cheevoCount);
-        pb.setProgress(unlockedCheevoCount);
-
-        final ImageView icon = ((ImageView) view.findViewById(R.id.icon));
-        final String badgePath = hi.getCheevoGameIconPath();
-        if (badgePath != null) {
-            new ImageLoadTask(icon).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, badgePath);
-        }
-    }
-
-    private void sortAchievements() {
-        Arrays.sort(mAchievements, (o1, o2) -> {
-            if (o2.isLocked() && !o1.isLocked())
-                return -1;
-            else if (o1.isLocked() && !o2.isLocked())
-                return 1;
-
-            return o1.getName().compareTo(o2.getName());
-        });
-    }
-
-    private static class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener, View.OnLongClickListener {
-        private final View mItemView;
-
-        public ViewHolder(@NonNull View itemView) {
-            super(itemView);
-            mItemView = itemView;
-            mItemView.setOnClickListener(this);
-            mItemView.setOnLongClickListener(this);
-        }
-
-        public void bindToEntry(Achievement cheevo) {
-            ImageView icon = ((ImageView) mItemView.findViewById(R.id.icon));
-            icon.setImageDrawable(mItemView.getContext().getDrawable(R.drawable.ic_baseline_lock_24));
-
-            final String badgePath = cheevo.getBadgePath();
-            if (badgePath != null) {
-                new ImageLoadTask(icon).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, badgePath);
-            }
-
-            ((TextView) mItemView.findViewById(R.id.title)).setText(cheevo.getName());
-            ((TextView) mItemView.findViewById(R.id.description)).setText(cheevo.getDescription());
-
-            ((ImageView) mItemView.findViewById(R.id.locked_icon)).setImageDrawable(
-                    mItemView.getContext().getDrawable(cheevo.isLocked() ? R.drawable.ic_baseline_lock_24 : R.drawable.ic_baseline_lock_open_24));
-
-            final String pointsString = String.format(mItemView.getContext().getString(R.string.achievement_points_format_string), cheevo.getPoints());
-            ((TextView) mItemView.findViewById(R.id.points)).setText(pointsString);
-        }
-
-        @Override
-        public void onClick(View v) {
-            //
-        }
-
-        @Override
-        public boolean onLongClick(View v) {
-            return false;
-        }
-    }
-
-    private static class ViewAdapter extends RecyclerView.Adapter<AchievementListFragment.ViewHolder> {
-        private final LayoutInflater mInflater;
-        private final Achievement[] mAchievements;
-
-        public ViewAdapter(@NonNull Context context, Achievement[] achievements) {
-            mInflater = LayoutInflater.from(context);
-            mAchievements = achievements;
-        }
-
-        @NonNull
-        @Override
-        public AchievementListFragment.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
-            return new AchievementListFragment.ViewHolder(mInflater.inflate(R.layout.layout_achievement_entry, parent, false));
-        }
-
-        @Override
-        public void onBindViewHolder(@NonNull AchievementListFragment.ViewHolder holder, int position) {
-            holder.bindToEntry(mAchievements[position]);
-        }
-
-        @Override
-        public int getItemCount() {
-            return (mAchievements != null) ? mAchievements.length : 0;
-        }
-
-        @Override
-        public int getItemViewType(int position) {
-            return R.layout.layout_game_list_entry;
-        }
-    }
-}
diff --git a/android/app/src/main/java/com/github/stenzek/duckstation/AchievementSettingsFragment.java b/android/app/src/main/java/com/github/stenzek/duckstation/AchievementSettingsFragment.java
deleted file mode 100644
index 0b4c1a149..000000000
--- a/android/app/src/main/java/com/github/stenzek/duckstation/AchievementSettingsFragment.java
+++ /dev/null
@@ -1,266 +0,0 @@
-package com.github.stenzek.duckstation;
-
-import android.app.Activity;
-import android.app.AlertDialog;
-import android.content.Intent;
-import android.content.SharedPreferences;
-import android.net.Uri;
-import android.os.AsyncTask;
-import android.os.Bundle;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.Button;
-import android.widget.EditText;
-import android.widget.ProgressBar;
-import android.widget.TextView;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.fragment.app.DialogFragment;
-import androidx.preference.Preference;
-import androidx.preference.PreferenceFragmentCompat;
-import androidx.preference.PreferenceScreen;
-
-import java.net.URLEncoder;
-import java.text.DateFormat;
-import java.util.Date;
-import java.util.Locale;
-
-public class AchievementSettingsFragment extends PreferenceFragmentCompat implements Preference.OnPreferenceClickListener {
-    private static final String REGISTER_URL = "http://retroachievements.org/createaccount.php";
-    private static final String PROFILE_URL_PREFIX = "https://retroachievements.org/user/";
-
-    private boolean isLoggedIn = false;
-    private String username;
-    private String loginTokenTime;
-
-    public AchievementSettingsFragment() {
-    }
-
-    @Override
-    public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
-        setPreferencesFromResource(R.xml.achievement_preferences, rootKey);
-        updateViews();
-    }
-
-    private void updateViews() {
-        final SharedPreferences prefs = getPreferenceManager().getSharedPreferences();
-
-        username = prefs.getString("Cheevos/Username", "");
-        isLoggedIn = (username != null && !username.isEmpty());
-        if (isLoggedIn) {
-            try {
-                final String loginTokenTimeString = prefs.getString("Cheevos/LoginTimestamp", "");
-                final long loginUnixTimestamp = Long.parseLong(loginTokenTimeString);
-
-                // TODO: Extract to a helper function.
-                final Date date = new Date(loginUnixTimestamp * 1000);
-                final DateFormat format = DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.SHORT, Locale.getDefault());
-                loginTokenTime = format.format(date);
-            } catch (Exception e) {
-                loginTokenTime = null;
-            }
-        }
-
-        final PreferenceScreen preferenceScreen = getPreferenceScreen();
-
-        Preference preference = preferenceScreen.findPreference("Cheevos/ChallengeMode");
-        if (preference != null) {
-            // toggling this is disabled while it's running to avoid the whole power off thing
-            preference.setEnabled(!AndroidHostInterface.getInstance().isEmulationThreadRunning());
-        }
-
-        preference = preferenceScreen.findPreference("Cheevos/Login");
-        if (preference != null)
-        {
-            preference.setVisible(!isLoggedIn);
-            preference.setOnPreferenceClickListener(this);
-        }
-
-        preference = preferenceScreen.findPreference("Cheevos/Register");
-        if (preference != null)
-        {
-            preference.setVisible(!isLoggedIn);
-            preference.setOnPreferenceClickListener(this);
-        }
-
-        preference = preferenceScreen.findPreference("Cheevos/Logout");
-        if (preference != null)
-        {
-            preference.setVisible(isLoggedIn);
-            preference.setOnPreferenceClickListener(this);
-        }
-
-        preference = preferenceScreen.findPreference("Cheevos/Username");
-        if (preference != null)
-        {
-            preference.setVisible(isLoggedIn);
-            preference.setSummary((username != null) ? username : "");
-        }
-
-        preference = preferenceScreen.findPreference("Cheevos/LoginTokenTime");
-        if (preference != null)
-        {
-            preference.setVisible(isLoggedIn);
-            preference.setSummary((loginTokenTime != null) ? loginTokenTime : "");
-        }
-
-        preference = preferenceScreen.findPreference("Cheevos/ViewProfile");
-        if (preference != null)
-        {
-            preference.setVisible(isLoggedIn);
-            preference.setOnPreferenceClickListener(this);
-        }
-    }
-
-    @Override
-    public boolean onPreferenceClick(Preference preference) {
-        final String key = preference.getKey();
-        if (key == null)
-            return false;
-
-        switch (key)
-        {
-            case "Cheevos/Login":
-            {
-                handleLogin();
-                return true;
-            }
-
-            case "Cheevos/Logout":
-            {
-                handleLogout();
-                return true;
-            }
-
-            case "Cheevos/Register":
-            {
-                openUrl(REGISTER_URL);
-                return true;
-            }
-
-            case "Cheevos/ViewProfile":
-            {
-                final String profileUrl = getProfileUrl(username);
-                if (profileUrl != null)
-                    openUrl(profileUrl);
-
-                return true;
-            }
-
-            default:
-                return false;
-        }
-    }
-
-    private void openUrl(String url) {
-        final Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
-        startActivity(browserIntent);
-    }
-
-    private void handleLogin() {
-        LoginDialogFragment loginDialog = new LoginDialogFragment(this);
-        loginDialog.show(getFragmentManager(), "fragment_achievement_login");
-    }
-
-    private void handleLogout() {
-        final AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
-        builder.setTitle(R.string.settings_achievements_confirm_logout_title);
-        builder.setMessage(R.string.settings_achievements_confirm_logout_message);
-        builder.setPositiveButton(R.string.settings_achievements_logout, (dialog, which) -> {
-                    AndroidHostInterface.getInstance().cheevosLogout();
-                    updateViews();
-        });
-        builder.setNegativeButton(R.string.achievement_settings_login_cancel_button, (dialog, which) -> dialog.dismiss());
-        builder.create().show();
-    }
-
-    private static String getProfileUrl(String username) {
-        try {
-            final String encodedUsername = URLEncoder.encode(username, "UTF-8");
-            return PROFILE_URL_PREFIX + encodedUsername;
-        } catch (Exception e) {
-            e.printStackTrace();
-            return null;
-        }
-    }
-
-    public static class LoginDialogFragment extends DialogFragment {
-        private AchievementSettingsFragment mParent;
-
-        public LoginDialogFragment(AchievementSettingsFragment parent) {
-            mParent = parent;
-        }
-
-        @Nullable
-        @Override
-        public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
-            return inflater.inflate(R.layout.fragment_achievements_login, container, false);
-        }
-
-        @Override
-        public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
-            super.onViewCreated(view, savedInstanceState);
-
-            ((Button)view.findViewById(R.id.login)).setOnClickListener((View.OnClickListener) v -> doLogin());
-            ((Button)view.findViewById(R.id.cancel)).setOnClickListener((View.OnClickListener) v -> dismiss());
-        }
-
-        private static class LoginTask extends AsyncTask<Void, Void, Void> {
-            private LoginDialogFragment mParent;
-            private String mUsername;
-            private String mPassword;
-            private boolean mResult;
-
-            public LoginTask(LoginDialogFragment parent, String username, String password) {
-                mParent = parent;
-                mUsername = username;
-                mPassword = password;
-            }
-
-            @Override
-            protected Void doInBackground(Void... voids) {
-                final Activity activity = mParent.getActivity();
-                if (activity == null)
-                    return null;
-
-                mResult = AndroidHostInterface.getInstance().cheevosLogin(mUsername, mPassword);
-
-                activity.runOnUiThread(() -> {
-                    if (!mResult) {
-                        ((TextView) mParent.getView().findViewById(R.id.error)).setText(R.string.achievement_settings_login_failed);
-                        mParent.enableUi(true);
-                        return;
-                    }
-
-                    mParent.mParent.updateViews();
-                    mParent.dismiss();
-                });
-
-                return null;
-            }
-        }
-
-        private void doLogin() {
-            final View rootView = getView();
-            final String username = ((EditText)rootView.findViewById(R.id.username)).getText().toString();
-            final String password = ((EditText)rootView.findViewById(R.id.password)).getText().toString();
-            if (username == null || username.length() == 0 || password == null || password.length() == 0)
-                return;
-
-            enableUi(false);
-            ((TextView)rootView.findViewById(R.id.error)).setText("");
-            new LoginDialogFragment.LoginTask(this, username, password).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
-        }
-
-        private void enableUi(boolean enabled) {
-            final View rootView = getView();
-            ((EditText)rootView.findViewById(R.id.username)).setEnabled(enabled);
-            ((EditText)rootView.findViewById(R.id.password)).setEnabled(enabled);
-            ((Button)rootView.findViewById(R.id.login)).setEnabled(enabled);
-            ((Button)rootView.findViewById(R.id.cancel)).setEnabled(enabled);
-            ((ProgressBar)rootView.findViewById(R.id.progressBar)).setVisibility(enabled ? View.GONE : View.VISIBLE);
-        }
-    }
-}
diff --git a/android/app/src/main/java/com/github/stenzek/duckstation/AndroidHostInterface.java b/android/app/src/main/java/com/github/stenzek/duckstation/AndroidHostInterface.java
deleted file mode 100644
index 48d70f7d3..000000000
--- a/android/app/src/main/java/com/github/stenzek/duckstation/AndroidHostInterface.java
+++ /dev/null
@@ -1,211 +0,0 @@
-package com.github.stenzek.duckstation;
-
-import android.content.Context;
-import android.content.SharedPreferences;
-import android.content.res.AssetManager;
-import android.os.Environment;
-import android.os.Process;
-import android.util.Log;
-import android.view.Surface;
-import android.widget.Toast;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.Locale;
-
-public class AndroidHostInterface {
-    public final static int DISPLAY_ALIGNMENT_TOP_OR_LEFT = 0;
-    public final static int DISPLAY_ALIGNMENT_CENTER = 1;
-    public final static int DISPLAY_ALIGNMENT_RIGHT_OR_BOTTOM = 2;
-
-    public final static int CONTROLLER_AXIS_TYPE_FULL = 0;
-    public final static int CONTROLLER_AXIS_TYPE_HALF = 1;
-
-    private long mNativePointer;
-    private Context mContext;
-    private FileHelper mFileHelper;
-    private EmulationActivity mEmulationActivity;
-
-    public AndroidHostInterface(Context context, FileHelper fileHelper) {
-        this.mContext = context;
-        this.mFileHelper = fileHelper;
-    }
-
-    public void reportError(String message) {
-        Toast.makeText(mContext, message, Toast.LENGTH_LONG).show();
-    }
-
-    public void reportMessage(String message) {
-        Toast.makeText(mContext, message, Toast.LENGTH_SHORT).show();
-    }
-
-    public InputStream openAssetStream(String path) {
-        try {
-            return mContext.getAssets().open(path, AssetManager.ACCESS_STREAMING);
-        } catch (IOException e) {
-            return null;
-        }
-    }
-
-    public void setContext(Context context) {
-        mContext = context;
-    }
-
-    public EmulationActivity getEmulationActivity() { return mEmulationActivity; }
-
-    static public native String getScmVersion();
-
-    static public native String getFullScmVersion();
-
-    static public native boolean setThreadAffinity(int[] cpus);
-
-    static public native AndroidHostInterface create(Context context, FileHelper fileHelper, String userDirectory);
-
-    public native boolean isEmulationThreadRunning();
-
-    public native boolean runEmulationThread(EmulationActivity emulationActivity, String filename, boolean resumeState, String state_filename);
-
-    public native boolean isEmulationThreadPaused();
-
-    public native void pauseEmulationThread(boolean paused);
-
-    public native void stopEmulationThreadLoop();
-
-    public native boolean hasSurface();
-
-    public native void surfaceChanged(Surface surface, int format, int width, int height);
-
-    public native void setControllerButtonState(int index, int buttonCode, boolean pressed);
-
-    public native void setControllerAxisState(int index, int axisCode, float value);
-
-    public native void setControllerAutoFireState(int controllerIndex, int autoFireIndex, boolean active);
-
-    public native void setMousePosition(int positionX, int positionY);
-
-    public static native int getControllerButtonCode(String controllerType, String buttonName);
-
-    public static native int getControllerAxisCode(String controllerType, String axisName);
-
-    public static native int getControllerAxisType(String controllerType, String axisName);
-
-    public static native String[] getControllerButtonNames(String controllerType);
-
-    public static native String[] getControllerAxisNames(String controllerType);
-
-    public static native int getControllerVibrationMotorCount(String controllerType);
-
-    public native void handleControllerButtonEvent(int controllerIndex, int buttonIndex, boolean pressed);
-
-    public native void handleControllerAxisEvent(int controllerIndex, int axisIndex, float value);
-
-    public native boolean hasControllerButtonBinding(int controllerIndex, int buttonIndex);
-
-    public native void toggleControllerAnalogMode();
-
-    public native String[] getInputProfileNames();
-
-    public native boolean loadInputProfile(String name);
-
-    public native boolean saveInputProfile(String name);
-
-    public native HotkeyInfo[] getHotkeyInfoList();
-
-    public native void refreshGameList(boolean invalidateCache, boolean invalidateDatabase, AndroidProgressCallback progressCallback);
-
-    public native GameListEntry[] getGameListEntries();
-
-    public native GameListEntry getGameListEntry(String path);
-
-    public native String getGameSettingValue(String path, String key);
-
-    public native void setGameSettingValue(String path, String key, String value);
-
-    public native void resetSystem();
-
-    public native void loadState(boolean global, int slot);
-
-    public native void saveState(boolean global, int slot);
-
-    public native void saveResumeState(boolean waitForCompletion);
-
-    public native void applySettings();
-    public native void updateInputMap();
-
-    public native void setDisplayAlignment(int alignment);
-
-    public native PatchCode[] getPatchCodeList();
-
-    public native void setPatchCodeEnabled(int index, boolean enabled);
-
-    public native boolean importPatchCodesFromString(String str);
-
-    public native void addOSDMessage(String message, float duration);
-
-    public native boolean hasAnyBIOSImages();
-
-    public native String importBIOSImage(byte[] data);
-
-    public native boolean isFastForwardEnabled();
-
-    public native void setFastForwardEnabled(boolean enabled);
-
-    public native boolean hasMediaSubImages();
-
-    public native String[] getMediaSubImageTitles();
-
-    public native int getMediaSubImageIndex();
-
-    public native boolean switchMediaSubImage(int index);
-
-    public native boolean setMediaFilename(String filename);
-
-    public native SaveStateInfo[] getSaveStateInfo(boolean includeEmpty);
-
-    public native void setFullscreenUINotificationVerticalPosition(float position, float direction);
-
-    public native boolean isCheevosActive();
-    public native boolean isCheevosChallengeModeActive();
-    public native Achievement[] getCheevoList();
-    public native int getCheevoCount();
-    public native int getUnlockedCheevoCount();
-    public native int getCheevoPointsForGame();
-    public native int getCheevoMaximumPointsForGame();
-    public native String getCheevoGameTitle();
-    public native String getCheevoGameIconPath();
-    public native boolean cheevosLogin(String username, String password);
-    public native void cheevosLogout();
-
-    static {
-        System.loadLibrary("duckstation-native");
-    }
-
-    static private AndroidHostInterface mInstance;
-    static private String mUserDirectory;
-
-    static public boolean createInstance(Context context) {
-        // Set user path.
-        mUserDirectory = Environment.getExternalStorageDirectory().getAbsolutePath();
-        if (mUserDirectory.isEmpty())
-            mUserDirectory = "/sdcard";
-
-        mUserDirectory += "/duckstation";
-        Log.i("AndroidHostInterface", "User directory: " + mUserDirectory);
-        mInstance = create(context, new FileHelper(context), mUserDirectory);
-        return mInstance != null;
-    }
-
-    static public boolean hasInstance() {
-        return mInstance != null;
-    }
-
-    static public AndroidHostInterface getInstance() {
-        return mInstance;
-    }
-
-    static public String getUserDirectory() { return mUserDirectory; }
-
-    static public boolean hasInstanceAndEmulationThreadIsRunning() {
-        return hasInstance() && getInstance().isEmulationThreadRunning();
-    }
-}
diff --git a/android/app/src/main/java/com/github/stenzek/duckstation/AndroidProgressCallback.java b/android/app/src/main/java/com/github/stenzek/duckstation/AndroidProgressCallback.java
deleted file mode 100644
index a77b9b3b9..000000000
--- a/android/app/src/main/java/com/github/stenzek/duckstation/AndroidProgressCallback.java
+++ /dev/null
@@ -1,141 +0,0 @@
-package com.github.stenzek.duckstation;
-
-import android.app.Activity;
-import android.app.ProgressDialog;
-
-import androidx.appcompat.app.AlertDialog;
-
-public class AndroidProgressCallback {
-    private Activity mContext;
-    private ProgressDialog mDialog;
-
-    public AndroidProgressCallback(Activity context) {
-        mContext = context;
-        mDialog = new ProgressDialog(context);
-        mDialog.setCancelable(false);
-        mDialog.setCanceledOnTouchOutside(false);
-        mDialog.setMessage(context.getString(R.string.android_progress_callback_please_wait));
-        mDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
-        mDialog.setIndeterminate(false);
-        mDialog.setMax(100);
-        mDialog.setProgress(0);
-        mDialog.show();
-    }
-
-    public void dismiss() {
-        mDialog.dismiss();
-    }
-
-    public void setTitle(String text) {
-        mContext.runOnUiThread(() -> {
-            mDialog.setTitle(text);
-        });
-    }
-
-    public void setStatusText(String text) {
-        mContext.runOnUiThread(() -> {
-            mDialog.setMessage(text);
-        });
-    }
-
-    public void setProgressRange(int range) {
-        mContext.runOnUiThread(() -> {
-            mDialog.setMax(range);
-        });
-    }
-
-    public void setProgressValue(int value) {
-        mContext.runOnUiThread(() -> {
-            mDialog.setProgress(value);
-        });
-    }
-
-    public void modalError(String message) {
-        Object lock = new Object();
-        mContext.runOnUiThread(() -> {
-            new AlertDialog.Builder(mContext)
-                    .setTitle("Error")
-                    .setMessage(message)
-                    .setPositiveButton(mContext.getString(R.string.android_progress_callback_ok), (dialog, button) -> {
-                        dialog.dismiss();
-                    })
-                    .setOnDismissListener((dialogInterface) -> {
-                        synchronized (lock) {
-                            lock.notify();
-                        }
-                    })
-                    .create()
-                    .show();
-        });
-
-        synchronized (lock) {
-            try {
-                lock.wait();
-            } catch (InterruptedException e) {
-            }
-        }
-    }
-
-    public void modalInformation(String message) {
-        Object lock = new Object();
-        mContext.runOnUiThread(() -> {
-            new AlertDialog.Builder(mContext)
-                    .setTitle(mContext.getString(R.string.android_progress_callback_information))
-                    .setMessage(message)
-                    .setPositiveButton(mContext.getString(R.string.android_progress_callback_ok), (dialog, button) -> {
-                        dialog.dismiss();
-                    })
-                    .setOnDismissListener((dialogInterface) -> {
-                        synchronized (lock) {
-                            lock.notify();
-                        }
-                    })
-                    .create()
-                    .show();
-        });
-
-        synchronized (lock) {
-            try {
-                lock.wait();
-            } catch (InterruptedException e) {
-            }
-        }
-    }
-
-    private class ConfirmationResult {
-        public boolean result = false;
-    }
-
-    public boolean modalConfirmation(String message) {
-        ConfirmationResult result = new ConfirmationResult();
-        mContext.runOnUiThread(() -> {
-            new AlertDialog.Builder(mContext)
-                    .setTitle(mContext.getString(R.string.android_progress_callback_confirmation))
-                    .setMessage(message)
-                    .setPositiveButton(mContext.getString(R.string.android_progress_callback_yes), (dialog, button) -> {
-                        result.result = true;
-                        dialog.dismiss();
-                    })
-                    .setNegativeButton(mContext.getString(R.string.android_progress_callback_no), (dialog, button) -> {
-                        result.result = false;
-                        dialog.dismiss();
-                    })
-                    .setOnDismissListener((dialogInterface) -> {
-                        synchronized (result) {
-                            result.notify();
-                        }
-                    })
-                    .create()
-                    .show();
-        });
-
-        synchronized (result) {
-            try {
-                result.wait();
-            } catch (InterruptedException e) {
-            }
-        }
-
-        return result.result;
-    }
-}
diff --git a/android/app/src/main/java/com/github/stenzek/duckstation/ConsoleRegion.java b/android/app/src/main/java/com/github/stenzek/duckstation/ConsoleRegion.java
deleted file mode 100644
index 0f56417a1..000000000
--- a/android/app/src/main/java/com/github/stenzek/duckstation/ConsoleRegion.java
+++ /dev/null
@@ -1,8 +0,0 @@
-package com.github.stenzek.duckstation;
-
-public enum ConsoleRegion {
-    AutoDetect,
-    NTSC_J,
-    NTSC_U,
-    PAL
-}
diff --git a/android/app/src/main/java/com/github/stenzek/duckstation/ControllerAutoMapper.java b/android/app/src/main/java/com/github/stenzek/duckstation/ControllerAutoMapper.java
deleted file mode 100644
index 175fb3cb3..000000000
--- a/android/app/src/main/java/com/github/stenzek/duckstation/ControllerAutoMapper.java
+++ /dev/null
@@ -1,295 +0,0 @@
-package com.github.stenzek.duckstation;
-
-import android.content.Context;
-import android.content.SharedPreferences;
-import android.os.Vibrator;
-import android.text.InputType;
-import android.view.InputDevice;
-import android.view.KeyEvent;
-import android.view.MotionEvent;
-import android.widget.EditText;
-import android.widget.TextView;
-
-import androidx.appcompat.app.AlertDialog;
-import androidx.preference.PreferenceManager;
-
-import java.util.ArrayList;
-import java.util.List;
-
-public class ControllerAutoMapper {
-    public interface CompleteCallback {
-        public void onComplete();
-    }
-
-    private final Context context;
-    private final int port;
-    private final CompleteCallback completeCallback;
-
-    private InputDevice device;
-    private SharedPreferences prefs;
-    private SharedPreferences.Editor editor;
-    private StringBuilder log;
-    private String keyBase;
-    private String controllerType;
-
-    public ControllerAutoMapper(Context context, int port, CompleteCallback completeCallback) {
-        this.context = context;
-        this.port = port;
-        this.completeCallback = completeCallback;
-    }
-
-    private void log(String format, Object... args) {
-        log.append(String.format(format, args));
-        log.append('\n');
-    }
-
-    private void setButtonBindingToKeyCode(String buttonName, int keyCode) {
-        log("Binding button '%s' to key '%s' (%d)", buttonName, KeyEvent.keyCodeToString(keyCode), keyCode);
-
-        final String key = String.format("%sButton%s", keyBase, buttonName);
-        final String value = String.format("%s/Button%d", device.getDescriptor(), keyCode);
-        editor.putString(key, value);
-    }
-
-    private void setButtonBindingToAxis(String buttonName, int axis, int direction) {
-        final char directionIndicator = (direction < 0) ? '-' : '+';
-        log("Binding button '%s' to axis '%s' (%d) direction %c", buttonName, MotionEvent.axisToString(axis), axis, directionIndicator);
-
-        final String key = String.format("%sButton%s", keyBase, buttonName);
-        final String value = String.format("%s/%cAxis%d", device.getDescriptor(), directionIndicator, axis);
-        editor.putString(key, value);
-    }
-
-    private void setAxisBindingToAxis(String axisName, int axis) {
-        log("Binding axis '%s' to axis '%s' (%d)", axisName, MotionEvent.axisToString(axis), axis);
-
-        final String key = String.format("%sAxis%s", keyBase, axisName);
-        final String value = String.format("%s/Axis%d", device.getDescriptor(), axis);
-        editor.putString(key, value);
-    }
-
-    private void doAutoBindingButton(String buttonName, int[] keyCodes, int[][] axisCodes) {
-        // Prefer the axis codes, as it dispatches to that first.
-        if (axisCodes != null) {
-            final List<InputDevice.MotionRange> motionRangeList = device.getMotionRanges();
-            for (int[] axisAndDirection : axisCodes) {
-                final int axis = axisAndDirection[0];
-                final int direction = axisAndDirection[1];
-                for (InputDevice.MotionRange range : motionRangeList) {
-                    if (range.getAxis() == axis) {
-                        setButtonBindingToAxis(buttonName, axis, direction);
-                        return;
-                    }
-                }
-            }
-        }
-
-        if (keyCodes != null) {
-            final boolean[] keysPresent = device.hasKeys(keyCodes);
-            for (int i = 0; i < keysPresent.length; i++) {
-                if (keysPresent[i]) {
-                    setButtonBindingToKeyCode(buttonName, keyCodes[i]);
-                    return;
-                }
-            }
-        }
-
-        log("No automatic bindings found for button '%s'", buttonName);
-    }
-
-    private void doAutoBindingAxis(String axisName, int[] axisCodes) {
-        // Prefer the axis codes, as it dispatches to that first.
-        if (axisCodes != null) {
-            final List<InputDevice.MotionRange> motionRangeList = device.getMotionRanges();
-            for (final int axis : axisCodes) {
-                for (InputDevice.MotionRange range : motionRangeList) {
-                    if (range.getAxis() == axis) {
-                        setAxisBindingToAxis(axisName, axis);
-                        return;
-                    }
-                }
-            }
-        }
-
-        log.append(String.format("No automatic bindings found for axis '%s'\n", axisName));
-    }
-
-    public void start() {
-        final ArrayList<InputDevice> deviceList = new ArrayList<>();
-        for (final int deviceId : InputDevice.getDeviceIds()) {
-            final InputDevice inputDevice = InputDevice.getDevice(deviceId);
-            if (inputDevice == null || !EmulationSurfaceView.isBindableDevice(inputDevice) ||
-                    !EmulationSurfaceView.isGamepadDevice(inputDevice)) {
-                continue;
-            }
-
-            deviceList.add(inputDevice);
-        }
-
-        if (deviceList.isEmpty()) {
-            final AlertDialog.Builder builder = new AlertDialog.Builder(context);
-            builder.setTitle(R.string.main_activity_error);
-            builder.setMessage(R.string.controller_auto_mapping_no_devices);
-            builder.setPositiveButton(R.string.main_activity_ok, (dialog, which) -> dialog.dismiss());
-            builder.create().show();
-            return;
-        }
-
-        final String[] deviceNames = new String[deviceList.size()];
-        for (int i = 0; i < deviceList.size(); i++)
-            deviceNames[i] = deviceList.get(i).getName();
-
-        final AlertDialog.Builder builder = new AlertDialog.Builder(context);
-        builder.setTitle(R.string.controller_auto_mapping_select_device);
-        builder.setItems(deviceNames, (dialog, which) -> {
-            process(deviceList.get(which));
-        });
-        builder.create().show();
-    }
-
-    private void process(InputDevice device) {
-        this.prefs = PreferenceManager.getDefaultSharedPreferences(context);
-        this.editor = prefs.edit();
-        this.log = new StringBuilder();
-        this.device = device;
-
-        this.keyBase = String.format("Controller%d/", port);
-        this.controllerType = ControllerSettingsCollectionFragment.getControllerType(prefs, port);
-
-        setButtonBindings();
-        setAxisBindings();
-        setVibrationBinding();
-
-        this.editor.commit();
-        this.editor = null;
-
-        final AlertDialog.Builder builder = new AlertDialog.Builder(context);
-        builder.setTitle(R.string.controller_auto_mapping_results);
-
-        final EditText editText = new EditText(context);
-        editText.setText(log.toString());
-        editText.setInputType(InputType.TYPE_NULL | InputType.TYPE_TEXT_FLAG_MULTI_LINE);
-        editText.setSingleLine(false);
-        builder.setView(editText);
-
-        builder.setPositiveButton(R.string.main_activity_ok, (dialog, which) -> dialog.dismiss());
-        builder.create().show();
-
-        if (completeCallback != null)
-            completeCallback.onComplete();
-    }
-
-    private void setButtonBindings() {
-        final String[] buttonNames = AndroidHostInterface.getInstance().getControllerButtonNames(controllerType);
-        if (buttonNames == null || buttonNames.length == 0) {
-            log("No axes to bind.");
-            return;
-        }
-
-        for (final String buttonName : buttonNames) {
-            switch (buttonName) {
-                case "Up":
-                    doAutoBindingButton(buttonName, new int[]{KeyEvent.KEYCODE_DPAD_UP}, new int[][]{{MotionEvent.AXIS_HAT_Y, -1}});
-                    break;
-                case "Down":
-                    doAutoBindingButton(buttonName, new int[]{KeyEvent.KEYCODE_DPAD_DOWN}, new int[][]{{MotionEvent.AXIS_HAT_Y, 1}});
-                    break;
-                case "Left":
-                    doAutoBindingButton(buttonName, new int[]{KeyEvent.KEYCODE_DPAD_LEFT}, new int[][]{{MotionEvent.AXIS_HAT_X, -1}});
-                    break;
-                case "Right":
-                    doAutoBindingButton(buttonName, new int[]{KeyEvent.KEYCODE_DPAD_RIGHT}, new int[][]{{MotionEvent.AXIS_HAT_X, 1}});
-                    break;
-                case "Select":
-                    doAutoBindingButton(buttonName, new int[]{KeyEvent.KEYCODE_BUTTON_SELECT}, null);
-                    break;
-                case "Start":
-                    doAutoBindingButton(buttonName, new int[]{KeyEvent.KEYCODE_BUTTON_START}, null);
-                    break;
-                case "Triangle":
-                    doAutoBindingButton(buttonName, new int[]{KeyEvent.KEYCODE_BUTTON_Y}, null);
-                    break;
-                case "Cross":
-                    doAutoBindingButton(buttonName, new int[]{KeyEvent.KEYCODE_BUTTON_A}, null);
-                    break;
-                case "Circle":
-                    doAutoBindingButton(buttonName, new int[]{KeyEvent.KEYCODE_BUTTON_B}, null);
-                    break;
-                case "Square":
-                    doAutoBindingButton(buttonName, new int[]{KeyEvent.KEYCODE_BUTTON_X}, null);
-                    break;
-                case "L1":
-                    doAutoBindingButton(buttonName, new int[]{KeyEvent.KEYCODE_BUTTON_L1}, null);
-                    break;
-                case "L2":
-                    doAutoBindingButton(buttonName, new int[]{KeyEvent.KEYCODE_BUTTON_L2}, new int[][]{{MotionEvent.AXIS_LTRIGGER, 1}, {MotionEvent.AXIS_Z, 1}, {MotionEvent.AXIS_BRAKE, 1}});
-                    break;
-                case "R1":
-                    doAutoBindingButton(buttonName, new int[]{KeyEvent.KEYCODE_BUTTON_R1}, null);
-                    break;
-                case "R2":
-                    doAutoBindingButton(buttonName, new int[]{KeyEvent.KEYCODE_BUTTON_R2}, new int[][]{{MotionEvent.AXIS_RTRIGGER, 1}, {MotionEvent.AXIS_RZ, 1}, {MotionEvent.AXIS_GAS, 1}});
-                    break;
-                case "L3":
-                    doAutoBindingButton(buttonName, new int[]{KeyEvent.KEYCODE_BUTTON_THUMBL}, null);
-                    break;
-                case "R3":
-                    doAutoBindingButton(buttonName, new int[]{KeyEvent.KEYCODE_BUTTON_THUMBR}, null);
-                    break;
-                case "Analog":
-                    doAutoBindingButton(buttonName, new int[]{KeyEvent.KEYCODE_BUTTON_MODE}, null);
-                    break;
-                default:
-                    log("Button '%s' not supported by auto mapping.", buttonName);
-                    break;
-            }
-        }
-    }
-
-    private void setAxisBindings() {
-        final String[] axisNames = AndroidHostInterface.getInstance().getControllerAxisNames(controllerType);
-        if (axisNames == null || axisNames.length == 0) {
-            log("No axes to bind.");
-            return;
-        }
-
-        for (final String axisName : axisNames) {
-            switch (axisName) {
-                case "LeftX":
-                    doAutoBindingAxis(axisName, new int[]{MotionEvent.AXIS_X});
-                    break;
-                case "LeftY":
-                    doAutoBindingAxis(axisName, new int[]{MotionEvent.AXIS_Y});
-                    break;
-                case "RightX":
-                    doAutoBindingAxis(axisName, new int[]{MotionEvent.AXIS_RX, MotionEvent.AXIS_Z});
-                    break;
-                case "RightY":
-                    doAutoBindingAxis(axisName, new int[]{MotionEvent.AXIS_RY, MotionEvent.AXIS_RZ});
-                    break;
-                default:
-                    log("Axis '%s' not supported by auto mapping.", axisName);
-                    break;
-            }
-        }
-    }
-
-    private void setVibrationBinding() {
-        final int motorCount = AndroidHostInterface.getInstance().getControllerVibrationMotorCount(controllerType);
-        if (motorCount == 0) {
-            log("No vibration motors to bind.");
-            return;
-        }
-
-        final Vibrator vibrator = device.getVibrator();
-        if (vibrator == null || !vibrator.hasVibrator()) {
-            log("Selected device has no vibrator, cannot bind vibration.");
-            return;
-        }
-
-        log("Binding vibration to device '%s'.", device.getDescriptor());
-
-        final String key = String.format("%sRumble", keyBase);
-        editor.putString(key, device.getDescriptor());
-    }
-}
diff --git a/android/app/src/main/java/com/github/stenzek/duckstation/ControllerBindingDialog.java b/android/app/src/main/java/com/github/stenzek/duckstation/ControllerBindingDialog.java
deleted file mode 100644
index 8b6344c25..000000000
--- a/android/app/src/main/java/com/github/stenzek/duckstation/ControllerBindingDialog.java
+++ /dev/null
@@ -1,170 +0,0 @@
-package com.github.stenzek.duckstation;
-
-import android.app.AlertDialog;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.content.SharedPreferences;
-import android.preference.PreferenceManager;
-import android.util.ArraySet;
-import android.view.InputDevice;
-import android.view.KeyEvent;
-import android.view.MotionEvent;
-import android.widget.Toast;
-
-import androidx.annotation.NonNull;
-
-import java.util.HashMap;
-import java.util.List;
-
-public class ControllerBindingDialog extends AlertDialog {
-    final static float DETECT_THRESHOLD = 0.25f;
-    private final ControllerBindingPreference.Type mType;
-    private final String mSettingKey;
-    private String mCurrentBinding;
-    private int mUpdatedAxisCode = -1;
-    private final HashMap<Integer, float[]> mStartingAxisValues = new HashMap<>();
-
-    public ControllerBindingDialog(Context context, String buttonName, String settingKey, String currentBinding, ControllerBindingPreference.Type type) {
-        super(context);
-
-        mType = type;
-        mSettingKey = settingKey;
-        mCurrentBinding = currentBinding;
-        if (mCurrentBinding == null)
-            mCurrentBinding = getContext().getString(R.string.controller_binding_dialog_no_binding);
-
-        setTitle(buttonName);
-        updateMessage();
-        setButton(BUTTON_POSITIVE, context.getString(R.string.controller_binding_dialog_cancel), (dialogInterface, button) -> dismiss());
-        setButton(BUTTON_NEGATIVE, context.getString(R.string.controller_binding_dialog_clear), (dialogInterface, button) -> {
-            mCurrentBinding = null;
-            updateBinding();
-            dismiss();
-        });
-
-        setOnKeyListener(new DialogInterface.OnKeyListener() {
-            @Override
-            public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) {
-                return onKeyDown(keyCode, event);
-            }
-        });
-    }
-
-    private void updateMessage() {
-        setMessage(String.format(getContext().getString(R.string.controller_binding_dialog_message), mCurrentBinding));
-    }
-
-    private void updateBinding() {
-        SharedPreferences.Editor editor = PreferenceManager.getDefaultSharedPreferences(getContext()).edit();
-        if (mCurrentBinding != null) {
-            ArraySet<String> values = new ArraySet<>();
-            values.add(mCurrentBinding);
-            editor.putStringSet(mSettingKey, values);
-        } else {
-            try {
-                editor.remove(mSettingKey);
-            } catch (Exception e) {
-
-            }
-        }
-
-        editor.commit();
-    }
-
-    @Override
-    public boolean onKeyDown(int keyCode, KeyEvent event) {
-        final InputDevice device = event.getDevice();
-        if (!EmulationSurfaceView.isBindableDevice(device) || !EmulationSurfaceView.isBindableKeyEvent(event)) {
-            return super.onKeyDown(keyCode, event);
-        }
-
-        if (mType == ControllerBindingPreference.Type.BUTTON || mType == ControllerBindingPreference.Type.HALF_AXIS) {
-            mCurrentBinding = String.format("%s/Button%d", device.getDescriptor(), event.getKeyCode());
-        }  else if (mType == ControllerBindingPreference.Type.VIBRATION) {
-            if (device.getVibrator() == null || !device.getVibrator().hasVibrator()) {
-                Toast.makeText(getContext(), getContext().getString(R.string.controller_settings_vibration_unsupported), Toast.LENGTH_LONG).show();
-                dismiss();
-                return true;
-            }
-
-            mCurrentBinding = device.getDescriptor();
-        } else {
-            return super.onKeyDown(keyCode, event);
-        }
-
-        updateMessage();
-        updateBinding();
-        dismiss();
-        return true;
-    }
-
-    private void setAxisCode(InputDevice device, int axisCode, boolean positive) {
-        if (mUpdatedAxisCode >= 0)
-            return;
-
-        mUpdatedAxisCode = axisCode;
-
-        final int controllerIndex = 0;
-        if (mType == ControllerBindingPreference.Type.AXIS || mType == ControllerBindingPreference.Type.HALF_AXIS)
-            mCurrentBinding = String.format("%s/Axis%d", device.getDescriptor(), axisCode);
-        else
-            mCurrentBinding = String.format("%s/%cAxis%d", device.getDescriptor(), (positive) ? '+' : '-', axisCode);
-
-        updateBinding();
-        updateMessage();
-        dismiss();
-    }
-
-    private boolean doAxisDetection(MotionEvent event) {
-        if (!EmulationSurfaceView.isBindableDevice(event.getDevice()) || !EmulationSurfaceView.isJoystickMotionEvent(event))
-            return false;
-
-        final List<InputDevice.MotionRange> motionEventList = event.getDevice().getMotionRanges();
-        if (motionEventList == null || motionEventList.isEmpty())
-            return false;
-
-        final int deviceId = event.getDeviceId();
-        if (!mStartingAxisValues.containsKey(deviceId)) {
-            final float[] axisValues = new float[motionEventList.size()];
-            for (int axisIndex = 0; axisIndex < motionEventList.size(); axisIndex++) {
-                final int axisCode = motionEventList.get(axisIndex).getAxis();
-
-                if (event.getHistorySize() > 0)
-                    axisValues[axisIndex] = event.getHistoricalAxisValue(axisCode, 0);
-                else if (axisCode == MotionEvent.AXIS_HAT_X || axisCode == MotionEvent.AXIS_HAT_Y)
-                    axisValues[axisIndex] = 0.0f;
-                else
-                    axisValues[axisIndex] = event.getAxisValue(axisCode);
-            }
-
-            mStartingAxisValues.put(deviceId, axisValues);
-        }
-
-        final float[] axisValues = mStartingAxisValues.get(deviceId);
-        for (int axisIndex = 0; axisIndex < motionEventList.size(); axisIndex++) {
-            final int axisCode = motionEventList.get(axisIndex).getAxis();
-            final float newValue = event.getAxisValue(axisCode);
-            final float delta = newValue - axisValues[axisIndex];
-            if (Math.abs(delta) >= DETECT_THRESHOLD) {
-                setAxisCode(event.getDevice(), axisCode, delta >= 0.0f);
-                break;
-            }
-        }
-
-        return true;
-    }
-
-    @Override
-    public boolean onGenericMotionEvent(@NonNull MotionEvent event) {
-        if (mType != ControllerBindingPreference.Type.AXIS &&
-            mType != ControllerBindingPreference.Type.HALF_AXIS &&
-            mType != ControllerBindingPreference.Type.BUTTON) {
-            return false;
-        }
-
-        if (doAxisDetection(event))
-            return true;
-
-        return super.onGenericMotionEvent(event);
-    }
-}
diff --git a/android/app/src/main/java/com/github/stenzek/duckstation/ControllerBindingPreference.java b/android/app/src/main/java/com/github/stenzek/duckstation/ControllerBindingPreference.java
deleted file mode 100644
index 0aa4ad707..000000000
--- a/android/app/src/main/java/com/github/stenzek/duckstation/ControllerBindingPreference.java
+++ /dev/null
@@ -1,268 +0,0 @@
-package com.github.stenzek.duckstation;
-
-import android.content.Context;
-import android.content.SharedPreferences;
-import android.util.AttributeSet;
-import android.view.InputDevice;
-import android.widget.ImageView;
-import android.widget.TextView;
-
-import androidx.core.content.ContextCompat;
-import androidx.preference.Preference;
-import androidx.preference.PreferenceManager;
-import androidx.preference.PreferenceViewHolder;
-
-import java.util.Set;
-
-public class ControllerBindingPreference extends Preference {
-    public enum Type {
-        BUTTON,
-        AXIS,
-        HALF_AXIS,
-        VIBRATION
-    }
-
-    private enum VisualType {
-        BUTTON,
-        AXIS,
-        VIBRATION,
-        HOTKEY
-    }
-
-    private String mBindingName;
-    private String mDisplayName;
-    private String mValue;
-    private TextView mValueView;
-    private Type mType = Type.BUTTON;
-    private VisualType mVisualType = VisualType.BUTTON;
-
-    private static int getIconForButton(String buttonName) {
-        if (buttonName.equals("Up")) {
-            return R.drawable.ic_controller_up_button_pressed;
-        } else if (buttonName.equals("Right")) {
-            return R.drawable.ic_controller_right_button_pressed;
-        } else if (buttonName.equals("Down")) {
-            return R.drawable.ic_controller_down_button_pressed;
-        } else if (buttonName.equals("Left")) {
-            return R.drawable.ic_controller_left_button_pressed;
-        } else if (buttonName.equals("Triangle")) {
-            return R.drawable.ic_controller_triangle_button_pressed;
-        } else if (buttonName.equals("Circle")) {
-            return R.drawable.ic_controller_circle_button_pressed;
-        } else if (buttonName.equals("Cross")) {
-            return R.drawable.ic_controller_cross_button_pressed;
-        } else if (buttonName.equals("Square")) {
-            return R.drawable.ic_controller_square_button_pressed;
-        } else if (buttonName.equals("Start")) {
-            return R.drawable.ic_controller_start_button_pressed;
-        } else if (buttonName.equals("Select")) {
-            return R.drawable.ic_controller_select_button_pressed;
-        } else if (buttonName.equals("L1")) {
-            return R.drawable.ic_controller_l1_button_pressed;
-        } else if (buttonName.equals("L2")) {
-            return R.drawable.ic_controller_l2_button_pressed;
-        } else if (buttonName.equals("R1")) {
-            return R.drawable.ic_controller_r1_button_pressed;
-        } else if (buttonName.equals("R2")) {
-            return R.drawable.ic_controller_r2_button_pressed;
-        }
-
-        return R.drawable.ic_baseline_radio_button_unchecked_24;
-    }
-
-    private static int getIconForAxis(String axisName) {
-        return R.drawable.ic_baseline_radio_button_checked_24;
-    }
-
-    private static int getIconForHotkey(String hotkeyDisplayName) {
-        switch (hotkeyDisplayName) {
-            case "FastForward":
-            case "ToggleFastForward":
-            case "Turbo":
-            case "ToggleTurbo":
-                return R.drawable.ic_controller_fast_forward;
-
-            default:
-                return R.drawable.ic_baseline_category_24;
-        }
-    }
-
-    public ControllerBindingPreference(Context context, AttributeSet attrs) {
-        this(context, attrs, 0);
-        setWidgetLayoutResource(R.layout.layout_controller_binding_preference);
-        setIconSpaceReserved(false);
-    }
-
-    public ControllerBindingPreference(Context context, AttributeSet attrs, int defStyleAttr) {
-        super(context, attrs, defStyleAttr);
-        setWidgetLayoutResource(R.layout.layout_controller_binding_preference);
-        setIconSpaceReserved(false);
-    }
-
-    public ControllerBindingPreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
-        super(context, attrs, defStyleAttr, defStyleRes);
-        setWidgetLayoutResource(R.layout.layout_controller_binding_preference);
-        setIconSpaceReserved(false);
-    }
-
-    @Override
-    public void onBindViewHolder(PreferenceViewHolder holder) {
-        super.onBindViewHolder(holder);
-
-        ImageView iconView = ((ImageView) holder.findViewById(R.id.controller_binding_icon));
-        TextView nameView = ((TextView) holder.findViewById(R.id.controller_binding_name));
-        mValueView = ((TextView) holder.findViewById(R.id.controller_binding_value));
-
-        int drawableId = R.drawable.ic_baseline_radio_button_checked_24;
-        switch (mVisualType) {
-            case BUTTON:
-                drawableId = getIconForButton(mBindingName);
-                break;
-            case AXIS:
-                drawableId = getIconForAxis(mBindingName);
-                break;
-            case HOTKEY:
-                drawableId = getIconForHotkey(mBindingName);
-                break;
-            case VIBRATION:
-                drawableId = R.drawable.ic_baseline_vibration_24;
-                break;
-        }
-
-        iconView.setImageDrawable(ContextCompat.getDrawable(getContext(), drawableId));
-        nameView.setText(mDisplayName);
-        updateValue();
-    }
-
-    @Override
-    protected void onClick() {
-        ControllerBindingDialog dialog = new ControllerBindingDialog(getContext(), mBindingName, getKey(), mValue, mType);
-        dialog.setOnDismissListener((dismissedDialog) -> updateValue());
-        dialog.show();
-    }
-
-    public void initButton(int controllerIndex, String buttonName) {
-        mBindingName = buttonName;
-        mDisplayName = buttonName;
-        mType = Type.BUTTON;
-        mVisualType = VisualType.BUTTON;
-        setKey(String.format("Controller%d/Button%s", controllerIndex, buttonName));
-        updateValue();
-    }
-
-    public void initAxis(int controllerIndex, String axisName, int axisType) {
-        mBindingName = axisName;
-        mDisplayName = axisName;
-        mType = (axisType == AndroidHostInterface.CONTROLLER_AXIS_TYPE_HALF) ? Type.HALF_AXIS : Type.AXIS;
-        mVisualType = VisualType.AXIS;
-        setKey(String.format("Controller%d/Axis%s", controllerIndex, axisName));
-        updateValue();
-    }
-
-    public void initVibration(int controllerIndex) {
-        mBindingName = "Rumble";
-        mDisplayName = getContext().getString(R.string.controller_binding_device_for_vibration);
-        mType = Type.VIBRATION;
-        mVisualType = VisualType.VIBRATION;
-        setKey(String.format("Controller%d/Rumble", controllerIndex));
-        updateValue();
-    }
-
-    public void initHotkey(HotkeyInfo hotkeyInfo) {
-        mBindingName = hotkeyInfo.getName();
-        mDisplayName = hotkeyInfo.getDisplayName();
-        mType = Type.BUTTON;
-        mVisualType = VisualType.HOTKEY;
-        setKey(hotkeyInfo.getBindingConfigKey());
-        updateValue();
-    }
-
-    public void initAutoFireButton(int controllerIndex, int autoFireSlot) {
-        mBindingName = String.format("AutoFire%d", autoFireSlot);
-        mDisplayName = getContext().getString(R.string.controller_binding_auto_fire_n, autoFireSlot);
-        mType = Type.BUTTON;
-        mVisualType = VisualType.BUTTON;
-        setKey(String.format("Controller%d/AutoFire%d", controllerIndex, autoFireSlot));
-        updateValue();
-    }
-
-    private String prettyPrintBinding(String value) {
-        final int index = value.indexOf('/');
-        String device, binding;
-        if (index >= 0) {
-            device = value.substring(0, index);
-            binding = value.substring(index);
-        } else {
-            device = value;
-            binding = "";
-        }
-
-        String humanName = device;
-        int deviceIndex = -1;
-
-        final int[] deviceIds = InputDevice.getDeviceIds();
-        for (int i = 0; i < deviceIds.length; i++) {
-            final InputDevice inputDevice = InputDevice.getDevice(deviceIds[i]);
-            if (inputDevice == null || !inputDevice.getDescriptor().equals(device)) {
-                continue;
-            }
-
-            humanName = inputDevice.getName();
-            deviceIndex = i;
-            break;
-        }
-
-        final int MAX_LENGTH = 40;
-        if (humanName.length() > MAX_LENGTH) {
-            final StringBuilder shortenedName = new StringBuilder();
-            shortenedName.append(humanName, 0, MAX_LENGTH / 2);
-            shortenedName.append("...");
-            shortenedName.append(humanName, humanName.length() - (MAX_LENGTH / 2),
-                    humanName.length());
-
-            humanName = shortenedName.toString();
-        }
-
-        if (deviceIndex < 0)
-            return String.format("%s[??]%s", humanName, binding);
-        else
-            return String.format("%s[%d]%s", humanName, deviceIndex, binding);
-    }
-
-    private void updateValue(String value) {
-        mValue = value;
-        if (mValueView != null) {
-            if (value != null)
-                mValueView.setText(value);
-            else
-                mValueView.setText(getContext().getString(R.string.controller_binding_dialog_no_binding));
-        }
-    }
-
-    public void updateValue() {
-        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getContext());
-        Set<String> values = PreferenceHelpers.getStringSet(prefs, getKey());
-        if (values != null) {
-            StringBuilder sb = new StringBuilder();
-            for (String value : values) {
-                if (sb.length() > 0)
-                    sb.append(", ");
-                sb.append(prettyPrintBinding(value));
-            }
-
-            updateValue(sb.toString());
-        } else {
-            updateValue(null);
-        }
-    }
-
-    public void clearBinding(SharedPreferences.Editor prefEditor) {
-        try {
-            prefEditor.remove(getKey());
-        } catch (Exception e) {
-
-        }
-
-        updateValue(null);
-    }
-}
diff --git a/android/app/src/main/java/com/github/stenzek/duckstation/ControllerSettingsActivity.java b/android/app/src/main/java/com/github/stenzek/duckstation/ControllerSettingsActivity.java
deleted file mode 100644
index 73448dbc8..000000000
--- a/android/app/src/main/java/com/github/stenzek/duckstation/ControllerSettingsActivity.java
+++ /dev/null
@@ -1,132 +0,0 @@
-package com.github.stenzek.duckstation;
-
-import android.content.SharedPreferences;
-import android.os.Bundle;
-import android.view.Menu;
-import android.view.MenuItem;
-import android.widget.EditText;
-import android.widget.Toast;
-
-import androidx.annotation.NonNull;
-import androidx.appcompat.app.ActionBar;
-import androidx.appcompat.app.AlertDialog;
-import androidx.appcompat.app.AppCompatActivity;
-import androidx.preference.PreferenceManager;
-
-import java.util.ArrayList;
-
-public class ControllerSettingsActivity extends AppCompatActivity {
-    private ControllerSettingsCollectionFragment fragment;
-
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(null);
-        setContentView(R.layout.settings_activity);
-
-        fragment = new ControllerSettingsCollectionFragment();
-        fragment.setMultitapModeChangedListener(this::recreate);
-
-        getSupportFragmentManager()
-                .beginTransaction()
-                .replace(R.id.settings, fragment)
-                .commit();
-        ActionBar actionBar = getSupportActionBar();
-        if (actionBar != null) {
-            actionBar.setDisplayHomeAsUpEnabled(true);
-            actionBar.setTitle(R.string.controller_mapping_activity_title);
-        }
-    }
-
-    @Override
-    public boolean onCreateOptionsMenu(Menu menu) {
-        // Inflate the menu; this adds items to the action bar if it is present.
-        getMenuInflater().inflate(R.menu.menu_controller_mapping, menu);
-        return true;
-    }
-
-    @Override
-    public boolean onOptionsItemSelected(@NonNull MenuItem item) {
-        if (item.getItemId() == android.R.id.home) {
-            onBackPressed();
-            return true;
-        }
-
-        final int id = item.getItemId();
-
-        //noinspection SimplifiableIfStatement
-        if (id == R.id.action_load_profile) {
-            doLoadProfile();
-            return true;
-        } else if (id == R.id.action_save_profile) {
-            doSaveProfile();
-            return true;
-        } else if (id == R.id.action_clear_bindings) {
-            fragment.clearAllBindings();
-            return true;
-        } else {
-            return super.onOptionsItemSelected(item);
-        }
-    }
-
-    private void displayError(String text) {
-        new AlertDialog.Builder(this)
-                .setTitle(R.string.emulation_activity_error)
-                .setMessage(text)
-                .setNegativeButton(R.string.main_activity_ok, ((dialog, which) -> dialog.dismiss()))
-                .create()
-                .show();
-    }
-
-    private void doLoadProfile() {
-        final String[] profileNames = AndroidHostInterface.getInstance().getInputProfileNames();
-        if (profileNames == null) {
-            displayError(getString(R.string.controller_mapping_activity_no_profiles_found));
-            return;
-        }
-
-        new AlertDialog.Builder(this)
-                .setTitle(R.string.controller_mapping_activity_select_input_profile)
-                .setItems(profileNames, (dialog, choice) -> {
-                    doLoadProfile(profileNames[choice]);
-                    dialog.dismiss();
-                })
-                .setNegativeButton(R.string.controller_mapping_activity_cancel, ((dialog, which) -> dialog.dismiss()))
-                .create()
-                .show();
-    }
-
-    private void doLoadProfile(String profileName) {
-        if (!AndroidHostInterface.getInstance().loadInputProfile(profileName)) {
-            displayError(String.format(getString(R.string.controller_mapping_activity_failed_to_load_profile), profileName));
-            return;
-        }
-
-        fragment.updateAllBindings();
-    }
-
-    private void doSaveProfile() {
-        final AlertDialog.Builder builder = new AlertDialog.Builder(this);
-        final EditText input = new EditText(this);
-        builder.setTitle(R.string.controller_mapping_activity_input_profile_name);
-        builder.setView(input);
-        builder.setPositiveButton(R.string.controller_mapping_activity_save, (dialog, which) -> {
-            final String name = input.getText().toString();
-            if (name.isEmpty()) {
-                displayError(getString(R.string.controller_mapping_activity_name_must_be_provided));
-                return;
-            }
-
-            if (!AndroidHostInterface.getInstance().saveInputProfile(name)) {
-                displayError(getString(R.string.controller_mapping_activity_failed_to_save_input_profile));
-                return;
-            }
-
-            Toast.makeText(ControllerSettingsActivity.this, String.format(ControllerSettingsActivity.this.getString(R.string.controller_mapping_activity_input_profile_saved), name),
-                    Toast.LENGTH_LONG).show();
-        });
-        builder.setNegativeButton(R.string.controller_mapping_activity_cancel, (dialog, which) -> dialog.dismiss());
-        builder.create().show();
-    }
-
-
-}
\ No newline at end of file
diff --git a/android/app/src/main/java/com/github/stenzek/duckstation/ControllerSettingsCollectionFragment.java b/android/app/src/main/java/com/github/stenzek/duckstation/ControllerSettingsCollectionFragment.java
deleted file mode 100644
index 00b86191d..000000000
--- a/android/app/src/main/java/com/github/stenzek/duckstation/ControllerSettingsCollectionFragment.java
+++ /dev/null
@@ -1,459 +0,0 @@
-package com.github.stenzek.duckstation;
-
-
-import android.annotation.SuppressLint;
-import android.app.Dialog;
-import android.content.SharedPreferences;
-import android.os.Bundle;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.Window;
-import android.widget.Toast;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.appcompat.app.AlertDialog;
-import androidx.fragment.app.DialogFragment;
-import androidx.fragment.app.Fragment;
-import androidx.preference.ListPreference;
-import androidx.preference.Preference;
-import androidx.preference.PreferenceCategory;
-import androidx.preference.PreferenceFragmentCompat;
-import androidx.preference.PreferenceManager;
-import androidx.preference.PreferenceScreen;
-import androidx.preference.SeekBarPreference;
-import androidx.preference.SwitchPreferenceCompat;
-import androidx.viewpager2.adapter.FragmentStateAdapter;
-import androidx.viewpager2.widget.ViewPager2;
-
-import com.google.android.material.tabs.TabLayout;
-import com.google.android.material.tabs.TabLayoutMediator;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-
-public class ControllerSettingsCollectionFragment extends Fragment {
-    public static final String MULTITAP_MODE_SETTINGS_KEY = "ControllerPorts/MultitapMode";
-    private static final int NUM_MAIN_CONTROLLER_PORTS = 2;
-    private static final int NUM_SUB_CONTROLLER_PORTS = 4;
-    private static final char[] SUB_CONTROLLER_PORT_NAMES = new char[]{'A', 'B', 'C', 'D'};
-    private static final int NUM_AUTO_FIRE_BUTTONS = 4;
-
-    public interface MultitapModeChangedListener {
-        void onChanged();
-    }
-
-    private final ArrayList<ControllerBindingPreference> preferences = new ArrayList<>();
-    private SettingsCollectionAdapter adapter;
-    private ViewPager2 viewPager;
-    private String[] controllerPortNames;
-
-    private MultitapModeChangedListener multitapModeChangedListener;
-
-    public ControllerSettingsCollectionFragment() {
-    }
-
-    public static String getControllerTypeKey(int port) {
-        return String.format("Controller%d/Type", port);
-    }
-
-    public static String getControllerType(SharedPreferences prefs, int port) {
-        final String defaultControllerType = (port == 1) ? "DigitalController" : "None";
-        return prefs.getString(getControllerTypeKey(port), defaultControllerType);
-    }
-
-    @Nullable
-    @Override
-    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
-        return inflater.inflate(R.layout.fragment_controller_settings, container, false);
-    }
-
-    @Override
-    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
-        final String multitapMode = PreferenceManager.getDefaultSharedPreferences(getContext()).getString(
-                MULTITAP_MODE_SETTINGS_KEY, "Disabled");
-
-        final ArrayList<String> portNames = new ArrayList<>();
-        for (int i = 0; i < NUM_MAIN_CONTROLLER_PORTS; i++) {
-            final boolean isMultitap = (multitapMode.equals("BothPorts") ||
-                    (i == 0 && multitapMode.equals("Port1Only")) ||
-                    (i == 1 && multitapMode.equals("Port2Only")));
-
-            if (isMultitap) {
-                for (int j = 0; j < NUM_SUB_CONTROLLER_PORTS; j++) {
-                    portNames.add(getContext().getString(
-                            R.string.controller_settings_sub_port_format,
-                            i + 1, SUB_CONTROLLER_PORT_NAMES[j]));
-                }
-            } else {
-                portNames.add(getContext().getString(
-                        R.string.controller_settings_main_port_format,
-                        i + 1));
-            }
-        }
-
-        controllerPortNames = new String[portNames.size()];
-        portNames.toArray(controllerPortNames);
-
-        adapter = new SettingsCollectionAdapter(this, controllerPortNames.length);
-        viewPager = view.findViewById(R.id.view_pager);
-        viewPager.setAdapter(adapter);
-
-        TabLayout tabLayout = view.findViewById(R.id.tab_layout);
-        new TabLayoutMediator(tabLayout, viewPager, (tab, position) -> {
-            if (position == 0)
-                tab.setText(R.string.controller_settings_tab_settings);
-            else if (position <= controllerPortNames.length)
-                tab.setText(controllerPortNames[position - 1]);
-            else
-                tab.setText(R.string.controller_settings_tab_hotkeys);
-        }).attach();
-    }
-
-    public void setMultitapModeChangedListener(MultitapModeChangedListener multitapModeChangedListener) {
-        this.multitapModeChangedListener = multitapModeChangedListener;
-    }
-
-    public void clearAllBindings() {
-        SharedPreferences.Editor prefEdit = PreferenceManager.getDefaultSharedPreferences(getContext()).edit();
-        for (ControllerBindingPreference pref : preferences)
-            pref.clearBinding(prefEdit);
-        prefEdit.commit();
-    }
-
-    public void updateAllBindings() {
-        for (ControllerBindingPreference pref : preferences)
-            pref.updateValue();
-    }
-
-    public static class SettingsFragment extends PreferenceFragmentCompat {
-        private final ControllerSettingsCollectionFragment parent;
-
-        public SettingsFragment(ControllerSettingsCollectionFragment parent) {
-            this.parent = parent;
-        }
-
-        @Override
-        public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
-            setPreferencesFromResource(R.xml.controllers_preferences, rootKey);
-
-            final Preference multitapModePreference = getPreferenceScreen().findPreference(MULTITAP_MODE_SETTINGS_KEY);
-            if (multitapModePreference != null) {
-                multitapModePreference.setOnPreferenceChangeListener((pref, newValue) -> {
-                    if (parent.multitapModeChangedListener != null)
-                        parent.multitapModeChangedListener.onChanged();
-
-                    return true;
-                });
-            }
-        }
-    }
-
-    public static class ControllerPortFragment extends PreferenceFragmentCompat {
-        private final ControllerSettingsCollectionFragment parent;
-        private final int controllerIndex;
-        private PreferenceCategory mButtonsCategory;
-        private PreferenceCategory mAxisCategory;
-        private PreferenceCategory mSettingsCategory;
-        private PreferenceCategory mAutoFireCategory;
-        private PreferenceCategory mAutoFireBindingsCategory;
-
-        public ControllerPortFragment(ControllerSettingsCollectionFragment parent, int controllerIndex) {
-            this.parent = parent;
-            this.controllerIndex = controllerIndex;
-        }
-
-        private static void clearBindingsInCategory(SharedPreferences.Editor editor, PreferenceCategory category) {
-            for (int i = 0; i < category.getPreferenceCount(); i++) {
-                final Preference preference = category.getPreference(i);
-                if (preference instanceof ControllerBindingPreference)
-                    ((ControllerBindingPreference) preference).clearBinding(editor);
-            }
-        }
-
-        @Override
-        public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
-            final PreferenceScreen ps = getPreferenceManager().createPreferenceScreen(getContext());
-            setPreferenceScreen(ps);
-            createPreferences();
-        }
-
-        private SwitchPreferenceCompat createTogglePreference(String key, int title, int summary, boolean defaultValue) {
-            final SwitchPreferenceCompat pref = new SwitchPreferenceCompat(getContext());
-            pref.setKey(key);
-            pref.setTitle(title);
-            pref.setSummary(summary);
-            pref.setIconSpaceReserved(false);
-            pref.setDefaultValue(defaultValue);
-            return pref;
-        }
-
-        private String getAutoToggleSummary(SharedPreferences sp, int slot) {
-            final String button = sp.getString(String.format("AutoFire%dButton", slot), null);
-            if (button == null || button.length() == 0)
-                return "Not Configured";
-
-            return String.format("%s every %d frames", button, sp.getInt("AutoFire%dFrequency", 2));
-        }
-
-        private void createPreferences() {
-            final PreferenceScreen ps = getPreferenceScreen();
-            final SharedPreferences sp = getPreferenceManager().getSharedPreferences();
-            final String controllerType = getControllerType(sp, controllerIndex);
-            final String[] controllerButtons = AndroidHostInterface.getControllerButtonNames(controllerType);
-            final String[] axisButtons = AndroidHostInterface.getControllerAxisNames(controllerType);
-            final int vibrationMotors = AndroidHostInterface.getControllerVibrationMotorCount(controllerType);
-
-            final ListPreference typePreference = new ListPreference(getContext());
-            typePreference.setEntries(R.array.settings_controller_type_entries);
-            typePreference.setEntryValues(R.array.settings_controller_type_values);
-            typePreference.setKey(getControllerTypeKey(controllerIndex));
-            typePreference.setValue(controllerType);
-            typePreference.setTitle(R.string.settings_controller_type);
-            typePreference.setSummaryProvider(ListPreference.SimpleSummaryProvider.getInstance());
-            typePreference.setIconSpaceReserved(false);
-            typePreference.setOnPreferenceChangeListener((pref, value) -> {
-                removePreferences();
-                createPreferences(value.toString());
-                return true;
-            });
-            ps.addPreference(typePreference);
-
-            final Preference autoBindPreference = new Preference(getContext());
-            autoBindPreference.setTitle(R.string.controller_settings_automatic_mapping);
-            autoBindPreference.setSummary(R.string.controller_settings_summary_automatic_mapping);
-            autoBindPreference.setIconSpaceReserved(false);
-            autoBindPreference.setOnPreferenceClickListener(preference -> {
-                final ControllerAutoMapper mapper = new ControllerAutoMapper(getContext(), controllerIndex, () -> {
-                    removePreferences();
-                    createPreferences(typePreference.getValue());
-                });
-                mapper.start();
-                return true;
-            });
-            ps.addPreference(autoBindPreference);
-
-            final Preference clearBindingsPreference = new Preference(getContext());
-            clearBindingsPreference.setTitle(R.string.controller_settings_clear_controller_bindings);
-            clearBindingsPreference.setSummary(R.string.controller_settings_summary_clear_controller_bindings);
-            clearBindingsPreference.setIconSpaceReserved(false);
-            clearBindingsPreference.setOnPreferenceClickListener(preference -> {
-                final AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
-                builder.setMessage(R.string.controller_settings_clear_controller_bindings_confirm);
-                builder.setPositiveButton(R.string.main_activity_yes, (dialog, which) -> {
-                    dialog.dismiss();
-                    clearBindings();
-                });
-                builder.setNegativeButton(R.string.main_activity_no, (dialog, which) -> dialog.dismiss());
-                builder.create().show();
-                return true;
-            });
-            ps.addPreference(clearBindingsPreference);
-
-            mButtonsCategory = new PreferenceCategory(getContext());
-            mButtonsCategory.setTitle(R.string.controller_settings_category_button_bindings);
-            mButtonsCategory.setIconSpaceReserved(false);
-            ps.addPreference(mButtonsCategory);
-
-            mAxisCategory = new PreferenceCategory(getContext());
-            mAxisCategory.setTitle(R.string.controller_settings_category_axis_bindings);
-            mAxisCategory.setIconSpaceReserved(false);
-            ps.addPreference(mAxisCategory);
-
-            mSettingsCategory = new PreferenceCategory(getContext());
-            mSettingsCategory.setTitle(R.string.controller_settings_category_settings);
-            mSettingsCategory.setIconSpaceReserved(false);
-            ps.addPreference(mSettingsCategory);
-
-            mAutoFireCategory = new PreferenceCategory(getContext());
-            mAutoFireCategory.setTitle(R.string.controller_settings_category_auto_fire_buttons);
-            mAutoFireCategory.setIconSpaceReserved(false);
-            ps.addPreference(mAutoFireCategory);
-
-            mAutoFireBindingsCategory = new PreferenceCategory(getContext());
-            mAutoFireBindingsCategory.setTitle(R.string.controller_settings_category_auto_fire_bindings);
-            mAutoFireBindingsCategory.setIconSpaceReserved(false);
-            ps.addPreference(mAutoFireBindingsCategory);
-
-            createPreferences(controllerType);
-        }
-
-        @SuppressLint("DefaultLocale")
-        private void createPreferences(String controllerType) {
-            final PreferenceScreen ps = getPreferenceScreen();
-            final SharedPreferences sp = getPreferenceManager().getSharedPreferences();
-            final String[] buttonNames = AndroidHostInterface.getControllerButtonNames(controllerType);
-            final String[] axisNames = AndroidHostInterface.getControllerAxisNames(controllerType);
-            final int vibrationMotors = AndroidHostInterface.getControllerVibrationMotorCount(controllerType);
-
-            if (buttonNames != null) {
-                for (String buttonName : buttonNames) {
-                    final ControllerBindingPreference cbp = new ControllerBindingPreference(getContext(), null);
-                    cbp.initButton(controllerIndex, buttonName);
-                    mButtonsCategory.addPreference(cbp);
-                    parent.preferences.add(cbp);
-                }
-            }
-
-            if (axisNames != null) {
-                for (String axisName : axisNames) {
-                    final int axisType = AndroidHostInterface.getControllerAxisType(controllerType, axisName);
-                    final ControllerBindingPreference cbp = new ControllerBindingPreference(getContext(), null);
-                    cbp.initAxis(controllerIndex, axisName, axisType);
-                    mAxisCategory.addPreference(cbp);
-                    parent.preferences.add(cbp);
-                }
-            }
-
-            if (vibrationMotors > 0) {
-                final ControllerBindingPreference cbp = new ControllerBindingPreference(getContext(), null);
-                cbp.initVibration(controllerIndex);
-                mSettingsCategory.addPreference(cbp);
-                parent.preferences.add(cbp);
-            }
-
-            if (controllerType.equals("AnalogController")) {
-                mSettingsCategory.addPreference(
-                        createTogglePreference(String.format("Controller%d/ForceAnalogOnReset", controllerIndex),
-                                R.string.settings_enable_analog_mode_on_reset, R.string.settings_summary_enable_analog_mode_on_reset, true));
-
-                mSettingsCategory.addPreference(
-                        createTogglePreference(String.format("Controller%d/AnalogDPadInDigitalMode", controllerIndex),
-                                R.string.settings_use_analog_sticks_for_dpad, R.string.settings_summary_use_analog_sticks_for_dpad, true));
-            }
-
-            if (buttonNames != null) {
-              for (int autoFireSlot = 1; autoFireSlot <= NUM_AUTO_FIRE_BUTTONS; autoFireSlot++) {
-                  final ListPreference autoFirePreference = new ListPreference(getContext());
-                  autoFirePreference.setEntries(buttonNames);
-                  autoFirePreference.setEntryValues(buttonNames);
-                  autoFirePreference.setKey(String.format("Controller%d/AutoFire%dButton", controllerIndex, autoFireSlot));
-                  autoFirePreference.setTitle(getContext().getString(R.string.controller_settings_auto_fire_n_button, autoFireSlot));
-                  autoFirePreference.setSummaryProvider(ListPreference.SimpleSummaryProvider.getInstance());
-                  autoFirePreference.setIconSpaceReserved(false);
-                  mAutoFireCategory.addPreference(autoFirePreference);
-
-                  final SeekBarPreference frequencyPreference = new SeekBarPreference(getContext());
-                  frequencyPreference.setMin(1);
-                  frequencyPreference.setMax(60);
-                  frequencyPreference.setKey(String.format("Controller%d/AutoFire%dFrequency", controllerIndex, autoFireSlot));
-                  frequencyPreference.setDefaultValue(2);
-                  frequencyPreference.setTitle(getContext().getString(R.string.controller_settings_auto_fire_n_frequency, autoFireSlot));
-                  frequencyPreference.setIconSpaceReserved(false);
-                  frequencyPreference.setShowSeekBarValue(true);
-                  mAutoFireCategory.addPreference(frequencyPreference);
-              }
-
-              for (int autoFireSlot = 1; autoFireSlot <= NUM_AUTO_FIRE_BUTTONS; autoFireSlot++) {
-                  final ControllerBindingPreference bindingPreference = new ControllerBindingPreference(getContext(), null);
-                  bindingPreference.initAutoFireButton(controllerIndex, autoFireSlot);
-                  mAutoFireBindingsCategory.addPreference(bindingPreference);
-              }
-            }
-        }
-
-        private void removePreferences() {
-            for (int i = 0; i < mButtonsCategory.getPreferenceCount(); i++) {
-                parent.preferences.remove(mButtonsCategory.getPreference(i));
-            }
-            mButtonsCategory.removeAll();
-
-            for (int i = 0; i < mAxisCategory.getPreferenceCount(); i++) {
-                parent.preferences.remove(mAxisCategory.getPreference(i));
-            }
-            mAxisCategory.removeAll();
-
-            for (int i = 0; i < mSettingsCategory.getPreferenceCount(); i++) {
-                parent.preferences.remove(mSettingsCategory.getPreference(i));
-            }
-            mSettingsCategory.removeAll();
-
-            for (int i = 0; i < mAutoFireCategory.getPreferenceCount(); i++) {
-                parent.preferences.remove(mAutoFireCategory.getPreference(i));
-            }
-            mAutoFireCategory.removeAll();
-
-            for (int i = 0; i < mAutoFireBindingsCategory.getPreferenceCount(); i++) {
-                parent.preferences.remove(mAutoFireBindingsCategory.getPreference(i));
-            }
-            mAutoFireBindingsCategory.removeAll();
-        }
-
-        private void clearBindings() {
-            final SharedPreferences.Editor editor = getPreferenceManager().getSharedPreferences().edit();
-            clearBindingsInCategory(editor, mButtonsCategory);
-            clearBindingsInCategory(editor, mAxisCategory);
-            clearBindingsInCategory(editor, mSettingsCategory);
-            editor.commit();
-
-            Toast.makeText(parent.getContext(), parent.getString(
-                    R.string.controller_settings_clear_controller_bindings_done, controllerIndex),
-                    Toast.LENGTH_LONG).show();
-        }
-    }
-
-    public static class HotkeyFragment extends PreferenceFragmentCompat {
-        private final ControllerSettingsCollectionFragment parent;
-        private final HotkeyInfo[] mHotkeyInfo;
-
-        public HotkeyFragment(ControllerSettingsCollectionFragment parent) {
-            this.parent = parent;
-            this.mHotkeyInfo = AndroidHostInterface.getInstance().getHotkeyInfoList();
-        }
-
-        @Override
-        public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
-            final PreferenceScreen ps = getPreferenceManager().createPreferenceScreen(getContext());
-            if (mHotkeyInfo != null) {
-                final HashMap<String, PreferenceCategory> categoryMap = new HashMap<>();
-
-                for (HotkeyInfo hotkeyInfo : mHotkeyInfo) {
-                    PreferenceCategory category = categoryMap.containsKey(hotkeyInfo.getCategory()) ?
-                            categoryMap.get(hotkeyInfo.getCategory()) : null;
-                    if (category == null) {
-                        category = new PreferenceCategory(getContext());
-                        category.setTitle(hotkeyInfo.getCategory());
-                        category.setIconSpaceReserved(false);
-                        categoryMap.put(hotkeyInfo.getCategory(), category);
-                        ps.addPreference(category);
-                    }
-
-                    final ControllerBindingPreference cbp = new ControllerBindingPreference(getContext(), null);
-                    cbp.initHotkey(hotkeyInfo);
-                    category.addPreference(cbp);
-                    parent.preferences.add(cbp);
-                }
-            }
-
-            setPreferenceScreen(ps);
-        }
-    }
-
-    public static class SettingsCollectionAdapter extends FragmentStateAdapter {
-        private final ControllerSettingsCollectionFragment parent;
-        private final int controllerPorts;
-
-        public SettingsCollectionAdapter(@NonNull ControllerSettingsCollectionFragment parent, int controllerPorts) {
-            super(parent);
-            this.parent = parent;
-            this.controllerPorts = controllerPorts;
-        }
-
-        @NonNull
-        @Override
-        public Fragment createFragment(int position) {
-            if (position == 0)
-                return new SettingsFragment(parent);
-            else if (position <= controllerPorts)
-                return new ControllerPortFragment(parent, position);
-            else
-                return new HotkeyFragment(parent);
-        }
-
-        @Override
-        public int getItemCount() {
-            return controllerPorts + 2;
-        }
-    }
-}
\ No newline at end of file
diff --git a/android/app/src/main/java/com/github/stenzek/duckstation/DiscRegion.java b/android/app/src/main/java/com/github/stenzek/duckstation/DiscRegion.java
deleted file mode 100644
index 813d9e717..000000000
--- a/android/app/src/main/java/com/github/stenzek/duckstation/DiscRegion.java
+++ /dev/null
@@ -1,8 +0,0 @@
-package com.github.stenzek.duckstation;
-
-public enum DiscRegion {
-    NTSC_J,
-    NTSC_U,
-    PAL,
-    Other
-}
diff --git a/android/app/src/main/java/com/github/stenzek/duckstation/EmptyGameListFragment.java b/android/app/src/main/java/com/github/stenzek/duckstation/EmptyGameListFragment.java
deleted file mode 100644
index 793cf2d7d..000000000
--- a/android/app/src/main/java/com/github/stenzek/duckstation/EmptyGameListFragment.java
+++ /dev/null
@@ -1,36 +0,0 @@
-package com.github.stenzek.duckstation;
-
-import android.os.Bundle;
-import android.view.View;
-import android.widget.Button;
-import android.widget.TextView;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.fragment.app.Fragment;
-
-public class EmptyGameListFragment extends Fragment {
-    private static final String SUPPORTED_FORMATS_STRING =
-            ".cue (Cue Sheets)\n" +
-            ".iso/.img (Single Track Image)\n" +
-            ".ecm (Error Code Modeling Image)\n" +
-            ".mds (Media Descriptor Sidecar)\n" +
-            ".chd (Compressed Hunks of Data)\n" +
-            ".pbp (PlayStation Portable, Only Decrypted)";
-
-    private MainActivity parent;
-
-    public EmptyGameListFragment(MainActivity parent) {
-        super(R.layout.fragment_empty_game_list);
-        this.parent = parent;
-    }
-
-    @Override
-    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
-        super.onViewCreated(view, savedInstanceState);
-
-        ((TextView) view.findViewById(R.id.supported_formats)).setText(
-                getString(R.string.main_activity_empty_game_list_supported_formats, SUPPORTED_FORMATS_STRING));
-        ((Button) view.findViewById(R.id.add_game_directory)).setOnClickListener(v -> parent.startAddGameDirectory());
-    }
-}
diff --git a/android/app/src/main/java/com/github/stenzek/duckstation/EmulationActivity.java b/android/app/src/main/java/com/github/stenzek/duckstation/EmulationActivity.java
deleted file mode 100644
index 8192df706..000000000
--- a/android/app/src/main/java/com/github/stenzek/duckstation/EmulationActivity.java
+++ /dev/null
@@ -1,988 +0,0 @@
-package com.github.stenzek.duckstation;
-
-import android.content.Context;
-import android.content.DialogInterface;
-import android.content.Intent;
-import android.content.SharedPreferences;
-import android.content.pm.ActivityInfo;
-import android.content.res.Configuration;
-import android.hardware.input.InputManager;
-import android.net.Uri;
-import android.os.AsyncTask;
-import android.os.Build;
-import android.os.Bundle;
-import android.os.Vibrator;
-import android.util.Log;
-import android.view.Display;
-import android.view.KeyEvent;
-import android.view.LayoutInflater;
-import android.view.MotionEvent;
-import android.view.SurfaceHolder;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.WindowManager;
-import android.widget.FrameLayout;
-import android.widget.ImageButton;
-import android.widget.ImageView;
-import android.widget.ListView;
-import android.widget.TextView;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.appcompat.app.AlertDialog;
-import androidx.appcompat.app.AppCompatActivity;
-import androidx.fragment.app.DialogFragment;
-import androidx.fragment.app.Fragment;
-import androidx.fragment.app.FragmentTransaction;
-import androidx.preference.Preference;
-import androidx.preference.PreferenceFragmentCompat;
-import androidx.preference.PreferenceManager;
-
-/**
- * An example full-screen activity that shows and hides the system UI (i.e.
- * status bar and navigation/system bar) with user interaction.
- */
-public class EmulationActivity extends AppCompatActivity implements SurfaceHolder.Callback {
-    /**
-     * Settings interfaces.
-     */
-    private SharedPreferences mPreferences;
-    private boolean mWasDestroyed = false;
-    private boolean mStopRequested = false;
-    private boolean mApplySettingsOnSurfaceRestored = false;
-    private String mGamePath = null;
-    private String mGameCode = null;
-    private String mGameTitle = null;
-    private String mGameCoverPath = null;
-    private EmulationSurfaceView mContentView;
-    private MenuDialogFragment mPauseMenu;
-
-    private boolean getBooleanSetting(String key, boolean defaultValue) {
-        return mPreferences.getBoolean(key, defaultValue);
-    }
-
-    private void setBooleanSetting(String key, boolean value) {
-        SharedPreferences.Editor editor = mPreferences.edit();
-        editor.putBoolean(key, value);
-        editor.apply();
-    }
-
-    private String getStringSetting(String key, String defaultValue) {
-        return mPreferences.getString(key, defaultValue);
-    }
-
-    private int getIntSetting(String key, int defaultValue) {
-        try {
-            return mPreferences.getInt(key, defaultValue);
-        } catch (ClassCastException e) {
-            try {
-                final String stringValue = mPreferences.getString(key, Integer.toString(defaultValue));
-                return Integer.parseInt(stringValue);
-            } catch (Exception e2) {
-                return defaultValue;
-            }
-        }
-    }
-
-    private void setStringSetting(String key, String value) {
-        SharedPreferences.Editor editor = mPreferences.edit();
-        editor.putString(key, value);
-        editor.apply();
-    }
-
-    private void reportErrorOnUIThread(String message) {
-        // Toast.makeText(this, message, Toast.LENGTH_LONG);
-        new AlertDialog.Builder(this)
-                .setTitle(R.string.emulation_activity_error)
-                .setMessage(message)
-                .setPositiveButton(R.string.emulation_activity_ok, (dialog, button) -> {
-                    dialog.dismiss();
-                    enableFullscreenImmersive();
-                })
-                .create()
-                .show();
-    }
-
-    public void reportError(String message) {
-        Log.e("EmulationActivity", message);
-
-        Object lock = new Object();
-        runOnUiThread(() -> {
-            // Toast.makeText(this, message, Toast.LENGTH_LONG);
-            new AlertDialog.Builder(this)
-                    .setTitle(R.string.emulation_activity_error)
-                    .setMessage(message)
-                    .setPositiveButton(R.string.emulation_activity_ok, (dialog, button) -> {
-                        dialog.dismiss();
-                        enableFullscreenImmersive();
-                        synchronized (lock) {
-                            lock.notify();
-                        }
-                    })
-                    .create()
-                    .show();
-        });
-
-        synchronized (lock) {
-            try {
-                lock.wait();
-            } catch (InterruptedException e) {
-            }
-        }
-    }
-
-    private EmulationThread mEmulationThread;
-
-    private void stopEmulationThread() {
-        if (mEmulationThread == null)
-            return;
-
-        mEmulationThread.stopAndJoin();
-        mEmulationThread = null;
-    }
-
-    public void onEmulationStarted() {
-        runOnUiThread(() -> {
-            updateRequestedOrientation();
-            updateOrientation();
-        });
-    }
-
-    public void onEmulationStopped() {
-        runOnUiThread(() -> {
-            if (!mWasDestroyed && !mStopRequested)
-                finish();
-        });
-    }
-
-    public void onRunningGameChanged(String path, String code, String title, String coverPath) {
-        runOnUiThread(() -> {
-            mGamePath = path;
-            mGameTitle = title;
-            mGameCode = code;
-            mGameCoverPath = coverPath;
-        });
-    }
-
-    public float getRefreshRate() {
-        WindowManager windowManager = getWindowManager();
-        if (windowManager == null) {
-            windowManager = ((WindowManager) getSystemService(Context.WINDOW_SERVICE));
-            if (windowManager == null)
-                return -1.0f;
-        }
-
-        Display display = windowManager.getDefaultDisplay();
-        if (display == null)
-            return -1.0f;
-
-        return display.getRefreshRate();
-    }
-
-    public void openPauseMenu() {
-        runOnUiThread(() -> {
-            showPauseMenu();
-        });
-    }
-
-    public String[] getInputDeviceNames() {
-        return (mContentView != null) ? mContentView.getInputDeviceNames() : null;
-    }
-
-    public boolean hasInputDeviceVibration(int controllerIndex) {
-        return (mContentView != null) ? mContentView.hasInputDeviceVibration(controllerIndex) : null;
-    }
-
-    public void setInputDeviceVibration(int controllerIndex, float smallMotor, float largeMotor) {
-        if (mContentView != null)
-            mContentView.setInputDeviceVibration(controllerIndex, smallMotor, largeMotor);
-    }
-
-    private void doApplySettings() {
-        AndroidHostInterface.getInstance().applySettings();
-        updateRequestedOrientation();
-        updateControllers();
-        updateSustainedPerformanceMode();
-        updateDisplayInCutout();
-    }
-
-    private void applySettings() {
-        if (!AndroidHostInterface.getInstance().isEmulationThreadRunning())
-            return;
-
-        if (AndroidHostInterface.getInstance().hasSurface()) {
-            doApplySettings();
-        } else {
-            mApplySettingsOnSurfaceRestored = true;
-        }
-    }
-
-    /// Ends the activity if it was restored without properly being created.
-    private boolean checkActivityIsValid() {
-        if (!AndroidHostInterface.hasInstance() || !AndroidHostInterface.getInstance().isEmulationThreadRunning()) {
-            finish();
-            return false;
-        }
-
-        return true;
-    }
-
-    @Override
-    public void surfaceCreated(SurfaceHolder holder) {
-    }
-
-    @Override
-    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
-        // Once we get a surface, we can boot.
-        AndroidHostInterface.getInstance().surfaceChanged(holder.getSurface(), format, width, height);
-
-        if (mEmulationThread != null) {
-            updateOrientation();
-
-            if (mApplySettingsOnSurfaceRestored) {
-                mApplySettingsOnSurfaceRestored = false;
-                doApplySettings();
-            }
-
-            return;
-        }
-
-        final String bootPath = getIntent().getStringExtra("bootPath");
-        final boolean saveStateOnExit = getBooleanSetting("Main/SaveStateOnExit", true);
-        final boolean resumeState = getIntent().getBooleanExtra("resumeState", saveStateOnExit);
-        final String bootSaveStatePath = getIntent().getStringExtra("saveStatePath");
-
-        mEmulationThread = EmulationThread.create(this, bootPath, resumeState, bootSaveStatePath);
-    }
-
-    @Override
-    public void surfaceDestroyed(SurfaceHolder holder) {
-        Log.i("EmulationActivity", "Surface destroyed");
-
-        if (mPauseMenu != null)
-            mPauseMenu.close(false);
-
-        // Save the resume state in case we never get back again...
-        if (AndroidHostInterface.getInstance().isEmulationThreadRunning() && !mStopRequested)
-            AndroidHostInterface.getInstance().saveResumeState(true);
-
-        AndroidHostInterface.getInstance().surfaceChanged(null, 0, 0, 0);
-    }
-
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        mPreferences = PreferenceManager.getDefaultSharedPreferences(this);
-        super.onCreate(savedInstanceState);
-
-        Log.i("EmulationActivity", "OnCreate");
-
-        // we might be coming from a third-party launcher if the host interface isn't setup
-        if (!AndroidHostInterface.hasInstance() && !AndroidHostInterface.createInstance(this)) {
-            finish();
-            return;
-        }
-
-        enableFullscreenImmersive();
-        setContentView(R.layout.activity_emulation);
-
-        mContentView = findViewById(R.id.fullscreen_content);
-        mContentView.getHolder().addCallback(this);
-        mContentView.setFocusableInTouchMode(true);
-        mContentView.setFocusable(true);
-        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
-            mContentView.setFocusedByDefault(true);
-        }
-        mContentView.requestFocus();
-
-        // Sort out rotation.
-        updateOrientation();
-        updateSustainedPerformanceMode();
-        updateDisplayInCutout();
-
-        // Hook up controller input.
-        updateControllers();
-        registerInputDeviceListener();
-    }
-
-    @Override
-    protected void onPostCreate(Bundle savedInstanceState) {
-        super.onPostCreate(savedInstanceState);
-        enableFullscreenImmersive();
-    }
-
-    @Override
-    protected void onPostResume() {
-        super.onPostResume();
-        enableFullscreenImmersive();
-    }
-
-    @Override
-    protected void onDestroy() {
-        super.onDestroy();
-        Log.i("EmulationActivity", "OnStop");
-        if (mEmulationThread != null) {
-            mWasDestroyed = true;
-            stopEmulationThread();
-        }
-
-        unregisterInputDeviceListener();
-    }
-
-    @Override
-    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
-        super.onActivityResult(requestCode, resultCode, data);
-
-        if (!checkActivityIsValid()) {
-            // we must've got killed off in the background :(
-            return;
-        }
-
-        if (requestCode == REQUEST_CODE_SETTINGS) {
-            if (AndroidHostInterface.getInstance().isEmulationThreadRunning()) {
-                applySettings();
-            }
-        } else if (requestCode == REQUEST_IMPORT_PATCH_CODES) {
-            if (data == null || data.getData() == null)
-                return;
-
-            importPatchesFromFile(data.getData());
-        } else if (requestCode == REQUEST_CHANGE_DISC_FILE) {
-            if (data == null || data.getData() == null)
-                return;
-
-            AndroidHostInterface.getInstance().setMediaFilename(data.getDataString());
-        }
-    }
-
-    @Override
-    public void onBackPressed() {
-        showPauseMenu();
-    }
-
-    @Override
-    public boolean dispatchKeyEvent(KeyEvent event) {
-        if (event.getAction() == KeyEvent.ACTION_DOWN) {
-            if (mContentView.onKeyDown(event.getKeyCode(), event))
-                return true;
-        } else if (event.getAction() == KeyEvent.ACTION_UP) {
-            if (mContentView.onKeyUp(event.getKeyCode(), event))
-                return true;
-        }
-
-        return super.dispatchKeyEvent(event);
-    }
-
-    @Override
-    public boolean dispatchGenericMotionEvent(MotionEvent ev) {
-        if (mContentView.onGenericMotionEvent(ev))
-            return true;
-
-        return super.dispatchGenericMotionEvent(ev);
-    }
-
-    @Override
-    public void onConfigurationChanged(@NonNull Configuration newConfig) {
-        super.onConfigurationChanged(newConfig);
-
-        if (checkActivityIsValid())
-            updateOrientation(newConfig.orientation);
-    }
-
-    private void updateRequestedOrientation() {
-        final String orientation = getStringSetting("Main/EmulationScreenOrientation", "unspecified");
-        if (orientation.equals("portrait"))
-            setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_USER_PORTRAIT);
-        else if (orientation.equals("landscape"))
-            setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_USER_LANDSCAPE);
-        else if (orientation.equals("sensor"))
-            setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR);
-        else
-            setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
-    }
-
-    private void updateOrientation() {
-        final int orientation = getResources().getConfiguration().orientation;
-        updateOrientation(orientation);
-    }
-
-    private void updateOrientation(int newOrientation) {
-        if (newOrientation == Configuration.ORIENTATION_PORTRAIT)
-            AndroidHostInterface.getInstance().setDisplayAlignment(AndroidHostInterface.DISPLAY_ALIGNMENT_TOP_OR_LEFT);
-        else
-            AndroidHostInterface.getInstance().setDisplayAlignment(AndroidHostInterface.DISPLAY_ALIGNMENT_CENTER);
-
-        if (mTouchscreenController != null)
-            mTouchscreenController.updateOrientation();
-    }
-
-    private void enableFullscreenImmersive() {
-        getWindow().getDecorView().setSystemUiVisibility(
-                View.SYSTEM_UI_FLAG_LAYOUT_STABLE |
-                        View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION |
-                        View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN |
-                        View.SYSTEM_UI_FLAG_HIDE_NAVIGATION |
-                        View.SYSTEM_UI_FLAG_FULLSCREEN |
-                        View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
-        if (mContentView != null)
-            mContentView.requestFocus();
-    }
-
-    private void updateDisplayInCutout() {
-        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P)
-            return;
-
-        final boolean shouldExpand = getBooleanSetting("Display/ExpandToCutout", false);
-        final boolean isExpanded = getWindow().getAttributes().layoutInDisplayCutoutMode ==
-                WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
-
-        if (shouldExpand == isExpanded)
-            return;
-
-        WindowManager.LayoutParams attribs = getWindow().getAttributes();
-        attribs.layoutInDisplayCutoutMode = shouldExpand ?
-                WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES :
-                WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT;
-        getWindow().setAttributes(attribs);
-    }
-
-    private static final int REQUEST_CODE_SETTINGS = 0;
-    private static final int REQUEST_IMPORT_PATCH_CODES = 1;
-    private static final int REQUEST_CHANGE_DISC_FILE = 2;
-
-    private void onMenuClosed() {
-        enableFullscreenImmersive();
-
-        if (AndroidHostInterface.getInstance().isEmulationThreadPaused())
-            AndroidHostInterface.getInstance().pauseEmulationThread(false);
-    }
-
-    private boolean disableDialogMenuItem(AlertDialog dialog, int index) {
-        final ListView listView = dialog.getListView();
-        if (listView == null)
-            return false;
-
-        final View childItem = listView.getChildAt(index);
-        if (childItem == null)
-            return false;
-
-        childItem.setEnabled(false);
-        childItem.setClickable(false);
-        childItem.setOnClickListener((v) -> {});
-        return true;
-    }
-
-    private void showPauseMenu() {
-        if (!AndroidHostInterface.getInstance().isEmulationThreadPaused()) {
-            AndroidHostInterface.getInstance().pauseEmulationThread(true);
-        }
-
-        if (mPauseMenu != null)
-            mPauseMenu.close(false);
-
-        mPauseMenu = new MenuDialogFragment(this);
-        mPauseMenu.show(getSupportFragmentManager(), "MenuDialogFragment");
-    }
-
-    private void showSaveStateMenu(boolean saving) {
-        final SaveStateInfo[] infos = AndroidHostInterface.getInstance().getSaveStateInfo(true);
-        if (infos == null) {
-            onMenuClosed();
-            return;
-        }
-
-        final AlertDialog.Builder builder = new AlertDialog.Builder(this);
-        final ListView listView = new ListView(this);
-        listView.setAdapter(new SaveStateInfo.ListAdapter(this, infos));
-        builder.setView(listView);
-        builder.setOnDismissListener((dialog) -> {
-            onMenuClosed();
-        });
-
-        final AlertDialog dialog = builder.create();
-
-        listView.setOnItemClickListener((parent, view, position, id) -> {
-            SaveStateInfo info = infos[position];
-            if (saving) {
-                AndroidHostInterface.getInstance().saveState(info.isGlobal(), info.getSlot());
-            } else {
-                AndroidHostInterface.getInstance().loadState(info.isGlobal(), info.getSlot());
-            }
-            dialog.dismiss();
-        });
-
-        dialog.show();
-    }
-
-    private void showTouchscreenControllerMenu() {
-        AlertDialog.Builder builder = new AlertDialog.Builder(this);
-        builder.setTitle(R.string.dialog_touchscreen_controller_settings);
-        builder.setItems(R.array.emulation_touchscreen_menu, (dialogInterface, i) -> {
-            switch (i) {
-                case 0:     // Change Type
-                {
-                    final String currentValue = getStringSetting("Controller1/TouchscreenControllerView", "");
-                    final String[] values = getResources().getStringArray(R.array.settings_touchscreen_controller_view_values);
-                    int currentIndex = -1;
-                    for (int k = 0; k < values.length; k++) {
-                        if (currentValue.equals(values[k])) {
-                            currentIndex = k;
-                            break;
-                        }
-                    }
-
-                    final AlertDialog.Builder subBuilder = new AlertDialog.Builder(this);
-                    subBuilder.setTitle(R.string.dialog_touchscreen_controller_type);
-                    subBuilder.setSingleChoiceItems(R.array.settings_touchscreen_controller_view_entries, currentIndex, (dialog, j) -> {
-                        setStringSetting("Controller1/TouchscreenControllerView", values[j]);
-                        updateControllers();
-                    });
-                    subBuilder.setNegativeButton(R.string.dialog_done, (dialog, which) -> {
-                        dialog.dismiss();
-                    });
-                    subBuilder.setOnDismissListener(dialog -> onMenuClosed());
-                    subBuilder.create().show();
-                }
-                break;
-
-                case 1:     // Change Opacity
-                {
-                    if (mTouchscreenController != null) {
-                        AlertDialog.Builder subBuilder = mTouchscreenController.createOpacityDialog(this);
-                        subBuilder.setOnDismissListener(dialog -> onMenuClosed());
-                        subBuilder.create().show();
-                    } else {
-                        onMenuClosed();
-                    }
-
-                }
-                break;
-
-                case 2:     // Add/Remove Buttons
-                {
-                    if (mTouchscreenController != null) {
-                        AlertDialog.Builder subBuilder = mTouchscreenController.createAddRemoveButtonDialog(this);
-                        subBuilder.setOnDismissListener(dialog -> onMenuClosed());
-                        subBuilder.create().show();
-                    } else {
-                        onMenuClosed();
-                    }
-                }
-                break;
-
-                case 3:     // Edit Positions
-                case 4:     // Edit Scale
-                {
-                    if (mTouchscreenController != null) {
-                        // we deliberately don't call onMenuClosed() here to keep the system paused.
-                        // but we need to re-enable immersive mode to get proper editing.
-                        enableFullscreenImmersive();
-                        mTouchscreenController.startLayoutEditing(
-                                (i == 4) ? TouchscreenControllerView.EditMode.SCALE :
-                                        TouchscreenControllerView.EditMode.POSITION);
-                    } else {
-                        // no controller
-                        onMenuClosed();
-                    }
-                }
-                break;
-            }
-        });
-
-        builder.setOnCancelListener(dialogInterface -> onMenuClosed());
-        builder.create().show();
-    }
-
-    private void showPatchesMenu() {
-        final AlertDialog.Builder builder = new AlertDialog.Builder(this);
-
-        final PatchCode[] codes = AndroidHostInterface.getInstance().getPatchCodeList();
-        if (codes != null) {
-            CharSequence[] items = new CharSequence[codes.length];
-            boolean[] itemsChecked = new boolean[codes.length];
-            for (int i = 0; i < codes.length; i++) {
-                final PatchCode cc = codes[i];
-                items[i] = cc.getDisplayText();
-                itemsChecked[i] = cc.isEnabled();
-            }
-
-            builder.setMultiChoiceItems(items, itemsChecked, (dialogInterface, i, checked) -> {
-                AndroidHostInterface.getInstance().setPatchCodeEnabled(i, checked);
-            });
-        }
-
-        builder.setNegativeButton(R.string.emulation_activity_ok, (dialogInterface, i) -> {
-            dialogInterface.dismiss();
-        });
-        builder.setNeutralButton(R.string.emulation_activity_import_patch_codes, (dialogInterface, i) -> {
-            Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
-            intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
-            intent.setType("*/*");
-            intent.addCategory(Intent.CATEGORY_OPENABLE);
-            startActivityForResult(Intent.createChooser(intent, getString(R.string.emulation_activity_choose_patch_code_file)), REQUEST_IMPORT_PATCH_CODES);
-        });
-
-        builder.setOnDismissListener(dialogInterface -> onMenuClosed());
-        builder.create().show();
-    }
-
-    private void importPatchesFromFile(Uri uri) {
-        String str = FileHelper.readStringFromUri(this, uri, 512 * 1024);
-        if (str == null || !AndroidHostInterface.getInstance().importPatchCodesFromString(str)) {
-            reportErrorOnUIThread(getString(R.string.emulation_activity_failed_to_import_patch_codes));
-        }
-    }
-
-    private void startDiscChangeFromFile() {
-        Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
-        intent.setType("*/*");
-        intent.addCategory(Intent.CATEGORY_OPENABLE);
-        startActivityForResult(Intent.createChooser(intent, getString(R.string.main_activity_choose_disc_image)), REQUEST_CHANGE_DISC_FILE);
-    }
-
-    private void showDiscChangeMenu() {
-        final AndroidHostInterface hi = AndroidHostInterface.getInstance();
-
-        if (!hi.hasMediaSubImages()) {
-            startDiscChangeFromFile();
-            return;
-        }
-
-        final String[] paths = AndroidHostInterface.getInstance().getMediaSubImageTitles();
-        final int currentPath = AndroidHostInterface.getInstance().getMediaSubImageIndex();
-        final int numPaths = (paths != null) ? paths.length : 0;
-
-        AlertDialog.Builder builder = new AlertDialog.Builder(this);
-
-        CharSequence[] items = new CharSequence[numPaths + 1];
-        for (int i = 0; i < numPaths; i++)
-            items[i] = FileHelper.getFileNameForPath(paths[i]);
-        items[numPaths] = getString(R.string.emulation_activity_change_disc_select_new_file);
-
-        builder.setSingleChoiceItems(items, (currentPath < numPaths) ? currentPath : -1, (dialogInterface, i) -> {
-            dialogInterface.dismiss();
-            onMenuClosed();
-
-            if (i < numPaths) {
-                AndroidHostInterface.getInstance().switchMediaSubImage(i);
-            } else {
-                startDiscChangeFromFile();
-            }
-        });
-        builder.setOnCancelListener(dialogInterface -> onMenuClosed());
-        builder.create().show();
-    }
-
-    private void showAchievementsPopup() {
-        final Achievement[] achievements = AndroidHostInterface.getInstance().getCheevoList();
-        if (achievements == null) {
-            onMenuClosed();
-            return;
-        }
-
-        final AchievementListFragment alf = new AchievementListFragment(achievements);
-        alf.show(getSupportFragmentManager(), "fragment_achievement_list");
-        alf.setOnDismissListener(dialog -> onMenuClosed());
-    }
-
-    /**
-     * Touchscreen controller overlay
-     */
-    TouchscreenControllerView mTouchscreenController;
-
-    public void updateControllers() {
-        final int touchscreenControllerIndex = getIntSetting("TouchscreenController/PortIndex", 0);
-        final String touchscreenControllerPrefix = String.format("Controller%d/", touchscreenControllerIndex + 1);
-        final String controllerType = getStringSetting(touchscreenControllerPrefix + "Type", "DigitalController");
-        final String viewType = getStringSetting("Controller1/TouchscreenControllerView", "digital");
-        final boolean autoHideTouchscreenController = getBooleanSetting("Controller1/AutoHideTouchscreenController", false);
-        final boolean touchGliding = getBooleanSetting("Controller1/TouchGliding", false);
-        final boolean hapticFeedback = getBooleanSetting("Controller1/HapticFeedback", false);
-        final boolean vibration = getBooleanSetting("Controller1/Vibration", false);
-        final FrameLayout activityLayout = findViewById(R.id.frameLayout);
-
-        Log.i("EmulationActivity", "Controller type: " + controllerType);
-        Log.i("EmulationActivity", "View type: " + viewType);
-
-        mContentView.updateInputDevices();
-        AndroidHostInterface.getInstance().updateInputMap();
-
-        final boolean hasAnyControllers = mContentView.hasAnyGamePads();
-        if (controllerType.equals("None") || viewType.equals("none") || (hasAnyControllers && autoHideTouchscreenController)) {
-            if (mTouchscreenController != null) {
-                activityLayout.removeView(mTouchscreenController);
-                mTouchscreenController = null;
-            }
-        } else {
-            if (mTouchscreenController == null) {
-                mTouchscreenController = new TouchscreenControllerView(this);
-                activityLayout.addView(mTouchscreenController);
-            }
-
-            mTouchscreenController.init(touchscreenControllerIndex, controllerType, viewType, hapticFeedback, touchGliding);
-        }
-
-        if (vibration)
-            mVibratorService = (Vibrator) getSystemService(VIBRATOR_SERVICE);
-        else
-            mVibratorService = null;
-
-        // Place notifications in the middle of the screen, rather then the bottom (because touchscreen).
-        float notificationVerticalPosition = 1.0f;
-        float notificationVerticalDirection = -1.0f;
-        if (mTouchscreenController != null) {
-            notificationVerticalPosition = 0.3f;
-            notificationVerticalDirection = -1.0f;
-        }
-        AndroidHostInterface.getInstance().setFullscreenUINotificationVerticalPosition(
-                notificationVerticalPosition, notificationVerticalDirection);
-    }
-
-    private InputManager.InputDeviceListener mInputDeviceListener;
-
-    private void registerInputDeviceListener() {
-        if (mInputDeviceListener != null)
-            return;
-
-        mInputDeviceListener = new InputManager.InputDeviceListener() {
-            @Override
-            public void onInputDeviceAdded(int i) {
-                Log.i("EmulationActivity", String.format("InputDeviceAdded %d", i));
-                updateControllers();
-            }
-
-            @Override
-            public void onInputDeviceRemoved(int i) {
-                Log.i("EmulationActivity", String.format("InputDeviceRemoved %d", i));
-                updateControllers();
-            }
-
-            @Override
-            public void onInputDeviceChanged(int i) {
-                Log.i("EmulationActivity", String.format("InputDeviceChanged %d", i));
-                updateControllers();
-            }
-        };
-
-        InputManager inputManager = ((InputManager) getSystemService(Context.INPUT_SERVICE));
-        if (inputManager != null)
-            inputManager.registerInputDeviceListener(mInputDeviceListener, null);
-    }
-
-    private void unregisterInputDeviceListener() {
-        if (mInputDeviceListener == null)
-            return;
-
-        InputManager inputManager = ((InputManager) getSystemService(Context.INPUT_SERVICE));
-        if (inputManager != null)
-            inputManager.unregisterInputDeviceListener(mInputDeviceListener);
-
-        mInputDeviceListener = null;
-    }
-
-    private Vibrator mVibratorService;
-
-    public void setVibration(boolean enabled) {
-        if (mVibratorService == null)
-            return;
-
-        runOnUiThread(() -> {
-            if (mVibratorService == null)
-                return;
-
-            if (enabled)
-                mVibratorService.vibrate(1000);
-            else
-                mVibratorService.cancel();
-        });
-    }
-
-    private boolean mSustainedPerformanceModeEnabled = false;
-
-    private void updateSustainedPerformanceMode() {
-        final boolean enabled = getBooleanSetting("Main/SustainedPerformanceMode", false);
-        if (mSustainedPerformanceModeEnabled == enabled)
-            return;
-
-        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
-            getWindow().setSustainedPerformanceMode(enabled);
-            Log.i("EmulationActivity", String.format("%s sustained performance mode.", enabled ? "enabling" : "disabling"));
-        } else {
-            Log.e("EmulationActivity", "Sustained performance mode not supported.");
-        }
-        mSustainedPerformanceModeEnabled = enabled;
-
-    }
-
-    public static class MenuDialogFragment extends DialogFragment {
-        private EmulationActivity emulationActivity;
-        private boolean settingsChanged = false;
-
-        public MenuDialogFragment(EmulationActivity emulationActivity) {
-            this.emulationActivity = emulationActivity;
-        }
-
-        @Override
-        public void onCreate(@Nullable Bundle savedInstanceState) {
-            super.onCreate(savedInstanceState);
-            setStyle(STYLE_NO_FRAME, R.style.EmulationActivityOverlay);
-        }
-
-        @Nullable
-        @Override
-        public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
-            return inflater.inflate(R.layout.fragment_emulation_activity_overlay, container, false);
-        }
-
-        @Override
-        public void onViewCreated(View view, Bundle savedInstanceState) {
-            setContentFragment(new MenuSettingsFragment(this, emulationActivity), false);
-
-            final ImageView coverView =((ImageView)view.findViewById(R.id.cover_image));
-            if (emulationActivity.mGameCoverPath != null && !emulationActivity.mGameCoverPath.isEmpty()) {
-                new ImageLoadTask(coverView).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,
-                        emulationActivity.mGameCoverPath);
-            } else if (emulationActivity.mGameTitle != null) {
-                new GenerateCoverTask(getContext(), coverView, emulationActivity.mGameTitle)
-                        .executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
-            }
-            coverView.setOnClickListener(v -> close(true));
-
-            if (emulationActivity.mGameTitle != null)
-              ((TextView)view.findViewById(R.id.title)).setText(emulationActivity.mGameTitle);
-
-            if (emulationActivity.mGameCode != null && emulationActivity.mGamePath != null)
-            {
-              final String subtitle = String.format("%s - %s", emulationActivity.mGameCode,
-                      FileHelper.getFileNameForPath(emulationActivity.mGamePath));
-              ((TextView)view.findViewById(R.id.subtitle)).setText(subtitle);
-            }
-
-            ((ImageButton)view.findViewById(R.id.menu)).setOnClickListener(v -> onMenuClicked());
-            ((ImageButton)view.findViewById(R.id.controller_settings)).setOnClickListener(v -> onControllerSettingsClicked());
-            ((ImageButton)view.findViewById(R.id.settings)).setOnClickListener(v -> onSettingsClicked());
-            ((ImageButton)view.findViewById(R.id.close)).setOnClickListener(v -> close(true));
-        }
-
-        @Override
-        public void onCancel(@NonNull DialogInterface dialog) {
-            onClosed(true);
-        }
-
-        private void onClosed(boolean resumeGame) {
-            if (settingsChanged)
-                emulationActivity.applySettings();
-
-            if (resumeGame)
-                emulationActivity.onMenuClosed();
-
-            emulationActivity.mPauseMenu = null;
-        }
-
-        public void close(boolean resumeGame) {
-            dismiss();
-            onClosed(resumeGame);
-        }
-
-        private void setContentFragment(Fragment fragment, boolean transition) {
-            FragmentTransaction transaction = getChildFragmentManager().beginTransaction();
-            if (transition)
-                transaction.setCustomAnimations(android.R.anim.fade_in, android.R.anim.fade_out);
-            transaction.replace(R.id.content, fragment).commit();
-        }
-
-        private void onMenuClicked() {
-            setContentFragment(new MenuSettingsFragment(this, emulationActivity), true);
-        }
-
-        private void onControllerSettingsClicked() {
-            ControllerSettingsCollectionFragment fragment = new ControllerSettingsCollectionFragment();
-            setContentFragment(fragment, true);
-            fragment.setMultitapModeChangedListener(this::onControllerSettingsClicked);
-            settingsChanged = true;
-        }
-
-        private void onSettingsClicked() {
-            setContentFragment(new SettingsCollectionFragment(), true);
-            settingsChanged = true;
-        }
-    }
-
-    public static class MenuSettingsFragment extends PreferenceFragmentCompat {
-        private MenuDialogFragment menuDialogFragment;
-        private EmulationActivity emulationActivity;
-
-        public MenuSettingsFragment(MenuDialogFragment menuDialogFragment, EmulationActivity emulationActivity) {
-            this.menuDialogFragment = menuDialogFragment;
-            this.emulationActivity = emulationActivity;
-        }
-
-        @Override
-        public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
-            setPreferenceScreen(getPreferenceManager().createPreferenceScreen(getContext()));
-
-            final boolean cheevosActive = AndroidHostInterface.getInstance().isCheevosActive();
-            final boolean cheevosChallengeModeEnabled = AndroidHostInterface.getInstance().isCheevosChallengeModeActive();
-
-            createPreference(R.string.emulation_menu_load_state, R.drawable.ic_baseline_folder_open_24, !cheevosChallengeModeEnabled, preference -> {
-                menuDialogFragment.close(false);
-                emulationActivity.showSaveStateMenu(false);
-                return true;
-            });
-            createPreference(R.string.emulation_menu_save_state, R.drawable.ic_baseline_save_24, true, preference -> {
-                menuDialogFragment.close(false);
-                emulationActivity.showSaveStateMenu(true);
-                return true;
-            });
-            createPreference(R.string.emulation_menu_toggle_fast_forward, R.drawable.ic_baseline_fast_forward_24, !cheevosChallengeModeEnabled, preference -> {
-                AndroidHostInterface.getInstance().setFastForwardEnabled(!AndroidHostInterface.getInstance().isFastForwardEnabled());
-                menuDialogFragment.close(true);
-                return true;
-            });
-            createPreference(R.string.emulation_menu_achievements, R.drawable.ic_baseline_trophy_24, cheevosActive, preference -> {
-                menuDialogFragment.close(false);
-                emulationActivity.showAchievementsPopup();
-                return true;
-            });
-            createPreference(R.string.emulation_menu_exit_game, R.drawable.ic_baseline_exit_to_app_24, true, preference -> {
-                menuDialogFragment.close(false);
-                emulationActivity.mStopRequested = true;
-                emulationActivity.finish();
-                return true;
-            });
-            createPreference(R.string.emulation_menu_patch_codes, R.drawable.ic_baseline_tips_and_updates_24, !cheevosChallengeModeEnabled, preference -> {
-                menuDialogFragment.close(false);
-                emulationActivity.showPatchesMenu();
-                return true;
-            });
-            createPreference(R.string.emulation_menu_change_disc, R.drawable.ic_baseline_album_24, true, preference -> {
-                menuDialogFragment.close(false);
-                emulationActivity.showDiscChangeMenu();
-                return true;
-            });
-            createPreference(R.string.emulation_menu_touchscreen_controller_settings, R.drawable.ic_baseline_touch_app_24, true, preference -> {
-                menuDialogFragment.close(false);
-                emulationActivity.showTouchscreenControllerMenu();
-                return true;
-            });
-            createPreference(R.string.emulation_menu_toggle_analog_mode, R.drawable.ic_baseline_gamepad_24, true, preference -> {
-                AndroidHostInterface.getInstance().toggleControllerAnalogMode();
-                menuDialogFragment.close(true);
-                return true;
-            });
-            createPreference(R.string.emulation_menu_reset_console, R.drawable.ic_baseline_restart_alt_24, true, preference -> {
-                AndroidHostInterface.getInstance().resetSystem();
-                menuDialogFragment.close(true);
-                return true;
-            });
-        }
-
-        private void createPreference(int titleId, int icon, boolean enabled, Preference.OnPreferenceClickListener action) {
-            final Preference preference = new Preference(getContext());
-            preference.setTitle(titleId);
-            preference.setIcon(icon);
-            preference.setOnPreferenceClickListener(action);
-            preference.setEnabled(enabled);
-            getPreferenceScreen().addPreference(preference);
-        }
-    }
-}
diff --git a/android/app/src/main/java/com/github/stenzek/duckstation/EmulationSurfaceView.java b/android/app/src/main/java/com/github/stenzek/duckstation/EmulationSurfaceView.java
deleted file mode 100644
index 2305caf16..000000000
--- a/android/app/src/main/java/com/github/stenzek/duckstation/EmulationSurfaceView.java
+++ /dev/null
@@ -1,302 +0,0 @@
-package com.github.stenzek.duckstation;
-
-import android.content.Context;
-import android.os.Vibrator;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.view.InputDevice;
-import android.view.KeyEvent;
-import android.view.MotionEvent;
-import android.view.SurfaceView;
-
-import java.util.ArrayList;
-import java.util.List;
-
-public class EmulationSurfaceView extends SurfaceView {
-    public EmulationSurfaceView(Context context) {
-        super(context);
-    }
-
-    public EmulationSurfaceView(Context context, AttributeSet attrs) {
-        super(context, attrs);
-    }
-
-    public EmulationSurfaceView(Context context, AttributeSet attrs, int defStyle) {
-        super(context, attrs, defStyle);
-    }
-
-    public static boolean isBindableDevice(InputDevice inputDevice) {
-        if (inputDevice == null)
-            return false;
-
-        // Accept all devices with an axis or buttons, filter in events.
-        final int sources = inputDevice.getSources();
-        return ((sources & InputDevice.SOURCE_CLASS_JOYSTICK) == InputDevice.SOURCE_CLASS_JOYSTICK) ||
-                ((sources & InputDevice.SOURCE_CLASS_BUTTON) == InputDevice.SOURCE_CLASS_BUTTON);
-    }
-
-    public static boolean isGamepadDevice(InputDevice inputDevice) {
-        final int sources = (inputDevice != null) ? inputDevice.getSources() : 0;
-        return ((sources & InputDevice.SOURCE_GAMEPAD) == InputDevice.SOURCE_GAMEPAD);
-    }
-
-    public static boolean isJoystickMotionEvent(MotionEvent event) {
-        final int source = event.getSource();
-        return ((source & InputDevice.SOURCE_CLASS_JOYSTICK) == InputDevice.SOURCE_CLASS_JOYSTICK);
-    }
-
-    public static boolean isBindableKeyEvent(KeyEvent event) {
-        switch (event.getKeyCode()) {
-            case KeyEvent.KEYCODE_BACK:
-            case KeyEvent.KEYCODE_HOME:
-            case KeyEvent.KEYCODE_POWER:
-                // We're okay if we get these from a gamepad.
-                return isGamepadDevice(event.getDevice());
-
-            default:
-                return true;
-        }
-    }
-
-    private static boolean isSystemKeyCode(int keyCode) {
-        switch (keyCode) {
-            case KeyEvent.KEYCODE_MENU:
-            case KeyEvent.KEYCODE_SOFT_RIGHT:
-            case KeyEvent.KEYCODE_HOME:
-            case KeyEvent.KEYCODE_BACK:
-            case KeyEvent.KEYCODE_CALL:
-            case KeyEvent.KEYCODE_ENDCALL:
-            case KeyEvent.KEYCODE_VOLUME_UP:
-            case KeyEvent.KEYCODE_VOLUME_DOWN:
-            case KeyEvent.KEYCODE_VOLUME_MUTE:
-            case KeyEvent.KEYCODE_MUTE:
-            case KeyEvent.KEYCODE_POWER:
-            case KeyEvent.KEYCODE_HEADSETHOOK:
-            case KeyEvent.KEYCODE_MEDIA_PLAY:
-            case KeyEvent.KEYCODE_MEDIA_PAUSE:
-            case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
-            case KeyEvent.KEYCODE_MEDIA_STOP:
-            case KeyEvent.KEYCODE_MEDIA_NEXT:
-            case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
-            case KeyEvent.KEYCODE_MEDIA_REWIND:
-            case KeyEvent.KEYCODE_MEDIA_RECORD:
-            case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD:
-            case KeyEvent.KEYCODE_CAMERA:
-            case KeyEvent.KEYCODE_FOCUS:
-            case KeyEvent.KEYCODE_SEARCH:
-            case KeyEvent.KEYCODE_BRIGHTNESS_DOWN:
-            case KeyEvent.KEYCODE_BRIGHTNESS_UP:
-            case KeyEvent.KEYCODE_MEDIA_AUDIO_TRACK:
-            case KeyEvent.KEYCODE_SYSTEM_NAVIGATION_UP:
-            case KeyEvent.KEYCODE_SYSTEM_NAVIGATION_DOWN:
-            case KeyEvent.KEYCODE_SYSTEM_NAVIGATION_LEFT:
-            case KeyEvent.KEYCODE_SYSTEM_NAVIGATION_RIGHT:
-                return true;
-
-            default:
-                return false;
-        }
-    }
-
-    private class InputDeviceData {
-        private int deviceId;
-        private String descriptor;
-        private int[] axes;
-        private float[] axisValues;
-        private int controllerIndex;
-        private Vibrator vibrator;
-
-        public InputDeviceData(InputDevice device, int controllerIndex) {
-            deviceId = device.getId();
-            descriptor = device.getDescriptor();
-            this.controllerIndex = controllerIndex;
-
-            List<InputDevice.MotionRange> motionRanges = device.getMotionRanges();
-            if (motionRanges != null && !motionRanges.isEmpty()) {
-                axes = new int[motionRanges.size()];
-                axisValues = new float[motionRanges.size()];
-                for (int i = 0; i < motionRanges.size(); i++)
-                    axes[i] = motionRanges.get(i).getAxis();
-            }
-
-            // device.getVibrator() always returns null, but might return a "null vibrator".
-            final Vibrator potentialVibrator = device.getVibrator();
-            if (potentialVibrator != null && potentialVibrator.hasVibrator())
-                vibrator = potentialVibrator;
-        }
-    }
-
-    private InputDeviceData[] mInputDevices = null;
-    private String[] mControllerDescriptors = null;
-    private boolean mHasAnyGamepads = false;
-
-    public boolean hasAnyGamePads() {
-        return mHasAnyGamepads;
-    }
-
-    public synchronized void updateInputDevices() {
-        mInputDevices = null;
-        mControllerDescriptors = null;
-        mHasAnyGamepads = false;
-
-        final ArrayList<InputDeviceData> inputDeviceIds = new ArrayList<>();
-        final ArrayList<String> controllerDescriptors = new ArrayList<>();
-
-        for (int deviceId : InputDevice.getDeviceIds()) {
-            final InputDevice device = InputDevice.getDevice(deviceId);
-            if (device == null || !isBindableDevice(device)) {
-                Log.d("EmulationSurfaceView",
-                        String.format("Skipping device %s sources %d",
-                                (device != null) ? device.toString() : "",
-                                (device != null) ? device.getSources() : 0));
-                continue;
-            }
-
-            if (isGamepadDevice(device))
-                mHasAnyGamepads = true;
-
-            // Some phones seem to have duplicate descriptors for multiple devices.
-            // Combine them all into one controller index if so.
-            final String descriptor = device.getDescriptor();
-            int controllerIndex = controllerDescriptors.size();
-            for (int i = 0; i < controllerDescriptors.size(); i++) {
-                if (controllerDescriptors.get(i).equals(descriptor)) {
-                    controllerIndex = i;
-                    break;
-                }
-            }
-            if (controllerIndex == controllerDescriptors.size()) {
-                controllerDescriptors.add(descriptor);
-            }
-
-            Log.d("EmulationSurfaceView", String.format("Tracking device %d/%s (%s, sources %d, controller %d)",
-                    controllerIndex, descriptor, device.getName(), device.getSources(), controllerIndex));
-            inputDeviceIds.add(new InputDeviceData(device, controllerIndex));
-        }
-
-        if (inputDeviceIds.isEmpty())
-            return;
-
-        mInputDevices = new InputDeviceData[inputDeviceIds.size()];
-        inputDeviceIds.toArray(mInputDevices);
-
-        mControllerDescriptors = new String[controllerDescriptors.size()];
-        controllerDescriptors.toArray(mControllerDescriptors);
-    }
-
-    public synchronized String[] getInputDeviceNames() {
-        return mControllerDescriptors;
-    }
-
-    public synchronized boolean hasInputDeviceVibration(int controllerIndex) {
-        if (mInputDevices == null || controllerIndex >= mInputDevices.length)
-            return false;
-
-        return (mInputDevices[controllerIndex].vibrator != null);
-    }
-
-    public synchronized void setInputDeviceVibration(int controllerIndex, float smallMotor, float largeMotor) {
-        if (mInputDevices == null || controllerIndex >= mInputDevices.length)
-            return;
-
-        // shouldn't get here
-        final InputDeviceData data = mInputDevices[controllerIndex];
-        if (data.vibrator == null)
-            return;
-
-        final float MINIMUM_INTENSITY = 0.1f;
-        if (smallMotor >= MINIMUM_INTENSITY || largeMotor >= MINIMUM_INTENSITY)
-            data.vibrator.vibrate(1000);
-        else
-            data.vibrator.cancel();
-    }
-
-    public InputDeviceData getDataForDeviceId(int deviceId) {
-        if (mInputDevices == null)
-            return null;
-
-        for (InputDeviceData data : mInputDevices) {
-            if (data.deviceId == deviceId)
-                return data;
-        }
-
-        return null;
-    }
-
-    public int getControllerIndexForDeviceId(int deviceId) {
-        final InputDeviceData data = getDataForDeviceId(deviceId);
-        return (data != null) ? data.controllerIndex : -1;
-    }
-
-    private boolean handleKeyEvent(int deviceId, int repeatCount, int keyCode, boolean pressed) {
-        final int controllerIndex = getControllerIndexForDeviceId(deviceId);
-        Log.d("EmulationSurfaceView", String.format("Controller %d Code %d RC %d Pressed %d",
-                controllerIndex, keyCode, repeatCount, pressed? 1 : 0));
-
-        final AndroidHostInterface hi = AndroidHostInterface.getInstance();
-        if (repeatCount == 0 && controllerIndex >= 0)
-            hi.handleControllerButtonEvent(controllerIndex, keyCode, pressed);
-
-        // We don't want to eat external button events unless it's actually bound.
-        if (isSystemKeyCode(keyCode))
-            return (controllerIndex >= 0 && hi.hasControllerButtonBinding(controllerIndex, keyCode));
-        else
-            return true;
-    }
-
-    @Override
-    public boolean onKeyDown(int keyCode, KeyEvent event) {
-        return handleKeyEvent(event.getDeviceId(), event.getRepeatCount(), keyCode, true);
-    }
-
-    @Override
-    public boolean onKeyUp(int keyCode, KeyEvent event) {
-        return handleKeyEvent(event.getDeviceId(), 0, keyCode, false);
-    }
-
-    private float clamp(float value, float min, float max) {
-        return (value < min) ? min : ((value > max) ? max : value);
-    }
-
-    @Override
-    public boolean onGenericMotionEvent(MotionEvent event) {
-        if (!isJoystickMotionEvent(event))
-            return false;
-
-        final InputDeviceData data = getDataForDeviceId(event.getDeviceId());
-        if (data == null || data.axes == null)
-            return false;
-
-        for (int i = 0; i < data.axes.length; i++) {
-            final int axis = data.axes[i];
-            final float axisValue = event.getAxisValue(axis);
-            float emuValue;
-
-            switch (axis) {
-                case MotionEvent.AXIS_BRAKE:
-                case MotionEvent.AXIS_GAS:
-                case MotionEvent.AXIS_LTRIGGER:
-                case MotionEvent.AXIS_RTRIGGER:
-                    // Scale 0..1 -> -1..1.
-                    emuValue = (clamp(axisValue, 0.0f, 1.0f) * 2.0f) - 1.0f;
-                    break;
-
-                default:
-                    // Everything else should already by -1..1 as per Android documentation.
-                    emuValue = clamp(axisValue, -1.0f, 1.0f);
-                    break;
-            }
-
-            if (data.axisValues[i] == emuValue)
-                continue;
-
-            Log.d("EmulationSurfaceView",
-                    String.format("axis %d value %f emuvalue %f", axis, axisValue, emuValue));
-
-            data.axisValues[i] = emuValue;
-            AndroidHostInterface.getInstance().handleControllerAxisEvent(data.controllerIndex, axis, emuValue);
-        }
-
-        return true;
-    }
-}
diff --git a/android/app/src/main/java/com/github/stenzek/duckstation/EmulationThread.java b/android/app/src/main/java/com/github/stenzek/duckstation/EmulationThread.java
deleted file mode 100644
index 0bdcf25d9..000000000
--- a/android/app/src/main/java/com/github/stenzek/duckstation/EmulationThread.java
+++ /dev/null
@@ -1,67 +0,0 @@
-package com.github.stenzek.duckstation;
-
-import android.os.Build;
-import android.os.Process;
-import android.util.Log;
-import android.view.Surface;
-
-import androidx.annotation.NonNull;
-
-public class EmulationThread extends Thread {
-    private EmulationActivity emulationActivity;
-    private String filename;
-    private boolean resumeState;
-    private String stateFilename;
-
-    private EmulationThread(EmulationActivity emulationActivity, String filename, boolean resumeState, String stateFilename) {
-        super("EmulationThread");
-        this.emulationActivity = emulationActivity;
-        this.filename = filename;
-        this.resumeState = resumeState;
-        this.stateFilename = stateFilename;
-    }
-
-    public static EmulationThread create(EmulationActivity emulationActivity, String filename, boolean resumeState, String stateFilename) {
-        Log.i("EmulationThread", String.format("Starting emulation thread (%s)...", filename));
-
-        EmulationThread thread = new EmulationThread(emulationActivity, filename, resumeState, stateFilename);
-        thread.start();
-        return thread;
-    }
-
-    private void setExclusiveCores() {
-        try {
-            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
-                int[] cores = Process.getExclusiveCores();
-                if (cores == null || cores.length == 0)
-                    throw new Exception("Invalid return value from getExclusiveCores()");
-
-                AndroidHostInterface.setThreadAffinity(cores);
-            }
-        } catch (Exception e) {
-            Log.e("EmulationThread", "getExclusiveCores() failed");
-        }
-    }
-
-    @Override
-    public void run() {
-        try {
-            Process.setThreadPriority(Process.THREAD_PRIORITY_MORE_FAVORABLE);
-            setExclusiveCores();
-        } catch (Exception e) {
-            Log.i("EmulationThread", "Failed to set priority for emulation thread: " + e.getMessage());
-        }
-
-        AndroidHostInterface.getInstance().runEmulationThread(emulationActivity, filename, resumeState, stateFilename);
-        Log.i("EmulationThread", "Emulation thread exiting.");
-    }
-
-    public void stopAndJoin() {
-        AndroidHostInterface.getInstance().stopEmulationThreadLoop();
-        try {
-            join();
-        } catch (InterruptedException e) {
-            Log.i("EmulationThread", "join() interrupted: " + e.getMessage());
-        }
-    }
-}
diff --git a/android/app/src/main/java/com/github/stenzek/duckstation/FileHelper.java b/android/app/src/main/java/com/github/stenzek/duckstation/FileHelper.java
deleted file mode 100644
index 258350d0d..000000000
--- a/android/app/src/main/java/com/github/stenzek/duckstation/FileHelper.java
+++ /dev/null
@@ -1,613 +0,0 @@
-package com.github.stenzek.duckstation;
-
-import android.annotation.SuppressLint;
-import android.annotation.TargetApi;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.database.Cursor;
-import android.graphics.Bitmap;
-import android.graphics.ImageDecoder;
-import android.net.Uri;
-import android.os.Build;
-import android.os.ParcelFileDescriptor;
-import android.os.storage.StorageManager;
-import android.provider.DocumentsContract;
-import android.provider.MediaStore;
-
-import androidx.annotation.Nullable;
-
-import java.io.ByteArrayOutputStream;
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.OutputStream;
-import java.lang.reflect.Array;
-import java.lang.reflect.Method;
-import java.nio.charset.Charset;
-import java.nio.charset.StandardCharsets;
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * File helper class - used to bridge native code to Java storage access framework APIs.
- */
-public class FileHelper {
-    /**
-     * Native filesystem flags.
-     */
-    public static final int FILESYSTEM_FILE_ATTRIBUTE_DIRECTORY = 1;
-    public static final int FILESYSTEM_FILE_ATTRIBUTE_READ_ONLY = 2;
-    public static final int FILESYSTEM_FILE_ATTRIBUTE_COMPRESSED = 4;
-
-    /**
-     * Native filesystem find result flags.
-     */
-    public static final int FILESYSTEM_FIND_RECURSIVE = (1 << 0);
-    public static final int FILESYSTEM_FIND_RELATIVE_PATHS = (1 << 1);
-    public static final int FILESYSTEM_FIND_HIDDEN_FILES = (1 << 2);
-    public static final int FILESYSTEM_FIND_FOLDERS = (1 << 3);
-    public static final int FILESYSTEM_FIND_FILES = (1 << 4);
-    public static final int FILESYSTEM_FIND_KEEP_ARRAY = (1 << 5);
-
-    /**
-     * Projection used when searching for files.
-     */
-    private static final String[] findProjection = new String[]{
-            DocumentsContract.Document.COLUMN_DOCUMENT_ID,
-            DocumentsContract.Document.COLUMN_DISPLAY_NAME,
-            DocumentsContract.Document.COLUMN_MIME_TYPE,
-            DocumentsContract.Document.COLUMN_SIZE,
-            DocumentsContract.Document.COLUMN_LAST_MODIFIED
-    };
-
-    /**
-     * Projection used when getting the display name for a file.
-     */
-    private static final String[] getDisplayNameProjection = new String[]{
-            DocumentsContract.Document.COLUMN_DISPLAY_NAME,
-    };
-
-    /**
-     * Projection used when getting a relative file for a file.
-     */
-    private static final String[] getRelativeFileProjection = new String[]{
-            DocumentsContract.Document.COLUMN_DOCUMENT_ID,
-            DocumentsContract.Document.COLUMN_DISPLAY_NAME,
-    };
-
-    private final Context context;
-    private final ContentResolver contentResolver;
-
-    /**
-     * File helper class - used to bridge native code to Java storage access framework APIs.
-     *
-     * @param context Context in which to perform file actions as.
-     */
-    public FileHelper(Context context) {
-        this.context = context;
-        this.contentResolver = context.getContentResolver();
-    }
-
-    /**
-     * Reads the specified file as a string, under the specified context.
-     *
-     * @param context context to access file under
-     * @param uri     uri to write data to
-     * @param maxSize maximum file size to read
-     * @return String containing the file data, otherwise null
-     */
-    public static String readStringFromUri(final Context context, final Uri uri, int maxSize) {
-        InputStream stream = null;
-        try {
-            stream = context.getContentResolver().openInputStream(uri);
-        } catch (FileNotFoundException e) {
-            return null;
-        }
-
-        StringBuilder os = new StringBuilder();
-        try {
-            char[] buffer = new char[1024];
-            InputStreamReader reader = new InputStreamReader(stream, Charset.forName(StandardCharsets.UTF_8.name()));
-            int len;
-            while ((len = reader.read(buffer)) > 0) {
-                os.append(buffer, 0, len);
-                if (os.length() > maxSize)
-                    return null;
-            }
-
-            stream.close();
-        } catch (IOException e) {
-            return null;
-        }
-
-        if (os.length() == 0)
-            return null;
-
-        return os.toString();
-    }
-
-    /**
-     * Reads the specified file as a byte array, under the specified context.
-     *
-     * @param context context to access file under
-     * @param uri     uri to write data to
-     * @param maxSize maximum file size to read
-     * @return byte array containing the file data, otherwise null
-     */
-    public static byte[] readBytesFromUri(final Context context, final Uri uri, int maxSize) {
-        InputStream stream = null;
-        try {
-            stream = context.getContentResolver().openInputStream(uri);
-        } catch (FileNotFoundException e) {
-            return null;
-        }
-
-        ByteArrayOutputStream os = new ByteArrayOutputStream();
-        try {
-            byte[] buffer = new byte[512 * 1024];
-            int len;
-            while ((len = stream.read(buffer)) > 0) {
-                os.write(buffer, 0, len);
-                if (maxSize > 0 && os.size() > maxSize) {
-                    return null;
-                }
-            }
-
-            stream.close();
-        } catch (IOException e) {
-            e.printStackTrace();
-            return null;
-        }
-
-        if (os.size() == 0)
-            return null;
-
-        return os.toByteArray();
-    }
-
-    /**
-     * Writes the specified data to a file referenced by the URI, as the specified context.
-     *
-     * @param context context to access file under
-     * @param uri     uri to write data to
-     * @param bytes   data to write file to
-     * @return true if write was succesful, otherwise false
-     */
-    public static boolean writeBytesToUri(final Context context, final Uri uri, final byte[] bytes) {
-        OutputStream stream = null;
-        try {
-            stream = context.getContentResolver().openOutputStream(uri);
-        } catch (FileNotFoundException e) {
-            e.printStackTrace();
-            return false;
-        }
-
-        if (bytes != null && bytes.length > 0) {
-            try {
-                stream.write(bytes);
-                stream.close();
-            } catch (IOException e) {
-                e.printStackTrace();
-                return false;
-            }
-        }
-
-        return true;
-    }
-
-    /**
-     * Deletes the file referenced by the URI, under the specified context.
-     *
-     * @param context context to delete file under
-     * @param uri     uri to delete
-     * @return
-     */
-    public static boolean deleteFileAtUri(final Context context, final Uri uri) {
-        try {
-            if (uri.getScheme() == "file") {
-                final File file = new File(uri.getPath());
-                if (!file.isFile())
-                    return false;
-
-                return file.delete();
-            }
-            return (context.getContentResolver().delete(uri, null, null) > 0);
-        } catch (Exception e) {
-            e.printStackTrace();
-            return false;
-        }
-    }
-
-    /**
-     * Returns the name of the file pointed at by a SAF URI.
-     *
-     * @param context context to access file under
-     * @param uri     uri to retrieve file name for
-     * @return the name of the file, or null
-     */
-    public static String getDocumentNameFromUri(final Context context, final Uri uri) {
-        Cursor cursor = null;
-        try {
-            final String[] proj = {DocumentsContract.Document.COLUMN_DISPLAY_NAME};
-            cursor = context.getContentResolver().query(uri, proj, null, null, null);
-            final int columnIndex = cursor.getColumnIndexOrThrow(DocumentsContract.Document.COLUMN_DISPLAY_NAME);
-            cursor.moveToFirst();
-            return cursor.getString(columnIndex);
-        } catch (Exception e) {
-            e.printStackTrace();
-            return null;
-        } finally {
-            if (cursor != null)
-                cursor.close();
-        }
-    }
-
-    /**
-     * Loads a bitmap from the provided SAF URI.
-     *
-     * @param context context to access file under
-     * @param uri     uri to retrieve file name for
-     * @return a decoded bitmap for the file, or null
-     */
-    public static Bitmap loadBitmapFromUri(final Context context, final Uri uri) {
-        InputStream stream = null;
-        try {
-            if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.P) {
-                final ImageDecoder.Source source = ImageDecoder.createSource(context.getContentResolver(), uri);
-                return ImageDecoder.decodeBitmap(source);
-            } else {
-                return MediaStore.Images.Media.getBitmap(context.getContentResolver(), uri);
-            }
-        } catch (Exception e) {
-            e.printStackTrace();
-            return null;
-        }
-    }
-
-    /**
-     * Returns the file name component of a path or URI.
-     *
-     * @param path Path/URI to examine.
-     * @return File name component of path/URI.
-     */
-    public static String getFileNameForPath(String path) {
-        if (path.startsWith("content:/") || path.startsWith("file:/")) {
-            try {
-                final Uri uri = Uri.parse(path);
-                final String lastPathSegment = uri.getLastPathSegment();
-                if (lastPathSegment != null)
-                    path = lastPathSegment;
-            } catch (Exception e) {
-            }
-        }
-
-        int lastSlash = path.lastIndexOf('/');
-        if (lastSlash > 0 && lastSlash < path.length() - 1)
-            return path.substring(lastSlash + 1);
-        else
-            return path;
-    }
-
-    /**
-     * Test if the given URI represents a {@link DocumentsContract.Document} tree.
-     */
-    public static boolean isTreeUri(Uri uri) {
-        final List<String> paths = uri.getPathSegments();
-        return (paths.size() >= 2 && paths.get(0).equals("tree"));
-    }
-
-    /**
-     * Retrieves a file descriptor for a content URI string. Called by native code.
-     *
-     * @param uriString string of the URI to open
-     * @param mode      Java open mode
-     * @return file descriptor for URI, or -1
-     */
-    public int openURIAsFileDescriptor(String uriString, String mode) {
-        try {
-            final Uri uri = Uri.parse(uriString);
-            final ParcelFileDescriptor fd = contentResolver.openFileDescriptor(uri, mode);
-            if (fd == null)
-                return -1;
-            return fd.detachFd();
-        } catch (Exception e) {
-            return -1;
-        }
-    }
-
-    /**
-     * Recursively iterates documents in the specified tree, searching for files.
-     *
-     * @param treeUri    Root tree in which to search for documents.
-     * @param documentId Document ID representing the directory to start searching.
-     * @param flags      Native search flags.
-     * @param results    Cumulative result array.
-     */
-    private void doFindFiles(Uri treeUri, String documentId, int flags, ArrayList<FindResult> results) {
-        try {
-            final Uri queryUri = DocumentsContract.buildChildDocumentsUriUsingTree(treeUri, documentId);
-            final Cursor cursor = contentResolver.query(queryUri, findProjection, null, null, null);
-            final int count = cursor.getCount();
-
-            while (cursor.moveToNext()) {
-                try {
-                    final String mimeType = cursor.getString(2);
-                    final String childDocumentId = cursor.getString(0);
-                    final Uri uri = DocumentsContract.buildDocumentUriUsingTree(treeUri, childDocumentId);
-                    final long size = cursor.getLong(3);
-                    final long lastModified = cursor.getLong(4);
-
-                    if (DocumentsContract.Document.MIME_TYPE_DIR.equals(mimeType)) {
-                        if ((flags & FILESYSTEM_FIND_FOLDERS) != 0) {
-                            results.add(new FindResult(childDocumentId, uri.toString(), size, lastModified, FILESYSTEM_FILE_ATTRIBUTE_DIRECTORY));
-                        }
-
-                        if ((flags & FILESYSTEM_FIND_RECURSIVE) != 0)
-                            doFindFiles(treeUri, childDocumentId, flags, results);
-                    } else {
-                        if ((flags & FILESYSTEM_FIND_FILES) != 0) {
-                            results.add(new FindResult(childDocumentId, uri.toString(), size, lastModified, 0));
-                        }
-                    }
-                } catch (Exception e) {
-                    e.printStackTrace();
-                }
-            }
-            cursor.close();
-        } catch (Exception e) {
-            e.printStackTrace();
-        }
-    }
-
-    /**
-     * Recursively iterates documents in the specified URI, searching for files.
-     *
-     * @param uriString URI containing directory to search.
-     * @param flags     Native filter flags.
-     * @return Array of find results.
-     */
-    public FindResult[] findFiles(String uriString, int flags) {
-        try {
-            final Uri fullUri = Uri.parse(uriString);
-            final String documentId = DocumentsContract.getTreeDocumentId(fullUri);
-            final ArrayList<FindResult> results = new ArrayList<>();
-            doFindFiles(fullUri, documentId, flags, results);
-            if (results.isEmpty())
-                return null;
-
-            final FindResult[] resultsArray = new FindResult[results.size()];
-            results.toArray(resultsArray);
-            return resultsArray;
-        } catch (Exception e) {
-            e.printStackTrace();
-            return null;
-        }
-    }
-
-    /**
-     * Returns the display name for the given URI.
-     *
-     * @param uriString URI to resolve display name for.
-     * @return display name for the URI, or null.
-     */
-    public String getDisplayNameForURIPath(String uriString) {
-        try {
-            final Uri fullUri = Uri.parse(uriString);
-            final Cursor cursor = contentResolver.query(fullUri, getDisplayNameProjection,
-                    null, null, null);
-            if (cursor.getCount() == 0 || !cursor.moveToNext())
-                return null;
-
-            return cursor.getString(0);
-        } catch (Exception e) {
-            e.printStackTrace();
-            return null;
-        }
-    }
-
-    /**
-     * Returns the path for a sibling file relative to another URI.
-     *
-     * @param uriString   URI to find the file relative to.
-     * @param newFileName Sibling file name.
-     * @return URI for the sibling file name, or null.
-     */
-    public String getRelativePathForURIPath(String uriString, String newFileName) {
-        try {
-            final Uri fullUri = Uri.parse(uriString);
-
-            // if this is a document (expected)...
-            Uri treeUri;
-            String treeDocId;
-            if (DocumentsContract.isDocumentUri(context, fullUri)) {
-                // we need to remove the last part of the URI (the specific document ID) to get the parent
-                final String lastPathSegment = fullUri.getLastPathSegment();
-                int lastSeparatorIndex = lastPathSegment.lastIndexOf('/');
-                if (lastSeparatorIndex < 0)
-                    lastSeparatorIndex = lastPathSegment.lastIndexOf(':');
-                if (lastSeparatorIndex < 0)
-                    return null;
-
-                // the parent becomes the document ID
-                treeDocId = lastPathSegment.substring(0, lastSeparatorIndex);
-
-                // but, we need to access it through the subtree if this was a tree URI (permissions...)
-                if (isTreeUri(fullUri)) {
-                    treeUri = DocumentsContract.buildTreeDocumentUri(fullUri.getAuthority(), DocumentsContract.getTreeDocumentId(fullUri));
-                } else {
-                    treeUri = DocumentsContract.buildTreeDocumentUri(fullUri.getAuthority(), treeDocId);
-                }
-            } else {
-                treeDocId = DocumentsContract.getDocumentId(fullUri);
-                treeUri = fullUri;
-            }
-
-            final Uri queryUri = DocumentsContract.buildChildDocumentsUriUsingTree(treeUri, treeDocId);
-            final Cursor cursor = contentResolver.query(queryUri, getRelativeFileProjection, null, null, null);
-            final int count = cursor.getCount();
-
-            while (cursor.moveToNext()) {
-                try {
-                    final String displayName = cursor.getString(1);
-                    if (!displayName.equalsIgnoreCase(newFileName))
-                        continue;
-
-                    final String childDocumentId = cursor.getString(0);
-                    final Uri uri = DocumentsContract.buildDocumentUriUsingTree(treeUri, childDocumentId);
-                    cursor.close();
-                    return uri.toString();
-                } catch (Exception e) {
-                    e.printStackTrace();
-                }
-            }
-
-            cursor.close();
-            return null;
-        } catch (Exception e) {
-            e.printStackTrace();
-            return null;
-        }
-    }
-
-    private static final String PRIMARY_VOLUME_NAME = "primary";
-
-    @Nullable
-    public static String getFullPathFromTreeUri(@Nullable final Uri treeUri, Context con) {
-        if (treeUri == null) return null;
-        String volumePath = getVolumePath(getVolumeIdFromTreeUri(treeUri), con);
-        if (volumePath == null) return File.separator;
-        if (volumePath.endsWith(File.separator))
-            volumePath = volumePath.substring(0, volumePath.length() - 1);
-
-        String documentPath = getDocumentPathFromTreeUri(treeUri);
-        if (documentPath.endsWith(File.separator))
-            documentPath = documentPath.substring(0, documentPath.length() - 1);
-
-        if (documentPath.length() > 0) {
-            if (documentPath.startsWith(File.separator))
-                return volumePath + documentPath;
-            else
-                return volumePath + File.separator + documentPath;
-        } else return volumePath;
-    }
-
-    @SuppressLint("ObsoleteSdkInt")
-    private static String getVolumePath(final String volumeId, Context context) {
-        if (volumeId == null)
-            return null;
-
-        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) return null;
-        try {
-            StorageManager mStorageManager =
-                    (StorageManager) context.getSystemService(Context.STORAGE_SERVICE);
-            Class<?> storageVolumeClazz = Class.forName("android.os.storage.StorageVolume");
-            Method getVolumeList = mStorageManager.getClass().getMethod("getVolumeList");
-            Method getUuid = storageVolumeClazz.getMethod("getUuid");
-            Method getPath = storageVolumeClazz.getMethod("getPath");
-            Method isPrimary = storageVolumeClazz.getMethod("isPrimary");
-            Object result = getVolumeList.invoke(mStorageManager);
-
-            final int length = Array.getLength(result);
-            for (int i = 0; i < length; i++) {
-                Object storageVolumeElement = Array.get(result, i);
-                String uuid = (String) getUuid.invoke(storageVolumeElement);
-                Boolean primary = (Boolean) isPrimary.invoke(storageVolumeElement);
-
-                // primary volume?
-                if (primary && PRIMARY_VOLUME_NAME.equals(volumeId))
-                    return (String) getPath.invoke(storageVolumeElement);
-
-                // other volumes?
-                if (uuid != null && uuid.equals(volumeId))
-                    return (String) getPath.invoke(storageVolumeElement);
-            }
-            // not found.
-            return null;
-        } catch (Exception ex) {
-            return null;
-        }
-    }
-
-    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
-    private static String getVolumeIdFromTreeUri(final Uri treeUri) {
-        final String docId = DocumentsContract.getTreeDocumentId(treeUri);
-        final String[] split = docId.split(":");
-        if (split.length > 0) return split[0];
-        else return null;
-    }
-
-
-    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
-    private static String getDocumentPathFromTreeUri(final Uri treeUri) {
-        final String docId = DocumentsContract.getTreeDocumentId(treeUri);
-        final String[] split = docId.split(":");
-        if ((split.length >= 2) && (split[1] != null)) return split[1];
-        else return File.separator;
-    }
-
-    @Nullable
-    public static String getFullPathFromUri(@Nullable final Uri treeUri, Context con) {
-        if (treeUri == null) return null;
-        String volumePath = getVolumePath(getVolumeIdFromUri(treeUri), con);
-        if (volumePath == null) return File.separator;
-        if (volumePath.endsWith(File.separator))
-            volumePath = volumePath.substring(0, volumePath.length() - 1);
-
-        String documentPath = getDocumentPathFromUri(treeUri);
-        if (documentPath.endsWith(File.separator))
-            documentPath = documentPath.substring(0, documentPath.length() - 1);
-
-        if (documentPath.length() > 0) {
-            if (documentPath.startsWith(File.separator))
-                return volumePath + documentPath;
-            else
-                return volumePath + File.separator + documentPath;
-        } else return volumePath;
-    }
-
-    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
-    private static String getVolumeIdFromUri(final Uri treeUri) {
-        try {
-            final String docId = DocumentsContract.getDocumentId(treeUri);
-            final String[] split = docId.split(":");
-            if (split.length > 0) return split[0];
-            else return null;
-        } catch (Exception e) {
-            return null;
-        }
-    }
-
-
-    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
-    private static String getDocumentPathFromUri(final Uri treeUri) {
-        try {
-            final String docId = DocumentsContract.getDocumentId(treeUri);
-            final String[] split = docId.split(":");
-            if ((split.length >= 2) && (split[1] != null)) return split[1];
-            else return File.separator;
-        } catch (Exception e) {
-            return null;
-        }
-    }
-
-    /**
-     * Java class containing the data for a file in a find operation.
-     */
-    public static class FindResult {
-        public String name;
-        public String relativeName;
-        public long size;
-        public long modifiedTime;
-        public int flags;
-
-        public FindResult(String relativeName, String name, long size, long modifiedTime, int flags) {
-            this.relativeName = relativeName;
-            this.name = name;
-            this.size = size;
-            this.modifiedTime = modifiedTime;
-            this.flags = flags;
-        }
-    }
-}
diff --git a/android/app/src/main/java/com/github/stenzek/duckstation/GameDirectoriesActivity.java b/android/app/src/main/java/com/github/stenzek/duckstation/GameDirectoriesActivity.java
deleted file mode 100644
index 4c1bd85b2..000000000
--- a/android/app/src/main/java/com/github/stenzek/duckstation/GameDirectoriesActivity.java
+++ /dev/null
@@ -1,348 +0,0 @@
-package com.github.stenzek.duckstation;
-
-import android.app.Activity;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.content.Intent;
-import android.content.SharedPreferences;
-import android.net.Uri;
-import android.os.Bundle;
-import android.os.FileUtils;
-import android.util.Log;
-import android.util.Property;
-import android.view.LayoutInflater;
-import android.view.Menu;
-import android.view.MenuItem;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.BaseAdapter;
-import android.widget.EditText;
-import android.widget.ImageButton;
-import android.widget.ListAdapter;
-import android.widget.TextView;
-import android.widget.Toast;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.appcompat.app.ActionBar;
-import androidx.appcompat.app.AlertDialog;
-import androidx.appcompat.app.AppCompatActivity;
-import androidx.appcompat.widget.Toolbar;
-import androidx.fragment.app.Fragment;
-import androidx.fragment.app.ListFragment;
-import androidx.preference.PreferenceFragmentCompat;
-import androidx.preference.PreferenceManager;
-import androidx.preference.PreferenceScreen;
-import androidx.recyclerview.widget.DividerItemDecoration;
-import androidx.recyclerview.widget.LinearLayoutManager;
-import androidx.recyclerview.widget.RecyclerView;
-import androidx.viewpager2.adapter.FragmentStateAdapter;
-import androidx.viewpager2.widget.ViewPager2;
-
-import com.google.android.material.tabs.TabLayout;
-import com.google.android.material.tabs.TabLayoutMediator;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Comparator;
-import java.util.HashSet;
-import java.util.Set;
-
-public class GameDirectoriesActivity extends AppCompatActivity {
-    private static final int REQUEST_ADD_DIRECTORY_TO_GAME_LIST = 1;
-    private static final String FORCE_SAF_CONFIG_KEY = "GameList/ForceStorageAccessFramework";
-
-    private class DirectoryListAdapter extends RecyclerView.Adapter {
-        private class Entry {
-            private String mPath;
-            private boolean mRecursive;
-
-            public Entry(String path, boolean recursive) {
-                mPath = path;
-                mRecursive = recursive;
-            }
-
-            public String getPath() {
-                return mPath;
-            }
-
-            public boolean isRecursive() {
-                return mRecursive;
-            }
-
-            public void toggleRecursive() {
-                mRecursive = !mRecursive;
-            }
-        }
-
-        private class EntryComparator implements Comparator<Entry> {
-            @Override
-            public int compare(Entry left, Entry right) {
-                return left.getPath().compareTo(right.getPath());
-            }
-        }
-
-        private Context mContext;
-        private Entry[] mEntries;
-
-        public DirectoryListAdapter(Context context) {
-            mContext = context;
-            reload();
-        }
-
-        public void reload() {
-            SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(mContext);
-            ArrayList<Entry> entries = new ArrayList<>();
-
-            try {
-                Set<String> paths = prefs.getStringSet("GameList/Paths", null);
-                if (paths != null) {
-                    for (String path : paths)
-                        entries.add(new Entry(path, false));
-                }
-            } catch (Exception e) {
-            }
-
-            try {
-                Set<String> paths = prefs.getStringSet("GameList/RecursivePaths", null);
-                if (paths != null) {
-                    for (String path : paths)
-                        entries.add(new Entry(path, true));
-                }
-            } catch (Exception e) {
-            }
-
-            mEntries = new Entry[entries.size()];
-            entries.toArray(mEntries);
-            Arrays.sort(mEntries, new EntryComparator());
-            notifyDataSetChanged();
-        }
-
-        private class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
-            private int mPosition;
-            private Entry mEntry;
-            private TextView mPathView;
-            private TextView mRecursiveView;
-            private ImageButton mToggleRecursiveView;
-            private ImageButton mRemoveView;
-
-            public ViewHolder(View rootView) {
-                super(rootView);
-                mPathView = rootView.findViewById(R.id.path);
-                mRecursiveView = rootView.findViewById(R.id.recursive);
-                mToggleRecursiveView = rootView.findViewById(R.id.toggle_recursive);
-                mToggleRecursiveView.setOnClickListener(this);
-                mRemoveView = rootView.findViewById(R.id.remove);
-                mRemoveView.setOnClickListener(this);
-            }
-
-            public void bindData(int position, Entry entry) {
-                mPosition = position;
-                mEntry = entry;
-                updateText();
-            }
-
-            private void updateText() {
-                mPathView.setText(mEntry.getPath());
-                mRecursiveView.setText(getString(mEntry.isRecursive() ? R.string.game_directories_scanning_subdirectories : R.string.game_directories_not_scanning_subdirectories));
-                mToggleRecursiveView.setImageDrawable(getDrawable(mEntry.isRecursive() ? R.drawable.ic_baseline_folder_24 : R.drawable.ic_baseline_folder_open_24));
-            }
-
-            @Override
-            public void onClick(View v) {
-                if (mToggleRecursiveView == v) {
-                    removeSearchDirectory(mContext, mEntry.getPath(), mEntry.isRecursive());
-                    mEntry.toggleRecursive();
-                    addSearchDirectory(mContext, mEntry.getPath(), mEntry.isRecursive());
-                    updateText();
-                } else if (mRemoveView == v) {
-                    removeSearchDirectory(mContext, mEntry.getPath(), mEntry.isRecursive());
-                    reload();
-                }
-            }
-        }
-
-        @NonNull
-        @Override
-        public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
-            final View view = LayoutInflater.from(parent.getContext()).inflate(viewType, parent, false);
-            return new ViewHolder(view);
-        }
-
-        @Override
-        public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
-            ((ViewHolder) holder).bindData(position, mEntries[position]);
-        }
-
-        @Override
-        public int getItemViewType(int position) {
-            return R.layout.layout_game_directory_entry;
-        }
-
-        @Override
-        public long getItemId(int position) {
-            return mEntries[position].getPath().hashCode();
-        }
-
-        @Override
-        public int getItemCount() {
-            return mEntries.length;
-        }
-    }
-
-    DirectoryListAdapter mDirectoryListAdapter;
-    RecyclerView mRecyclerView;
-
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-
-        setContentView(R.layout.activity_game_directories);
-        Toolbar toolbar = findViewById(R.id.toolbar);
-        setSupportActionBar(toolbar);
-
-        ActionBar actionBar = getSupportActionBar();
-        if (actionBar != null) {
-            actionBar.setDisplayHomeAsUpEnabled(true);
-        }
-
-        mDirectoryListAdapter = new DirectoryListAdapter(this);
-        mRecyclerView = findViewById(R.id.recycler_view);
-        mRecyclerView.setAdapter(mDirectoryListAdapter);
-        mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
-        mRecyclerView.addItemDecoration(new DividerItemDecoration(mRecyclerView.getContext(),
-                DividerItemDecoration.VERTICAL));
-
-        findViewById(R.id.fab).setOnClickListener((v) -> startAddGameDirectory());
-    }
-
-    @Override
-    public boolean onCreateOptionsMenu(Menu menu) {
-        // Inflate the menu; this adds items to the action bar if it is present.
-        getMenuInflater().inflate(R.menu.menu_edit_game_directories, menu);
-
-        menu.findItem(R.id.force_saf)
-                .setEnabled(android.os.Build.VERSION.SDK_INT < 30)
-                .setChecked(PreferenceManager.getDefaultSharedPreferences(this).getBoolean(
-                        FORCE_SAF_CONFIG_KEY, false))
-                .setOnMenuItemClickListener(item -> {
-                    final SharedPreferences sharedPreferences =
-                            PreferenceManager.getDefaultSharedPreferences(this);
-                    final boolean newValue =!sharedPreferences.getBoolean(
-                            FORCE_SAF_CONFIG_KEY, false);
-                    sharedPreferences.edit()
-                            .putBoolean(FORCE_SAF_CONFIG_KEY, newValue)
-                            .commit();
-                    item.setChecked(newValue);
-                    return true;
-                });
-
-        return true;
-    }
-
-    @Override
-    public boolean onOptionsItemSelected(@NonNull MenuItem item) {
-        if (item.getItemId() == android.R.id.home) {
-            onBackPressed();
-            return true;
-        }
-
-        if (item.getItemId() == R.id.add_directory) {
-            startAddGameDirectory();
-            return true;
-        } else if (item.getItemId() == R.id.add_path) {
-            startAddPath();
-            return true;
-        }
-
-        return super.onOptionsItemSelected(item);
-    }
-
-    public static boolean useStorageAccessFramework(Context context) {
-        // Use legacy storage on devices older than Android 11... apparently some of them
-        // have broken storage access framework....
-        if (android.os.Build.VERSION.SDK_INT >= 30)
-            return true;
-
-        return PreferenceManager.getDefaultSharedPreferences(context).getBoolean(
-                "GameList/ForceStorageAccessFramework", false);
-    }
-
-    public static void addSearchDirectory(Context context, String path, boolean recursive) {
-        final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
-        final String key = recursive ? "GameList/RecursivePaths" : "GameList/Paths";
-        PreferenceHelpers.addToStringList(prefs, key, path);
-        Log.i("GameDirectoriesActivity", "Added path '" + path + "' to game list search directories");
-    }
-
-    public static void removeSearchDirectory(Context context, String path, boolean recursive) {
-        final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
-        final String key = recursive ? "GameList/RecursivePaths" : "GameList/Paths";
-        PreferenceHelpers.removeFromStringList(prefs, key, path);
-        Log.i("GameDirectoriesActivity", "Removed path '" + path + "' from game list search directories");
-    }
-
-    private void startAddGameDirectory() {
-        Intent i = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
-        i.addCategory(Intent.CATEGORY_DEFAULT);
-        i.putExtra(Intent.EXTRA_LOCAL_ONLY, true);
-        i.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
-        i.addFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION);
-        startActivityForResult(Intent.createChooser(i, getString(R.string.main_activity_choose_directory)),
-                REQUEST_ADD_DIRECTORY_TO_GAME_LIST);
-    }
-
-    private void startAddPath() {
-        final EditText text = new EditText(this);
-        text.setSingleLine();
-
-        new AlertDialog.Builder(this)
-                .setTitle(R.string.edit_game_directories_add_path)
-                .setMessage(R.string.edit_game_directories_add_path_summary)
-                .setView(text)
-                .setPositiveButton("Add", (dialog, which) -> {
-                    final String path = text.getText().toString();
-                    if (!path.isEmpty()) {
-                        addSearchDirectory(GameDirectoriesActivity.this, path, true);
-                        mDirectoryListAdapter.reload();
-                    }
-                })
-                .setNegativeButton("Cancel", (dialog, which) -> dialog.dismiss())
-                .show();
-    }
-
-    @Override
-    public void onActivityResult(int requestCode, int resultCode, Intent data) {
-        super.onActivityResult(requestCode, resultCode, data);
-
-        switch (requestCode) {
-            case REQUEST_ADD_DIRECTORY_TO_GAME_LIST: {
-                if (resultCode != RESULT_OK || data.getData() == null)
-                    return;
-
-                // Use legacy storage on devices older than Android 11... apparently some of them
-                // have broken storage access framework....
-                if (!useStorageAccessFramework(this)) {
-                    final String path = FileHelper.getFullPathFromTreeUri(data.getData(), this);
-                    if (path != null) {
-                        addSearchDirectory(this, path, true);
-                        mDirectoryListAdapter.reload();
-                        return;
-                    }
-                }
-
-                try {
-                    getContentResolver().takePersistableUriPermission(data.getData(),
-                            Intent.FLAG_GRANT_READ_URI_PERMISSION);
-                } catch (Exception e) {
-                    Toast.makeText(this, "Failed to take persistable permission.", Toast.LENGTH_LONG);
-                    e.printStackTrace();
-                }
-
-                addSearchDirectory(this, data.getDataString(), true);
-                mDirectoryListAdapter.reload();
-            }
-            break;
-        }
-    }
-}
\ No newline at end of file
diff --git a/android/app/src/main/java/com/github/stenzek/duckstation/GameGridFragment.java b/android/app/src/main/java/com/github/stenzek/duckstation/GameGridFragment.java
deleted file mode 100644
index d72b80501..000000000
--- a/android/app/src/main/java/com/github/stenzek/duckstation/GameGridFragment.java
+++ /dev/null
@@ -1,139 +0,0 @@
-package com.github.stenzek.duckstation;
-
-import android.os.AsyncTask;
-import android.os.Bundle;
-import android.util.TypedValue;
-import android.view.Gravity;
-import android.view.LayoutInflater;
-import android.view.MenuItem;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.ImageView;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.appcompat.widget.PopupMenu;
-import androidx.core.content.ContextCompat;
-import androidx.fragment.app.Fragment;
-import androidx.recyclerview.widget.RecyclerView;
-
-public class GameGridFragment extends Fragment implements GameList.OnRefreshListener {
-    private static final int SPACING_DIPS = 25;
-    private static final int WIDTH_DIPS = 160;
-
-    private final MainActivity mParent;
-    private RecyclerView mRecyclerView;
-    private ViewAdapter mAdapter;
-    private GridAutofitLayoutManager mLayoutManager;
-
-    public GameGridFragment(MainActivity parent) {
-        super(R.layout.fragment_game_grid);
-        this.mParent = parent;
-    }
-
-    private GameList getGameList() {
-        return mParent.getGameList();
-    }
-
-    @Override
-    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
-        super.onViewCreated(view, savedInstanceState);
-
-        mAdapter = new ViewAdapter(mParent, getGameList());
-        getGameList().addRefreshListener(this);
-
-        mRecyclerView = view.findViewById(R.id.game_list_view);
-        mRecyclerView.setAdapter(mAdapter);
-
-        final int columnWidth = Math.round(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
-                WIDTH_DIPS + SPACING_DIPS, getResources().getDisplayMetrics()));
-        mLayoutManager = new GridAutofitLayoutManager(getContext(), columnWidth);
-        mRecyclerView.setLayoutManager(mLayoutManager);
-    }
-
-    @Override
-    public void onDestroyView() {
-        super.onDestroyView();
-
-        getGameList().removeRefreshListener(this);
-    }
-
-    @Override
-    public void onGameListRefresh() {
-        mAdapter.notifyDataSetChanged();
-    }
-
-    private static class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener, View.OnLongClickListener {
-        private final MainActivity mParent;
-        private final ImageView mImageView;
-        private GameListEntry mEntry;
-
-        public ViewHolder(@NonNull MainActivity parent, @NonNull View itemView) {
-            super(itemView);
-            mParent = parent;
-            mImageView = itemView.findViewById(R.id.imageView);
-            mImageView.setOnClickListener(this);
-            mImageView.setOnLongClickListener(this);
-        }
-
-        public void bindToEntry(GameListEntry entry) {
-            mEntry = entry;
-
-            // while it loads/generates
-            mImageView.setImageDrawable(ContextCompat.getDrawable(mParent, R.drawable.ic_media_cdrom));
-
-            final String coverPath = entry.getCoverPath();
-            if (coverPath == null) {
-                new GenerateCoverTask(mParent, mImageView, mEntry.getTitle()).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
-                return;
-            }
-
-            new ImageLoadTask(mImageView).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, coverPath);
-        }
-
-        @Override
-        public void onClick(View v) {
-            mParent.startEmulation(mEntry.getPath(), mParent.shouldResumeStateByDefault());
-        }
-
-        @Override
-        public boolean onLongClick(View v) {
-            mParent.openGamePopupMenu(v, mEntry);
-            return true;
-        }
-    }
-
-    private static class ViewAdapter extends RecyclerView.Adapter<ViewHolder> {
-        private final MainActivity mParent;
-        private final LayoutInflater mInflater;
-        private final GameList mGameList;
-
-        public ViewAdapter(@NonNull MainActivity parent, @NonNull GameList gameList) {
-            mParent = parent;
-            mInflater = LayoutInflater.from(parent);
-            mGameList = gameList;
-        }
-
-        @NonNull
-        @Override
-        public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
-            return new ViewHolder(mParent, mInflater.inflate(R.layout.layout_game_grid_entry, parent, false));
-        }
-
-        @Override
-        public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
-            GameListEntry entry = mGameList.getEntry(position);
-            holder.bindToEntry(entry);
-        }
-
-        @Override
-        public int getItemCount() {
-            return mGameList.getEntryCount();
-        }
-
-        @Override
-        public int getItemViewType(int position) {
-            return R.layout.layout_game_grid_entry;
-        }
-    }
-}
diff --git a/android/app/src/main/java/com/github/stenzek/duckstation/GameList.java b/android/app/src/main/java/com/github/stenzek/duckstation/GameList.java
deleted file mode 100644
index f835dce22..000000000
--- a/android/app/src/main/java/com/github/stenzek/duckstation/GameList.java
+++ /dev/null
@@ -1,84 +0,0 @@
-package com.github.stenzek.duckstation;
-
-import android.app.Activity;
-import android.os.AsyncTask;
-import android.util.Log;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.BaseAdapter;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Comparator;
-
-public class GameList {
-    public interface OnRefreshListener {
-        void onGameListRefresh();
-    }
-
-    private Activity mContext;
-    private GameListEntry[] mEntries;
-    private ArrayList<OnRefreshListener> mRefreshListeners = new ArrayList<>();
-
-    public GameList(Activity context) {
-        mContext = context;
-        mEntries = new GameListEntry[0];
-    }
-
-    public void addRefreshListener(OnRefreshListener listener) {
-        mRefreshListeners.add(listener);
-    }
-    public void removeRefreshListener(OnRefreshListener listener) {
-        mRefreshListeners.remove(listener);
-    }
-    public void fireRefreshListeners() {
-        for (OnRefreshListener listener : mRefreshListeners)
-            listener.onGameListRefresh();
-    }
-
-    private class GameListEntryComparator implements Comparator<GameListEntry> {
-        @Override
-        public int compare(GameListEntry left, GameListEntry right) {
-            return left.getTitle().compareTo(right.getTitle());
-        }
-    }
-
-    public void refresh(boolean invalidateCache, boolean invalidateDatabase, Activity parentActivity) {
-        // Search and get entries from native code
-        AndroidProgressCallback progressCallback = new AndroidProgressCallback(mContext);
-        AsyncTask.execute(() -> {
-            AndroidHostInterface.getInstance().refreshGameList(invalidateCache, invalidateDatabase, progressCallback);
-            GameListEntry[] newEntries = AndroidHostInterface.getInstance().getGameListEntries();
-            Arrays.sort(newEntries, new GameListEntryComparator());
-
-            mContext.runOnUiThread(() -> {
-                try {
-                    progressCallback.dismiss();
-                } catch (Exception e) {
-                    Log.e("GameList", "Exception dismissing refresh progress");
-                    e.printStackTrace();
-                }
-                mEntries = newEntries;
-                fireRefreshListeners();
-            });
-        });
-    }
-
-    public int getEntryCount() {
-        return mEntries.length;
-    }
-
-    public GameListEntry getEntry(int index) {
-        return mEntries[index];
-    }
-
-    public GameListEntry getEntryForPath(String path) {
-        for (final GameListEntry entry : mEntries) {
-            if (entry.getPath().equals(path))
-                return entry;
-        }
-
-        return null;
-    }
-}
diff --git a/android/app/src/main/java/com/github/stenzek/duckstation/GameListEntry.java b/android/app/src/main/java/com/github/stenzek/duckstation/GameListEntry.java
deleted file mode 100644
index 95e5674b5..000000000
--- a/android/app/src/main/java/com/github/stenzek/duckstation/GameListEntry.java
+++ /dev/null
@@ -1,99 +0,0 @@
-package com.github.stenzek.duckstation;
-
-import android.os.AsyncTask;
-import android.view.View;
-import android.widget.ImageView;
-import android.widget.TextView;
-
-import androidx.core.content.ContextCompat;
-
-public class GameListEntry {
-    public enum EntryType {
-        Disc,
-        PSExe,
-        Playlist,
-        PSF
-    }
-
-    public enum CompatibilityRating {
-        Unknown,
-        DoesntBoot,
-        CrashesInIntro,
-        CrashesInGame,
-        GraphicalAudioIssues,
-        NoIssues,
-    }
-
-    private String mPath;
-    private String mCode;
-    private String mTitle;
-    private long mSize;
-    private String mModifiedTime;
-    private DiscRegion mRegion;
-    private EntryType mType;
-    private CompatibilityRating mCompatibilityRating;
-    private String mCoverPath;
-
-    public GameListEntry(String path, String code, String title, long size, String modifiedTime, String region,
-                         String type, String compatibilityRating, String coverPath) {
-        mPath = path;
-        mCode = code;
-        mTitle = title;
-        mSize = size;
-        mModifiedTime = modifiedTime;
-        mCoverPath = coverPath;
-
-        try {
-            mRegion = DiscRegion.valueOf(region);
-        } catch (IllegalArgumentException e) {
-            mRegion = DiscRegion.NTSC_U;
-        }
-
-        try {
-            mType = EntryType.valueOf(type);
-        } catch (IllegalArgumentException e) {
-            mType = EntryType.Disc;
-        }
-
-        try {
-            mCompatibilityRating = CompatibilityRating.valueOf(compatibilityRating);
-        } catch (IllegalArgumentException e) {
-            mCompatibilityRating = CompatibilityRating.Unknown;
-        }
-    }
-
-    public String getPath() {
-        return mPath;
-    }
-
-    public String getCode() {
-        return mCode;
-    }
-
-    public String getTitle() {
-        return mTitle;
-    }
-
-    public long getSize() { return mSize; }
-
-    public String getModifiedTime() {
-        return mModifiedTime;
-    }
-
-    public DiscRegion getRegion() {
-        return mRegion;
-    }
-
-    public EntryType getType() {
-        return mType;
-    }
-
-    public CompatibilityRating getCompatibilityRating() {
-        return mCompatibilityRating;
-    }
-
-    public String getCoverPath() { return mCoverPath; }
-
-    public void setCoverPath(String coverPath) { mCoverPath = coverPath; }
-
-}
diff --git a/android/app/src/main/java/com/github/stenzek/duckstation/GameListFragment.java b/android/app/src/main/java/com/github/stenzek/duckstation/GameListFragment.java
deleted file mode 100644
index 01635d7b5..000000000
--- a/android/app/src/main/java/com/github/stenzek/duckstation/GameListFragment.java
+++ /dev/null
@@ -1,204 +0,0 @@
-package com.github.stenzek.duckstation;
-
-import android.os.AsyncTask;
-import android.os.Bundle;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.ImageView;
-import android.widget.TextView;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.core.content.ContextCompat;
-import androidx.fragment.app.Fragment;
-import androidx.recyclerview.widget.DividerItemDecoration;
-import androidx.recyclerview.widget.LinearLayoutManager;
-import androidx.recyclerview.widget.RecyclerView;
-
-public class GameListFragment extends Fragment implements GameList.OnRefreshListener {
-    private MainActivity mParent;
-    private RecyclerView mRecyclerView;
-    private GameListFragment.ViewAdapter mAdapter;
-
-    public GameListFragment(MainActivity parent) {
-        super(R.layout.fragment_game_list);
-        this.mParent = parent;
-    }
-
-    private GameList getGameList() {
-        return mParent.getGameList();
-    }
-
-    @Override
-    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
-        super.onViewCreated(view, savedInstanceState);
-
-        mAdapter = new GameListFragment.ViewAdapter(mParent, getGameList());
-        getGameList().addRefreshListener(this);
-
-        mRecyclerView = view.findViewById(R.id.game_list_view);
-        mRecyclerView.setAdapter(mAdapter);
-        mRecyclerView.setLayoutManager(new LinearLayoutManager(mParent));
-        mRecyclerView.addItemDecoration(new DividerItemDecoration(mRecyclerView.getContext(),
-                DividerItemDecoration.VERTICAL));
-    }
-
-    @Override
-    public void onDestroyView() {
-        super.onDestroyView();
-
-        getGameList().removeRefreshListener(this);
-    }
-
-    @Override
-    public void onGameListRefresh() {
-        mAdapter.notifyDataSetChanged();
-    }
-
-    private static class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener, View.OnLongClickListener {
-        private MainActivity mParent;
-        private View mItemView;
-        private GameListEntry mEntry;
-
-        public ViewHolder(@NonNull MainActivity parent, @NonNull View itemView) {
-            super(itemView);
-            mParent = parent;
-            mItemView = itemView;
-            mItemView.setOnClickListener(this);
-            mItemView.setOnLongClickListener(this);
-        }
-
-        private String getSubTitle() {
-            String fileName = FileHelper.getFileNameForPath(mEntry.getPath());
-            String sizeString = String.format("%.2f MB", (double) mEntry.getSize() / 1048576.0);
-            return String.format("%s (%s)", fileName, sizeString);
-        }
-
-        public void bindToEntry(GameListEntry entry) {
-            mEntry = entry;
-
-            ((TextView) mItemView.findViewById(R.id.game_list_view_entry_title)).setText(entry.getTitle());
-            ((TextView) mItemView.findViewById(R.id.game_list_view_entry_subtitle)).setText(getSubTitle());
-
-            int regionDrawableId;
-            switch (entry.getRegion()) {
-                case NTSC_J:
-                    regionDrawableId = R.drawable.flag_jp;
-                    break;
-                case PAL:
-                    regionDrawableId = R.drawable.flag_eu;
-                    break;
-                case Other:
-                    regionDrawableId = R.drawable.ic_baseline_help_24;
-                    break;
-                case NTSC_U:
-                default:
-                    regionDrawableId = R.drawable.flag_us;
-                    break;
-            }
-
-            ((ImageView) mItemView.findViewById(R.id.game_list_view_entry_region_icon))
-                    .setImageDrawable(ContextCompat.getDrawable(mItemView.getContext(), regionDrawableId));
-
-            int typeDrawableId;
-            switch (entry.getType()) {
-                case PSExe:
-                    typeDrawableId = R.drawable.ic_emblem_system;
-                    break;
-
-                case Playlist:
-                    typeDrawableId = R.drawable.ic_baseline_playlist_play_24;
-                    break;
-
-                case PSF:
-                    typeDrawableId = R.drawable.ic_baseline_library_music_24;
-                    break;
-
-                case Disc:
-                default:
-                    typeDrawableId = R.drawable.ic_media_cdrom;
-                    break;
-            }
-
-            ImageView icon = ((ImageView) mItemView.findViewById(R.id.game_list_view_entry_type_icon));
-            icon.setImageDrawable(ContextCompat.getDrawable(mItemView.getContext(), typeDrawableId));
-
-            final String coverPath = entry.getCoverPath();
-            if (coverPath != null) {
-                new ImageLoadTask(icon).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, coverPath);
-            }
-
-            int compatibilityDrawableId;
-            switch (entry.getCompatibilityRating()) {
-                case DoesntBoot:
-                    compatibilityDrawableId = R.drawable.ic_star_1;
-                    break;
-                case CrashesInIntro:
-                    compatibilityDrawableId = R.drawable.ic_star_2;
-                    break;
-                case CrashesInGame:
-                    compatibilityDrawableId = R.drawable.ic_star_3;
-                    break;
-                case GraphicalAudioIssues:
-                    compatibilityDrawableId = R.drawable.ic_star_4;
-                    break;
-                case NoIssues:
-                    compatibilityDrawableId = R.drawable.ic_star_5;
-                    break;
-                case Unknown:
-                default:
-                    compatibilityDrawableId = R.drawable.ic_star_0;
-                    break;
-            }
-
-            ((ImageView) mItemView.findViewById(R.id.game_list_view_compatibility_icon))
-                    .setImageDrawable(ContextCompat.getDrawable(mItemView.getContext(), compatibilityDrawableId));
-        }
-
-        @Override
-        public void onClick(View v) {
-            mParent.startEmulation(mEntry.getPath(), mParent.shouldResumeStateByDefault());
-        }
-
-        @Override
-        public boolean onLongClick(View v) {
-            mParent.openGamePopupMenu(v, mEntry);
-            return true;
-        }
-    }
-
-    private static class ViewAdapter extends RecyclerView.Adapter<GameListFragment.ViewHolder> {
-        private MainActivity mParent;
-        private LayoutInflater mInflater;
-        private GameList mGameList;
-
-        public ViewAdapter(@NonNull MainActivity parent, @NonNull GameList gameList) {
-            mParent = parent;
-            mInflater = LayoutInflater.from(parent);
-            mGameList = gameList;
-        }
-
-        @NonNull
-        @Override
-        public GameListFragment.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
-            return new GameListFragment.ViewHolder(mParent, mInflater.inflate(R.layout.layout_game_list_entry, parent, false));
-        }
-
-        @Override
-        public void onBindViewHolder(@NonNull GameListFragment.ViewHolder holder, int position) {
-            GameListEntry entry = mGameList.getEntry(position);
-            holder.bindToEntry(entry);
-        }
-
-        @Override
-        public int getItemCount() {
-            return mGameList.getEntryCount();
-        }
-
-        @Override
-        public int getItemViewType(int position) {
-            return R.layout.layout_game_list_entry;
-        }
-    }
-}
diff --git a/android/app/src/main/java/com/github/stenzek/duckstation/GamePropertiesActivity.java b/android/app/src/main/java/com/github/stenzek/duckstation/GamePropertiesActivity.java
deleted file mode 100644
index 2ca556229..000000000
--- a/android/app/src/main/java/com/github/stenzek/duckstation/GamePropertiesActivity.java
+++ /dev/null
@@ -1,253 +0,0 @@
-package com.github.stenzek.duckstation;
-
-import android.os.Bundle;
-import android.view.LayoutInflater;
-import android.view.MenuItem;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.ListAdapter;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.appcompat.app.ActionBar;
-import androidx.appcompat.app.AlertDialog;
-import androidx.appcompat.app.AppCompatActivity;
-import androidx.fragment.app.Fragment;
-import androidx.fragment.app.ListFragment;
-import androidx.preference.PreferenceFragmentCompat;
-import androidx.preference.PreferenceScreen;
-import androidx.viewpager2.adapter.FragmentStateAdapter;
-import androidx.viewpager2.widget.ViewPager2;
-
-import com.google.android.material.tabs.TabLayout;
-import com.google.android.material.tabs.TabLayoutMediator;
-
-public class GamePropertiesActivity extends AppCompatActivity {
-    PropertyListAdapter mPropertiesListAdapter;
-    GameListEntry mGameListEntry;
-
-    public ListAdapter getPropertyListAdapter() {
-        if (mPropertiesListAdapter != null)
-            return mPropertiesListAdapter;
-
-        mPropertiesListAdapter = new PropertyListAdapter(this);
-        mPropertiesListAdapter.addItem("title", "Title", mGameListEntry.getTitle());
-        mPropertiesListAdapter.addItem("serial", "Serial", mGameListEntry.getCode());
-        mPropertiesListAdapter.addItem("type", "Type", mGameListEntry.getType().toString());
-        mPropertiesListAdapter.addItem("path", "Path", mGameListEntry.getPath());
-        mPropertiesListAdapter.addItem("region", "Region", mGameListEntry.getRegion().toString());
-        mPropertiesListAdapter.addItem("compatibility", "Compatibility Rating", mGameListEntry.getCompatibilityRating().toString());
-        return mPropertiesListAdapter;
-    }
-
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(null);
-
-        String path = getIntent().getStringExtra("path");
-        if (path == null || path.isEmpty()) {
-            finish();
-            return;
-        }
-
-        mGameListEntry = AndroidHostInterface.getInstance().getGameListEntry(path);
-        if (mGameListEntry == null) {
-            finish();
-            return;
-        }
-
-        setContentView(R.layout.settings_activity);
-        getSupportFragmentManager()
-                .beginTransaction()
-                .replace(R.id.settings, new SettingsCollectionFragment(this))
-                .commit();
-        ActionBar actionBar = getSupportActionBar();
-        if (actionBar != null) {
-            actionBar.setDisplayHomeAsUpEnabled(true);
-        }
-
-        setTitle(mGameListEntry.getTitle());
-    }
-
-    @Override
-    public boolean onOptionsItemSelected(@NonNull MenuItem item) {
-        if (item.getItemId() == android.R.id.home) {
-            onBackPressed();
-            return true;
-        }
-
-        return super.onOptionsItemSelected(item);
-    }
-
-    private void displayError(String text) {
-        new AlertDialog.Builder(this)
-                .setTitle(R.string.emulation_activity_error)
-                .setMessage(text)
-                .setNegativeButton(R.string.main_activity_ok, ((dialog, which) -> dialog.dismiss()))
-                .create()
-                .show();
-    }
-
-    private void createBooleanGameSetting(PreferenceScreen ps, String key, int titleId) {
-        GameSettingPreference pref = new GameSettingPreference(ps.getContext(), mGameListEntry.getPath(), key, titleId);
-        ps.addPreference(pref);
-    }
-
-    private void createTraitGameSetting(PreferenceScreen ps, String key, int titleId) {
-        GameTraitPreference pref = new GameTraitPreference(ps.getContext(), mGameListEntry.getPath(), key, titleId);
-        ps.addPreference(pref);
-    }
-
-    private void createListGameSetting(PreferenceScreen ps, String key, int titleId, int entryId, int entryValuesId) {
-        GameSettingPreference pref = new GameSettingPreference(ps.getContext(), mGameListEntry.getPath(), key, titleId, entryId, entryValuesId);
-        ps.addPreference(pref);
-    }
-
-    public static class GameSettingsFragment extends PreferenceFragmentCompat {
-        private GamePropertiesActivity activity;
-
-        public GameSettingsFragment(GamePropertiesActivity activity) {
-            this.activity = activity;
-        }
-
-        @Override
-        public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
-            final PreferenceScreen ps = getPreferenceManager().createPreferenceScreen(getContext());
-            activity.createListGameSetting(ps, "CPUOverclock", R.string.settings_cpu_overclocking, R.array.settings_advanced_cpu_overclock_entries, R.array.settings_advanced_cpu_overclock_values);
-            activity.createListGameSetting(ps, "CDROMReadSpeedup", R.string.settings_cdrom_read_speedup, R.array.settings_cdrom_read_speedup_entries, R.array.settings_cdrom_read_speedup_values);
-            activity.createListGameSetting(ps, "CDROMSeekSpeedup", R.string.settings_cdrom_seek_speedup, R.array.settings_cdrom_seek_speedup_entries, R.array.settings_cdrom_seek_speedup_values);
-
-            activity.createListGameSetting(ps, "GPURenderer", R.string.settings_gpu_renderer, R.array.gpu_renderer_entries, R.array.gpu_renderer_values);
-            activity.createListGameSetting(ps, "DisplayAspectRatio", R.string.settings_aspect_ratio, R.array.settings_display_aspect_ratio_names, R.array.settings_display_aspect_ratio_values);
-            activity.createListGameSetting(ps, "DisplayCropMode", R.string.settings_crop_mode, R.array.settings_display_crop_mode_entries, R.array.settings_display_crop_mode_values);
-            activity.createListGameSetting(ps, "GPUDownsampleMode", R.string.settings_downsample_mode, R.array.settings_downsample_mode_entries, R.array.settings_downsample_mode_values);
-            activity.createBooleanGameSetting(ps, "DisplayLinearUpscaling", R.string.settings_linear_upscaling);
-            activity.createBooleanGameSetting(ps, "DisplayIntegerUpscaling", R.string.settings_integer_upscaling);
-            activity.createBooleanGameSetting(ps, "DisplayForce4_3For24Bit", R.string.settings_force_4_3_for_24bit);
-
-            activity.createListGameSetting(ps, "GPUResolutionScale", R.string.settings_gpu_resolution_scale, R.array.settings_gpu_resolution_scale_entries, R.array.settings_gpu_resolution_scale_values);
-            activity.createListGameSetting(ps, "GPUMSAA", R.string.settings_msaa, R.array.settings_gpu_msaa_entries, R.array.settings_gpu_msaa_values);
-            activity.createBooleanGameSetting(ps, "GPUTrueColor", R.string.settings_true_color);
-            activity.createBooleanGameSetting(ps, "GPUScaledDithering", R.string.settings_scaled_dithering);
-            activity.createListGameSetting(ps, "GPUTextureFilter", R.string.settings_texture_filtering, R.array.settings_gpu_texture_filter_names, R.array.settings_gpu_texture_filter_values);
-            activity.createBooleanGameSetting(ps, "GPUForceNTSCTimings", R.string.settings_force_ntsc_timings);
-            activity.createBooleanGameSetting(ps, "GPUWidescreenHack", R.string.settings_widescreen_hack);
-            activity.createBooleanGameSetting(ps, "GPUPGXP", R.string.settings_pgxp_geometry_correction);
-            activity.createBooleanGameSetting(ps, "PGXPPreserveProjFP", R.string.settings_pgxp_preserve_projection_precision);
-            activity.createBooleanGameSetting(ps, "GPUPGXPDepthBuffer", R.string.settings_pgxp_depth_buffer);
-            activity.createTraitGameSetting(ps, "ForceSoftwareRenderer", R.string.settings_use_software_renderer);
-            activity.createTraitGameSetting(ps, "ForceSoftwareRendererForReadbacks", R.string.settings_use_software_renderer_for_readbacks);
-            activity.createTraitGameSetting(ps, "DisableWidescreen", R.string.settings_disable_widescreen);
-            activity.createTraitGameSetting(ps, "ForcePGXPVertexCache", R.string.settings_pgxp_vertex_cache);
-            activity.createTraitGameSetting(ps, "ForcePGXPCPUMode", R.string.settings_pgxp_cpu_mode);
-
-            setPreferenceScreen(ps);
-        }
-    }
-
-    public static class ControllerSettingsFragment extends PreferenceFragmentCompat {
-        private GamePropertiesActivity activity;
-
-        public ControllerSettingsFragment(GamePropertiesActivity activity) {
-            this.activity = activity;
-        }
-
-        private void createInputProfileSetting(PreferenceScreen ps) {
-            final GameSettingPreference pref = new GameSettingPreference(ps.getContext(), activity.mGameListEntry.getPath(), "InputProfileName", R.string.settings_input_profile);
-
-            final String[] inputProfileNames = AndroidHostInterface.getInstance().getInputProfileNames();
-            pref.setEntries(inputProfileNames);
-            pref.setEntryValues(inputProfileNames);
-            ps.addPreference(pref);
-        }
-
-        @Override
-        public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
-            final PreferenceScreen ps = getPreferenceManager().createPreferenceScreen(getContext());
-
-            activity.createListGameSetting(ps, "Controller1Type", R.string.settings_controller_type, R.array.settings_controller_type_entries, R.array.settings_controller_type_values);
-            activity.createListGameSetting(ps, "MemoryCard1Type", R.string.settings_memory_card_1_type, R.array.settings_memory_card_mode_entries, R.array.settings_memory_card_mode_values);
-            activity.createListGameSetting(ps, "MemoryCard2Type", R.string.settings_memory_card_2_type, R.array.settings_memory_card_mode_entries, R.array.settings_memory_card_mode_values);
-            createInputProfileSetting(ps);
-
-            setPreferenceScreen(ps);
-        }
-    }
-
-    public static class SettingsCollectionFragment extends Fragment {
-        private GamePropertiesActivity activity;
-        private SettingsCollectionAdapter adapter;
-        private ViewPager2 viewPager;
-
-        public SettingsCollectionFragment(GamePropertiesActivity activity) {
-            this.activity = activity;
-        }
-
-        @Nullable
-        @Override
-        public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
-            return inflater.inflate(R.layout.fragment_controller_settings, container, false);
-        }
-
-        @Override
-        public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
-            adapter = new SettingsCollectionAdapter(activity, this);
-            viewPager = view.findViewById(R.id.view_pager);
-            viewPager.setAdapter(adapter);
-
-            TabLayout tabLayout = view.findViewById(R.id.tab_layout);
-            new TabLayoutMediator(tabLayout, viewPager, (tab, position) -> {
-                switch (position) {
-                    case 0:
-                        tab.setText(R.string.game_properties_tab_summary);
-                        break;
-                    case 1:
-                        tab.setText(R.string.game_properties_tab_game_settings);
-                        break;
-                    case 2:
-                        tab.setText(R.string.game_properties_tab_controller_settings);
-                        break;
-                }
-            }).attach();
-        }
-    }
-
-    public static class SettingsCollectionAdapter extends FragmentStateAdapter {
-        private GamePropertiesActivity activity;
-
-        public SettingsCollectionAdapter(@NonNull GamePropertiesActivity activity, @NonNull Fragment fragment) {
-            super(fragment);
-            this.activity = activity;
-        }
-
-        @NonNull
-        @Override
-        public Fragment createFragment(int position) {
-            switch (position) {
-                case 0: {           // Summary
-                    ListFragment lf = new ListFragment();
-                    lf.setListAdapter(activity.getPropertyListAdapter());
-                    return lf;
-                }
-
-                case 1: {           // Game Settings
-                    return new GameSettingsFragment(activity);
-                }
-
-                case 2: {           // Controller Settings
-                    return new ControllerSettingsFragment(activity);
-                }
-
-                // TODO: Memory Card Editor
-
-                default:
-                    return null;
-            }
-        }
-
-        @Override
-        public int getItemCount() {
-            return 3;
-        }
-    }
-}
\ No newline at end of file
diff --git a/android/app/src/main/java/com/github/stenzek/duckstation/GameSettingPreference.java b/android/app/src/main/java/com/github/stenzek/duckstation/GameSettingPreference.java
deleted file mode 100644
index d86e8af41..000000000
--- a/android/app/src/main/java/com/github/stenzek/duckstation/GameSettingPreference.java
+++ /dev/null
@@ -1,83 +0,0 @@
-package com.github.stenzek.duckstation;
-
-import android.content.Context;
-import android.util.AttributeSet;
-
-import androidx.preference.ListPreference;
-
-public class GameSettingPreference extends ListPreference {
-    private String mGamePath;
-
-    /**
-     * Creates a boolean game property preference.
-     */
-    public GameSettingPreference(Context context, String gamePath, String settingKey, int titleId) {
-        super(context);
-        mGamePath = gamePath;
-        setPersistent(false);
-        setTitle(titleId);
-        setKey(settingKey);
-        setIconSpaceReserved(false);
-        setSummaryProvider(SimpleSummaryProvider.getInstance());
-
-        setEntries(R.array.settings_boolean_entries);
-        setEntryValues(R.array.settings_boolean_values);
-
-        updateValue();
-    }
-
-    /**
-     * Creates a list game property preference.
-     */
-    public GameSettingPreference(Context context, String gamePath, String settingKey, int titleId, int entryArray, int entryValuesArray) {
-        super(context);
-        mGamePath = gamePath;
-        setPersistent(false);
-        setTitle(titleId);
-        setKey(settingKey);
-        setIconSpaceReserved(false);
-        setSummaryProvider(SimpleSummaryProvider.getInstance());
-
-        setEntries(entryArray);
-        setEntryValues(entryValuesArray);
-
-        updateValue();
-    }
-
-    private void updateValue() {
-        final String value = AndroidHostInterface.getInstance().getGameSettingValue(mGamePath, getKey());
-        if (value == null)
-            super.setValue("null");
-        else
-            super.setValue(value);
-    }
-
-    @Override
-    public void setValue(String value) {
-        super.setValue(value);
-        if (value.equals("null"))
-            AndroidHostInterface.getInstance().setGameSettingValue(mGamePath, getKey(), null);
-        else
-            AndroidHostInterface.getInstance().setGameSettingValue(mGamePath, getKey(), value);
-    }
-
-    @Override
-    public void setEntries(CharSequence[] entries) {
-        final int length = (entries != null) ? entries.length : 0;
-        CharSequence[] newEntries = new CharSequence[length + 1];
-        newEntries[0] = getContext().getString(R.string.game_properties_preference_use_global_setting);
-        if (entries != null)
-            System.arraycopy(entries, 0, newEntries, 1, entries.length);
-        super.setEntries(newEntries);
-    }
-
-    @Override
-    public void setEntryValues(CharSequence[] entryValues) {
-        final int length = (entryValues != null) ? entryValues.length : 0;
-        CharSequence[] newEntryValues = new CharSequence[length + 1];
-        newEntryValues[0] = "null";
-        if (entryValues != null)
-            System.arraycopy(entryValues, 0, newEntryValues, 1, length);
-        super.setEntryValues(newEntryValues);
-    }
-}
diff --git a/android/app/src/main/java/com/github/stenzek/duckstation/GameTraitPreference.java b/android/app/src/main/java/com/github/stenzek/duckstation/GameTraitPreference.java
deleted file mode 100644
index a3eb13aab..000000000
--- a/android/app/src/main/java/com/github/stenzek/duckstation/GameTraitPreference.java
+++ /dev/null
@@ -1,34 +0,0 @@
-package com.github.stenzek.duckstation;
-
-import android.content.Context;
-
-import androidx.preference.ListPreference;
-import androidx.preference.SwitchPreference;
-
-public class GameTraitPreference extends SwitchPreference {
-    private String mGamePath;
-
-    /**
-     * Creates a boolean game property preference.
-     */
-    public GameTraitPreference(Context context, String gamePath, String settingKey, int titleId) {
-        super(context);
-        mGamePath = gamePath;
-        setPersistent(false);
-        setTitle(titleId);
-        setKey(settingKey);
-        setIconSpaceReserved(false);
-        updateValue();
-    }
-
-    private void updateValue() {
-        final String value = AndroidHostInterface.getInstance().getGameSettingValue(mGamePath, getKey());
-        super.setChecked(value != null && value.equals("true"));
-    }
-
-    @Override
-    public void setChecked(boolean checked) {
-        super.setChecked(checked);
-        AndroidHostInterface.getInstance().setGameSettingValue(mGamePath, getKey(), checked ? "true" : "false");
-    }
-}
diff --git a/android/app/src/main/java/com/github/stenzek/duckstation/GenerateCoverTask.java b/android/app/src/main/java/com/github/stenzek/duckstation/GenerateCoverTask.java
deleted file mode 100644
index f503d4e15..000000000
--- a/android/app/src/main/java/com/github/stenzek/duckstation/GenerateCoverTask.java
+++ /dev/null
@@ -1,64 +0,0 @@
-package com.github.stenzek.duckstation;
-
-import android.content.Context;
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.Paint;
-import android.os.AsyncTask;
-import android.text.Layout;
-import android.text.StaticLayout;
-import android.text.TextPaint;
-import android.widget.ImageView;
-
-import java.lang.ref.WeakReference;
-
-public class GenerateCoverTask extends AsyncTask<Void, Void, Bitmap> {
-    private final Context mContext;
-    private final WeakReference<ImageView> mView;
-    private final String mTitle;
-
-    public GenerateCoverTask(Context context, ImageView view, String title) {
-        mContext = context;
-        mView = new WeakReference<>(view);
-        mTitle = title;
-    }
-
-    @Override
-    protected Bitmap doInBackground(Void... voids) {
-        try {
-            final Bitmap background = BitmapFactory.decodeResource(mContext.getResources(), R.drawable.cover_placeholder);
-            if (background == null)
-                return null;
-
-            final Bitmap bitmap = Bitmap.createBitmap(background.getWidth(), background.getHeight(), background.getConfig());
-            final Canvas canvas = new Canvas(bitmap);
-            final TextPaint paint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
-            canvas.drawBitmap(background, 0.0f, 0.0f, paint);
-
-            paint.setColor(Color.rgb(255, 255, 255));
-            paint.setTextSize(100);
-            paint.setShadowLayer(1.0f, 0.0f, 1.0f, Color.DKGRAY);
-            paint.setTextAlign(Paint.Align.CENTER);
-
-            final StaticLayout staticLayout = new StaticLayout(mTitle, paint,
-                    canvas.getWidth(), Layout.Alignment.ALIGN_NORMAL, 1, 0, false);
-            canvas.save();
-            canvas.translate(canvas.getWidth() / 2, (canvas.getHeight() / 2) - (staticLayout.getHeight() / 2));
-            staticLayout.draw(canvas);
-            canvas.restore();
-            return bitmap;
-        } catch (Exception e) {
-            e.printStackTrace();
-            return null;
-        }
-    }
-
-    @Override
-    protected void onPostExecute(Bitmap bitmap) {
-        ImageView iv = mView.get();
-        if (iv != null)
-            iv.setImageBitmap(bitmap);
-    }
-}
diff --git a/android/app/src/main/java/com/github/stenzek/duckstation/GridAutofitLayoutManager.java b/android/app/src/main/java/com/github/stenzek/duckstation/GridAutofitLayoutManager.java
deleted file mode 100644
index f7e3325c2..000000000
--- a/android/app/src/main/java/com/github/stenzek/duckstation/GridAutofitLayoutManager.java
+++ /dev/null
@@ -1,73 +0,0 @@
-package com.github.stenzek.duckstation;
-
-// https://stackoverflow.com/questions/26666143/recyclerview-gridlayoutmanager-how-to-auto-detect-span-count
-
-import android.content.Context;
-import android.util.TypedValue;
-
-import androidx.annotation.NonNull;
-import androidx.recyclerview.widget.GridLayoutManager;
-import androidx.recyclerview.widget.RecyclerView;
-
-public class GridAutofitLayoutManager extends GridLayoutManager
-{
-    private int columnWidth;
-    private boolean isColumnWidthChanged = true;
-    private int lastWidth;
-    private int lastHeight;
-
-    public GridAutofitLayoutManager(@NonNull final Context context, final int columnWidth) {
-        /* Initially set spanCount to 1, will be changed automatically later. */
-        super(context, 1);
-        setColumnWidth(checkedColumnWidth(context, columnWidth));
-    }
-
-    public GridAutofitLayoutManager(
-            @NonNull final Context context,
-            final int columnWidth,
-            final int orientation,
-            final boolean reverseLayout) {
-
-        /* Initially set spanCount to 1, will be changed automatically later. */
-        super(context, 1, orientation, reverseLayout);
-        setColumnWidth(checkedColumnWidth(context, columnWidth));
-    }
-
-    private int checkedColumnWidth(@NonNull final Context context, int columnWidth) {
-        if (columnWidth <= 0) {
-            /* Set default columnWidth value (48dp here). It is better to move this constant
-            to static constant on top, but we need context to convert it to dp, so can't really
-            do so. */
-            columnWidth = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 48,
-                    context.getResources().getDisplayMetrics());
-        }
-        return columnWidth;
-    }
-
-    public void setColumnWidth(final int newColumnWidth) {
-        if (newColumnWidth > 0 && newColumnWidth != columnWidth) {
-            columnWidth = newColumnWidth;
-            isColumnWidthChanged = true;
-        }
-    }
-
-    @Override
-    public void onLayoutChildren(@NonNull final RecyclerView.Recycler recycler, @NonNull final RecyclerView.State state) {
-        final int width = getWidth();
-        final int height = getHeight();
-        if (columnWidth > 0 && width > 0 && height > 0 && (isColumnWidthChanged || lastWidth != width || lastHeight != height)) {
-            final int totalSpace;
-            if (getOrientation() == VERTICAL) {
-                totalSpace = width - getPaddingRight() - getPaddingLeft();
-            } else {
-                totalSpace = height - getPaddingTop() - getPaddingBottom();
-            }
-            final int spanCount = Math.max(1, totalSpace / columnWidth);
-            setSpanCount(spanCount);
-            isColumnWidthChanged = false;
-        }
-        lastWidth = width;
-        lastHeight = height;
-        super.onLayoutChildren(recycler, state);
-    }
-}
\ No newline at end of file
diff --git a/android/app/src/main/java/com/github/stenzek/duckstation/HotkeyInfo.java b/android/app/src/main/java/com/github/stenzek/duckstation/HotkeyInfo.java
deleted file mode 100644
index f16ce9f15..000000000
--- a/android/app/src/main/java/com/github/stenzek/duckstation/HotkeyInfo.java
+++ /dev/null
@@ -1,29 +0,0 @@
-package com.github.stenzek.duckstation;
-
-public class HotkeyInfo {
-    private String mCategory;
-    private String mName;
-    private String mDisplayName;
-
-    public HotkeyInfo(String category, String name, String displayName) {
-        mCategory = category;
-        mName = name;
-        mDisplayName = displayName;
-    }
-
-    public String getCategory() {
-        return mCategory;
-    }
-
-    public String getName() {
-        return mName;
-    }
-
-    public String getDisplayName() {
-        return mDisplayName;
-    }
-
-    public String getBindingConfigKey() {
-        return String.format("Hotkeys/%s", mName);
-    }
-}
diff --git a/android/app/src/main/java/com/github/stenzek/duckstation/ImageLoadTask.java b/android/app/src/main/java/com/github/stenzek/duckstation/ImageLoadTask.java
deleted file mode 100644
index 447a4c87c..000000000
--- a/android/app/src/main/java/com/github/stenzek/duckstation/ImageLoadTask.java
+++ /dev/null
@@ -1,32 +0,0 @@
-package com.github.stenzek.duckstation;
-
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.os.AsyncTask;
-import android.widget.ImageView;
-
-import java.lang.ref.WeakReference;
-
-public class ImageLoadTask extends AsyncTask<String, Void, Bitmap> {
-    private WeakReference<ImageView> mView;
-
-    public ImageLoadTask(ImageView view) {
-        mView = new WeakReference<>(view);
-    }
-
-    @Override
-    protected Bitmap doInBackground(String... strings) {
-        try {
-            return BitmapFactory.decodeFile(strings[0]);
-        } catch (Exception e) {
-            return null;
-        }
-    }
-
-    @Override
-    protected void onPostExecute(Bitmap bitmap) {
-        ImageView iv = mView.get();
-        if (iv != null)
-            iv.setImageBitmap(bitmap);
-    }
-}
diff --git a/android/app/src/main/java/com/github/stenzek/duckstation/MainActivity.java b/android/app/src/main/java/com/github/stenzek/duckstation/MainActivity.java
deleted file mode 100644
index c849fa1d7..000000000
--- a/android/app/src/main/java/com/github/stenzek/duckstation/MainActivity.java
+++ /dev/null
@@ -1,556 +0,0 @@
-package com.github.stenzek.duckstation;
-
-import android.Manifest;
-import android.content.ClipData;
-import android.content.ClipboardManager;
-import android.content.Intent;
-import android.content.SharedPreferences;
-import android.content.pm.PackageManager;
-import android.content.res.Configuration;
-import android.content.res.Resources;
-import android.graphics.Bitmap;
-import android.net.Uri;
-import android.os.Build;
-import android.os.Bundle;
-import android.util.Log;
-import android.view.Gravity;
-import android.view.Menu;
-import android.view.MenuItem;
-import android.view.View;
-import android.widget.ListView;
-import android.widget.Toast;
-
-import androidx.annotation.NonNull;
-import androidx.appcompat.app.AlertDialog;
-import androidx.appcompat.app.AppCompatActivity;
-import androidx.appcompat.app.AppCompatDelegate;
-import androidx.appcompat.widget.Toolbar;
-import androidx.core.app.ActivityCompat;
-import androidx.core.content.ContextCompat;
-import androidx.fragment.app.Fragment;
-import androidx.preference.PreferenceManager;
-
-import java.io.ByteArrayOutputStream;
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.util.Locale;
-
-public class MainActivity extends AppCompatActivity {
-    private static final int REQUEST_EXTERNAL_STORAGE_PERMISSIONS = 1;
-    private static final int REQUEST_ADD_DIRECTORY_TO_GAME_LIST = 2;
-    private static final int REQUEST_IMPORT_BIOS_IMAGE = 3;
-    private static final int REQUEST_START_FILE = 4;
-    private static final int REQUEST_SETTINGS = 5;
-    private static final int REQUEST_EDIT_GAME_DIRECTORIES = 6;
-    private static final int REQUEST_CHOOSE_COVER_IMAGE = 7;
-
-    private GameList mGameList;
-    private ListView mGameListView;
-    private GameListFragment mGameListFragment;
-    private GameGridFragment mGameGridFragment;
-    private Fragment mEmptyGameListFragment;
-    private boolean mHasExternalStoragePermissions = false;
-    private boolean mIsShowingGameGrid = false;
-    private String mPathForChosenCoverImage = null;
-
-    public GameList getGameList() {
-        return mGameList;
-    }
-
-    public boolean shouldResumeStateByDefault() {
-        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
-        if (!prefs.getBoolean("Main/SaveStateOnExit", true))
-            return false;
-
-        // don't resume with challenge mode on
-        if (Achievement.willChallengeModeBeEnabled(this))
-            return false;
-
-        return true;
-    }
-
-    private void setLanguage() {
-        String language = PreferenceManager.getDefaultSharedPreferences(this).getString("Main/Language", "none");
-        if (language == null || language.equals("none")) {
-            return;
-        }
-
-        String[] parts = language.split("-");
-        if (parts.length < 2)
-            return;
-
-        Locale locale = new Locale(parts[0], parts[1]);
-        Locale.setDefault(locale);
-
-        Resources res = getResources();
-        Configuration config = res.getConfiguration();
-        config.setLocale(locale);
-        res.updateConfiguration(config, res.getDisplayMetrics());
-    }
-
-    private void setTheme() {
-        String theme = PreferenceManager.getDefaultSharedPreferences(this).getString("Main/Theme", "follow_system");
-        if (theme == null)
-            return;
-
-        if (theme.equals("follow_system")) {
-            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q)
-                AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM);
-        } else if (theme.equals("light")) {
-            AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO);
-        } else if (theme.equals("dark")) {
-            AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES);
-        }
-    }
-
-    private void loadSettings() {
-        setLanguage();
-        setTheme();
-
-        mIsShowingGameGrid = PreferenceManager.getDefaultSharedPreferences(this).getBoolean("Main/GameGridView", false);
-    }
-
-    private void switchGameListView() {
-        mIsShowingGameGrid = !mIsShowingGameGrid;
-        PreferenceManager.getDefaultSharedPreferences(this)
-                .edit()
-                .putBoolean("Main/GameGridView", mIsShowingGameGrid)
-                .commit();
-
-        updateGameListFragment(true);
-        invalidateOptionsMenu();
-    }
-
-    private void updateGameListFragment(boolean allowEmpty) {
-        final Fragment listFragment = (allowEmpty && mGameList.getEntryCount() == 0) ?
-                mEmptyGameListFragment :
-                (mIsShowingGameGrid ? mGameGridFragment : mGameListFragment);
-
-        getSupportFragmentManager()
-                .beginTransaction()
-                .setReorderingAllowed(true).
-                replace(R.id.content_fragment, listFragment)
-                .commitAllowingStateLoss();
-    }
-
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        loadSettings();
-        setTitle(null);
-
-        super.onCreate(null);
-
-        setContentView(R.layout.activity_main);
-        Toolbar toolbar = findViewById(R.id.toolbar);
-        setSupportActionBar(toolbar);
-
-        findViewById(R.id.fab_resume).setOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View view) {
-                startEmulation(null, shouldResumeStateByDefault());
-            }
-        });
-
-        // Set up game list view.
-        mGameList = new GameList(this);
-        mGameList.addRefreshListener(() -> updateGameListFragment(true));
-        mGameListFragment = new GameListFragment(this);
-        mGameGridFragment = new GameGridFragment(this);
-        mEmptyGameListFragment = new EmptyGameListFragment(this);
-        updateGameListFragment(false);
-
-        mHasExternalStoragePermissions = checkForExternalStoragePermissions();
-        if (mHasExternalStoragePermissions)
-            completeStartup();
-    }
-
-    private void completeStartup() {
-        if (!AndroidHostInterface.hasInstance() && !AndroidHostInterface.createInstance(this)) {
-            Log.i("MainActivity", "Failed to create host interface");
-            throw new RuntimeException("Failed to create host interface");
-        }
-
-        AndroidHostInterface.getInstance().setContext(this);
-        mGameList.refresh(false, false, this);
-        UpdateNotes.displayUpdateNotes(this);
-    }
-
-    public void startAddGameDirectory() {
-        if (!checkForExternalStoragePermissions())
-            return;
-
-        Intent i = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
-        i.addCategory(Intent.CATEGORY_DEFAULT);
-        i.putExtra(Intent.EXTRA_LOCAL_ONLY, true);
-        i.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
-        i.addFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION);
-        startActivityForResult(Intent.createChooser(i, getString(R.string.main_activity_choose_directory)),
-                REQUEST_ADD_DIRECTORY_TO_GAME_LIST);
-    }
-
-    @Override
-    public boolean onCreateOptionsMenu(Menu menu) {
-        // Inflate the menu; this adds items to the action bar if it is present.
-        getMenuInflater().inflate(R.menu.menu_main, menu);
-
-        final MenuItem switchViewItem = menu.findItem(R.id.action_switch_view);
-        if (switchViewItem != null) {
-            switchViewItem.setTitle(mIsShowingGameGrid ? R.string.action_show_game_list : R.string.action_show_game_grid);
-            switchViewItem.setIcon(mIsShowingGameGrid ? R.drawable.ic_baseline_view_list_24 : R.drawable.ic_baseline_grid_view_24);
-        }
-
-        return true;
-    }
-
-    @Override
-    public boolean onOptionsItemSelected(MenuItem item) {
-        // Handle action bar item clicks here. The action bar will
-        // automatically handle clicks on the Home/Up button, so long
-        // as you specify a parent activity in AndroidManifest.xml.
-        int id = item.getItemId();
-
-        //noinspection SimplifiableIfStatement
-        if (id == R.id.action_start_bios) {
-            startEmulation(null, false);
-        } else if (id == R.id.action_start_file) {
-            startStartFile();
-        } else if (id == R.id.action_edit_game_directories) {
-            Intent intent = new Intent(this, GameDirectoriesActivity.class);
-            startActivityForResult(intent, REQUEST_EDIT_GAME_DIRECTORIES);
-            return true;
-        } else if (id == R.id.action_scan_for_new_games) {
-            mGameList.refresh(false, false, this);
-        } else if (id == R.id.action_rescan_all_games) {
-            mGameList.refresh(true, true, this);
-        } else if (id == R.id.action_import_bios) {
-            importBIOSImage();
-        } else if (id == R.id.action_settings) {
-            Intent intent = new Intent(this, SettingsActivity.class);
-            startActivityForResult(intent, REQUEST_SETTINGS);
-            return true;
-        } else if (id == R.id.action_controller_settings) {
-            Intent intent = new Intent(this, ControllerSettingsActivity.class);
-            startActivity(intent);
-            return true;
-        } else if (id == R.id.action_memory_card_editor) {
-            Intent intent = new Intent(this, MemoryCardEditorActivity.class);
-            startActivity(intent);
-            return true;
-        } else if (id == R.id.action_switch_view) {
-            switchGameListView();
-            return true;
-        } else if (id == R.id.action_show_version) {
-            showVersion();
-            return true;
-        } else if (id == R.id.action_github_respository) {
-            openGithubRepository();
-            return true;
-        } else if (id == R.id.action_discord_server) {
-            openDiscordServer();
-            return true;
-        }
-
-        return super.onOptionsItemSelected(item);
-    }
-
-    @Override
-    public void onActivityResult(int requestCode, int resultCode, Intent data) {
-        super.onActivityResult(requestCode, resultCode, data);
-
-        switch (requestCode) {
-            case REQUEST_ADD_DIRECTORY_TO_GAME_LIST: {
-                if (resultCode != RESULT_OK || data.getData() == null)
-                    return;
-
-                // Use legacy storage on devices older than Android 11... apparently some of them
-                // have broken storage access framework....
-                if (!GameDirectoriesActivity.useStorageAccessFramework(this)) {
-                    final String path = FileHelper.getFullPathFromTreeUri(data.getData(), this);
-                    if (path != null) {
-                        GameDirectoriesActivity.addSearchDirectory(this, path, true);
-                        mGameList.refresh(false, false, this);
-                        return;
-                    }
-                }
-
-                try {
-                    getContentResolver().takePersistableUriPermission(data.getData(),
-                            Intent.FLAG_GRANT_READ_URI_PERMISSION);
-                } catch (Exception e) {
-                    Toast.makeText(this, "Failed to take persistable permission.", Toast.LENGTH_LONG);
-                    e.printStackTrace();
-                }
-
-                GameDirectoriesActivity.addSearchDirectory(this, data.getDataString(), true);
-                mGameList.refresh(false, false, this);
-            }
-            break;
-
-            case REQUEST_IMPORT_BIOS_IMAGE: {
-                if (resultCode != RESULT_OK)
-                    return;
-
-                onImportBIOSImageResult(data.getData());
-            }
-            break;
-
-            case REQUEST_START_FILE: {
-                if (resultCode != RESULT_OK || data.getData() == null)
-                    return;
-
-                startEmulation(data.getDataString(), shouldResumeStateByDefault());
-            }
-            break;
-
-            case REQUEST_SETTINGS: {
-                loadSettings();
-            }
-            break;
-
-            case REQUEST_EDIT_GAME_DIRECTORIES: {
-                mGameList.refresh(false, false, this);
-            }
-            break;
-
-            case REQUEST_CHOOSE_COVER_IMAGE: {
-                final String gamePath = mPathForChosenCoverImage;
-                mPathForChosenCoverImage = null;
-                if (resultCode != RESULT_OK)
-                    return;
-
-                finishChooseCoverImage(gamePath, data.getData());
-            }
-            break;
-        }
-    }
-
-    private boolean checkForExternalStoragePermissions() {
-        if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) ==
-                PackageManager.PERMISSION_GRANTED &&
-                ContextCompat
-                        .checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) ==
-                        PackageManager.PERMISSION_GRANTED) {
-            return true;
-        }
-
-        ActivityCompat.requestPermissions(this,
-                new String[]{Manifest.permission.READ_EXTERNAL_STORAGE,
-                        Manifest.permission.WRITE_EXTERNAL_STORAGE},
-                REQUEST_EXTERNAL_STORAGE_PERMISSIONS);
-        return false;
-    }
-
-    public void onRequestPermissionsResult(int requestCode, String[] permissions,
-                                           int[] grantResults) {
-        // check that all were successful
-        for (int i = 0; i < grantResults.length; i++) {
-            if (grantResults[i] == PackageManager.PERMISSION_GRANTED) {
-                if (!mHasExternalStoragePermissions) {
-                    mHasExternalStoragePermissions = true;
-                    completeStartup();
-                }
-            } else {
-                Toast.makeText(this,
-                        R.string.main_activity_external_storage_permissions_error,
-                        Toast.LENGTH_LONG);
-                finish();
-            }
-        }
-    }
-
-    public boolean openGameProperties(String path) {
-        Intent intent = new Intent(this, GamePropertiesActivity.class);
-        intent.putExtra("path", path);
-        startActivity(intent);
-        return true;
-    }
-
-    public void openGamePopupMenu(View anchorToView, GameListEntry entry) {
-        androidx.appcompat.widget.PopupMenu menu = new androidx.appcompat.widget.PopupMenu(this, anchorToView, Gravity.RIGHT | Gravity.TOP);
-        menu.getMenuInflater().inflate(R.menu.menu_game_list_entry, menu.getMenu());
-        menu.setOnMenuItemClickListener(item -> {
-            int id = item.getItemId();
-            if (id == R.id.game_list_entry_menu_start_game) {
-                startEmulation(entry.getPath(), false);
-                return true;
-            } else if (id == R.id.game_list_entry_menu_resume_game) {
-                startEmulation(entry.getPath(), true);
-                return true;
-            } else if (id == R.id.game_list_entry_menu_properties) {
-                openGameProperties(entry.getPath());
-                return true;
-            } else if (id == R.id.game_list_entry_menu_choose_cover_image) {
-                startChooseCoverImage(entry.getPath());
-                return true;
-            }
-            return false;
-        });
-
-        // disable resume state when challenge mode is on
-        if (Achievement.willChallengeModeBeEnabled(this)) {
-            MenuItem item = menu.getMenu().findItem(R.id.game_list_entry_menu_resume_game);
-            if (item != null)
-                item.setEnabled(false);
-        }
-
-        menu.show();
-    }
-
-    public boolean startEmulation(String bootPath, boolean resumeState) {
-        if (!doBIOSCheck())
-            return false;
-
-        Intent intent = new Intent(this, EmulationActivity.class);
-        intent.putExtra("bootPath", bootPath);
-        intent.putExtra("resumeState", resumeState);
-        startActivity(intent);
-        return true;
-    }
-
-    public void startStartFile() {
-        Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
-        intent.setType("*/*");
-        intent.addCategory(Intent.CATEGORY_OPENABLE);
-        startActivityForResult(Intent.createChooser(intent, getString(R.string.main_activity_choose_disc_image)), REQUEST_START_FILE);
-    }
-
-    private void startChooseCoverImage(String gamePath) {
-        Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
-        intent.setType("image/*");
-        intent.addCategory(Intent.CATEGORY_OPENABLE);
-        mPathForChosenCoverImage = gamePath;
-        startActivityForResult(Intent.createChooser(intent, getString(R.string.menu_game_list_entry_choose_cover_image)),
-                REQUEST_CHOOSE_COVER_IMAGE);
-    }
-
-    private void finishChooseCoverImage(String gamePath, Uri uri) {
-        final GameListEntry gameListEntry = mGameList.getEntryForPath(gamePath);
-        if (gameListEntry == null)
-            return;
-
-        final Bitmap bitmap = FileHelper.loadBitmapFromUri(this, uri);
-        if (bitmap == null) {
-            Toast.makeText(this, "Failed to open/decode image.", Toast.LENGTH_LONG).show();
-            return;
-        }
-
-        final String coverFileName = String.format("%s/covers/%s.png",
-                AndroidHostInterface.getUserDirectory(), gameListEntry.getTitle());
-        try {
-            final File file = new File(coverFileName);
-            final OutputStream outputStream = new FileOutputStream(file);
-            final boolean result = bitmap.compress(Bitmap.CompressFormat.PNG, 100, outputStream);
-            outputStream.close();;
-            if (!result) {
-                file.delete();
-                throw new Exception("Failed to compress bitmap.");
-            }
-
-            gameListEntry.setCoverPath(coverFileName);
-            mGameList.fireRefreshListeners();
-        } catch (Exception e) {
-            e.printStackTrace();
-            Toast.makeText(this, "Failed to save image.", Toast.LENGTH_LONG).show();
-        }
-
-        bitmap.recycle();
-    }
-
-    private boolean doBIOSCheck() {
-        if (AndroidHostInterface.getInstance().hasAnyBIOSImages())
-            return true;
-
-        new AlertDialog.Builder(this)
-                .setTitle(R.string.main_activity_missing_bios_image)
-                .setMessage(R.string.main_activity_missing_bios_image_prompt)
-                .setPositiveButton(R.string.main_activity_yes, (dialog, button) -> importBIOSImage())
-                .setNegativeButton(R.string.main_activity_no, (dialog, button) -> {
-                })
-                .create()
-                .show();
-
-        return false;
-    }
-
-    private void importBIOSImage() {
-        Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
-        intent.setType("*/*");
-        intent.addCategory(Intent.CATEGORY_OPENABLE);
-        startActivityForResult(Intent.createChooser(intent, getString(R.string.main_activity_choose_bios_image)), REQUEST_IMPORT_BIOS_IMAGE);
-    }
-
-    private void onImportBIOSImageResult(Uri uri) {
-        // This should really be 512K but just in case we wanted to support the other BIOSes in the future...
-        final int MAX_BIOS_SIZE = 2 * 1024 * 1024;
-
-        InputStream stream = null;
-        try {
-            stream = getContentResolver().openInputStream(uri);
-        } catch (FileNotFoundException e) {
-            Toast.makeText(this, R.string.main_activity_failed_to_open_bios_image, Toast.LENGTH_LONG);
-            return;
-        }
-
-        ByteArrayOutputStream os = new ByteArrayOutputStream();
-        try {
-            byte[] buffer = new byte[512 * 1024];
-            int len;
-            while ((len = stream.read(buffer)) > 0) {
-                os.write(buffer, 0, len);
-                if (os.size() > MAX_BIOS_SIZE) {
-                    throw new IOException(getString(R.string.main_activity_bios_image_too_large));
-                }
-            }
-        } catch (IOException e) {
-            new AlertDialog.Builder(this)
-                    .setMessage(getString(R.string.main_activity_failed_to_read_bios_image_prefix) + e.getMessage())
-                    .setPositiveButton(R.string.main_activity_ok, (dialog, button) -> {
-                    })
-                    .create()
-                    .show();
-            return;
-        }
-
-        String importResult = AndroidHostInterface.getInstance().importBIOSImage(os.toByteArray());
-        String message = (importResult == null) ? getString(R.string.main_activity_invalid_error) : ("BIOS '" + importResult + "' imported.");
-
-        new AlertDialog.Builder(this)
-                .setMessage(message)
-                .setPositiveButton(R.string.main_activity_ok, (dialog, button) -> {
-                })
-                .create()
-                .show();
-    }
-
-    private void showVersion() {
-        final String message = AndroidHostInterface.getFullScmVersion();
-        new AlertDialog.Builder(this)
-                .setTitle(R.string.main_activity_show_version_title)
-                .setMessage(message)
-                .setPositiveButton(R.string.main_activity_ok, (dialog, button) -> {
-                })
-                .setNeutralButton(R.string.main_activity_copy, (dialog, button) -> {
-                    ClipboardManager clipboard = (ClipboardManager) getSystemService(CLIPBOARD_SERVICE);
-                    if (clipboard != null)
-                        clipboard.setPrimaryClip(ClipData.newPlainText(getString(R.string.main_activity_show_version_title), message));
-                })
-                .create()
-                .show();
-    }
-
-    private void openGithubRepository() {
-        final String url = "https://github.com/stenzek/duckstation";
-        final Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
-        startActivity(browserIntent);
-    }
-
-    private void openDiscordServer() {
-        final String url = "https://discord.gg/Buktv3t";
-        final Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
-        startActivity(browserIntent);
-    }
-}
diff --git a/android/app/src/main/java/com/github/stenzek/duckstation/MemoryCardEditorActivity.java b/android/app/src/main/java/com/github/stenzek/duckstation/MemoryCardEditorActivity.java
deleted file mode 100644
index dfe1323b3..000000000
--- a/android/app/src/main/java/com/github/stenzek/duckstation/MemoryCardEditorActivity.java
+++ /dev/null
@@ -1,524 +0,0 @@
-package com.github.stenzek.duckstation;
-
-import android.app.AlertDialog;
-import android.content.Intent;
-import android.graphics.Bitmap;
-import android.net.Uri;
-import android.os.Bundle;
-
-import com.google.android.material.tabs.TabLayout;
-import com.google.android.material.tabs.TabLayoutMediator;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.appcompat.app.ActionBar;
-import androidx.appcompat.widget.Toolbar;
-import androidx.fragment.app.Fragment;
-import androidx.recyclerview.widget.DividerItemDecoration;
-import androidx.recyclerview.widget.LinearLayoutManager;
-import androidx.recyclerview.widget.RecyclerView;
-import androidx.appcompat.app.AppCompatActivity;
-import androidx.viewpager2.adapter.FragmentStateAdapter;
-import androidx.viewpager2.widget.ViewPager2;
-
-import android.view.LayoutInflater;
-import android.view.Menu;
-import android.view.MenuItem;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.ImageView;
-import android.widget.TextView;
-import android.widget.Toast;
-
-import java.util.ArrayList;
-
-public class MemoryCardEditorActivity extends AppCompatActivity {
-    public static final int REQUEST_IMPORT_CARD = 1;
-
-    private final ArrayList<MemoryCardImage> cards = new ArrayList<>();
-    private CollectionAdapter adapter;
-    private ViewPager2 viewPager;
-    private TabLayout tabLayout;
-    private TabLayoutMediator tabLayoutMediator;
-
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(null);
-        setContentView(R.layout.activity_memory_card_editor);
-
-        Toolbar toolbar = findViewById(R.id.toolbar);
-        setSupportActionBar(toolbar);
-
-        ActionBar actionBar = getSupportActionBar();
-        if (actionBar != null) {
-            actionBar.setDisplayHomeAsUpEnabled(true);
-        }
-
-        adapter = new CollectionAdapter(this);
-        viewPager = findViewById(R.id.view_pager);
-        viewPager.setAdapter(adapter);
-
-        tabLayout = findViewById(R.id.tab_layout);
-        tabLayoutMediator = new TabLayoutMediator(tabLayout, viewPager, adapter.getTabConfigurationStrategy());
-        tabLayoutMediator.attach();
-
-        findViewById(R.id.open_card).setOnClickListener((v) -> openCard());
-        findViewById(R.id.close_card).setOnClickListener((v) -> closeCard());
-    }
-
-    @Override
-    public boolean onCreateOptionsMenu(Menu menu) {
-        getMenuInflater().inflate(R.menu.menu_memory_card_editor, menu);
-
-        final boolean hasCurrentCard = (getCurrentCard() != null);
-        menu.findItem(R.id.action_delete_card).setEnabled(hasCurrentCard);
-        menu.findItem(R.id.action_format_card).setEnabled(hasCurrentCard);
-        menu.findItem(R.id.action_import_card).setEnabled(hasCurrentCard);
-
-        return true;
-    }
-
-    @Override
-    public boolean onOptionsItemSelected(MenuItem item) {
-       switch (item.getItemId()) {
-            case android.R.id.home: {
-                onBackPressed();
-                return true;
-            }
-
-            case R.id.action_import_card: {
-                importCard();
-                return true;
-            }
-
-            case R.id.action_delete_card: {
-                deleteCard();
-                return true;
-            }
-
-            case R.id.action_format_card: {
-                formatCard();
-                return true;
-            }
-
-           default: {
-               return super.onOptionsItemSelected(item);
-           }
-        }
-    }
-
-    private void openCard() {
-        final Uri[] uris = MemoryCardImage.getCardUris(this);
-        if (uris == null) {
-            displayMessage(getString(R.string.memory_card_editor_no_cards_found));
-            return;
-        }
-
-        final String[] uriTitles = new String[uris.length];
-        for (int i = 0; i < uris.length; i++)
-            uriTitles[i] = MemoryCardImage.getTitleForUri(uris[i]);
-
-        final AlertDialog.Builder builder = new AlertDialog.Builder(this);
-        builder.setTitle(R.string.memory_card_editor_select_card);
-        builder.setItems(uriTitles, (dialog, which) -> {
-            final Uri uri = uris[which];
-            for (int i = 0; i < cards.size(); i++) {
-                if (cards.get(i).getUri().equals(uri)) {
-                    displayError(getString(R.string.memory_card_editor_card_already_open));
-                    tabLayout.getTabAt(i).select();
-                    return;
-                }
-            }
-
-            final MemoryCardImage card = MemoryCardImage.open(MemoryCardEditorActivity.this, uri);
-            if (card == null) {
-                displayError(getString(R.string.memory_card_editor_failed_to_open_card));
-                return;
-            }
-
-            cards.add(card);
-            refreshView(card);
-        });
-        builder.create().show();
-    }
-
-    private void closeCard() {
-        final int index = tabLayout.getSelectedTabPosition();
-        if (index < 0)
-            return;
-
-        cards.remove(index);
-        refreshView(index);
-    }
-
-    private void displayMessage(String message) {
-        Toast.makeText(this, message, Toast.LENGTH_LONG).show();
-    }
-
-    private void displayError(String message) {
-        final AlertDialog.Builder errorBuilder = new AlertDialog.Builder(this);
-        errorBuilder.setTitle(R.string.memory_card_editor_error);
-        errorBuilder.setMessage(message);
-        errorBuilder.setPositiveButton(R.string.main_activity_ok, (dialog1, which1) -> dialog1.dismiss());
-        errorBuilder.create().show();
-    }
-
-    private void copySave(MemoryCardImage sourceCard, MemoryCardFileInfo sourceFile) {
-        if (cards.size() < 2) {
-            displayError(getString(R.string.memory_card_editor_must_have_at_least_two_cards_to_copy));
-            return;
-        }
-
-        if (cards.indexOf(sourceCard) < 0) {
-            // this shouldn't happen..
-            return;
-        }
-
-        final MemoryCardImage[] destinationCards = new MemoryCardImage[cards.size() - 1];
-        final String[] cardTitles = new String[cards.size() - 1];
-        for (int i = 0, d = 0; i < cards.size(); i++) {
-            if (cards.get(i) == sourceCard)
-                continue;
-
-            destinationCards[d] = cards.get(i);
-            cardTitles[d] = cards.get(i).getTitle();
-            d++;
-        }
-
-        final AlertDialog.Builder builder = new AlertDialog.Builder(this);
-        builder.setTitle(getString(R.string.memory_card_editor_copy_save_to, sourceFile.getTitle()));
-        builder.setItems(cardTitles, (dialog, which) -> {
-            dialog.dismiss();
-
-            final MemoryCardImage destinationCard = destinationCards[which];
-
-            byte[] data = null;
-            if (destinationCard.getFreeBlocks() < sourceFile.getNumBlocks()) {
-                displayError(getString(R.string.memory_card_editor_copy_insufficient_blocks, sourceFile.getNumBlocks(),
-                        destinationCard.getFreeBlocks()));
-            } else if (destinationCard.hasFile(sourceFile.getFilename())) {
-                displayError(getString(R.string.memory_card_editor_copy_already_exists, sourceFile.getFilename()));
-            } else if ((data = sourceCard.readFile(sourceFile.getFilename())) == null) {
-                displayError(getString(R.string.memory_card_editor_copy_read_failed, sourceFile.getFilename()));
-            } else if (!destinationCard.writeFile(sourceFile.getFilename(), data)) {
-                displayMessage(getString(R.string.memory_card_editor_copy_write_failed, sourceFile.getFilename()));
-            } else {
-                displayMessage(getString(R.string.memory_card_editor_copy_success, sourceFile.getFilename(),
-                        destinationCard.getTitle()));
-                refreshView(destinationCard);
-            }
-        });
-        builder.create().show();
-    }
-
-    private void deleteSave(MemoryCardImage card, MemoryCardFileInfo file) {
-        final AlertDialog.Builder builder = new AlertDialog.Builder(this);
-        builder.setMessage(getString(R.string.memory_card_editor_delete_confirm, file.getFilename()));
-        builder.setPositiveButton(R.string.main_activity_yes, (dialog, which) -> {
-            if (card.deleteFile(file.getFilename())) {
-                displayMessage(getString(R.string.memory_card_editor_delete_success, file.getFilename()));
-                refreshView(card);
-            } else {
-                displayError(getString(R.string.memory_card_editor_delete_failed, file.getFilename()));
-            }
-        });
-        builder.setNegativeButton(R.string.main_activity_no, (dialog, which) -> dialog.dismiss());
-        builder.create().show();
-    }
-
-    private void refreshView(int newSelection) {
-        final int oldPos = viewPager.getCurrentItem();
-        tabLayoutMediator.detach();
-        viewPager.setAdapter(null);
-        viewPager.setAdapter(adapter);
-        tabLayoutMediator.attach();
-
-        if (cards.isEmpty())
-            return;
-
-        if (newSelection < 0 || newSelection >= tabLayout.getTabCount()) {
-            if (oldPos < cards.size())
-                tabLayout.getTabAt(oldPos).select();
-            else
-                tabLayout.getTabAt(cards.size() - 1).select();
-        } else {
-            tabLayout.getTabAt(newSelection).select();
-        }
-    }
-
-    private void refreshView(MemoryCardImage newSelectedCard) {
-        if (newSelectedCard == null)
-            refreshView(-1);
-        else
-            refreshView(cards.indexOf(newSelectedCard));
-
-        invalidateOptionsMenu();
-    }
-
-    private MemoryCardImage getCurrentCard() {
-        final int index = tabLayout.getSelectedTabPosition();
-        if (index < 0 || index >= cards.size())
-            return null;
-
-        return cards.get(index);
-    }
-
-    private void importCard() {
-        if (getCurrentCard() == null) {
-            displayMessage(getString(R.string.memory_card_editor_no_card_selected));
-            return;
-        }
-
-        Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
-        intent.setType("*/*");
-        intent.addCategory(Intent.CATEGORY_OPENABLE);
-        startActivityForResult(Intent.createChooser(intent, getString(R.string.main_activity_choose_disc_image)), REQUEST_IMPORT_CARD);
-    }
-
-    private void importCard(Uri uri) {
-        final MemoryCardImage card = getCurrentCard();
-        if (card == null)
-            return;
-
-        final byte[] data = FileHelper.readBytesFromUri(this, uri, 16 * 1024 * 1024);
-        if (data == null) {
-            displayError(getString(R.string.memory_card_editor_import_card_read_failed, uri.toString()));
-            return;
-        }
-
-        String importFileName = FileHelper.getDocumentNameFromUri(this, uri);
-        if (importFileName == null) {
-            importFileName = uri.getPath();
-            if (importFileName == null || importFileName.isEmpty())
-                importFileName = uri.toString();
-        }
-
-        final String captureImportFileName = importFileName;
-        final AlertDialog.Builder builder = new AlertDialog.Builder(this);
-        builder.setMessage(getString(R.string.memory_card_editor_import_card_confirm_message,
-            importFileName, card.getTitle()));
-        builder.setPositiveButton(R.string.main_activity_yes, (dialog, which) -> {
-            dialog.dismiss();
-
-            if (!card.importCard(captureImportFileName, data)) {
-                displayError(getString(R.string.memory_card_editor_import_failed));
-                return;
-            }
-
-            refreshView(card);
-        });
-        builder.setNegativeButton(R.string.main_activity_no, (dialog, which) -> dialog.dismiss());
-        builder.create().show();
-    }
-
-    private void formatCard() {
-        final MemoryCardImage card = getCurrentCard();
-        if (card == null) {
-            displayMessage(getString(R.string.memory_card_editor_no_card_selected));
-            return;
-        }
-
-        final AlertDialog.Builder builder = new AlertDialog.Builder(this);
-        builder.setMessage(getString(R.string.memory_card_editor_format_card_confirm_message, card.getTitle()));
-        builder.setPositiveButton(R.string.main_activity_yes, (dialog, which) -> {
-            dialog.dismiss();
-
-            if (!card.format()) {
-                displayError(getString(R.string.memory_card_editor_format_card_failed, card.getUri().toString()));
-                return;
-            }
-
-            displayMessage(getString(R.string.memory_card_editor_format_card_success, card.getUri().toString()));
-            refreshView(card);
-        });
-        builder.setNegativeButton(R.string.main_activity_no, (dialog, which) -> dialog.dismiss());
-        builder.create().show();
-    }
-
-    private void deleteCard() {
-        final MemoryCardImage card = getCurrentCard();
-        if (card == null) {
-            displayMessage(getString(R.string.memory_card_editor_no_card_selected));
-            return;
-        }
-
-        final AlertDialog.Builder builder = new AlertDialog.Builder(this);
-        builder.setMessage(getString(R.string.memory_card_editor_delete_card_confirm_message, card.getTitle()));
-        builder.setPositiveButton(R.string.main_activity_yes, (dialog, which) -> {
-            dialog.dismiss();
-
-            if (!card.delete()) {
-                displayError(getString(R.string.memory_card_editor_delete_card_failed, card.getUri().toString()));
-                return;
-            }
-
-            displayMessage(getString(R.string.memory_card_editor_delete_card_success, card.getUri().toString()));
-            cards.remove(card);
-            refreshView(-1);
-        });
-        builder.setNegativeButton(R.string.main_activity_no, (dialog, which) -> dialog.dismiss());
-        builder.create().show();
-    }
-
-    @Override
-    public void onActivityResult(int requestCode, int resultCode, Intent data) {
-        super.onActivityResult(requestCode, resultCode, data);
-
-        switch (requestCode) {
-            case REQUEST_IMPORT_CARD: {
-                if (resultCode != RESULT_OK)
-                    return;
-
-                importCard(data.getData());
-            }
-            break;
-        }
-    }
-
-    private static class SaveViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
-        private MemoryCardEditorActivity mParent;
-        private View mItemView;
-        private MemoryCardImage mCard;
-        private MemoryCardFileInfo mFile;
-
-        public SaveViewHolder(MemoryCardEditorActivity parent, @NonNull View itemView) {
-            super(itemView);
-            mParent = parent;
-            mItemView = itemView;
-            mItemView.setOnClickListener(this);
-        }
-
-        public void bindToEntry(MemoryCardImage card, MemoryCardFileInfo file) {
-            mCard = card;
-            mFile = file;
-
-            ((TextView) mItemView.findViewById(R.id.title)).setText(mFile.getTitle());
-            ((TextView) mItemView.findViewById(R.id.filename)).setText(mFile.getFilename());
-
-            final String blocksText = String.format("%d Blocks", mFile.getNumBlocks());
-            final String sizeText = String.format("%.1f KB", (float)mFile.getSize() / 1024.0f);
-            ((TextView) mItemView.findViewById(R.id.block_size)).setText(blocksText);
-            ((TextView) mItemView.findViewById(R.id.file_size)).setText(sizeText);
-
-            if (mFile.getNumIconFrames() > 0) {
-                final Bitmap bitmap = mFile.getIconFrameBitmap(0);
-                if (bitmap != null) {
-                    ((ImageView) mItemView.findViewById(R.id.icon)).setImageBitmap(bitmap);
-                }
-            }
-        }
-
-        @Override
-        public void onClick(View v) {
-            final AlertDialog.Builder builder = new AlertDialog.Builder(mItemView.getContext());
-            builder.setTitle(mFile.getFilename());
-            builder.setItems(R.array.memory_card_editor_save_menu, ((dialog, which) -> {
-                switch (which) {
-                    // Copy Save
-                    case 0: {
-                        dialog.dismiss();
-                        mParent.copySave(mCard, mFile);
-                    }
-                    break;
-
-                    // Delete Save
-                    case 1: {
-                        dialog.dismiss();
-                        mParent.deleteSave(mCard, mFile);
-                    }
-                    break;
-                }
-            }));
-            builder.create().show();
-        }
-    }
-
-    private static class SaveViewAdapter extends RecyclerView.Adapter<SaveViewHolder> {
-        private MemoryCardEditorActivity parent;
-        private MemoryCardImage card;
-        private MemoryCardFileInfo[] files;
-
-        public SaveViewAdapter(MemoryCardEditorActivity parent, MemoryCardImage card) {
-            this.parent = parent;
-            this.card = card;
-            this.files = card.getFiles();
-        }
-
-        @NonNull
-        @Override
-        public SaveViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
-            final View rootView = LayoutInflater.from(parent.getContext()).inflate(R.layout.layout_memory_card_save, parent, false);
-            return new SaveViewHolder(this.parent, rootView);
-        }
-
-        @Override
-        public void onBindViewHolder(@NonNull SaveViewHolder holder, int position) {
-            holder.bindToEntry(card, files[position]);
-        }
-
-        @Override
-        public int getItemCount() {
-            return (files != null) ? files.length : 0;
-        }
-
-        @Override
-        public int getItemViewType(int position) {
-            return R.layout.layout_memory_card_save;
-        }
-    }
-
-    public static class MemoryCardFileFragment extends Fragment {
-        private MemoryCardEditorActivity parent;
-        private MemoryCardImage card;
-        private SaveViewAdapter adapter;
-        private RecyclerView recyclerView;
-
-        public MemoryCardFileFragment(MemoryCardEditorActivity parent, MemoryCardImage card) {
-            this.parent = parent;
-            this.card = card;
-        }
-
-        @Nullable
-        @Override
-        public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
-            return inflater.inflate(R.layout.fragment_memory_card_file, container, false);
-        }
-
-        @Override
-        public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
-            adapter = new SaveViewAdapter(parent, card);
-            recyclerView = view.findViewById(R.id.recyclerView);
-            recyclerView.setAdapter(adapter);
-            recyclerView.setLayoutManager(new LinearLayoutManager(recyclerView.getContext()));
-            recyclerView.addItemDecoration(new DividerItemDecoration(recyclerView.getContext(),
-                    DividerItemDecoration.VERTICAL));
-        }
-    }
-
-    public static class CollectionAdapter extends FragmentStateAdapter {
-        private MemoryCardEditorActivity parent;
-        private final TabLayoutMediator.TabConfigurationStrategy tabConfigurationStrategy = (tab, position) -> {
-            tab.setText(parent.cards.get(position).getTitle());
-        };
-
-        public CollectionAdapter(MemoryCardEditorActivity parent) {
-            super(parent);
-            this.parent = parent;
-        }
-
-        public TabLayoutMediator.TabConfigurationStrategy getTabConfigurationStrategy() {
-            return tabConfigurationStrategy;
-        }
-
-        @NonNull
-        @Override
-        public Fragment createFragment(int position) {
-            return new MemoryCardFileFragment(parent, parent.cards.get(position));
-        }
-
-        @Override
-        public int getItemCount() {
-            return parent.cards.size();
-        }
-    }
-}
\ No newline at end of file
diff --git a/android/app/src/main/java/com/github/stenzek/duckstation/MemoryCardFileInfo.java b/android/app/src/main/java/com/github/stenzek/duckstation/MemoryCardFileInfo.java
deleted file mode 100644
index e520c2db5..000000000
--- a/android/app/src/main/java/com/github/stenzek/duckstation/MemoryCardFileInfo.java
+++ /dev/null
@@ -1,64 +0,0 @@
-package com.github.stenzek.duckstation;
-
-import android.graphics.Bitmap;
-
-import java.nio.ByteBuffer;
-
-public class MemoryCardFileInfo {
-    public static final int ICON_WIDTH = 16;
-    public static final int ICON_HEIGHT = 16;
-
-    private final String filename;
-    private final String title;
-    private final int size;
-    private final int firstBlock;
-    private final int numBlocks;
-    private final byte[][] iconFrames;
-
-    public MemoryCardFileInfo(String filename, String title, int size, int firstBlock, int numBlocks, byte[][] iconFrames) {
-        this.filename = filename;
-        this.title = title;
-        this.size = size;
-        this.firstBlock = firstBlock;
-        this.numBlocks = numBlocks;
-        this.iconFrames = iconFrames;
-    }
-
-    public String getFilename() {
-        return filename;
-    }
-
-    public String getTitle() {
-        return title;
-    }
-
-    public int getSize() {
-        return size;
-    }
-
-    public int getFirstBlock() {
-        return firstBlock;
-    }
-
-    public int getNumBlocks() {
-        return numBlocks;
-    }
-
-    public int getNumIconFrames() {
-        return (iconFrames != null) ? iconFrames.length : 0;
-    }
-
-    public byte[] getIconFrame(int index) {
-        return iconFrames[index];
-    }
-
-    public Bitmap getIconFrameBitmap(int index) {
-        final byte[] data = getIconFrame(index);
-        if (data == null)
-            return null;
-
-        final Bitmap bitmap = Bitmap.createBitmap(ICON_WIDTH, ICON_HEIGHT, Bitmap.Config.ARGB_8888);
-        bitmap.copyPixelsFromBuffer(ByteBuffer.wrap(data));
-        return bitmap;
-    }
-}
diff --git a/android/app/src/main/java/com/github/stenzek/duckstation/MemoryCardImage.java b/android/app/src/main/java/com/github/stenzek/duckstation/MemoryCardImage.java
deleted file mode 100644
index 5417ecc3d..000000000
--- a/android/app/src/main/java/com/github/stenzek/duckstation/MemoryCardImage.java
+++ /dev/null
@@ -1,204 +0,0 @@
-package com.github.stenzek.duckstation;
-
-import android.content.ContentResolver;
-import android.content.Context;
-import android.database.Cursor;
-import android.net.Uri;
-import android.provider.DocumentsContract;
-
-import java.io.File;
-import java.util.ArrayList;
-import java.util.Collections;
-
-public class MemoryCardImage {
-    public static final int DATA_SIZE = 128 * 1024;
-    public static final String FILE_EXTENSION = ".mcd";
-
-    private final Context context;
-    private final Uri uri;
-    private final byte[] data;
-
-    private MemoryCardImage(Context context, Uri uri, byte[] data) {
-        this.context = context;
-        this.uri = uri;
-        this.data = data;
-    }
-
-    public static String getTitleForUri(Uri uri) {
-        String name = uri.getLastPathSegment();
-        if (name != null) {
-            final int lastSlash = name.lastIndexOf('/');
-            if (lastSlash >= 0)
-                name = name.substring(lastSlash + 1);
-
-            if (name.endsWith(FILE_EXTENSION))
-                name = name.substring(0, name.length() - FILE_EXTENSION.length());
-        } else {
-            name = uri.toString();
-        }
-
-        return name;
-    }
-
-    public static MemoryCardImage open(Context context, Uri uri) {
-        byte[] data = FileHelper.readBytesFromUri(context, uri, DATA_SIZE);
-        if (data == null)
-            return null;
-
-        if (!isValid(data))
-            return null;
-
-        return new MemoryCardImage(context, uri, data);
-    }
-
-    public static MemoryCardImage create(Context context, Uri uri) {
-        byte[] data = new byte[DATA_SIZE];
-        format(data);
-
-        MemoryCardImage card = new MemoryCardImage(context, uri, data);
-        if (!card.save())
-            return null;
-
-        return card;
-    }
-
-    public static Uri[] getCardUris(Context context) {
-        final String directory = String.format("%s/memcards",
-                AndroidHostInterface.getUserDirectory());
-        final ArrayList<Uri> results = new ArrayList<>();
-
-        if (directory.charAt(0) == '/') {
-            // native path
-            final File directoryFile = new File(directory);
-            final File[] files = directoryFile.listFiles();
-            for (File file : files) {
-                if (!file.isFile())
-                    continue;
-
-                if (!file.getName().endsWith(FILE_EXTENSION))
-                    continue;
-
-                results.add(Uri.fromFile(file));
-            }
-        } else {
-            try {
-                final Uri baseUri = null;
-                final String[] scanProjection = new String[]{
-                        DocumentsContract.Document.COLUMN_DOCUMENT_ID,
-                        DocumentsContract.Document.COLUMN_DISPLAY_NAME,
-                        DocumentsContract.Document.COLUMN_MIME_TYPE};
-                final ContentResolver resolver = context.getContentResolver();
-                final String treeDocId = DocumentsContract.getTreeDocumentId(baseUri);
-                final Uri queryUri = DocumentsContract.buildChildDocumentsUriUsingTree(baseUri, treeDocId);
-                final Cursor cursor = resolver.query(queryUri, scanProjection, null, null, null);
-
-                while (cursor.moveToNext()) {
-                    try {
-                        final String mimeType = cursor.getString(2);
-                        final String documentId = cursor.getString(0);
-                        final Uri uri = DocumentsContract.buildDocumentUriUsingTree(baseUri, documentId);
-                        if (DocumentsContract.Document.MIME_TYPE_DIR.equals(mimeType)) {
-                            continue;
-                        }
-
-                        final String uriString = uri.toString();
-                        if (!uriString.endsWith(FILE_EXTENSION))
-                            continue;
-
-                        results.add(uri);
-                    } catch (Exception e) {
-                        e.printStackTrace();
-                    }
-                }
-                cursor.close();
-            } catch (Exception e) {
-                e.printStackTrace();
-            }
-        }
-
-        if (results.isEmpty())
-            return null;
-
-        Collections.sort(results, (a, b) -> a.compareTo(b));
-
-        final Uri[] resultArray = new Uri[results.size()];
-        results.toArray(resultArray);
-        return resultArray;
-    }
-
-    private static native boolean isValid(byte[] data);
-
-    private static native void format(byte[] data);
-
-    private static native int getFreeBlocks(byte[] data);
-
-    private static native MemoryCardFileInfo[] getFiles(byte[] data);
-
-    private static native boolean hasFile(byte[] data, String filename);
-
-    private static native byte[] readFile(byte[] data, String filename);
-
-    private static native boolean writeFile(byte[] data, String filename, byte[] fileData);
-
-    private static native boolean deleteFile(byte[] data, String filename);
-
-    private static native boolean importCard(byte[] data, String filename, byte[] importData);
-
-    public boolean save() {
-        return FileHelper.writeBytesToUri(context, uri, data);
-    }
-
-    public boolean delete() {
-        return FileHelper.deleteFileAtUri(context, uri);
-    }
-
-    public boolean format() {
-        format(data);
-        return save();
-    }
-
-    public Uri getUri() {
-        return uri;
-    }
-
-    public String getTitle() {
-        return getTitleForUri(uri);
-    }
-
-    public int getFreeBlocks() {
-        return getFreeBlocks(data);
-    }
-
-    public MemoryCardFileInfo[] getFiles() {
-        return getFiles(data);
-    }
-
-    public boolean hasFile(String filename) {
-        return hasFile(data, filename);
-    }
-
-    public byte[] readFile(String filename) {
-        return readFile(data, filename);
-    }
-
-    public boolean writeFile(String filename, byte[] fileData) {
-        if (!writeFile(data, filename, fileData))
-            return false;
-
-        return save();
-    }
-
-    public boolean deleteFile(String filename) {
-        if (!deleteFile(data, filename))
-            return false;
-
-        return save();
-    }
-
-    public boolean importCard(String filename, byte[] importData) {
-        if (!importCard(data, filename, importData))
-            return false;
-
-        return save();
-    }
-}
diff --git a/android/app/src/main/java/com/github/stenzek/duckstation/PatchCode.java b/android/app/src/main/java/com/github/stenzek/duckstation/PatchCode.java
deleted file mode 100644
index c8de67096..000000000
--- a/android/app/src/main/java/com/github/stenzek/duckstation/PatchCode.java
+++ /dev/null
@@ -1,40 +0,0 @@
-package com.github.stenzek.duckstation;
-
-public class PatchCode {
-    private static final String UNGROUPED_NAME = "Ungrouped";
-
-    private int mIndex;
-    private String mGroup;
-    private String mDescription;
-    private boolean mEnabled;
-
-    public PatchCode(int index, String group, String description, boolean enabled) {
-        mIndex = index;
-        mGroup = group;
-        mDescription = description;
-        mEnabled = enabled;
-    }
-
-    public int getIndex() {
-        return mIndex;
-    }
-
-    public String getGroup() {
-        return mGroup;
-    }
-
-    public String getDescription() {
-        return mDescription;
-    }
-
-    public boolean isEnabled() {
-        return mEnabled;
-    }
-
-    public String getDisplayText() {
-        if (mGroup == null || mGroup.equals(UNGROUPED_NAME))
-          return mDescription;
-        else
-          return String.format("(%s) %s", mGroup, mDescription);
-    }
-}
diff --git a/android/app/src/main/java/com/github/stenzek/duckstation/PreferenceHelpers.java b/android/app/src/main/java/com/github/stenzek/duckstation/PreferenceHelpers.java
deleted file mode 100644
index 99e9ad815..000000000
--- a/android/app/src/main/java/com/github/stenzek/duckstation/PreferenceHelpers.java
+++ /dev/null
@@ -1,85 +0,0 @@
-package com.github.stenzek.duckstation;
-
-import android.content.SharedPreferences;
-import android.util.ArraySet;
-
-import java.util.Set;
-
-public class PreferenceHelpers {
-    /**
-     * Clears all preferences in the specified section (starting with sectionName/).
-     * We really don't want to have to do this with JNI...
-     *
-     * @param prefs       Preferences object.
-     * @param sectionName Section to clear keys for.
-     */
-    public static void clearSection(SharedPreferences prefs, String sectionName) {
-        String testSectionName = sectionName + "/";
-        SharedPreferences.Editor editor = prefs.edit();
-        for (String keyName : prefs.getAll().keySet()) {
-            if (keyName.startsWith(testSectionName)) {
-                editor.remove(keyName);
-            }
-        }
-
-        editor.commit();
-    }
-
-    public static Set<String> getStringSet(SharedPreferences prefs, String keyName) {
-        Set<String> values = null;
-        try {
-            values = prefs.getStringSet(keyName, null);
-        } catch (Exception e) {
-            try {
-                String singleValue = prefs.getString(keyName, null);
-                if (singleValue != null) {
-                    values = new ArraySet<>();
-                    values.add(singleValue);
-                }
-            } catch (Exception e2) {
-
-            }
-        }
-
-        return values;
-    }
-
-    public static boolean addToStringList(SharedPreferences prefs, String keyName, String valueToAdd) {
-        Set<String> values = getStringSet(prefs, keyName);
-        if (values == null) {
-            values = new ArraySet<>();
-        } else {
-            // We need to copy it otherwise the put doesn't save.
-            Set<String> valuesCopy = new ArraySet<>();
-            valuesCopy.addAll(values);
-            values = valuesCopy;
-        }
-
-        final boolean result = values.add(valueToAdd);
-        prefs.edit().putStringSet(keyName, values).commit();
-        return result;
-    }
-
-    public static boolean removeFromStringList(SharedPreferences prefs, String keyName, String valueToRemove) {
-        Set<String> values = getStringSet(prefs, keyName);
-        if (values == null)
-            return false;
-
-        // We need to copy it otherwise the put doesn't save.
-        Set<String> valuesCopy = new ArraySet<>();
-        valuesCopy.addAll(values);
-        values = valuesCopy;
-
-        final boolean result = values.remove(valueToRemove);
-        prefs.edit().putStringSet(keyName, values).commit();
-        return result;
-    }
-
-    public static void setStringList(SharedPreferences prefs, String keyName, String[] values) {
-        Set<String> valueSet = new ArraySet<String>();
-        for (String value : values)
-            valueSet.add(value);
-
-        prefs.edit().putStringSet(keyName, valueSet).commit();
-    }
-}
diff --git a/android/app/src/main/java/com/github/stenzek/duckstation/PropertyListAdapter.java b/android/app/src/main/java/com/github/stenzek/duckstation/PropertyListAdapter.java
deleted file mode 100644
index 3f9a01565..000000000
--- a/android/app/src/main/java/com/github/stenzek/duckstation/PropertyListAdapter.java
+++ /dev/null
@@ -1,84 +0,0 @@
-package com.github.stenzek.duckstation;
-
-import android.content.Context;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.BaseAdapter;
-import android.widget.TextView;
-
-import java.util.ArrayList;
-
-public class PropertyListAdapter extends BaseAdapter {
-    private class Item {
-        public String key;
-        public String title;
-        public String value;
-
-        Item(String key, String title, String value) {
-            this.key = key;
-            this.title = title;
-            this.value = value;
-        }
-    }
-
-    private Context mContext;
-    private ArrayList<Item> mItems = new ArrayList<>();
-
-    public PropertyListAdapter(Context context) {
-        mContext = context;
-    }
-
-    public Item getItemByKey(String key) {
-        for (Item it : mItems) {
-            if (it.key.equals(key))
-                return it;
-        }
-
-        return null;
-    }
-
-    public int addItem(String key, String title, String value) {
-        if (getItemByKey(key) != null)
-            return -1;
-
-        Item it = new Item(key, title, value);
-        int position = mItems.size();
-        mItems.add(it);
-        return position;
-    }
-
-    public boolean removeItem(Item item) {
-        return mItems.remove(item);
-    }
-
-    @Override
-    public int getCount() {
-        return mItems.size();
-    }
-
-    @Override
-    public Object getItem(int position) {
-        return mItems.get(position);
-    }
-
-    @Override
-    public long getItemId(int position) {
-        return position;
-    }
-
-    @Override
-    public View getView(int position, View convertView, ViewGroup parent) {
-        if (convertView == null) {
-            convertView = LayoutInflater.from(mContext)
-                    .inflate(R.layout.layout_game_property_entry, parent, false);
-        }
-
-        TextView titleView = (TextView) convertView.findViewById(R.id.property_title);
-        TextView valueView = (TextView) convertView.findViewById(R.id.property_value);
-        Item prop = mItems.get(position);
-        titleView.setText(prop.title);
-        valueView.setText(prop.value);
-        return convertView;
-    }
-}
diff --git a/android/app/src/main/java/com/github/stenzek/duckstation/RatioPreference.java b/android/app/src/main/java/com/github/stenzek/duckstation/RatioPreference.java
deleted file mode 100644
index fe6fc5b41..000000000
--- a/android/app/src/main/java/com/github/stenzek/duckstation/RatioPreference.java
+++ /dev/null
@@ -1,198 +0,0 @@
-package com.github.stenzek.duckstation;
-
-import android.content.Context;
-import android.content.SharedPreferences;
-import android.content.res.Resources;
-import android.util.AttributeSet;
-import android.util.TypedValue;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.AdapterView;
-import android.widget.BaseAdapter;
-import android.widget.Spinner;
-import android.widget.TextView;
-
-import androidx.annotation.Nullable;
-import androidx.preference.Preference;
-import androidx.preference.PreferenceDataStore;
-import androidx.preference.PreferenceManager;
-import androidx.preference.PreferenceViewHolder;
-
-public class RatioPreference extends Preference {
-    private String mNumeratorKey;
-    private String mDenominatorKey;
-
-    private int mNumeratorValue = 1;
-    private int mDenominatorValue = 1;
-
-    private int mMinimumNumerator = 1;
-    private int mMaximumNumerator = 50;
-    private int mDefaultNumerator = 1;
-    private int mMinimumDenominator = 1;
-    private int mMaximumDenominator = 50;
-    private int mDefaultDenominator = 1;
-
-    private void initAttributes(AttributeSet attrs) {
-        for (int i = 0; i < attrs.getAttributeCount(); i++) {
-            final String key = attrs.getAttributeName(i);
-            if (key.equals("numeratorKey")) {
-                mNumeratorKey = attrs.getAttributeValue(i);
-            } else if (key.equals("minimumNumerator")) {
-                mMinimumNumerator = attrs.getAttributeIntValue(i, 1);
-            } else if (key.equals("maximumNumerator")) {
-                mMaximumNumerator = attrs.getAttributeIntValue(i, 1);
-            } else if (key.equals("defaultNumerator")) {
-                mDefaultNumerator = attrs.getAttributeIntValue(i, 1);
-            } else if(key.equals("denominatorKey")) {
-                mDenominatorKey = attrs.getAttributeValue(i);
-            } else if (key.equals("minimumDenominator")) {
-                mMinimumDenominator = attrs.getAttributeIntValue(i, 1);
-            } else if (key.equals("maximumDenominator")) {
-                mMaximumDenominator = attrs.getAttributeIntValue(i, 1);
-            } else if (key.equals("defaultDenominator")) {
-                mDefaultDenominator = attrs.getAttributeIntValue(i, 1);
-            }
-        }
-    }
-
-    public RatioPreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
-        super(context, attrs, defStyleAttr, defStyleRes);
-        setWidgetLayoutResource(R.layout.layout_ratio_preference);
-        initAttributes(attrs);
-    }
-
-    public RatioPreference(Context context, AttributeSet attrs, int defStyleAttr) {
-        super(context, attrs, defStyleAttr);
-        setWidgetLayoutResource(R.layout.layout_ratio_preference);
-        initAttributes(attrs);
-    }
-
-    public RatioPreference(Context context, AttributeSet attrs) {
-        super(context, attrs);
-        setWidgetLayoutResource(R.layout.layout_ratio_preference);
-        initAttributes(attrs);
-    }
-
-    public RatioPreference(Context context) {
-        super(context);
-        setWidgetLayoutResource(R.layout.layout_ratio_preference);
-    }
-
-    private void persistValues() {
-        final PreferenceDataStore dataStore = getPreferenceDataStore();
-        if (dataStore != null) {
-            if (mNumeratorKey != null)
-                dataStore.putInt(mNumeratorKey, mNumeratorValue);
-            if (mDenominatorKey != null)
-                dataStore.putInt(mDenominatorKey, mDenominatorValue);
-        } else {
-            SharedPreferences.Editor editor = getPreferenceManager().getSharedPreferences().edit();
-            if (mNumeratorKey != null)
-                editor.putInt(mNumeratorKey, mNumeratorValue);
-            if (mDenominatorKey != null)
-                editor.putInt(mDenominatorKey, mDenominatorValue);
-            editor.commit();
-        }
-    }
-
-    @Override
-    protected void onAttachedToHierarchy(PreferenceManager preferenceManager) {
-        super.onAttachedToHierarchy(preferenceManager);
-        setInitialValue();
-    }
-
-    private void setInitialValue() {
-        final PreferenceDataStore dataStore = getPreferenceDataStore();
-        if (dataStore != null) {
-            if (mNumeratorKey != null)
-                mNumeratorValue = dataStore.getInt(mNumeratorKey, mDefaultNumerator);
-            if (mDenominatorKey != null)
-                mDenominatorValue = dataStore.getInt(mDenominatorKey, mDefaultDenominator);
-        } else {
-            final SharedPreferences pm = getPreferenceManager().getSharedPreferences();
-            if (mNumeratorKey != null)
-                mNumeratorValue = pm.getInt(mNumeratorKey, mDefaultNumerator);
-            if (mDenominatorKey != null)
-                mDenominatorValue = pm.getInt(mDenominatorKey, mDefaultDenominator);
-        }
-    }
-
-    private static BaseAdapter generateDropdownItems(int min, int max) {
-        return new BaseAdapter() {
-            @Override
-            public int getCount() {
-                return (max - min) + 1;
-            }
-
-            @Override
-            public Object getItem(int position) {
-                return Integer.toString(min + position);
-            }
-
-            @Override
-            public long getItemId(int position) {
-                return position;
-            }
-
-            @Override
-            public View getView(int position, View convertView, ViewGroup parent) {
-                TextView view;
-                if (convertView != null) {
-                    view = (TextView) convertView;
-                } else {
-                    view = new TextView(parent.getContext());
-
-                    Resources r = parent.getResources();
-                    float px = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 10.0f, r.getDisplayMetrics());
-                    view.setPadding((int) px, (int) px, (int) px, (int) px);
-                }
-
-                view.setText(Integer.toString(min + position));
-                return view;
-            }
-        };
-    }
-
-    @Override
-    public void onBindViewHolder(PreferenceViewHolder holder) {
-        super.onBindViewHolder(holder);
-        holder.itemView.setClickable(false);
-
-        Spinner numeratorSpinner = (Spinner) holder.findViewById(R.id.numerator);
-        numeratorSpinner.setAdapter(generateDropdownItems(mMinimumNumerator, mMaximumNumerator));
-        numeratorSpinner.setSelection(mNumeratorValue - mMinimumNumerator);
-        numeratorSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
-            @Override
-            public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
-                final int newValue = position + mMinimumNumerator;
-                if (newValue != mNumeratorValue) {
-                    mNumeratorValue = newValue;
-                    persistValues();
-                }
-            }
-
-            @Override
-            public void onNothingSelected(AdapterView<?> parent) {
-            }
-        });
-        Spinner denominatorSpinner = (Spinner) holder.findViewById(R.id.denominator);
-        denominatorSpinner.setAdapter(generateDropdownItems(mMinimumDenominator, mMaximumDenominator));
-        denominatorSpinner.setSelection(mDenominatorValue - mMinimumDenominator);
-        denominatorSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
-            @Override
-            public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
-                final int newValue = position + mMinimumDenominator;
-                if (newValue != mDenominatorValue) {
-                    mDenominatorValue = newValue;
-                    persistValues();
-                }
-            }
-
-            @Override
-            public void onNothingSelected(AdapterView<?> parent) {
-            }
-        });
-    }
-
-
-}
diff --git a/android/app/src/main/java/com/github/stenzek/duckstation/SaveStateInfo.java b/android/app/src/main/java/com/github/stenzek/duckstation/SaveStateInfo.java
deleted file mode 100644
index 7acd33f32..000000000
--- a/android/app/src/main/java/com/github/stenzek/duckstation/SaveStateInfo.java
+++ /dev/null
@@ -1,151 +0,0 @@
-package com.github.stenzek.duckstation;
-
-import android.content.Context;
-import android.graphics.Bitmap;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.BaseAdapter;
-import android.widget.ImageView;
-import android.widget.TextView;
-
-import java.nio.ByteBuffer;
-
-public class SaveStateInfo {
-    private String mPath;
-    private String mGameTitle;
-    private String mGameCode;
-    private String mMediaPath;
-    private String mTimestamp;
-    private int mSlot;
-    private boolean mGlobal;
-    private Bitmap mScreenshot;
-
-    public SaveStateInfo(String path, String gameTitle, String gameCode, String mediaPath, String timestamp, int slot, boolean global,
-                         int screenshotWidth, int screenshotHeight, byte[] screenshotData) {
-        mPath = path;
-        mGameTitle = gameTitle;
-        mGameCode = gameCode;
-        mMediaPath = mediaPath;
-        mTimestamp = timestamp;
-        mSlot = slot;
-        mGlobal = global;
-
-        if (screenshotData != null) {
-            try {
-                mScreenshot = Bitmap.createBitmap(screenshotWidth, screenshotHeight, Bitmap.Config.ARGB_8888);
-                mScreenshot.copyPixelsFromBuffer(ByteBuffer.wrap(screenshotData));
-            } catch (Exception e) {
-                mScreenshot = null;
-            }
-        }
-    }
-
-    public boolean exists() {
-        return mPath != null;
-    }
-
-    public String getPath() {
-        return mPath;
-    }
-
-    public String getGameTitle() {
-        return mGameTitle;
-    }
-
-    public String getGameCode() {
-        return mGameCode;
-    }
-
-    public String getMediaPath() {
-        return mMediaPath;
-    }
-
-    public String getTimestamp() {
-        return mTimestamp;
-    }
-
-    public int getSlot() {
-        return mSlot;
-    }
-
-    public boolean isGlobal() {
-        return mGlobal;
-    }
-
-    public Bitmap getScreenshot() {
-        return mScreenshot;
-    }
-
-    private void fillView(Context context, View view) {
-        ImageView imageView = (ImageView) view.findViewById(R.id.image);
-        TextView summaryView = (TextView) view.findViewById(R.id.summary);
-        TextView gameView = (TextView) view.findViewById(R.id.game);
-        TextView pathView = (TextView) view.findViewById(R.id.path);
-        TextView timestampView = (TextView) view.findViewById(R.id.timestamp);
-
-        if (mScreenshot != null)
-            imageView.setImageBitmap(mScreenshot);
-        else
-            imageView.setImageDrawable(context.getDrawable(R.drawable.ic_baseline_not_interested_60));
-
-        String summaryText;
-        if (mGlobal)
-            summaryView.setText(String.format(context.getString(R.string.save_state_info_global_save_n), mSlot));
-        else if (mSlot == 0)
-            summaryView.setText(R.string.save_state_info_quick_save);
-        else
-            summaryView.setText(String.format(context.getString(R.string.save_state_info_game_save_n), mSlot));
-
-        if (exists()) {
-            gameView.setText(String.format("%s - %s", mGameCode, mGameTitle));
-
-            int lastSlashPosition = mMediaPath.lastIndexOf('/');
-            if (lastSlashPosition >= 0)
-                pathView.setText(mMediaPath.substring(lastSlashPosition + 1));
-            else
-                pathView.setText(mMediaPath);
-
-            timestampView.setText(mTimestamp);
-        } else {
-            gameView.setText(R.string.save_state_info_slot_is_empty);
-            pathView.setText("");
-            timestampView.setText("");
-        }
-    }
-
-    public static class ListAdapter extends BaseAdapter {
-        private final Context mContext;
-        private final SaveStateInfo[] mInfos;
-
-        public ListAdapter(Context context, SaveStateInfo[] infos) {
-            mContext = context;
-            mInfos = infos;
-        }
-
-        @Override
-        public int getCount() {
-            return mInfos.length;
-        }
-
-        @Override
-        public Object getItem(int position) {
-            return mInfos[position];
-        }
-
-        @Override
-        public long getItemId(int position) {
-            return position;
-        }
-
-        @Override
-        public View getView(int position, View convertView, ViewGroup parent) {
-            if (convertView == null) {
-                convertView = LayoutInflater.from(mContext).inflate(R.layout.save_state_view_entry, parent, false);
-            }
-
-            mInfos[position].fillView(mContext, convertView);
-            return convertView;
-        }
-    }
-}
diff --git a/android/app/src/main/java/com/github/stenzek/duckstation/SettingsActivity.java b/android/app/src/main/java/com/github/stenzek/duckstation/SettingsActivity.java
deleted file mode 100644
index 47a9313c9..000000000
--- a/android/app/src/main/java/com/github/stenzek/duckstation/SettingsActivity.java
+++ /dev/null
@@ -1,38 +0,0 @@
-package com.github.stenzek.duckstation;
-
-import android.os.Bundle;
-import android.view.MenuItem;
-
-import androidx.annotation.NonNull;
-import androidx.appcompat.app.ActionBar;
-import androidx.appcompat.app.AppCompatActivity;
-import androidx.fragment.app.Fragment;
-import androidx.preference.PreferenceFragmentCompat;
-import androidx.viewpager2.adapter.FragmentStateAdapter;
-
-public class SettingsActivity extends AppCompatActivity {
-
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(null);
-        setContentView(R.layout.settings_activity);
-        getSupportFragmentManager()
-                .beginTransaction()
-                .replace(R.id.settings, new SettingsCollectionFragment())
-                .commit();
-        ActionBar actionBar = getSupportActionBar();
-        if (actionBar != null) {
-            actionBar.setDisplayHomeAsUpEnabled(true);
-        }
-    }
-
-    @Override
-    public boolean onOptionsItemSelected(@NonNull MenuItem item) {
-        if (item.getItemId() == android.R.id.home) {
-            onBackPressed();
-            return true;
-        }
-
-        return super.onOptionsItemSelected(item);
-    }
-}
\ No newline at end of file
diff --git a/android/app/src/main/java/com/github/stenzek/duckstation/SettingsCollectionFragment.java b/android/app/src/main/java/com/github/stenzek/duckstation/SettingsCollectionFragment.java
deleted file mode 100644
index b5aa1138b..000000000
--- a/android/app/src/main/java/com/github/stenzek/duckstation/SettingsCollectionFragment.java
+++ /dev/null
@@ -1,90 +0,0 @@
-package com.github.stenzek.duckstation;
-
-import android.os.Bundle;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.fragment.app.Fragment;
-import androidx.preference.PreferenceFragmentCompat;
-import androidx.viewpager2.adapter.FragmentStateAdapter;
-import androidx.viewpager2.widget.ViewPager2;
-
-import com.google.android.material.tabs.TabLayout;
-import com.google.android.material.tabs.TabLayoutMediator;
-
-public class SettingsCollectionFragment extends Fragment {
-    private SettingsCollectionAdapter adapter;
-    private ViewPager2 viewPager;
-
-    @Nullable
-    @Override
-    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
-        return inflater.inflate(R.layout.fragment_settings_collection, container, false);
-    }
-
-    @Override
-    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
-        adapter = new SettingsCollectionAdapter(this);
-        viewPager = view.findViewById(R.id.view_pager);
-        viewPager.setAdapter(adapter);
-
-        TabLayout tabLayout = view.findViewById(R.id.tab_layout);
-        new TabLayoutMediator(tabLayout, viewPager,
-                (tab, position) -> tab.setText(getResources().getStringArray(R.array.settings_tabs)[position])
-        ).attach();
-    }
-
-    public static class SettingsFragment extends PreferenceFragmentCompat {
-        private final int resourceId;
-
-        public SettingsFragment(int resourceId) {
-            this.resourceId = resourceId;
-        }
-
-        @Override
-        public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
-            setPreferencesFromResource(resourceId, rootKey);
-        }
-    }
-
-    public static class SettingsCollectionAdapter extends FragmentStateAdapter {
-        public SettingsCollectionAdapter(@NonNull Fragment fragment) {
-            super(fragment);
-        }
-
-        @NonNull
-        @Override
-        public Fragment createFragment(int position) {
-            switch (position) {
-                case 0:     // General
-                    return new SettingsFragment(R.xml.general_preferences);
-
-                case 1:     // Display
-                    return new SettingsFragment(R.xml.display_preferences);
-
-                case 2:     // Audio
-                    return new SettingsFragment(R.xml.audio_preferences);
-
-                case 3:     // Enhancements
-                    return new SettingsFragment(R.xml.enhancements_preferences);
-
-                case 4:     // Achievements
-                    return new AchievementSettingsFragment();
-
-                case 5:     // Advanced
-                    return new SettingsFragment(R.xml.advanced_preferences);
-
-                default:
-                    return new Fragment();
-            }
-        }
-
-        @Override
-        public int getItemCount() {
-            return 6;
-        }
-    }
-}
diff --git a/android/app/src/main/java/com/github/stenzek/duckstation/TouchscreenControllerAxisView.java b/android/app/src/main/java/com/github/stenzek/duckstation/TouchscreenControllerAxisView.java
deleted file mode 100644
index eca099791..000000000
--- a/android/app/src/main/java/com/github/stenzek/duckstation/TouchscreenControllerAxisView.java
+++ /dev/null
@@ -1,191 +0,0 @@
-package com.github.stenzek.duckstation;
-
-import android.content.Context;
-import android.graphics.Canvas;
-import android.graphics.drawable.Drawable;
-import android.util.AttributeSet;
-import android.view.View;
-
-public final class TouchscreenControllerAxisView extends View {
-    private Drawable mBaseDrawable;
-    private Drawable mStickUnpressedDrawable;
-    private Drawable mStickPressedDrawable;
-    private boolean mPressed = false;
-    private int mPointerId = 0;
-    private float mXValue = 0.0f;
-    private float mYValue = 0.0f;
-    private int mDrawXPos = 0;
-    private int mDrawYPos = 0;
-
-    private String mConfigName;
-    private boolean mDefaultVisibility = true;
-
-    private int mControllerIndex = -1;
-    private int mXAxisCode = -1;
-    private int mYAxisCode = -1;
-    private int mLeftButtonCode = -1;
-    private int mRightButtonCode = -1;
-    private int mUpButtonCode = -1;
-    private int mDownButtonCode = -1;
-
-    public TouchscreenControllerAxisView(Context context) {
-        super(context);
-        init();
-    }
-
-    public TouchscreenControllerAxisView(Context context, AttributeSet attrs) {
-        super(context, attrs);
-        init();
-    }
-
-    public TouchscreenControllerAxisView(Context context, AttributeSet attrs, int defStyle) {
-        super(context, attrs, defStyle);
-        init();
-    }
-
-    private void init() {
-        mBaseDrawable = getContext().getDrawable(R.drawable.ic_controller_analog_base);
-        mBaseDrawable.setCallback(this);
-        mStickUnpressedDrawable = getContext().getDrawable(R.drawable.ic_controller_analog_stick_unpressed);
-        mStickUnpressedDrawable.setCallback(this);
-        mStickPressedDrawable = getContext().getDrawable(R.drawable.ic_controller_analog_stick_pressed);
-        mStickPressedDrawable.setCallback(this);
-    }
-
-    public String getConfigName() {
-        return mConfigName;
-    }
-    public void setConfigName(String configName) {
-        mConfigName = configName;
-    }
-
-    public boolean getDefaultVisibility() { return mDefaultVisibility; }
-    public void setDefaultVisibility(boolean visibility) { mDefaultVisibility = visibility; }
-
-    public void setControllerAxis(int controllerIndex, int xCode, int yCode) {
-        mControllerIndex = controllerIndex;
-        mXAxisCode = xCode;
-        mYAxisCode = yCode;
-        mLeftButtonCode = -1;
-        mRightButtonCode = -1;
-        mUpButtonCode = -1;
-        mDownButtonCode = -1;
-    }
-
-    public void setControllerButtons(int controllerIndex, int leftCode, int rightCode, int upCode, int downCode) {
-        mControllerIndex = controllerIndex;
-        mXAxisCode = -1;
-        mYAxisCode = -1;
-        mLeftButtonCode = leftCode;
-        mRightButtonCode = rightCode;
-        mUpButtonCode = upCode;
-        mDownButtonCode = downCode;
-    }
-
-    public void setUnpressed() {
-        if (!mPressed && mXValue == 0.0f && mYValue == 0.0f)
-            return;
-
-        mPressed = false;
-        mXValue = 0.0f;
-        mYValue = 0.0f;
-        mDrawXPos = 0;
-        mDrawYPos = 0;
-        invalidate();
-        updateControllerState();
-    }
-
-    public void setPressed(int pointerId, float pointerX, float pointerY) {
-        final float dx = (pointerX / getScaleX()) - (float) (getWidth() / 2);
-        final float dy = (pointerY / getScaleY()) - (float) (getHeight() / 2);
-        // Log.i("SetPressed", String.format("px=%f,py=%f dx=%f,dy=%f", pointerX, pointerY, dx, dy));
-
-        final float pointerDistance = Math.max(Math.abs(dx), Math.abs(dy));
-        final float angle = (float) Math.atan2((double) dy, (double) dx);
-
-        final float maxDistance = (float) Math.min((getWidth() - getPaddingLeft() - getPaddingRight()) / 2, (getHeight() - getPaddingTop() - getPaddingBottom()) / 2);
-        final float length = Math.min(pointerDistance / maxDistance, 1.0f);
-        // Log.i("SetPressed", String.format("pointerDist=%f,angle=%f,w=%d,h=%d,maxDist=%f,length=%f", pointerDistance, angle, getWidth(), getHeight(), maxDistance, length));
-
-        final float xValue = (float) Math.cos((double) angle) * length;
-        final float yValue = (float) Math.sin((double) angle) * length;
-        mDrawXPos = (int) (xValue * maxDistance);
-        mDrawYPos = (int) (yValue * maxDistance);
-
-        boolean doUpdate = (pointerId != mPointerId || !mPressed || (xValue != mXValue || yValue != mYValue));
-        mPointerId = pointerId;
-        mPressed = true;
-        mXValue = xValue;
-        mYValue = yValue;
-        // Log.i("SetPressed", String.format("xval=%f,yval=%f,drawX=%d,drawY=%d", mXValue, mYValue, mDrawXPos, mDrawYPos));
-
-        if (doUpdate) {
-            invalidate();
-            updateControllerState();
-        }
-    }
-
-    private void updateControllerState() {
-        final float BUTTON_THRESHOLD = 0.33f;
-
-        AndroidHostInterface hostInterface = AndroidHostInterface.getInstance();
-        if (mXAxisCode >= 0)
-            hostInterface.setControllerAxisState(mControllerIndex, mXAxisCode, mXValue);
-        if (mYAxisCode >= 0)
-            hostInterface.setControllerAxisState(mControllerIndex, mYAxisCode, mYValue);
-
-        if (mLeftButtonCode >= 0)
-            hostInterface.setControllerButtonState(mControllerIndex, mLeftButtonCode, (mXValue <= -BUTTON_THRESHOLD));
-        if (mRightButtonCode >= 0)
-            hostInterface.setControllerButtonState(mControllerIndex, mRightButtonCode, (mXValue >= BUTTON_THRESHOLD));
-        if (mUpButtonCode >= 0)
-            hostInterface.setControllerButtonState(mControllerIndex, mUpButtonCode, (mYValue <= -BUTTON_THRESHOLD));
-        if (mDownButtonCode >= 0)
-            hostInterface.setControllerButtonState(mControllerIndex, mDownButtonCode, (mYValue >= BUTTON_THRESHOLD));
-    }
-
-    @Override
-    protected void onDraw(Canvas canvas) {
-        super.onDraw(canvas);
-
-        final int paddingLeft = getPaddingLeft();
-        final int paddingTop = getPaddingTop();
-        final int paddingRight = getPaddingRight();
-        final int paddingBottom = getPaddingBottom();
-        final int contentWidth = getWidth() - paddingLeft - paddingRight;
-        final int contentHeight = getHeight() - paddingTop - paddingBottom;
-
-        mBaseDrawable.setBounds(paddingLeft, paddingTop,
-                paddingLeft + contentWidth, paddingTop + contentHeight);
-        mBaseDrawable.draw(canvas);
-
-        final int stickWidth = contentWidth / 3;
-        final int stickHeight = contentHeight / 3;
-        final int halfStickWidth = stickWidth / 2;
-        final int halfStickHeight = stickHeight / 2;
-        final int centerX = getWidth() / 2;
-        final int centerY = getHeight() / 2;
-        final int drawX = centerX + mDrawXPos;
-        final int drawY = centerY + mDrawYPos;
-
-        Drawable stickDrawable = mPressed ? mStickPressedDrawable : mStickUnpressedDrawable;
-        stickDrawable.setBounds(drawX - halfStickWidth, drawY - halfStickHeight, drawX + halfStickWidth, drawY + halfStickHeight);
-        stickDrawable.draw(canvas);
-    }
-
-    public boolean isPressed() {
-        return mPressed;
-    }
-
-    public boolean hasPointerId() {
-        return mPointerId >= 0;
-    }
-
-    public int getPointerId() {
-        return mPointerId;
-    }
-
-    public void setPointerId(int mPointerId) {
-        this.mPointerId = mPointerId;
-    }
-}
diff --git a/android/app/src/main/java/com/github/stenzek/duckstation/TouchscreenControllerButtonView.java b/android/app/src/main/java/com/github/stenzek/duckstation/TouchscreenControllerButtonView.java
deleted file mode 100644
index b8f70a8a5..000000000
--- a/android/app/src/main/java/com/github/stenzek/duckstation/TouchscreenControllerButtonView.java
+++ /dev/null
@@ -1,204 +0,0 @@
-package com.github.stenzek.duckstation;
-
-import android.content.Context;
-import android.content.res.TypedArray;
-import android.graphics.Canvas;
-import android.graphics.drawable.Drawable;
-import android.util.AttributeSet;
-import android.util.TypedValue;
-import android.view.HapticFeedbackConstants;
-import android.view.View;
-
-/**
- * TODO: document your custom view class.
- */
-public final class TouchscreenControllerButtonView extends View {
-    public enum Hotkey
-    {
-        NONE,
-        FAST_FORWARD,
-        ANALOG_TOGGLE,
-        OPEN_PAUSE_MENU,
-        QUICK_LOAD,
-        QUICK_SAVE
-    }
-
-    private Drawable mUnpressedDrawable;
-    private Drawable mPressedDrawable;
-    private boolean mPressed = false;
-    private boolean mHapticFeedback = false;
-    private int mControllerIndex = -1;
-    private int mButtonCode = -1;
-    private int mAutoFireSlot = -1;
-    private Hotkey mHotkey = Hotkey.NONE;
-    private String mConfigName;
-    private boolean mDefaultVisibility = true;
-    private boolean mIsGlidable = true;
-
-    public TouchscreenControllerButtonView(Context context) {
-        super(context);
-        init(context, null, 0);
-    }
-
-    public TouchscreenControllerButtonView(Context context, AttributeSet attrs) {
-        super(context, attrs);
-        init(context, attrs, 0);
-    }
-
-    public TouchscreenControllerButtonView(Context context, AttributeSet attrs, int defStyle) {
-        super(context, attrs, defStyle);
-        init(context, attrs, defStyle);
-    }
-
-    private void init(Context context, AttributeSet attrs, int defStyle) {
-        // Load attributes
-        final TypedArray a = getContext().obtainStyledAttributes(
-                attrs, R.styleable.TouchscreenControllerButtonView, defStyle, 0);
-
-        if (a.hasValue(R.styleable.TouchscreenControllerButtonView_unpressedDrawable)) {
-            mUnpressedDrawable = a.getDrawable(R.styleable.TouchscreenControllerButtonView_unpressedDrawable);
-            mUnpressedDrawable.setCallback(this);
-        }
-
-        if (a.hasValue(R.styleable.TouchscreenControllerButtonView_pressedDrawable)) {
-            mPressedDrawable = a.getDrawable(R.styleable.TouchscreenControllerButtonView_pressedDrawable);
-            mPressedDrawable.setCallback(this);
-        }
-
-        a.recycle();
-    }
-
-    @Override
-    protected void onDraw(Canvas canvas) {
-        super.onDraw(canvas);
-
-        int leftBounds = 0;
-        int rightBounds = leftBounds + getWidth();
-        int topBounds = 0;
-        int bottomBounds = topBounds + getHeight();
-
-        if (mPressed) {
-            final int expandSize = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
-                    10.0f, getResources().getDisplayMetrics());
-            leftBounds -= expandSize;
-            rightBounds += expandSize;
-            topBounds -= expandSize;
-            bottomBounds += expandSize;
-        }
-
-        // Draw the example drawable on top of the text.
-        Drawable drawable = mPressed ? mPressedDrawable : mUnpressedDrawable;
-        if (drawable != null) {
-            drawable.setBounds(leftBounds, topBounds, rightBounds, bottomBounds);
-            drawable.draw(canvas);
-        }
-    }
-
-    public boolean isPressed() {
-        return mPressed;
-    }
-
-    public void setPressed(boolean pressed) {
-        if (pressed == mPressed)
-            return;
-
-        mPressed = pressed;
-        invalidate();
-        updateControllerState();
-
-        if (mHapticFeedback) {
-            performHapticFeedback(pressed ? HapticFeedbackConstants.VIRTUAL_KEY : HapticFeedbackConstants.VIRTUAL_KEY_RELEASE);
-        }
-    }
-
-    public void setButtonCode(int controllerIndex, int code) {
-        mControllerIndex = controllerIndex;
-        mButtonCode = code;
-    }
-
-    public void setAutoFireSlot(int controllerIndex, int slot) {
-        mControllerIndex = controllerIndex;
-        mAutoFireSlot = slot;
-    }
-
-    public void setHotkey(Hotkey hotkey) {
-        mHotkey = hotkey;
-    }
-
-    public String getConfigName() {
-        return mConfigName;
-    }
-    public void setConfigName(String name) {
-        mConfigName = name;
-    }
-
-    public boolean getIsGlidable() { return mIsGlidable; }
-    public void setIsGlidable(boolean isGlidable) { mIsGlidable = isGlidable; }
-
-    public boolean getDefaultVisibility() { return mDefaultVisibility; }
-    public void setDefaultVisibility(boolean visibility) { mDefaultVisibility = visibility; }
-
-    public void setHapticFeedback(boolean enabled) {
-        mHapticFeedback = enabled;
-    }
-
-    private void updateControllerState() {
-        final AndroidHostInterface hi = AndroidHostInterface.getInstance();
-        if (mButtonCode >= 0)
-            hi.setControllerButtonState(mControllerIndex, mButtonCode, mPressed);
-        if (mAutoFireSlot >= 0)
-            hi.setControllerAutoFireState(mControllerIndex, mAutoFireSlot, mPressed);
-
-        switch (mHotkey)
-        {
-            case FAST_FORWARD: {
-                hi.setFastForwardEnabled(mPressed);
-            }
-            break;
-
-            case ANALOG_TOGGLE: {
-                if (!mPressed)
-                    hi.toggleControllerAnalogMode();
-            }
-            break;
-
-            case OPEN_PAUSE_MENU: {
-                if (!mPressed)
-                    hi.getEmulationActivity().openPauseMenu();
-            }
-            break;
-
-            case QUICK_LOAD: {
-                if (!mPressed)
-                    hi.loadState(false, 0);
-            }
-            break;
-
-            case QUICK_SAVE: {
-                if (!mPressed)
-                    hi.saveState(false, 0);
-            }
-            break;
-
-            case NONE:
-            default:
-                break;
-        }
-    }
-
-    public Drawable getPressedDrawable() {
-        return mPressedDrawable;
-    }
-
-    public void setPressedDrawable(Drawable pressedDrawable) {
-        mPressedDrawable = pressedDrawable;
-    }
-
-    public Drawable getUnpressedDrawable() {
-        return mUnpressedDrawable;
-    }
-
-    public void setUnpressedDrawable(Drawable unpressedDrawable) {
-        mUnpressedDrawable = unpressedDrawable;
-    }
-}
diff --git a/android/app/src/main/java/com/github/stenzek/duckstation/TouchscreenControllerDPadView.java b/android/app/src/main/java/com/github/stenzek/duckstation/TouchscreenControllerDPadView.java
deleted file mode 100644
index 797abb267..000000000
--- a/android/app/src/main/java/com/github/stenzek/duckstation/TouchscreenControllerDPadView.java
+++ /dev/null
@@ -1,178 +0,0 @@
-package com.github.stenzek.duckstation;
-
-import android.content.Context;
-import android.graphics.Canvas;
-import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.util.TypedValue;
-import android.view.View;
-
-public final class TouchscreenControllerDPadView extends View {
-    private static final int NUM_DIRECTIONS = 4;
-    private static final int NUM_POSITIONS = 8;
-    private static final int DIRECTION_UP = 0;
-    private static final int DIRECTION_RIGHT = 1;
-    private static final int DIRECTION_DOWN = 2;
-    private static final int DIRECTION_LEFT = 3;
-
-    private final Drawable[] mUnpressedDrawables = new Drawable[NUM_DIRECTIONS];
-    private final Drawable[] mPressedDrawables = new Drawable[NUM_DIRECTIONS];
-    private final int[] mDirectionCodes = new int[] { -1, -1, -1, -1 };
-    private final boolean[] mDirectionStates = new boolean[NUM_DIRECTIONS];
-
-    private boolean mPressed = false;
-    private int mPointerId = 0;
-    private int mPointerX = 0;
-    private int mPointerY = 0;
-
-    private String mConfigName;
-    private boolean mDefaultVisibility = true;
-
-    private int mControllerIndex = -1;
-
-    private static final int[][] DRAWABLES = {
-            {R.drawable.ic_controller_up_button,R.drawable.ic_controller_up_button_pressed},
-            {R.drawable.ic_controller_right_button,R.drawable.ic_controller_right_button_pressed},
-            {R.drawable.ic_controller_down_button,R.drawable.ic_controller_down_button_pressed},
-            {R.drawable.ic_controller_left_button,R.drawable.ic_controller_left_button_pressed},
-    };
-
-
-    public TouchscreenControllerDPadView(Context context) {
-        super(context);
-        init();
-    }
-
-    public TouchscreenControllerDPadView(Context context, AttributeSet attrs) {
-        super(context, attrs);
-        init();
-    }
-
-    public TouchscreenControllerDPadView(Context context, AttributeSet attrs, int defStyle) {
-        super(context, attrs, defStyle);
-        init();
-    }
-
-    private void init() {
-        for (int i = 0; i < NUM_DIRECTIONS; i++) {
-            mUnpressedDrawables[i] = getContext().getDrawable(DRAWABLES[i][0]);
-            mPressedDrawables[i] = getContext().getDrawable(DRAWABLES[i][1]);
-        }
-    }
-
-    public String getConfigName() {
-        return mConfigName;
-    }
-    public void setConfigName(String configName) {
-        mConfigName = configName;
-    }
-
-    public boolean getDefaultVisibility() { return mDefaultVisibility; }
-    public void setDefaultVisibility(boolean visibility) { mDefaultVisibility = visibility; }
-
-    public void setControllerButtons(int controllerIndex, int leftCode, int rightCode, int upCode, int downCode) {
-        mControllerIndex = controllerIndex;
-        mDirectionCodes[DIRECTION_LEFT] = leftCode;
-        mDirectionCodes[DIRECTION_RIGHT] = rightCode;
-        mDirectionCodes[DIRECTION_UP] = upCode;
-        mDirectionCodes[DIRECTION_DOWN] = downCode;
-    }
-
-    public void setUnpressed() {
-        if (!mPressed && mPointerX == 0 && mPointerY == 0)
-            return;
-
-        mPressed = false;
-        mPointerX = 0;
-        mPointerY = 0;
-        updateControllerState();
-        invalidate();
-    }
-
-    public void setPressed(int pointerId, int pointerX, int pointerY) {
-        final int posX = (int)(pointerX / getScaleX());
-        final int posY = (int)(pointerY / getScaleY());
-
-        boolean doUpdate = (pointerId != mPointerId || !mPressed || (posX != mPointerX || posY != mPointerY));
-        mPointerId = pointerId;
-        mPointerX = posX;
-        mPointerY = posY;
-        mPressed = true;
-
-        if (doUpdate) {
-            updateControllerState();
-            invalidate();
-        }
-    }
-
-    private void updateControllerState() {
-        final int subX = mPointerX / (getWidth() / 3);
-        final int subY = mPointerY / (getHeight() / 3);
-
-        mDirectionStates[DIRECTION_UP] = (mPressed && subY == 0);
-        mDirectionStates[DIRECTION_RIGHT] = (mPressed && subX == 2);
-        mDirectionStates[DIRECTION_DOWN] = (mPressed && subY == 2);
-        mDirectionStates[DIRECTION_LEFT] = (mPressed && subX == 0);
-
-        AndroidHostInterface hostInterface = AndroidHostInterface.getInstance();
-        for (int i = 0; i < NUM_DIRECTIONS; i++) {
-            if (mDirectionCodes[i] >= 0)
-                hostInterface.setControllerButtonState(mControllerIndex, mDirectionCodes[i], mDirectionStates[i]);
-        }
-    }
-
-    private void drawDirection(int direction, int subX, int subY, Canvas canvas, int buttonWidth, int buttonHeight) {
-        int leftBounds = subX * buttonWidth;
-        int rightBounds = leftBounds + buttonWidth;
-        int topBounds = subY * buttonHeight;
-        int bottomBounds = topBounds + buttonHeight;
-
-        if (mDirectionStates[direction]) {
-            final int expandSize = (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
-                    10.0f, getResources().getDisplayMetrics());
-            leftBounds -= expandSize;
-            rightBounds += expandSize;
-            topBounds -= expandSize;
-            bottomBounds += expandSize;
-        }
-
-        final Drawable drawable = mDirectionStates[direction] ? mPressedDrawables[direction] : mUnpressedDrawables[direction];
-        drawable.setBounds(leftBounds, topBounds, rightBounds, bottomBounds);
-        drawable.draw(canvas);
-    }
-
-    @Override
-    protected void onDraw(Canvas canvas) {
-        super.onDraw(canvas);
-
-        final int width = getWidth();
-        final int height = getHeight();
-
-        // Divide it into thirds - draw between.
-        final int buttonWidth = width / 3;
-        final int buttonHeight = height / 3;
-
-        drawDirection(DIRECTION_UP, 1, 0, canvas, buttonWidth, buttonHeight);
-        drawDirection(DIRECTION_RIGHT, 2, 1, canvas, buttonWidth, buttonHeight);
-        drawDirection(DIRECTION_DOWN, 1, 2, canvas, buttonWidth, buttonHeight);
-        drawDirection(DIRECTION_LEFT, 0, 1, canvas, buttonWidth, buttonHeight);
-    }
-
-    public boolean isPressed() {
-        return mPressed;
-    }
-
-    public boolean hasPointerId() {
-        return mPointerId >= 0;
-    }
-
-    public int getPointerId() {
-        return mPointerId;
-    }
-
-    public void setPointerId(int mPointerId) {
-        this.mPointerId = mPointerId;
-    }
-}
diff --git a/android/app/src/main/java/com/github/stenzek/duckstation/TouchscreenControllerView.java b/android/app/src/main/java/com/github/stenzek/duckstation/TouchscreenControllerView.java
deleted file mode 100644
index 137e0bc75..000000000
--- a/android/app/src/main/java/com/github/stenzek/duckstation/TouchscreenControllerView.java
+++ /dev/null
@@ -1,858 +0,0 @@
-package com.github.stenzek.duckstation;
-
-import android.content.Context;
-import android.content.SharedPreferences;
-import android.content.res.Configuration;
-import android.graphics.Rect;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.util.TypedValue;
-import android.view.LayoutInflater;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.Button;
-import android.widget.FrameLayout;
-import android.widget.SeekBar;
-
-import androidx.appcompat.app.AlertDialog;
-import androidx.constraintlayout.widget.ConstraintLayout;
-import androidx.preference.PreferenceManager;
-
-import java.util.ArrayList;
-import java.util.Map;
-import java.util.HashMap;
-
-/**
- * TODO: document your custom view class.
- */
-public class TouchscreenControllerView extends FrameLayout {
-    public static final int DEFAULT_OPACITY = 100;
-
-    public static final float MIN_VIEW_SCALE = 0.25f;
-    public static final float MAX_VIEW_SCALE = 10.0f;
-
-    public enum EditMode {
-        NONE,
-        POSITION,
-        SCALE
-    }
-
-    private int mControllerIndex;
-    private String mControllerType;
-    private String mViewType;
-    private View mMainView;
-    private ArrayList<TouchscreenControllerButtonView> mButtonViews = new ArrayList<>();
-    private ArrayList<TouchscreenControllerAxisView> mAxisViews = new ArrayList<>();
-    private TouchscreenControllerDPadView mDPadView = null;
-    private int mPointerButtonCode = -1;
-    private int mPointerPointerId = -1;
-    private boolean mHapticFeedback;
-    private String mLayoutOrientation;
-    private EditMode mEditMode = EditMode.NONE;
-    private View mMovingView = null;
-    private String mMovingName = null;
-    private float mMovingLastX = 0.0f;
-    private float mMovingLastY = 0.0f;
-    private float mMovingLastScale = 0.0f;
-    private ConstraintLayout mEditLayout = null;
-    private int mOpacity = 100;
-    private Map<Integer, View> mGlidePairs = new HashMap<>();
-
-    public TouchscreenControllerView(Context context) {
-        super(context);
-        setFocusable(false);
-        setFocusableInTouchMode(false);
-    }
-
-    public TouchscreenControllerView(Context context, AttributeSet attrs) {
-        super(context, attrs);
-    }
-
-    public TouchscreenControllerView(Context context, AttributeSet attrs, int defStyle) {
-        super(context, attrs, defStyle);
-    }
-
-    private String getConfigKeyForXTranslation(String name) {
-        return String.format("TouchscreenController/%s/%s%sXTranslation", mViewType, name, mLayoutOrientation);
-    }
-
-    private String getConfigKeyForYTranslation(String name) {
-        return String.format("TouchscreenController/%s/%s%sYTranslation", mViewType, name, mLayoutOrientation);
-    }
-
-    private String getConfigKeyForScale(String name) {
-        return String.format("TouchscreenController/%s/%s%sScale", mViewType, name, mLayoutOrientation);
-    }
-
-    private String getConfigKeyForVisibility(String name) {
-        return String.format("TouchscreenController/%s/%s%sVisible", mViewType, name, mLayoutOrientation);
-    }
-
-    private void saveSettingsForButton(String name, View view) {
-        final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getContext());
-        final SharedPreferences.Editor editor = prefs.edit();
-        editor.putFloat(getConfigKeyForXTranslation(name), view.getTranslationX());
-        editor.putFloat(getConfigKeyForYTranslation(name), view.getTranslationY());
-        editor.putFloat(getConfigKeyForScale(name), view.getScaleX());
-        editor.commit();
-    }
-
-    private void saveVisibilityForButton(String name, boolean visible) {
-        final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getContext());
-        final SharedPreferences.Editor editor = prefs.edit();
-        editor.putBoolean(getConfigKeyForVisibility(name), visible);
-        editor.commit();
-    }
-
-    private void clearTranslationForAllButtons() {
-        final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getContext());
-        final SharedPreferences.Editor editor = prefs.edit();
-
-        for (TouchscreenControllerButtonView buttonView : mButtonViews) {
-            editor.remove(getConfigKeyForXTranslation(buttonView.getConfigName()));
-            editor.remove(getConfigKeyForYTranslation(buttonView.getConfigName()));
-            editor.remove(getConfigKeyForScale(buttonView.getConfigName()));
-            buttonView.setTranslationX(0.0f);
-            buttonView.setTranslationY(0.0f);
-            buttonView.setScaleX(1.0f);
-            buttonView.setScaleY(1.0f);
-        }
-
-        for (TouchscreenControllerAxisView axisView : mAxisViews) {
-            editor.remove(getConfigKeyForXTranslation(axisView.getConfigName()));
-            editor.remove(getConfigKeyForYTranslation(axisView.getConfigName()));
-            editor.remove(getConfigKeyForScale(axisView.getConfigName()));
-            axisView.setTranslationX(0.0f);
-            axisView.setTranslationY(0.0f);
-            axisView.setScaleX(1.0f);
-            axisView.setScaleY(1.0f);
-        }
-
-        if (mDPadView != null) {
-            editor.remove(getConfigKeyForXTranslation(mDPadView.getConfigName()));
-            editor.remove(getConfigKeyForYTranslation(mDPadView.getConfigName()));
-            editor.remove(getConfigKeyForScale(mDPadView.getConfigName()));
-            mDPadView.setTranslationX(0.0f);
-            mDPadView.setTranslationY(0.0f);
-            mDPadView.setScaleX(1.0f);
-            mDPadView.setScaleY(1.0f);
-        }
-
-        editor.commit();
-        requestLayout();
-    }
-
-    private void reloadButtonSettings() {
-        final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getContext());
-
-        for (TouchscreenControllerButtonView buttonView : mButtonViews) {
-            try {
-                buttonView.setTranslationX(prefs.getFloat(getConfigKeyForXTranslation(buttonView.getConfigName()), 0.0f));
-                buttonView.setTranslationY(prefs.getFloat(getConfigKeyForYTranslation(buttonView.getConfigName()), 0.0f));
-                buttonView.setScaleX(prefs.getFloat(getConfigKeyForScale(buttonView.getConfigName()), 1.0f));
-                buttonView.setScaleY(prefs.getFloat(getConfigKeyForScale(buttonView.getConfigName()), 1.0f));
-                //Log.i("TouchscreenController", String.format("Translation for %s %f %f", buttonView.getConfigName(),
-                //        buttonView.getTranslationX(), buttonView.getTranslationY()));
-
-                final boolean visible = prefs.getBoolean(getConfigKeyForVisibility(buttonView.getConfigName()), buttonView.getDefaultVisibility());
-                buttonView.setVisibility(visible ? VISIBLE : INVISIBLE);
-            } catch (ClassCastException ex) {
-
-            }
-        }
-
-        for (TouchscreenControllerAxisView axisView : mAxisViews) {
-            try {
-                axisView.setTranslationX(prefs.getFloat(getConfigKeyForXTranslation(axisView.getConfigName()), 0.0f));
-                axisView.setTranslationY(prefs.getFloat(getConfigKeyForYTranslation(axisView.getConfigName()), 0.0f));
-                axisView.setScaleX(prefs.getFloat(getConfigKeyForScale(axisView.getConfigName()), 1.0f));
-                axisView.setScaleY(prefs.getFloat(getConfigKeyForScale(axisView.getConfigName()), 1.0f));
-
-                final boolean visible = prefs.getBoolean(getConfigKeyForVisibility(axisView.getConfigName()), axisView.getDefaultVisibility());
-                axisView.setVisibility(visible ? VISIBLE : INVISIBLE);
-            } catch (ClassCastException ex) {
-
-            }
-        }
-
-        if (mDPadView != null) {
-            try {
-                mDPadView.setTranslationX(prefs.getFloat(getConfigKeyForXTranslation(mDPadView.getConfigName()), 0.0f));
-                mDPadView.setTranslationY(prefs.getFloat(getConfigKeyForYTranslation(mDPadView.getConfigName()), 0.0f));
-                mDPadView.setScaleX(prefs.getFloat(getConfigKeyForScale(mDPadView.getConfigName()), 1.0f));
-                mDPadView.setScaleY(prefs.getFloat(getConfigKeyForScale(mDPadView.getConfigName()), 1.0f));
-
-                final boolean visible = prefs.getBoolean(getConfigKeyForVisibility(mDPadView.getConfigName()), mDPadView.getDefaultVisibility());
-                mDPadView.setVisibility(visible ? VISIBLE : INVISIBLE);
-            } catch (ClassCastException ex) {
-
-            }
-        }
-    }
-
-    private void setOpacity(int opacity) {
-        final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getContext());
-        final SharedPreferences.Editor editor = prefs.edit();
-        editor.putInt("TouchscreenController/Opacity", opacity);
-        editor.commit();
-
-        updateOpacity();
-    }
-
-    private void updateOpacity() {
-        mOpacity = PreferenceManager.getDefaultSharedPreferences(getContext()).getInt("TouchscreenController/Opacity", DEFAULT_OPACITY);
-
-        float alpha = (float)mOpacity / 100.0f;
-        alpha = (alpha < 0.0f) ? 0.0f : ((alpha > 1.0f) ? 1.0f : alpha);
-
-        for (TouchscreenControllerButtonView buttonView : mButtonViews) {
-            buttonView.setAlpha(alpha);
-        }
-        for (TouchscreenControllerAxisView axisView : mAxisViews) {
-            axisView.setAlpha(alpha);
-        }
-        if (mDPadView != null)
-            mDPadView.setAlpha(alpha);
-    }
-
-    private String getOrientationString() {
-        switch (getContext().getResources().getConfiguration().orientation) {
-            case Configuration.ORIENTATION_PORTRAIT:
-                return "Portrait";
-            case Configuration.ORIENTATION_LANDSCAPE:
-            default:
-                return "Landscape";
-        }
-    }
-
-    /**
-     * Checks if the orientation of the layout has changed, and if so, reloads button translations.
-     */
-    public void updateOrientation() {
-        String newOrientation = getOrientationString();
-        if (mLayoutOrientation != null && mLayoutOrientation.equals(newOrientation))
-            return;
-
-        Log.i("TouchscreenController", "New orientation: " + newOrientation);
-        mLayoutOrientation = newOrientation;
-        reloadButtonSettings();
-        requestLayout();
-    }
-
-    public void init(int controllerIndex, String controllerType, String viewType, boolean hapticFeedback, boolean gliding) {
-        mControllerIndex = controllerIndex;
-        mControllerType = controllerType;
-        mViewType = viewType;
-        mHapticFeedback = hapticFeedback;
-        mLayoutOrientation = getOrientationString();
-
-        if (mEditMode != EditMode.NONE)
-            endLayoutEditing();
-
-        mButtonViews.clear();
-        mAxisViews.clear();
-        removeAllViews();
-
-        LayoutInflater inflater = LayoutInflater.from(getContext());
-        String pointerButtonName = null;
-        switch (viewType) {
-            case "digital":
-                mMainView = inflater.inflate(R.layout.layout_touchscreen_controller_digital, this, true);
-                break;
-
-            case "analog_stick":
-                mMainView = inflater.inflate(R.layout.layout_touchscreen_controller_analog_stick, this, true);
-                break;
-
-            case "analog_sticks":
-                mMainView = inflater.inflate(R.layout.layout_touchscreen_controller_analog_sticks, this, true);
-                break;
-
-            case "lightgun":
-                mMainView = inflater.inflate(R.layout.layout_touchscreen_controller_lightgun, this, true);
-                pointerButtonName = "Trigger";
-                break;
-
-            case "none":
-            default:
-                mMainView = null;
-                break;
-        }
-
-        if (mMainView == null)
-            return;
-
-        mMainView.setOnTouchListener((view1, event) -> {
-            if (mEditMode != EditMode.NONE)
-                return handleEditingTouchEvent(event);
-            else
-                return handleTouchEvent(event);
-        });
-
-        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getContext());
-
-        linkDPadToButtons(mMainView, R.id.controller_dpad, "DPad", "", true);
-        linkButton(mMainView, R.id.controller_button_l1, "L1Button", "L1", true, gliding);
-        linkButton(mMainView, R.id.controller_button_l2, "L2Button", "L2", true, gliding);
-        linkButton(mMainView, R.id.controller_button_select, "SelectButton", "Select", true, gliding);
-        linkButton(mMainView, R.id.controller_button_start, "StartButton", "Start", true, gliding);
-        linkButton(mMainView, R.id.controller_button_triangle, "TriangleButton", "Triangle", true, gliding);
-        linkButton(mMainView, R.id.controller_button_circle, "CircleButton", "Circle", true, gliding);
-        linkButton(mMainView, R.id.controller_button_cross, "CrossButton", "Cross", true, gliding);
-        linkButton(mMainView, R.id.controller_button_square, "SquareButton", "Square", true, gliding);
-        linkButton(mMainView, R.id.controller_button_r1, "R1Button", "R1", true, gliding);
-        linkButton(mMainView, R.id.controller_button_r2, "R2Button", "R2", true, gliding);
-
-        if (!linkAxis(mMainView, R.id.controller_axis_left, "LeftAxis", "Left", true))
-            linkAxisToButtons(mMainView, R.id.controller_axis_left, "LeftAxis", "");
-
-        linkAxis(mMainView, R.id.controller_axis_right, "RightAxis", "Right", true);
-
-        // GunCon
-        linkButton(mMainView, R.id.controller_button_a, "AButton", "A", true, true);
-        linkButton(mMainView, R.id.controller_button_b, "BButton", "B", true, true);
-        if (pointerButtonName != null)
-            linkPointer(pointerButtonName);
-
-        // Turbo/autofire buttons
-        linkAutoFireButton(mMainView, R.id.controller_button_autofire_1, "AutoFire1", 0, false);
-        linkAutoFireButton(mMainView, R.id.controller_button_autofire_2, "AutoFire2", 1, false);
-        linkAutoFireButton(mMainView, R.id.controller_button_autofire_3, "AutoFire3", 2, false);
-        linkAutoFireButton(mMainView, R.id.controller_button_autofire_4, "AutoFire4", 3, false);
-
-        // Hotkeys
-        linkHotkeyButton(mMainView, R.id.controller_button_fast_forward, "FastForward",
-                TouchscreenControllerButtonView.Hotkey.FAST_FORWARD, false);
-        linkHotkeyButton(mMainView, R.id.controller_button_analog, "AnalogToggle",
-                TouchscreenControllerButtonView.Hotkey.ANALOG_TOGGLE, false);
-        linkHotkeyButton(mMainView, R.id.controller_button_pause, "OpenPauseMenu",
-                TouchscreenControllerButtonView.Hotkey.OPEN_PAUSE_MENU, true);
-        linkHotkeyButton(mMainView, R.id.controller_button_quick_load, "QuickLoad",
-                TouchscreenControllerButtonView.Hotkey.QUICK_LOAD, false);
-        linkHotkeyButton(mMainView, R.id.controller_button_quick_save, "QuickSave",
-                TouchscreenControllerButtonView.Hotkey.QUICK_SAVE, false);
-
-        reloadButtonSettings();
-        updateOpacity();
-        requestLayout();
-    }
-
-    private void linkButton(View view, int id, String configName, String buttonName, boolean defaultVisibility, boolean isGlidable) {
-        TouchscreenControllerButtonView buttonView = (TouchscreenControllerButtonView) view.findViewById(id);
-        if (buttonView == null)
-            return;
-
-        buttonView.setConfigName(configName);
-        buttonView.setDefaultVisibility(defaultVisibility);
-        buttonView.setIsGlidable(isGlidable);
-        mButtonViews.add(buttonView);
-
-        int code = AndroidHostInterface.getControllerButtonCode(mControllerType, buttonName);
-        Log.i("TouchscreenController", String.format("%s -> %d", buttonName, code));
-
-        if (code >= 0) {
-            buttonView.setButtonCode(mControllerIndex, code);
-            buttonView.setHapticFeedback(mHapticFeedback);
-        } else {
-            Log.e("TouchscreenController", String.format("Unknown button name '%s' " +
-                    "for '%s'", buttonName, mControllerType));
-        }
-    }
-
-    private boolean linkAxis(View view, int id, String configName, String axisName, boolean defaultVisibility) {
-        TouchscreenControllerAxisView axisView = (TouchscreenControllerAxisView) view.findViewById(id);
-        if (axisView == null)
-            return false;
-
-        axisView.setConfigName(configName);
-        axisView.setDefaultVisibility(defaultVisibility);
-        mAxisViews.add(axisView);
-
-        int xCode = AndroidHostInterface.getControllerAxisCode(mControllerType, axisName + "X");
-        int yCode = AndroidHostInterface.getControllerAxisCode(mControllerType, axisName + "Y");
-        Log.i("TouchscreenController", String.format("%s -> %d/%d", axisName, xCode, yCode));
-        if (xCode < 0 && yCode < 0)
-            return false;
-
-        axisView.setControllerAxis(mControllerIndex, xCode, yCode);
-        return true;
-    }
-
-    private boolean linkAxisToButtons(View view, int id, String configName, String buttonPrefix) {
-        TouchscreenControllerAxisView axisView = (TouchscreenControllerAxisView) view.findViewById(id);
-        if (axisView == null)
-            return false;
-
-        int leftCode = AndroidHostInterface.getControllerButtonCode(mControllerType, buttonPrefix + "Left");
-        int rightCode = AndroidHostInterface.getControllerButtonCode(mControllerType, buttonPrefix + "Right");
-        int upCode = AndroidHostInterface.getControllerButtonCode(mControllerType, buttonPrefix + "Up");
-        int downCode = AndroidHostInterface.getControllerButtonCode(mControllerType, buttonPrefix + "Down");
-        Log.i("TouchscreenController", String.format("%s(ButtonAxis) -> %d,%d,%d,%d", buttonPrefix, leftCode, rightCode, upCode, downCode));
-        if (leftCode < 0 && rightCode < 0 && upCode < 0 && downCode < 0)
-            return false;
-
-        axisView.setControllerButtons(mControllerIndex, leftCode, rightCode, upCode, downCode);
-        return true;
-    }
-
-    private boolean linkDPadToButtons(View view, int id, String configName, String buttonPrefix, boolean defaultVisibility) {
-        TouchscreenControllerDPadView dpadView = (TouchscreenControllerDPadView) view.findViewById(id);
-        if (dpadView == null)
-            return false;
-
-        dpadView.setConfigName(configName);
-        dpadView.setDefaultVisibility(defaultVisibility);
-        mDPadView = dpadView;
-
-        int leftCode = AndroidHostInterface.getControllerButtonCode(mControllerType, buttonPrefix + "Left");
-        int rightCode = AndroidHostInterface.getControllerButtonCode(mControllerType, buttonPrefix + "Right");
-        int upCode = AndroidHostInterface.getControllerButtonCode(mControllerType, buttonPrefix + "Up");
-        int downCode = AndroidHostInterface.getControllerButtonCode(mControllerType, buttonPrefix + "Down");
-        Log.i("TouchscreenController", String.format("%s(DPad) -> %d,%d,%d,%d", buttonPrefix, leftCode, rightCode, upCode, downCode));
-        if (leftCode < 0 && rightCode < 0 && upCode < 0 && downCode < 0)
-            return false;
-
-        dpadView.setControllerButtons(mControllerIndex, leftCode, rightCode, upCode, downCode);
-        return true;
-    }
-
-    private void linkHotkeyButton(View view, int id, String configName, TouchscreenControllerButtonView.Hotkey hotkey, boolean defaultVisibility) {
-        TouchscreenControllerButtonView buttonView = (TouchscreenControllerButtonView) view.findViewById(id);
-        if (buttonView == null)
-            return;
-
-        buttonView.setConfigName(configName);
-        buttonView.setDefaultVisibility(defaultVisibility);
-        buttonView.setHotkey(hotkey);
-        buttonView.setIsGlidable(false);
-        mButtonViews.add(buttonView);
-    }
-
-    private void linkAutoFireButton(View view, int id, String configName, int slot, boolean defaultVisibility) {
-        TouchscreenControllerButtonView buttonView = (TouchscreenControllerButtonView) view.findViewById(id);
-        if (buttonView == null)
-            return;
-
-        buttonView.setConfigName(configName);
-        buttonView.setDefaultVisibility(defaultVisibility);
-        buttonView.setAutoFireSlot(mControllerIndex, slot);
-        buttonView.setIsGlidable(true);
-        mButtonViews.add(buttonView);
-    }
-
-    private boolean linkPointer(String buttonName) {
-        mPointerButtonCode = AndroidHostInterface.getInstance().getControllerButtonCode(mControllerType, buttonName);
-        Log.i("TouchscreenController", String.format("Pointer -> %s,%d", buttonName, mPointerButtonCode));
-        return (mPointerButtonCode >= 0);
-    }
-
-    private int dpToPixels(float dp) {
-        return Math.round(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, getResources().getDisplayMetrics()));
-    }
-
-    public void startLayoutEditing(EditMode mode) {
-        if (mEditLayout == null) {
-            LayoutInflater inflater = LayoutInflater.from(getContext());
-            mEditLayout = (ConstraintLayout) inflater.inflate(R.layout.layout_touchscreen_controller_edit, this, false);
-            ((Button) mEditLayout.findViewById(R.id.options)).setOnClickListener((view) -> showEditorMenu());
-            addView(mEditLayout);
-        }
-
-        mEditMode = mode;
-    }
-
-    public void endLayoutEditing() {
-        if (mEditLayout != null) {
-            ((ViewGroup) mMainView).removeView(mEditLayout);
-            mEditLayout = null;
-        }
-
-        mEditMode = EditMode.NONE;
-        mMovingView = null;
-        mMovingName = null;
-        mMovingLastX = 0.0f;
-        mMovingLastY = 0.0f;
-
-        // unpause if we're paused (from the setting)
-        if (AndroidHostInterface.getInstance().isEmulationThreadPaused())
-            AndroidHostInterface.getInstance().pauseEmulationThread(false);
-    }
-
-    private float snapToValue(float pos, float value) {
-        return Math.round(pos / value) * value;
-    }
-
-    private float snapToGrid(float pos) {
-        final float value = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 20.0f, getResources().getDisplayMetrics());
-        return snapToValue(pos, value);
-    }
-
-    private boolean handleEditingTouchEvent(MotionEvent event) {
-        switch (event.getActionMasked()) {
-            case MotionEvent.ACTION_UP: {
-                if (mMovingView != null) {
-                    // save position
-                    saveSettingsForButton(mMovingName, mMovingView);
-                    mMovingView = null;
-                    mMovingName = null;
-                    mMovingLastX = 0.0f;
-                    mMovingLastY = 0.0f;
-                    mMovingLastScale = 0.0f;
-                }
-
-                return true;
-            }
-
-            case MotionEvent.ACTION_DOWN: {
-                if (mMovingView != null) {
-                    // already moving a button
-                    return true;
-                }
-
-                Rect rect = new Rect();
-                final float x = event.getX();
-                final float y = event.getY();
-                for (TouchscreenControllerButtonView buttonView : mButtonViews) {
-                    buttonView.getHitRect(rect);
-                    if (rect.contains((int) x, (int) y)) {
-                        mMovingView = buttonView;
-                        mMovingName = buttonView.getConfigName();
-                        mMovingLastX = snapToGrid(x);
-                        mMovingLastY = snapToGrid(y);
-                        mMovingLastScale = buttonView.getScaleX();
-                        return true;
-                    }
-                }
-
-                for (TouchscreenControllerAxisView axisView : mAxisViews) {
-                    axisView.getHitRect(rect);
-                    if (rect.contains((int) x, (int) y)) {
-                        mMovingView = axisView;
-                        mMovingName = axisView.getConfigName();
-                        mMovingLastX = snapToGrid(x);
-                        mMovingLastY = snapToGrid(y);
-                        mMovingLastScale = axisView.getScaleX();
-                        return true;
-                    }
-                }
-
-                if (mDPadView != null) {
-                    mDPadView.getHitRect(rect);
-                    if (rect.contains((int) x, (int) y)) {
-                        mMovingView = mDPadView;
-                        mMovingName = mDPadView.getConfigName();
-                        mMovingLastX = snapToGrid(x);
-                        mMovingLastY = snapToGrid(y);
-                        mMovingLastScale = mDPadView.getScaleX();
-                        return true;
-                    }
-                }
-
-                // nothing..
-                return true;
-            }
-
-            case MotionEvent.ACTION_MOVE: {
-                if (mMovingView == null)
-                    return true;
-
-                final float x = snapToGrid(event.getX());
-                final float y = snapToGrid(event.getY());
-                if (mEditMode == EditMode.POSITION) {
-                    final float dx = x - mMovingLastX;
-                    final float dy = y - mMovingLastY;
-                    mMovingLastX = x;
-                    mMovingLastY = y;
-
-                    final float posX = mMovingView.getX() + dx;
-                    final float posY = mMovingView.getY() + dy;
-                    //Log.d("Position", String.format("%f %f -> (%f %f) %f %f",
-                    //        mMovingView.getX(), mMovingView.getY(), dx, dy, posX, posY));
-                    mMovingView.setX(posX);
-                    mMovingView.setY(posY);
-                } else {
-                    final float lastDx = mMovingLastX - mMovingView.getX();
-                    final float lastDy = mMovingLastY - mMovingView.getY();
-                    final float dx = x - mMovingView.getX();
-                    final float dy = y - mMovingView.getY();
-                    final float lastDistance = Math.max(Math.abs(lastDx), Math.abs(lastDy));
-                    final float distance =  Math.max(Math.abs(dx), Math.abs(dy));
-                    final float scaler = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 50.0f, getResources().getDisplayMetrics());
-                    final float scaleDiff = snapToValue((distance - lastDistance) / scaler, 0.1f);
-                    final float scale = Math.max(Math.min(mMovingLastScale + mMovingLastScale * scaleDiff, MAX_VIEW_SCALE), MIN_VIEW_SCALE);
-                    mMovingView.setScaleX(scale);
-                    mMovingView.setScaleY(scale);
-                }
-
-                mMovingView.invalidate();
-                mMainView.requestLayout();
-                return true;
-            }
-        }
-
-        return false;
-    }
-
-    private boolean updateTouchButtonsFromEvent(MotionEvent event) {
-        if (!AndroidHostInterface.hasInstanceAndEmulationThreadIsRunning())
-            return false;
-
-        Rect rect = new Rect();
-        final int actionMasked = event.getActionMasked();
-        final int pointerCount = event.getPointerCount();
-        final int liftedPointerIndex = (actionMasked == MotionEvent.ACTION_POINTER_UP) ? event.getActionIndex() : -1;
-        for (TouchscreenControllerButtonView buttonView : mButtonViews) {
-            if (buttonView.getVisibility() != VISIBLE)
-                continue;
-
-            buttonView.getHitRect(rect);
-            boolean pressed = false;
-            for (int i = 0; i < pointerCount; i++) {
-                if (i == liftedPointerIndex)
-                    continue;
-
-                final int x = (int) event.getX(i);
-                final int y = (int) event.getY(i);
-                if (rect.contains(x, y)) {
-                    buttonView.setPressed(true);
-                    final int pointerId = event.getPointerId(i);
-                    if (!mGlidePairs.containsKey(pointerId) && !mGlidePairs.containsValue(buttonView)) {
-                        if (buttonView.getIsGlidable())
-                            mGlidePairs.put(pointerId, buttonView);
-                        else { mGlidePairs.put(pointerId, null); }
-                    }
-                    pressed = true;
-                    break;
-                }
-            }
-
-            if (!pressed  && !mGlidePairs.containsValue(buttonView))
-                buttonView.setPressed(pressed);
-        }
-
-        for (TouchscreenControllerAxisView axisView : mAxisViews) {
-            if (axisView.getVisibility() != VISIBLE)
-                continue;
-
-            axisView.getHitRect(rect);
-            boolean pressed = false;
-            for (int i = 0; i < pointerCount; i++) {
-                if (i == liftedPointerIndex)
-                    continue;
-
-                final int pointerId = event.getPointerId(i);
-                final int x = (int) event.getX(i);
-                final int y = (int) event.getY(i);
-
-                if ((rect.contains(x, y) && !axisView.isPressed()) ||
-                        (axisView.isPressed() && axisView.getPointerId() == pointerId)) {
-                    axisView.setPressed(pointerId, x - rect.left, y - rect.top);
-                    pressed = true;
-                    mGlidePairs.put(pointerId, null);
-                    break;
-                }
-            }
-            if (!pressed)
-                axisView.setUnpressed();
-        }
-
-        if (mDPadView != null && mDPadView.getVisibility() == VISIBLE) {
-            mDPadView.getHitRect(rect);
-
-            boolean pressed = false;
-            for (int i = 0; i < pointerCount; i++) {
-                if (i == liftedPointerIndex)
-                    continue;
-
-                final int x = (int) event.getX(i);
-                final int y = (int) event.getY(i);
-                if (rect.contains(x, y)) {
-                    mDPadView.setPressed(event.getPointerId(i), x - rect.left, y - rect.top);
-                    pressed = true;
-                }
-            }
-
-            if (!pressed)
-                mDPadView.setUnpressed();
-        }
-
-        if (mPointerButtonCode >= 0) {
-            final int pointerIndex = event.getActionIndex();
-            final int pointerId = event.getPointerId(pointerIndex);
-            if (mPointerPointerId < 0 && (actionMasked == MotionEvent.ACTION_DOWN || actionMasked == MotionEvent.ACTION_POINTER_DOWN)) {
-                if (!mGlidePairs.containsKey(pointerId)) {
-                    AndroidHostInterface.getInstance().setControllerButtonState(mControllerIndex,
-                            mPointerButtonCode, true);
-                    mPointerPointerId = pointerId;
-                }
-            } else if (actionMasked == MotionEvent.ACTION_POINTER_UP) {
-                if (pointerId == mPointerPointerId) {
-                    AndroidHostInterface.getInstance().setControllerButtonState(mControllerIndex,
-                            mPointerButtonCode, false);
-                    mPointerPointerId = -1;
-                }
-            }
-
-            AndroidHostInterface.getInstance().setMousePosition(
-                    (int) event.getX(pointerIndex),
-                    (int) event.getY(pointerIndex));
-        }
-
-        return true;
-    }
-
-    private boolean handleTouchEvent(MotionEvent event) {
-        switch (event.getActionMasked()) {
-            case MotionEvent.ACTION_UP: {
-                if (!AndroidHostInterface.hasInstanceAndEmulationThreadIsRunning())
-                    return false;
-
-                mGlidePairs.clear();
-
-                for (TouchscreenControllerButtonView buttonView : mButtonViews) {
-                    buttonView.setPressed(false);
-                }
-
-                for (TouchscreenControllerAxisView axisView : mAxisViews) {
-                    axisView.setUnpressed();
-                }
-
-                if (mDPadView != null)
-                    mDPadView.setUnpressed();
-
-                if (mPointerPointerId >= 0) {
-                    AndroidHostInterface.getInstance().setControllerButtonState(
-                            mControllerIndex, mPointerButtonCode, false);
-                    mPointerPointerId = -1;
-                }
-
-                return true;
-            }
-
-            case MotionEvent.ACTION_DOWN:
-            case MotionEvent.ACTION_POINTER_DOWN:
-            case MotionEvent.ACTION_POINTER_UP: {
-                final int pointerId = event.getPointerId(event.getActionIndex());
-                if (mGlidePairs.containsKey(pointerId))
-                    mGlidePairs.remove(pointerId);
-
-                return updateTouchButtonsFromEvent(event);
-            }
-            case MotionEvent.ACTION_MOVE: {
-                return updateTouchButtonsFromEvent(event);
-            }
-        }
-
-        return false;
-    }
-
-    public AlertDialog.Builder createAddRemoveButtonDialog(Context context) {
-        final AlertDialog.Builder builder = new AlertDialog.Builder(context);
-        final CharSequence[] items = new CharSequence[mButtonViews.size() + mAxisViews.size()];
-        final boolean[] itemsChecked = new boolean[mButtonViews.size() + mAxisViews.size()];
-        int itemCount = 0;
-        for (TouchscreenControllerButtonView buttonView : mButtonViews) {
-            items[itemCount] = buttonView.getConfigName();
-            itemsChecked[itemCount] = buttonView.getVisibility() == VISIBLE;
-            itemCount++;
-        }
-        for (TouchscreenControllerAxisView axisView : mAxisViews) {
-            items[itemCount] = axisView.getConfigName();
-            itemsChecked[itemCount] = axisView.getVisibility() == VISIBLE;
-            itemCount++;
-        }
-
-        builder.setTitle(R.string.dialog_touchscreen_controller_buttons);
-        builder.setMultiChoiceItems(items, itemsChecked, (dialog, which, isChecked) -> {
-            if (which < mButtonViews.size()) {
-                TouchscreenControllerButtonView buttonView = mButtonViews.get(which);
-                buttonView.setVisibility(isChecked ? VISIBLE : INVISIBLE);
-                saveVisibilityForButton(buttonView.getConfigName(), isChecked);
-            } else {
-                TouchscreenControllerAxisView axisView = mAxisViews.get(which - mButtonViews.size());
-                axisView.setVisibility(isChecked ? VISIBLE : INVISIBLE);
-                saveVisibilityForButton(axisView.getConfigName(), isChecked);
-            }
-        });
-        builder.setNegativeButton(R.string.dialog_done, (dialog, which) -> {
-            dialog.dismiss();
-        });
-
-        return builder;
-    }
-
-    public AlertDialog.Builder createOpacityDialog(Context context) {
-        final SeekBar seekBar = new SeekBar(context);
-        seekBar.setMax(100);
-        seekBar.setProgress(mOpacity);
-        seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
-            @Override
-            public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
-                setOpacity(progress);
-            }
-
-            @Override
-            public void onStartTrackingTouch(SeekBar seekBar) {
-            }
-
-            @Override
-            public void onStopTrackingTouch(SeekBar seekBar) {
-            }
-        });
-
-        final AlertDialog.Builder builder = new AlertDialog.Builder(context);
-        builder.setTitle(R.string.dialog_touchscreen_controller_opacity);
-        builder.setView(seekBar);
-        builder.setNegativeButton(R.string.dialog_done, (dialog, which) -> {
-            dialog.dismiss();
-        });
-        return builder;
-    }
-
-    private void showEditorMenu() {
-        AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
-        builder.setItems(R.array.touchscreen_layout_menu, (dialogInterface, i) -> {
-            switch (i) {
-                case 0:     // Change Opacity
-                {
-                    AlertDialog.Builder subBuilder = createOpacityDialog(getContext());
-                    subBuilder.create().show();
-                }
-                break;
-
-                case 1:     // Add/Remove Buttons
-                {
-                    AlertDialog.Builder subBuilder = createAddRemoveButtonDialog(getContext());
-                    subBuilder.create().show();
-                }
-                break;
-
-                case 2:     // Edit Positions
-                {
-                    mEditMode = EditMode.POSITION;
-                }
-                break;
-
-                case 3:     // Edit Scale
-                {
-                    mEditMode = EditMode.SCALE;
-                }
-                break;
-
-                case 4:     // Reset Layout
-                {
-                    clearTranslationForAllButtons();
-                }
-                break;
-
-                case 5:     // Exit Editor
-                {
-                    endLayoutEditing();
-                }
-                break;
-            }
-        });
-        builder.create().show();
-    }
-}
diff --git a/android/app/src/main/java/com/github/stenzek/duckstation/URLDownloader.java b/android/app/src/main/java/com/github/stenzek/duckstation/URLDownloader.java
deleted file mode 100644
index 6da425237..000000000
--- a/android/app/src/main/java/com/github/stenzek/duckstation/URLDownloader.java
+++ /dev/null
@@ -1,96 +0,0 @@
-package com.github.stenzek.duckstation;
-
-import java.io.BufferedInputStream;
-import java.io.BufferedOutputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.net.HttpURLConnection;
-import java.net.URL;
-
-/**
- * Helper class for exposing HTTP downloads to native code without pulling in an external
- * dependency for doing so.
- */
-public class URLDownloader {
-    private int statusCode = -1;
-    private byte[] data = null;
-    private final String userAgent;
-
-    public URLDownloader(String userAgent) {
-        this.userAgent = userAgent;
-    }
-
-    private HttpURLConnection getConnection(String url) {
-        try {
-            final URL parsedUrl = new URL(url);
-            HttpURLConnection connection = (HttpURLConnection) parsedUrl.openConnection();
-            if (connection == null)
-                throw new RuntimeException(String.format("openConnection(%s) returned null", url));
-
-            if (userAgent != null)
-                connection.addRequestProperty("User-Agent", userAgent);
-            return connection;
-        } catch (Exception e) {
-            e.printStackTrace();
-            return null;
-        }
-    }
-
-    public int getStatusCode() {
-        return statusCode;
-    }
-
-    public byte[] getData() {
-        return data;
-    }
-
-    private boolean download(HttpURLConnection connection) {
-        try {
-            statusCode = connection.getResponseCode();
-            if (statusCode != HttpURLConnection.HTTP_OK)
-                return false;
-
-            final InputStream inStream = new BufferedInputStream(connection.getInputStream());
-            final ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
-            final int CHUNK_SIZE = 128 * 1024;
-            final byte[] chunk = new byte[CHUNK_SIZE];
-            int len;
-            while ((len = inStream.read(chunk)) > 0) {
-                outputStream.write(chunk, 0, len);
-            }
-
-            data = outputStream.toByteArray();
-            return true;
-        } catch (Exception e) {
-            e.printStackTrace();
-            return false;
-        }
-    }
-
-    public boolean get(String url) {
-        final HttpURLConnection connection = getConnection(url);
-        if (connection == null)
-            return false;
-
-        return download(connection);
-    }
-
-    public boolean post(String url, byte[] postData) {
-        final HttpURLConnection connection = getConnection(url);
-        if (connection == null)
-            return false;
-
-        try {
-            connection.setDoOutput(true);
-            connection.setChunkedStreamingMode(0);
-
-            OutputStream postStream = new BufferedOutputStream(connection.getOutputStream());
-            postStream.write(postData);
-            return download(connection);
-        } catch (Exception e) {
-            e.printStackTrace();
-            return false;
-        }
-    }
-}
diff --git a/android/app/src/main/java/com/github/stenzek/duckstation/UpdateNotes.java b/android/app/src/main/java/com/github/stenzek/duckstation/UpdateNotes.java
deleted file mode 100644
index 6ef63878f..000000000
--- a/android/app/src/main/java/com/github/stenzek/duckstation/UpdateNotes.java
+++ /dev/null
@@ -1,54 +0,0 @@
-package com.github.stenzek.duckstation;
-
-import android.app.AlertDialog;
-import android.content.Intent;
-import android.content.SharedPreferences;
-
-import androidx.preference.PreferenceManager;
-
-public class UpdateNotes {
-    private static final int VERSION_CONTROLLER_UPDATE = 1;
-    private static final int CURRENT_VERSION = VERSION_CONTROLLER_UPDATE;
-
-    private static final String CONFIG_KEY = "Main/UpdateNotesVersion";
-
-    private static int getVersion(MainActivity parent) {
-        try {
-            final SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(parent);
-            return sp.getInt(CONFIG_KEY, 0);
-        } catch (Exception e) {
-            e.printStackTrace();
-            return CURRENT_VERSION;
-        }
-    }
-
-    public static void setVersion(MainActivity parent, int version) {
-        final SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(parent);
-        sp.edit().putInt(CONFIG_KEY, version).commit();
-    }
-
-    public static boolean displayUpdateNotes(MainActivity parent) {
-        final int version = getVersion(parent);
-
-        if (version < VERSION_CONTROLLER_UPDATE ) {
-            displayControllerUpdateNotes(parent);
-            setVersion(parent, VERSION_CONTROLLER_UPDATE);
-            return true;
-        }
-
-        return false;
-    }
-
-    public static void displayControllerUpdateNotes(MainActivity parent) {
-        final AlertDialog.Builder builder = new AlertDialog.Builder(parent);
-        builder.setTitle(R.string.update_notes_title);
-        builder.setMessage(R.string.update_notes_message_version_controller_update);
-        builder.setPositiveButton(R.string.main_activity_yes, (dialog, which) -> {
-            dialog.dismiss();
-            Intent intent = new Intent(parent, ControllerSettingsActivity.class);
-            parent.startActivity(intent);
-        });
-        builder.setNegativeButton(R.string.main_activity_no, (dialog, which) -> dialog.dismiss());
-        builder.create().show();
-    }
-}
diff --git a/android/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/android/app/src/main/res/drawable-v24/ic_launcher_foreground.xml
deleted file mode 100644
index 1f6bb2906..000000000
--- a/android/app/src/main/res/drawable-v24/ic_launcher_foreground.xml
+++ /dev/null
@@ -1,34 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:aapt="http://schemas.android.com/aapt"
-    android:width="108dp"
-    android:height="108dp"
-    android:viewportWidth="108"
-    android:viewportHeight="108">
-    <path
-        android:fillType="evenOdd"
-        android:pathData="M32,64C32,64 38.39,52.99 44.13,50.95C51.37,48.37 70.14,49.57 70.14,49.57L108.26,87.69L108,109.01L75.97,107.97L32,64Z"
-        android:strokeWidth="1"
-        android:strokeColor="#00000000">
-        <aapt:attr name="android:fillColor">
-            <gradient
-                android:endX="78.5885"
-                android:endY="90.9159"
-                android:startX="48.7653"
-                android:startY="61.0927"
-                android:type="linear">
-                <item
-                    android:color="#44000000"
-                    android:offset="0.0" />
-                <item
-                    android:color="#00000000"
-                    android:offset="1.0" />
-            </gradient>
-        </aapt:attr>
-    </path>
-    <path
-        android:fillColor="#FFFFFF"
-        android:fillType="nonZero"
-        android:pathData="M66.94,46.02L66.94,46.02C72.44,50.07 76,56.61 76,64L32,64C32,56.61 35.56,50.11 40.98,46.06L36.18,41.19C35.45,40.45 35.45,39.3 36.18,38.56C36.91,37.81 38.05,37.81 38.78,38.56L44.25,44.05C47.18,42.57 50.48,41.71 54,41.71C57.48,41.71 60.78,42.57 63.68,44.05L69.11,38.56C69.84,37.81 70.98,37.81 71.71,38.56C72.44,39.3 72.44,40.45 71.71,41.19L66.94,46.02ZM62.94,56.92C64.08,56.92 65,56.01 65,54.88C65,53.76 64.08,52.85 62.94,52.85C61.8,52.85 60.88,53.76 60.88,54.88C60.88,56.01 61.8,56.92 62.94,56.92ZM45.06,56.92C46.2,56.92 47.13,56.01 47.13,54.88C47.13,53.76 46.2,52.85 45.06,52.85C43.92,52.85 43,53.76 43,54.88C43,56.01 43.92,56.92 45.06,56.92Z"
-        android:strokeWidth="1"
-        android:strokeColor="#00000000" />
-</vector>
diff --git a/android/app/src/main/res/drawable/cover_placeholder.png b/android/app/src/main/res/drawable/cover_placeholder.png
deleted file mode 100644
index 18dc446fe..000000000
Binary files a/android/app/src/main/res/drawable/cover_placeholder.png and /dev/null differ
diff --git a/android/app/src/main/res/drawable/duck.png b/android/app/src/main/res/drawable/duck.png
deleted file mode 100644
index f039412f2..000000000
Binary files a/android/app/src/main/res/drawable/duck.png and /dev/null differ
diff --git a/android/app/src/main/res/drawable/flag_eu.xml b/android/app/src/main/res/drawable/flag_eu.xml
deleted file mode 100644
index e545a72a2..000000000
--- a/android/app/src/main/res/drawable/flag_eu.xml
+++ /dev/null
@@ -1,71 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?><!-- https://raw.githubusercontent.com/Shusshu/android-flags/master/flags/src/main/res/drawable/flag_us2.xml -->
-<vector android:height="15dp"
-    android:viewportHeight="15"
-    android:viewportWidth="21"
-    android:width="21dp"
-    xmlns:aapt="http://schemas.android.com/aapt"
-    xmlns:android="http://schemas.android.com/apk/res/android">
-    <path
-        android:fillType="evenOdd"
-        android:pathData="M0,0h21v15h-21z"
-        android:strokeColor="#00000000"
-        android:strokeWidth="1">
-        <aapt:attr name="android:fillColor">
-            <gradient
-                android:endX="10.5"
-                android:endY="15"
-                android:startX="10.5"
-                android:startY="0"
-                android:type="linear">
-                <item
-                    android:color="#FFFFFFFF"
-                    android:offset="0" />
-                <item
-                    android:color="#FFF0F0F0"
-                    android:offset="1" />
-            </gradient>
-        </aapt:attr>
-    </path>
-    <path
-        android:fillType="evenOdd"
-        android:pathData="M0,0h21v15h-21z"
-        android:strokeColor="#00000000"
-        android:strokeWidth="1">
-        <aapt:attr name="android:fillColor">
-            <gradient
-                android:endX="10.5"
-                android:endY="15"
-                android:startX="10.5"
-                android:startY="0"
-                android:type="linear">
-                <item
-                    android:color="#FF043CAE"
-                    android:offset="0" />
-                <item
-                    android:color="#FF00339A"
-                    android:offset="1" />
-            </gradient>
-        </aapt:attr>
-    </path>
-    <path
-        android:fillType="evenOdd"
-        android:pathData="M10.5,3L9.7929,3.2071L10,2.5L9.7929,1.7929L10.5,2L11.2071,1.7929L11,2.5L11.2071,3.2071L10.5,3ZM10.5,13L9.7929,13.2071L10,12.5L9.7929,11.7929L10.5,12L11.2071,11.7929L11,12.5L11.2071,13.2071L10.5,13ZM15.5,8L14.7929,8.2071L15,7.5L14.7929,6.7929L15.5,7L16.2071,6.7929L16,7.5L16.2071,8.2071L15.5,8ZM5.5,8L4.7929,8.2071L5,7.5L4.7929,6.7929L5.5,7L6.2071,6.7929L6,7.5L6.2071,8.2071L5.5,8ZM14.8301,5.5L14.123,5.7071L14.3301,5L14.123,4.2929L14.8301,4.5L15.5372,4.2929L15.3301,5L15.5372,5.7071L14.8301,5.5ZM6.1699,10.5L5.4628,10.7071L5.6699,10L5.4628,9.2929L6.1699,9.5L6.877,9.2929L6.6699,10L6.877,10.7071L6.1699,10.5ZM13,3.6699L12.2929,3.877L12.5,3.1699L12.2929,2.4628L13,2.6699L13.7071,2.4628L13.5,3.1699L13.7071,3.877L13,3.6699ZM8,12.3301L7.2929,12.5372L7.5,11.8301L7.2929,11.123L8,11.3301L8.7071,11.123L8.5,11.8301L8.7071,12.5372L8,12.3301ZM14.8301,10.5L14.123,10.7071L14.3301,10L14.123,9.2929L14.8301,9.5L15.5372,9.2929L15.3301,10L15.5372,10.7071L14.8301,10.5ZM6.1699,5.5L5.4628,5.7071L5.6699,5L5.4628,4.2929L6.1699,4.5L6.877,4.2929L6.6699,5L6.877,5.7071L6.1699,5.5ZM13,12.3301L12.2929,12.5372L12.5,11.8301L12.2929,11.123L13,11.3301L13.7071,11.123L13.5,11.8301L13.7071,12.5372L13,12.3301ZM8,3.6699L7.2929,3.877L7.5,3.1699L7.2929,2.4628L8,2.6699L8.7071,2.4628L8.5,3.1699L8.7071,3.877L8,3.6699Z"
-        android:strokeColor="#00000000"
-        android:strokeWidth="1">
-        <aapt:attr name="android:fillColor">
-            <gradient
-                android:endX="10.5"
-                android:endY="13.2071"
-                android:startX="10.5"
-                android:startY="1.7929"
-                android:type="linear">
-                <item
-                    android:color="#FFFFD429"
-                    android:offset="0" />
-                <item
-                    android:color="#FFFFCC00"
-                    android:offset="1" />
-            </gradient>
-        </aapt:attr>
-    </path>
-</vector>
\ No newline at end of file
diff --git a/android/app/src/main/res/drawable/flag_jp.xml b/android/app/src/main/res/drawable/flag_jp.xml
deleted file mode 100644
index f7b9fe6bd..000000000
--- a/android/app/src/main/res/drawable/flag_jp.xml
+++ /dev/null
@@ -1,50 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?><!-- https://raw.githubusercontent.com/Shusshu/android-flags/master/flags/src/main/res/drawable/flag_hp.xml -->
-<vector android:height="15dp"
-    android:viewportHeight="15"
-    android:viewportWidth="21"
-    android:width="21dp"
-    xmlns:aapt="http://schemas.android.com/aapt"
-    xmlns:android="http://schemas.android.com/apk/res/android">
-    <path
-        android:fillType="evenOdd"
-        android:pathData="M0,0h21v15h-21z"
-        android:strokeColor="#00000000"
-        android:strokeWidth="1">
-        <aapt:attr name="android:fillColor">
-            <gradient
-                android:endX="10.5"
-                android:endY="15"
-                android:startX="10.5"
-                android:startY="0"
-                android:type="linear">
-                <item
-                    android:color="#FFFFFFFF"
-                    android:offset="0" />
-                <item
-                    android:color="#FFF0F0F0"
-                    android:offset="1" />
-            </gradient>
-        </aapt:attr>
-    </path>
-    <path
-        android:fillType="evenOdd"
-        android:pathData="M10.5,7.5m-4.5,0a4.5,4.5 0,1 1,9 0a4.5,4.5 0,1 1,-9 0"
-        android:strokeColor="#00000000"
-        android:strokeWidth="1">
-        <aapt:attr name="android:fillColor">
-            <gradient
-                android:endX="10.5"
-                android:endY="12"
-                android:startX="10.5"
-                android:startY="3"
-                android:type="linear">
-                <item
-                    android:color="#FFD81441"
-                    android:offset="0" />
-                <item
-                    android:color="#FFBB0831"
-                    android:offset="1" />
-            </gradient>
-        </aapt:attr>
-    </path>
-</vector>
diff --git a/android/app/src/main/res/drawable/flag_us.xml b/android/app/src/main/res/drawable/flag_us.xml
deleted file mode 100644
index d83fcb9e2..000000000
--- a/android/app/src/main/res/drawable/flag_us.xml
+++ /dev/null
@@ -1,539 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?><!-- https://raw.githubusercontent.com/Shusshu/android-flags/master/flags/src/main/res/drawable/flag_us2.xml -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="21dp"
-    android:height="21dp"
-    android:viewportWidth="10"
-    android:viewportHeight="13">
-    <path
-        android:fillColor="#bd3d44"
-        android:pathData="M0 0h13v1h-13Z" />
-    <path
-        android:fillColor="#fff"
-        android:pathData="M0 1h13v1h-13Z" />
-    <path
-        android:fillColor="#bd3d44"
-        android:pathData="M0 2h13v1h-13Z" />
-    <path
-        android:fillColor="#fff"
-        android:pathData="M0 3h13v1h-13Z" />
-    <path
-        android:fillColor="#bd3d44"
-        android:pathData="M0 4h13v1h-13Z" />
-    <path
-        android:fillColor="#fff"
-        android:pathData="M0 5h13v1h-13Z" />
-    <path
-        android:fillColor="#bd3d44"
-        android:pathData="M0 6h13v1h-13Z" />
-    <path
-        android:fillColor="#fff"
-        android:pathData="M0 7h13v1h-13Z" />
-    <path
-        android:fillColor="#bd3d44"
-        android:pathData="M0 8h13v1h-13Z" />
-    <path
-        android:fillColor="#fff"
-        android:pathData="M0 9h13v1h-13Z" />
-    <path
-        android:fillColor="#bd3d44"
-        android:pathData="M0 10h13v1h-13Z" />
-    <path
-        android:fillColor="#fff"
-        android:pathData="M0 11h13v1h-13Z" />
-    <path
-        android:fillColor="#bd3d44"
-        android:pathData="M0 12h13v1h-13Z" />
-    <path
-        android:fillColor="#192f5d"
-        android:pathData="M0 0h5.2v7h-5.2Z" />
-
-    <group
-        android:translateX="0.2"
-        android:translateY="0.2"
-        android:scaleX="0.009"
-        android:scaleY="0.012">
-        <path
-            android:fillColor="#fff"
-            android:pathData="M 48,54 L 31,42 15,54 21,35 6,23 25,23 32,4 40,23 58,23 42,35 z" />
-    </group>
-    <group
-        android:translateX="1.0"
-        android:translateY="0.2"
-        android:scaleX="0.009"
-        android:scaleY="0.012">
-        <path
-            android:fillColor="#fff"
-            android:pathData="M 48,54 L 31,42 15,54 21,35 6,23 25,23 32,4 40,23 58,23 42,35 z" />
-    </group>
-    <group
-        android:translateX="1.8"
-        android:translateY="0.2"
-        android:scaleX="0.009"
-        android:scaleY="0.012">
-        <path
-            android:fillColor="#fff"
-            android:pathData="M 48,54 L 31,42 15,54 21,35 6,23 25,23 32,4 40,23 58,23 42,35 z" />
-    </group>
-    <group
-        android:translateX="2.6"
-        android:translateY="0.2"
-        android:scaleX="0.009"
-        android:scaleY="0.012">
-        <path
-            android:fillColor="#fff"
-            android:pathData="M 48,54 L 31,42 15,54 21,35 6,23 25,23 32,4 40,23 58,23 42,35 z" />
-    </group>
-    <group
-        android:translateX="3.4"
-        android:translateY="0.2"
-        android:scaleX="0.009"
-        android:scaleY="0.012">
-        <path
-            android:fillColor="#fff"
-            android:pathData="M 48,54 L 31,42 15,54 21,35 6,23 25,23 32,4 40,23 58,23 42,35 z" />
-    </group>
-    <group
-        android:translateX="4.2"
-        android:translateY="0.2"
-        android:scaleX="0.009"
-        android:scaleY="0.012">
-        <path
-            android:fillColor="#fff"
-            android:pathData="M 48,54 L 31,42 15,54 21,35 6,23 25,23 32,4 40,23 58,23 42,35 z" />
-    </group>
-
-
-    <group android:translateY="1.4">
-        <group
-            android:translateX="0.2"
-            android:translateY="0.2"
-            android:scaleX="0.009"
-            android:scaleY="0.012">
-            <path
-                android:fillColor="#fff"
-                android:pathData="M 48,54 L 31,42 15,54 21,35 6,23 25,23 32,4 40,23 58,23 42,35 z" />
-        </group>
-        <group
-            android:translateX="1.0"
-            android:translateY="0.2"
-            android:scaleX="0.009"
-            android:scaleY="0.012">
-            <path
-                android:fillColor="#fff"
-                android:pathData="M 48,54 L 31,42 15,54 21,35 6,23 25,23 32,4 40,23 58,23 42,35 z" />
-        </group>
-        <group
-            android:translateX="1.8"
-            android:translateY="0.2"
-            android:scaleX="0.009"
-            android:scaleY="0.012">
-            <path
-                android:fillColor="#fff"
-                android:pathData="M 48,54 L 31,42 15,54 21,35 6,23 25,23 32,4 40,23 58,23 42,35 z" />
-        </group>
-        <group
-            android:translateX="2.6"
-            android:translateY="0.2"
-            android:scaleX="0.009"
-            android:scaleY="0.012">
-            <path
-                android:fillColor="#fff"
-                android:pathData="M 48,54 L 31,42 15,54 21,35 6,23 25,23 32,4 40,23 58,23 42,35 z" />
-        </group>
-        <group
-            android:translateX="3.4"
-            android:translateY="0.2"
-            android:scaleX="0.009"
-            android:scaleY="0.012">
-            <path
-                android:fillColor="#fff"
-                android:pathData="M 48,54 L 31,42 15,54 21,35 6,23 25,23 32,4 40,23 58,23 42,35 z" />
-        </group>
-        <group
-            android:translateX="4.2"
-            android:translateY="0.2"
-            android:scaleX="0.009"
-            android:scaleY="0.012">
-            <path
-                android:fillColor="#fff"
-                android:pathData="M 48,54 L 31,42 15,54 21,35 6,23 25,23 32,4 40,23 58,23 42,35 z" />
-        </group>
-    </group>
-
-
-    <group android:translateY="2.9">
-        <group
-            android:translateX="0.2"
-            android:translateY="0.2"
-            android:scaleX="0.009"
-            android:scaleY="0.012">
-            <path
-                android:fillColor="#fff"
-                android:pathData="M 48,54 L 31,42 15,54 21,35 6,23 25,23 32,4 40,23 58,23 42,35 z" />
-        </group>
-        <group
-            android:translateX="1.0"
-            android:translateY="0.2"
-            android:scaleX="0.009"
-            android:scaleY="0.012">
-            <path
-                android:fillColor="#fff"
-                android:pathData="M 48,54 L 31,42 15,54 21,35 6,23 25,23 32,4 40,23 58,23 42,35 z" />
-        </group>
-        <group
-            android:translateX="1.8"
-            android:translateY="0.2"
-            android:scaleX="0.009"
-            android:scaleY="0.012">
-            <path
-                android:fillColor="#fff"
-                android:pathData="M 48,54 L 31,42 15,54 21,35 6,23 25,23 32,4 40,23 58,23 42,35 z" />
-        </group>
-        <group
-            android:translateX="2.6"
-            android:translateY="0.2"
-            android:scaleX="0.009"
-            android:scaleY="0.012">
-            <path
-                android:fillColor="#fff"
-                android:pathData="M 48,54 L 31,42 15,54 21,35 6,23 25,23 32,4 40,23 58,23 42,35 z" />
-        </group>
-        <group
-            android:translateX="3.4"
-            android:translateY="0.2"
-            android:scaleX="0.009"
-            android:scaleY="0.012">
-            <path
-                android:fillColor="#fff"
-                android:pathData="M 48,54 L 31,42 15,54 21,35 6,23 25,23 32,4 40,23 58,23 42,35 z" />
-        </group>
-        <group
-            android:translateX="4.2"
-            android:translateY="0.2"
-            android:scaleX="0.009"
-            android:scaleY="0.012">
-            <path
-                android:fillColor="#fff"
-                android:pathData="M 48,54 L 31,42 15,54 21,35 6,23 25,23 32,4 40,23 58,23 42,35 z" />
-        </group>
-    </group>
-
-
-    <group android:translateY="4.3">
-        <group
-            android:translateX="0.2"
-            android:translateY="0.2"
-            android:scaleX="0.009"
-            android:scaleY="0.012">
-            <path
-                android:fillColor="#fff"
-                android:pathData="M 48,54 L 31,42 15,54 21,35 6,23 25,23 32,4 40,23 58,23 42,35 z" />
-        </group>
-        <group
-            android:translateX="1.0"
-            android:translateY="0.2"
-            android:scaleX="0.009"
-            android:scaleY="0.012">
-            <path
-                android:fillColor="#fff"
-                android:pathData="M 48,54 L 31,42 15,54 21,35 6,23 25,23 32,4 40,23 58,23 42,35 z" />
-        </group>
-        <group
-            android:translateX="1.8"
-            android:translateY="0.2"
-            android:scaleX="0.009"
-            android:scaleY="0.012">
-            <path
-                android:fillColor="#fff"
-                android:pathData="M 48,54 L 31,42 15,54 21,35 6,23 25,23 32,4 40,23 58,23 42,35 z" />
-        </group>
-        <group
-            android:translateX="2.6"
-            android:translateY="0.2"
-            android:scaleX="0.009"
-            android:scaleY="0.012">
-            <path
-                android:fillColor="#fff"
-                android:pathData="M 48,54 L 31,42 15,54 21,35 6,23 25,23 32,4 40,23 58,23 42,35 z" />
-        </group>
-        <group
-            android:translateX="3.4"
-            android:translateY="0.2"
-            android:scaleX="0.009"
-            android:scaleY="0.012">
-            <path
-                android:fillColor="#fff"
-                android:pathData="M 48,54 L 31,42 15,54 21,35 6,23 25,23 32,4 40,23 58,23 42,35 z" />
-        </group>
-        <group
-            android:translateX="4.2"
-            android:translateY="0.2"
-            android:scaleX="0.009"
-            android:scaleY="0.012">
-            <path
-                android:fillColor="#fff"
-                android:pathData="M 48,54 L 31,42 15,54 21,35 6,23 25,23 32,4 40,23 58,23 42,35 z" />
-        </group>
-    </group>
-
-
-    <group android:translateY="5.6">
-        <group
-            android:translateX="0.2"
-            android:translateY="0.2"
-            android:scaleX="0.009"
-            android:scaleY="0.012">
-            <path
-                android:fillColor="#fff"
-                android:pathData="M 48,54 L 31,42 15,54 21,35 6,23 25,23 32,4 40,23 58,23 42,35 z" />
-        </group>
-        <group
-            android:translateX="1.0"
-            android:translateY="0.2"
-            android:scaleX="0.009"
-            android:scaleY="0.012">
-            <path
-                android:fillColor="#fff"
-                android:pathData="M 48,54 L 31,42 15,54 21,35 6,23 25,23 32,4 40,23 58,23 42,35 z" />
-        </group>
-        <group
-            android:translateX="1.8"
-            android:translateY="0.2"
-            android:scaleX="0.009"
-            android:scaleY="0.012">
-            <path
-                android:fillColor="#fff"
-                android:pathData="M 48,54 L 31,42 15,54 21,35 6,23 25,23 32,4 40,23 58,23 42,35 z" />
-        </group>
-        <group
-            android:translateX="2.6"
-            android:translateY="0.2"
-            android:scaleX="0.009"
-            android:scaleY="0.012">
-            <path
-                android:fillColor="#fff"
-                android:pathData="M 48,54 L 31,42 15,54 21,35 6,23 25,23 32,4 40,23 58,23 42,35 z" />
-        </group>
-        <group
-            android:translateX="3.4"
-            android:translateY="0.2"
-            android:scaleX="0.009"
-            android:scaleY="0.012">
-            <path
-                android:fillColor="#fff"
-                android:pathData="M 48,54 L 31,42 15,54 21,35 6,23 25,23 32,4 40,23 58,23 42,35 z" />
-        </group>
-        <group
-            android:translateX="4.2"
-            android:translateY="0.2"
-            android:scaleX="0.009"
-            android:scaleY="0.012">
-            <path
-                android:fillColor="#fff"
-                android:pathData="M 48,54 L 31,42 15,54 21,35 6,23 25,23 32,4 40,23 58,23 42,35 z" />
-        </group>
-    </group>
-
-    <!-- Odd stars -->
-
-    <group
-        android:translateY="0.7"
-        android:translateX="0.4">
-        <group
-            android:translateX="0.2"
-            android:translateY="0.2"
-            android:scaleX="0.009"
-            android:scaleY="0.012">
-            <path
-                android:fillColor="#fff"
-                android:pathData="M 48,54 L 31,42 15,54 21,35 6,23 25,23 32,4 40,23 58,23 42,35 z" />
-        </group>
-        <group
-            android:translateX="1.0"
-            android:translateY="0.2"
-            android:scaleX="0.009"
-            android:scaleY="0.012">
-            <path
-                android:fillColor="#fff"
-                android:pathData="M 48,54 L 31,42 15,54 21,35 6,23 25,23 32,4 40,23 58,23 42,35 z" />
-        </group>
-        <group
-            android:translateX="1.8"
-            android:translateY="0.2"
-            android:scaleX="0.009"
-            android:scaleY="0.012">
-            <path
-                android:fillColor="#fff"
-                android:pathData="M 48,54 L 31,42 15,54 21,35 6,23 25,23 32,4 40,23 58,23 42,35 z" />
-        </group>
-        <group
-            android:translateX="2.6"
-            android:translateY="0.2"
-            android:scaleX="0.009"
-            android:scaleY="0.012">
-            <path
-                android:fillColor="#fff"
-                android:pathData="M 48,54 L 31,42 15,54 21,35 6,23 25,23 32,4 40,23 58,23 42,35 z" />
-        </group>
-        <group
-            android:translateX="3.4"
-            android:translateY="0.2"
-            android:scaleX="0.009"
-            android:scaleY="0.012">
-            <path
-                android:fillColor="#fff"
-                android:pathData="M 48,54 L 31,42 15,54 21,35 6,23 25,23 32,4 40,23 58,23 42,35 z" />
-        </group>
-    </group>
-
-    <group
-        android:translateY="2.1"
-        android:translateX="0.4">
-        <group
-            android:translateX="0.2"
-            android:translateY="0.2"
-            android:scaleX="0.009"
-            android:scaleY="0.012">
-            <path
-                android:fillColor="#fff"
-                android:pathData="M 48,54 L 31,42 15,54 21,35 6,23 25,23 32,4 40,23 58,23 42,35 z" />
-        </group>
-        <group
-            android:translateX="1.0"
-            android:translateY="0.2"
-            android:scaleX="0.009"
-            android:scaleY="0.012">
-            <path
-                android:fillColor="#fff"
-                android:pathData="M 48,54 L 31,42 15,54 21,35 6,23 25,23 32,4 40,23 58,23 42,35 z" />
-        </group>
-        <group
-            android:translateX="1.8"
-            android:translateY="0.2"
-            android:scaleX="0.009"
-            android:scaleY="0.012">
-            <path
-                android:fillColor="#fff"
-                android:pathData="M 48,54 L 31,42 15,54 21,35 6,23 25,23 32,4 40,23 58,23 42,35 z" />
-        </group>
-        <group
-            android:translateX="2.6"
-            android:translateY="0.2"
-            android:scaleX="0.009"
-            android:scaleY="0.012">
-            <path
-                android:fillColor="#fff"
-                android:pathData="M 48,54 L 31,42 15,54 21,35 6,23 25,23 32,4 40,23 58,23 42,35 z" />
-        </group>
-        <group
-            android:translateX="3.4"
-            android:translateY="0.2"
-            android:scaleX="0.009"
-            android:scaleY="0.012">
-            <path
-                android:fillColor="#fff"
-                android:pathData="M 48,54 L 31,42 15,54 21,35 6,23 25,23 32,4 40,23 58,23 42,35 z" />
-        </group>
-    </group>
-
-    <group
-        android:translateY="3.6"
-        android:translateX="0.4">
-        <group
-            android:translateX="0.2"
-            android:translateY="0.2"
-            android:scaleX="0.009"
-            android:scaleY="0.012">
-            <path
-                android:fillColor="#fff"
-                android:pathData="M 48,54 L 31,42 15,54 21,35 6,23 25,23 32,4 40,23 58,23 42,35 z" />
-        </group>
-        <group
-            android:translateX="1.0"
-            android:translateY="0.2"
-            android:scaleX="0.009"
-            android:scaleY="0.012">
-            <path
-                android:fillColor="#fff"
-                android:pathData="M 48,54 L 31,42 15,54 21,35 6,23 25,23 32,4 40,23 58,23 42,35 z" />
-        </group>
-        <group
-            android:translateX="1.8"
-            android:translateY="0.2"
-            android:scaleX="0.009"
-            android:scaleY="0.012">
-            <path
-                android:fillColor="#fff"
-                android:pathData="M 48,54 L 31,42 15,54 21,35 6,23 25,23 32,4 40,23 58,23 42,35 z" />
-        </group>
-        <group
-            android:translateX="2.6"
-            android:translateY="0.2"
-            android:scaleX="0.009"
-            android:scaleY="0.012">
-            <path
-                android:fillColor="#fff"
-                android:pathData="M 48,54 L 31,42 15,54 21,35 6,23 25,23 32,4 40,23 58,23 42,35 z" />
-        </group>
-        <group
-            android:translateX="3.4"
-            android:translateY="0.2"
-            android:scaleX="0.009"
-            android:scaleY="0.012">
-            <path
-                android:fillColor="#fff"
-                android:pathData="M 48,54 L 31,42 15,54 21,35 6,23 25,23 32,4 40,23 58,23 42,35 z" />
-        </group>
-    </group>
-
-    <group
-        android:translateY="5.0"
-        android:translateX="0.4">
-        <group
-            android:translateX="0.2"
-            android:translateY="0.2"
-            android:scaleX="0.009"
-            android:scaleY="0.012">
-            <path
-                android:fillColor="#fff"
-                android:pathData="M 48,54 L 31,42 15,54 21,35 6,23 25,23 32,4 40,23 58,23 42,35 z" />
-        </group>
-        <group
-            android:translateX="1.0"
-            android:translateY="0.2"
-            android:scaleX="0.009"
-            android:scaleY="0.012">
-            <path
-                android:fillColor="#fff"
-                android:pathData="M 48,54 L 31,42 15,54 21,35 6,23 25,23 32,4 40,23 58,23 42,35 z" />
-        </group>
-        <group
-            android:translateX="1.8"
-            android:translateY="0.2"
-            android:scaleX="0.009"
-            android:scaleY="0.012">
-            <path
-                android:fillColor="#fff"
-                android:pathData="M 48,54 L 31,42 15,54 21,35 6,23 25,23 32,4 40,23 58,23 42,35 z" />
-        </group>
-        <group
-            android:translateX="2.6"
-            android:translateY="0.2"
-            android:scaleX="0.009"
-            android:scaleY="0.012">
-            <path
-                android:fillColor="#fff"
-                android:pathData="M 48,54 L 31,42 15,54 21,35 6,23 25,23 32,4 40,23 58,23 42,35 z" />
-        </group>
-        <group
-            android:translateX="3.4"
-            android:translateY="0.2"
-            android:scaleX="0.009"
-            android:scaleY="0.012">
-            <path
-                android:fillColor="#fff"
-                android:pathData="M 48,54 L 31,42 15,54 21,35 6,23 25,23 32,4 40,23 58,23 42,35 z" />
-        </group>
-    </group>
-
-</vector>
\ No newline at end of file
diff --git a/android/app/src/main/res/drawable/ic_baseline_album_24.xml b/android/app/src/main/res/drawable/ic_baseline_album_24.xml
deleted file mode 100644
index 58c0ba697..000000000
--- a/android/app/src/main/res/drawable/ic_baseline_album_24.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="24dp"
-    android:height="24dp"
-    android:viewportWidth="24"
-    android:viewportHeight="24"
-    android:tint="?attr/colorControlNormal">
-  <path
-      android:fillColor="@android:color/white"
-      android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,16.5c-2.49,0 -4.5,-2.01 -4.5,-4.5S9.51,7.5 12,7.5s4.5,2.01 4.5,4.5 -2.01,4.5 -4.5,4.5zM12,11c-0.55,0 -1,0.45 -1,1s0.45,1 1,1 1,-0.45 1,-1 -0.45,-1 -1,-1z"/>
-</vector>
diff --git a/android/app/src/main/res/drawable/ic_baseline_arrow_back_24.xml b/android/app/src/main/res/drawable/ic_baseline_arrow_back_24.xml
deleted file mode 100644
index 2a31b2ef3..000000000
--- a/android/app/src/main/res/drawable/ic_baseline_arrow_back_24.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="24dp"
-    android:height="24dp"
-    android:viewportWidth="24"
-    android:viewportHeight="24"
-    android:tint="?attr/colorControlNormal"
-    android:autoMirrored="true">
-  <path
-      android:fillColor="@android:color/white"
-      android:pathData="M20,11H7.83l5.59,-5.59L12,4l-8,8 8,8 1.41,-1.41L7.83,13H20v-2z"/>
-</vector>
diff --git a/android/app/src/main/res/drawable/ic_baseline_category_24.xml b/android/app/src/main/res/drawable/ic_baseline_category_24.xml
deleted file mode 100644
index dead295df..000000000
--- a/android/app/src/main/res/drawable/ic_baseline_category_24.xml
+++ /dev/null
@@ -1,16 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="24dp"
-    android:height="24dp"
-    android:viewportWidth="24"
-    android:viewportHeight="24"
-    android:tint="?attr/colorControlNormal">
-    <path
-        android:fillColor="@android:color/white"
-        android:pathData="M12,2l-5.5,9h11z" />
-    <path
-        android:fillColor="@android:color/white"
-        android:pathData="M17.5,17.5m-4.5,0a4.5,4.5 0,1 1,9 0a4.5,4.5 0,1 1,-9 0" />
-    <path
-        android:fillColor="@android:color/white"
-        android:pathData="M3,13.5h8v8H3z" />
-</vector>
diff --git a/android/app/src/main/res/drawable/ic_baseline_close_24.xml b/android/app/src/main/res/drawable/ic_baseline_close_24.xml
deleted file mode 100644
index 16d6d37dd..000000000
--- a/android/app/src/main/res/drawable/ic_baseline_close_24.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="24dp"
-    android:height="24dp"
-    android:viewportWidth="24"
-    android:viewportHeight="24"
-    android:tint="?attr/colorControlNormal">
-  <path
-      android:fillColor="@android:color/white"
-      android:pathData="M19,6.41L17.59,5 12,10.59 6.41,5 5,6.41 10.59,12 5,17.59 6.41,19 12,13.41 17.59,19 19,17.59 13.41,12z"/>
-</vector>
diff --git a/android/app/src/main/res/drawable/ic_baseline_create_new_folder_24.xml b/android/app/src/main/res/drawable/ic_baseline_create_new_folder_24.xml
deleted file mode 100644
index 78c162283..000000000
--- a/android/app/src/main/res/drawable/ic_baseline_create_new_folder_24.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="24dp"
-    android:height="24dp"
-    android:viewportWidth="24"
-    android:viewportHeight="24"
-    android:tint="?attr/colorControlNormal">
-  <path
-      android:fillColor="@android:color/white"
-      android:pathData="M20,6h-8l-2,-2L4,4c-1.11,0 -1.99,0.89 -1.99,2L2,18c0,1.11 0.89,2 2,2h16c1.11,0 2,-0.89 2,-2L22,8c0,-1.11 -0.89,-2 -2,-2zM19,14h-3v3h-2v-3h-3v-2h3L14,9h2v3h3v2z"/>
-</vector>
diff --git a/android/app/src/main/res/drawable/ic_baseline_delete_24.xml b/android/app/src/main/res/drawable/ic_baseline_delete_24.xml
deleted file mode 100644
index 3c4030b03..000000000
--- a/android/app/src/main/res/drawable/ic_baseline_delete_24.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="24dp"
-    android:height="24dp"
-    android:viewportWidth="24"
-    android:viewportHeight="24"
-    android:tint="?attr/colorControlNormal">
-  <path
-      android:fillColor="@android:color/white"
-      android:pathData="M6,19c0,1.1 0.9,2 2,2h8c1.1,0 2,-0.9 2,-2V7H6v12zM19,4h-3.5l-1,-1h-5l-1,1H5v2h14V4z"/>
-</vector>
diff --git a/android/app/src/main/res/drawable/ic_baseline_delete_sweep_24.xml b/android/app/src/main/res/drawable/ic_baseline_delete_sweep_24.xml
deleted file mode 100644
index 22560a4f9..000000000
--- a/android/app/src/main/res/drawable/ic_baseline_delete_sweep_24.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="24dp"
-    android:height="24dp"
-    android:viewportWidth="24"
-    android:viewportHeight="24"
-    android:tint="?attr/colorControlNormal">
-  <path
-      android:fillColor="@android:color/white"
-      android:pathData="M15,16h4v2h-4zM15,8h7v2h-7zM15,12h6v2h-6zM3,18c0,1.1 0.9,2 2,2h6c1.1,0 2,-0.9 2,-2L13,8L3,8v10zM14,5h-3l-1,-1L6,4L5,5L2,5v2h12z"/>
-</vector>
diff --git a/android/app/src/main/res/drawable/ic_baseline_exit_to_app_24.xml b/android/app/src/main/res/drawable/ic_baseline_exit_to_app_24.xml
deleted file mode 100644
index ed42b700b..000000000
--- a/android/app/src/main/res/drawable/ic_baseline_exit_to_app_24.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="24dp"
-    android:height="24dp"
-    android:viewportWidth="24"
-    android:viewportHeight="24"
-    android:tint="?attr/colorControlNormal"
-    android:autoMirrored="true">
-  <path
-      android:fillColor="@android:color/white"
-      android:pathData="M10.09,15.59L11.5,17l5,-5 -5,-5 -1.41,1.41L12.67,11H3v2h9.67l-2.58,2.59zM19,3H5c-1.11,0 -2,0.9 -2,2v4h2V5h14v14H5v-4H3v4c0,1.1 0.89,2 2,2h14c1.1,0 2,-0.9 2,-2V5c0,-1.1 -0.9,-2 -2,-2z"/>
-</vector>
diff --git a/android/app/src/main/res/drawable/ic_baseline_fast_forward_24.xml b/android/app/src/main/res/drawable/ic_baseline_fast_forward_24.xml
deleted file mode 100644
index e3f30c6c7..000000000
--- a/android/app/src/main/res/drawable/ic_baseline_fast_forward_24.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="24dp"
-    android:height="24dp"
-    android:viewportWidth="24"
-    android:viewportHeight="24"
-    android:tint="?attr/colorControlNormal">
-  <path
-      android:fillColor="@android:color/white"
-      android:pathData="M4,18l8.5,-6L4,6v12zM13,6v12l8.5,-6L13,6z"/>
-</vector>
diff --git a/android/app/src/main/res/drawable/ic_baseline_fast_rewind_24.xml b/android/app/src/main/res/drawable/ic_baseline_fast_rewind_24.xml
deleted file mode 100644
index 81f79b322..000000000
--- a/android/app/src/main/res/drawable/ic_baseline_fast_rewind_24.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="24dp"
-    android:height="24dp"
-    android:viewportWidth="24"
-    android:viewportHeight="24"
-    android:tint="?attr/colorControlNormal">
-  <path
-      android:fillColor="@android:color/white"
-      android:pathData="M11,18L11,6l-8.5,6 8.5,6zM11.5,12l8.5,6L20,6l-8.5,6z"/>
-</vector>
diff --git a/android/app/src/main/res/drawable/ic_baseline_folder_24.xml b/android/app/src/main/res/drawable/ic_baseline_folder_24.xml
deleted file mode 100644
index bbfe9c931..000000000
--- a/android/app/src/main/res/drawable/ic_baseline_folder_24.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="24dp"
-    android:height="24dp"
-    android:viewportWidth="24"
-    android:viewportHeight="24"
-    android:tint="?attr/colorControlNormal">
-    <path
-        android:fillColor="@android:color/white"
-        android:pathData="M10,4H4c-1.1,0 -1.99,0.9 -1.99,2L2,18c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2V8c0,-1.1 -0.9,-2 -2,-2h-8l-2,-2z" />
-</vector>
diff --git a/android/app/src/main/res/drawable/ic_baseline_folder_open_24.xml b/android/app/src/main/res/drawable/ic_baseline_folder_open_24.xml
deleted file mode 100644
index f58b501e3..000000000
--- a/android/app/src/main/res/drawable/ic_baseline_folder_open_24.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="24dp"
-    android:height="24dp"
-    android:viewportWidth="24"
-    android:viewportHeight="24"
-    android:tint="?attr/colorControlNormal">
-  <path
-      android:fillColor="@android:color/white"
-      android:pathData="M20,6h-8l-2,-2L4,4c-1.1,0 -1.99,0.9 -1.99,2L2,18c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2L22,8c0,-1.1 -0.9,-2 -2,-2zM20,18L4,18L4,8h16v10z"/>
-</vector>
diff --git a/android/app/src/main/res/drawable/ic_baseline_gamepad_24.xml b/android/app/src/main/res/drawable/ic_baseline_gamepad_24.xml
deleted file mode 100644
index f4a8a8711..000000000
--- a/android/app/src/main/res/drawable/ic_baseline_gamepad_24.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="24dp"
-    android:height="24dp"
-    android:viewportWidth="24"
-    android:viewportHeight="24"
-    android:tint="?attr/colorControlNormal">
-    <path
-        android:fillColor="@android:color/white"
-        android:pathData="M15,7.5V2H9v5.5l3,3 3,-3zM7.5,9H2v6h5.5l3,-3 -3,-3zM9,16.5V22h6v-5.5l-3,-3 -3,3zM16.5,9l-3,3 3,3H22V9h-5.5z" />
-</vector>
diff --git a/android/app/src/main/res/drawable/ic_baseline_grid_view_24.xml b/android/app/src/main/res/drawable/ic_baseline_grid_view_24.xml
deleted file mode 100644
index 6d4f4a563..000000000
--- a/android/app/src/main/res/drawable/ic_baseline_grid_view_24.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="24dp"
-    android:height="24dp"
-    android:viewportWidth="24"
-    android:viewportHeight="24"
-    android:tint="?attr/colorControlNormal">
-  <path
-      android:fillColor="@android:color/white"
-      android:pathData="M3,3v8h8L11,3L3,3zM9,9L5,9L5,5h4v4zM3,13v8h8v-8L3,13zM9,19L5,19v-4h4v4zM13,3v8h8L21,3h-8zM19,9h-4L15,5h4v4zM13,13v8h8v-8h-8zM19,19h-4v-4h4v4z"/>
-</vector>
diff --git a/android/app/src/main/res/drawable/ic_baseline_help_24.xml b/android/app/src/main/res/drawable/ic_baseline_help_24.xml
deleted file mode 100644
index c0c92681d..000000000
--- a/android/app/src/main/res/drawable/ic_baseline_help_24.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="24dp"
-    android:height="24dp"
-    android:viewportWidth="24"
-    android:viewportHeight="24"
-    android:tint="?attr/colorControlNormal">
-  <path
-      android:fillColor="@android:color/white"
-      android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM13,19h-2v-2h2v2zM15.07,11.25l-0.9,0.92C13.45,12.9 13,13.5 13,15h-2v-0.5c0,-1.1 0.45,-2.1 1.17,-2.83l1.24,-1.26c0.37,-0.36 0.59,-0.86 0.59,-1.41 0,-1.1 -0.9,-2 -2,-2s-2,0.9 -2,2L8,9c0,-2.21 1.79,-4 4,-4s4,1.79 4,4c0,0.88 -0.36,1.68 -0.93,2.25z"/>
-</vector>
diff --git a/android/app/src/main/res/drawable/ic_baseline_import_contacts_24.xml b/android/app/src/main/res/drawable/ic_baseline_import_contacts_24.xml
deleted file mode 100644
index 99a23c4db..000000000
--- a/android/app/src/main/res/drawable/ic_baseline_import_contacts_24.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="24dp"
-    android:height="24dp"
-    android:viewportWidth="24"
-    android:viewportHeight="24"
-    android:tint="?attr/colorControlNormal">
-  <path
-      android:fillColor="@android:color/white"
-      android:pathData="M17.5,4.5c-1.95,0 -4.05,0.4 -5.5,1.5c-1.45,-1.1 -3.55,-1.5 -5.5,-1.5S2.45,4.9 1,6v14.65c0,0.65 0.73,0.45 0.75,0.45C3.1,20.45 5.05,20 6.5,20c1.95,0 4.05,0.4 5.5,1.5c1.35,-0.85 3.8,-1.5 5.5,-1.5c1.65,0 3.35,0.3 4.75,1.05C22.66,21.26 23,20.86 23,20.6V6C21.51,4.88 19.37,4.5 17.5,4.5zM21,18.5c-1.1,-0.35 -2.3,-0.5 -3.5,-0.5c-1.7,0 -4.15,0.65 -5.5,1.5V8c1.35,-0.85 3.8,-1.5 5.5,-1.5c1.2,0 2.4,0.15 3.5,0.5V18.5z"/>
-</vector>
diff --git a/android/app/src/main/res/drawable/ic_baseline_insert_drive_file_24.xml b/android/app/src/main/res/drawable/ic_baseline_insert_drive_file_24.xml
deleted file mode 100644
index 18b306228..000000000
--- a/android/app/src/main/res/drawable/ic_baseline_insert_drive_file_24.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="24dp"
-    android:height="24dp"
-    android:viewportWidth="24"
-    android:viewportHeight="24"
-    android:tint="?attr/colorControlNormal"
-    android:autoMirrored="true">
-  <path
-      android:fillColor="@android:color/white"
-      android:pathData="M6,2c-1.1,0 -1.99,0.9 -1.99,2L4,20c0,1.1 0.89,2 1.99,2L18,22c1.1,0 2,-0.9 2,-2L20,8l-6,-6L6,2zM13,9L13,3.5L18.5,9L13,9z"/>
-</vector>
diff --git a/android/app/src/main/res/drawable/ic_baseline_library_music_24.xml b/android/app/src/main/res/drawable/ic_baseline_library_music_24.xml
deleted file mode 100644
index 2ba294bd7..000000000
--- a/android/app/src/main/res/drawable/ic_baseline_library_music_24.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="24dp"
-    android:height="24dp"
-    android:viewportWidth="24"
-    android:viewportHeight="24"
-    android:tint="?attr/colorControlNormal">
-  <path
-      android:fillColor="@android:color/white"
-      android:pathData="M20,2L8,2c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2L22,4c0,-1.1 -0.9,-2 -2,-2zM18,7h-3v5.5c0,1.38 -1.12,2.5 -2.5,2.5S10,13.88 10,12.5s1.12,-2.5 2.5,-2.5c0.57,0 1.08,0.19 1.5,0.51L14,5h4v2zM4,6L2,6v14c0,1.1 0.9,2 2,2h14v-2L4,20L4,6z"/>
-</vector>
diff --git a/android/app/src/main/res/drawable/ic_baseline_lock_24.xml b/android/app/src/main/res/drawable/ic_baseline_lock_24.xml
deleted file mode 100644
index d6191026a..000000000
--- a/android/app/src/main/res/drawable/ic_baseline_lock_24.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="24dp"
-    android:height="24dp"
-    android:viewportWidth="24"
-    android:viewportHeight="24"
-    android:tint="?attr/colorControlNormal">
-  <path
-      android:fillColor="@android:color/white"
-      android:pathData="M18,8h-1L17,6c0,-2.76 -2.24,-5 -5,-5S7,3.24 7,6v2L6,8c-1.1,0 -2,0.9 -2,2v10c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2L20,10c0,-1.1 -0.9,-2 -2,-2zM12,17c-1.1,0 -2,-0.9 -2,-2s0.9,-2 2,-2 2,0.9 2,2 -0.9,2 -2,2zM15.1,8L8.9,8L8.9,6c0,-1.71 1.39,-3.1 3.1,-3.1 1.71,0 3.1,1.39 3.1,3.1v2z"/>
-</vector>
diff --git a/android/app/src/main/res/drawable/ic_baseline_lock_open_24.xml b/android/app/src/main/res/drawable/ic_baseline_lock_open_24.xml
deleted file mode 100644
index a11b70e62..000000000
--- a/android/app/src/main/res/drawable/ic_baseline_lock_open_24.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="24dp"
-    android:height="24dp"
-    android:viewportWidth="24"
-    android:viewportHeight="24"
-    android:tint="?attr/colorControlNormal">
-  <path
-      android:fillColor="@android:color/white"
-      android:pathData="M12,17c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2 -2,0.9 -2,2 0.9,2 2,2zM18,8h-1L17,6c0,-2.76 -2.24,-5 -5,-5S7,3.24 7,6h1.9c0,-1.71 1.39,-3.1 3.1,-3.1 1.71,0 3.1,1.39 3.1,3.1v2L6,8c-1.1,0 -2,0.9 -2,2v10c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2L20,10c0,-1.1 -0.9,-2 -2,-2zM18,20L6,20L6,10h12v10z"/>
-</vector>
diff --git a/android/app/src/main/res/drawable/ic_baseline_menu_24.xml b/android/app/src/main/res/drawable/ic_baseline_menu_24.xml
deleted file mode 100644
index 4350ba96a..000000000
--- a/android/app/src/main/res/drawable/ic_baseline_menu_24.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="24dp"
-    android:height="24dp"
-    android:viewportWidth="24"
-    android:viewportHeight="24"
-    android:tint="?attr/colorControlNormal">
-  <path
-      android:fillColor="@android:color/white"
-      android:pathData="M3,18h18v-2L3,16v2zM3,13h18v-2L3,11v2zM3,6v2h18L21,6L3,6z"/>
-</vector>
diff --git a/android/app/src/main/res/drawable/ic_baseline_not_interested_60.xml b/android/app/src/main/res/drawable/ic_baseline_not_interested_60.xml
deleted file mode 100644
index f5f7da3ae..000000000
--- a/android/app/src/main/res/drawable/ic_baseline_not_interested_60.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<vector android:height="60dp" android:tint="?attr/colorControlNormal"
-    android:viewportHeight="24" android:viewportWidth="24"
-    android:width="60dp" xmlns:android="http://schemas.android.com/apk/res/android">
-    <path android:fillColor="@android:color/white" android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.42,0 -8,-3.58 -8,-8 0,-1.85 0.63,-3.55 1.69,-4.9L16.9,18.31C15.55,19.37 13.85,20 12,20zM18.31,16.9L7.1,5.69C8.45,4.63 10.15,4 12,4c4.42,0 8,3.58 8,8 0,1.85 -0.63,3.55 -1.69,4.9z"/>
-</vector>
diff --git a/android/app/src/main/res/drawable/ic_baseline_play_arrow_24.xml b/android/app/src/main/res/drawable/ic_baseline_play_arrow_24.xml
deleted file mode 100644
index 41f4a52ed..000000000
--- a/android/app/src/main/res/drawable/ic_baseline_play_arrow_24.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="24dp"
-    android:height="24dp"
-    android:viewportWidth="24"
-    android:viewportHeight="24"
-    android:tint="?attr/colorControlNormal">
-    <path
-        android:fillColor="@android:color/white"
-        android:pathData="M8,5v14l11,-7z" />
-</vector>
diff --git a/android/app/src/main/res/drawable/ic_baseline_playlist_play_24.xml b/android/app/src/main/res/drawable/ic_baseline_playlist_play_24.xml
deleted file mode 100644
index 67f9b5735..000000000
--- a/android/app/src/main/res/drawable/ic_baseline_playlist_play_24.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="24dp"
-    android:height="24dp"
-    android:viewportWidth="24"
-    android:viewportHeight="24"
-    android:tint="?attr/colorControlNormal">
-    <path
-        android:fillColor="@android:color/white"
-        android:pathData="M4,10h12v2L4,12zM4,6h12v2L4,8zM4,14h8v2L4,16zM14,14v6l5,-3z" />
-</vector>
diff --git a/android/app/src/main/res/drawable/ic_baseline_radio_button_checked_24.xml b/android/app/src/main/res/drawable/ic_baseline_radio_button_checked_24.xml
deleted file mode 100644
index 05a669ab2..000000000
--- a/android/app/src/main/res/drawable/ic_baseline_radio_button_checked_24.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="24dp"
-    android:height="24dp"
-    android:viewportWidth="24"
-    android:viewportHeight="24"
-    android:tint="?attr/colorControlNormal">
-    <path
-        android:fillColor="@android:color/white"
-        android:pathData="M12,7c-2.76,0 -5,2.24 -5,5s2.24,5 5,5 5,-2.24 5,-5 -2.24,-5 -5,-5zM12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.42,0 -8,-3.58 -8,-8s3.58,-8 8,-8 8,3.58 8,8 -3.58,8 -8,8z" />
-</vector>
diff --git a/android/app/src/main/res/drawable/ic_baseline_radio_button_unchecked_24.xml b/android/app/src/main/res/drawable/ic_baseline_radio_button_unchecked_24.xml
deleted file mode 100644
index 2d5445cbe..000000000
--- a/android/app/src/main/res/drawable/ic_baseline_radio_button_unchecked_24.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="24dp"
-    android:height="24dp"
-    android:viewportWidth="24"
-    android:viewportHeight="24"
-    android:tint="?attr/colorControlNormal">
-    <path
-        android:fillColor="@android:color/white"
-        android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.42,0 -8,-3.58 -8,-8s3.58,-8 8,-8 8,3.58 8,8 -3.58,8 -8,8z" />
-</vector>
diff --git a/android/app/src/main/res/drawable/ic_baseline_restart_alt_24.xml b/android/app/src/main/res/drawable/ic_baseline_restart_alt_24.xml
deleted file mode 100644
index 2f9f24ca9..000000000
--- a/android/app/src/main/res/drawable/ic_baseline_restart_alt_24.xml
+++ /dev/null
@@ -1,13 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="24dp"
-    android:height="24dp"
-    android:viewportWidth="24"
-    android:viewportHeight="24"
-    android:tint="?attr/colorControlNormal">
-  <path
-      android:fillColor="@android:color/white"
-      android:pathData="M12,5V2L8,6l4,4V7c3.31,0 6,2.69 6,6c0,2.97 -2.17,5.43 -5,5.91v2.02c3.95,-0.49 7,-3.85 7,-7.93C20,8.58 16.42,5 12,5z"/>
-  <path
-      android:fillColor="@android:color/white"
-      android:pathData="M6,13c0,-1.65 0.67,-3.15 1.76,-4.24L6.34,7.34C4.9,8.79 4,10.79 4,13c0,4.08 3.05,7.44 7,7.93v-2.02C8.17,18.43 6,15.97 6,13z"/>
-</vector>
diff --git a/android/app/src/main/res/drawable/ic_baseline_save_24.xml b/android/app/src/main/res/drawable/ic_baseline_save_24.xml
deleted file mode 100644
index 955858d7d..000000000
--- a/android/app/src/main/res/drawable/ic_baseline_save_24.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="24dp"
-    android:height="24dp"
-    android:viewportWidth="24"
-    android:viewportHeight="24"
-    android:tint="?attr/colorControlNormal">
-    <path
-        android:fillColor="@android:color/white"
-        android:pathData="M17,3L5,3c-1.11,0 -2,0.9 -2,2v14c0,1.1 0.89,2 2,2h14c1.1,0 2,-0.9 2,-2L21,7l-4,-4zM12,19c-1.66,0 -3,-1.34 -3,-3s1.34,-3 3,-3 3,1.34 3,3 -1.34,3 -3,3zM15,9L5,9L5,5h10v4z" />
-</vector>
diff --git a/android/app/src/main/res/drawable/ic_baseline_sd_card_24.xml b/android/app/src/main/res/drawable/ic_baseline_sd_card_24.xml
deleted file mode 100644
index 84f6ea6ac..000000000
--- a/android/app/src/main/res/drawable/ic_baseline_sd_card_24.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="24dp"
-    android:height="24dp"
-    android:viewportWidth="24"
-    android:viewportHeight="24"
-    android:tint="?attr/colorControlNormal">
-  <path
-      android:fillColor="@android:color/white"
-      android:pathData="M18,2h-8L4.02,8 4,20c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2L20,4c0,-1.1 -0.9,-2 -2,-2zM12,8h-2L10,4h2v4zM15,8h-2L13,4h2v4zM18,8h-2L16,4h2v4z"/>
-</vector>
diff --git a/android/app/src/main/res/drawable/ic_baseline_settings_24.xml b/android/app/src/main/res/drawable/ic_baseline_settings_24.xml
deleted file mode 100644
index d99a8ae40..000000000
--- a/android/app/src/main/res/drawable/ic_baseline_settings_24.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="24dp"
-    android:height="24dp"
-    android:viewportWidth="24"
-    android:viewportHeight="24"
-    android:tint="?attr/colorControlNormal">
-    <path
-        android:fillColor="@android:color/white"
-        android:pathData="M19.14,12.94c0.04,-0.3 0.06,-0.61 0.06,-0.94c0,-0.32 -0.02,-0.64 -0.07,-0.94l2.03,-1.58c0.18,-0.14 0.23,-0.41 0.12,-0.61l-1.92,-3.32c-0.12,-0.22 -0.37,-0.29 -0.59,-0.22l-2.39,0.96c-0.5,-0.38 -1.03,-0.7 -1.62,-0.94L14.4,2.81c-0.04,-0.24 -0.24,-0.41 -0.48,-0.41h-3.84c-0.24,0 -0.43,0.17 -0.47,0.41L9.25,5.35C8.66,5.59 8.12,5.92 7.63,6.29L5.24,5.33c-0.22,-0.08 -0.47,0 -0.59,0.22L2.74,8.87C2.62,9.08 2.66,9.34 2.86,9.48l2.03,1.58C4.84,11.36 4.8,11.69 4.8,12s0.02,0.64 0.07,0.94l-2.03,1.58c-0.18,0.14 -0.23,0.41 -0.12,0.61l1.92,3.32c0.12,0.22 0.37,0.29 0.59,0.22l2.39,-0.96c0.5,0.38 1.03,0.7 1.62,0.94l0.36,2.54c0.05,0.24 0.24,0.41 0.48,0.41h3.84c0.24,0 0.44,-0.17 0.47,-0.41l0.36,-2.54c0.59,-0.24 1.13,-0.56 1.62,-0.94l2.39,0.96c0.22,0.08 0.47,0 0.59,-0.22l1.92,-3.32c0.12,-0.22 0.07,-0.47 -0.12,-0.61L19.14,12.94zM12,15.6c-1.98,0 -3.6,-1.62 -3.6,-3.6s1.62,-3.6 3.6,-3.6s3.6,1.62 3.6,3.6S13.98,15.6 12,15.6z" />
-</vector>
diff --git a/android/app/src/main/res/drawable/ic_baseline_tips_and_updates_24.xml b/android/app/src/main/res/drawable/ic_baseline_tips_and_updates_24.xml
deleted file mode 100644
index 93d588228..000000000
--- a/android/app/src/main/res/drawable/ic_baseline_tips_and_updates_24.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="24dp"
-    android:height="24dp"
-    android:viewportWidth="24"
-    android:viewportHeight="24"
-    android:tint="?attr/colorControlNormal">
-  <path
-      android:fillColor="@android:color/white"
-      android:pathData="M7,20h4c0,1.1 -0.9,2 -2,2S7,21.1 7,20zM5,19h8v-2H5V19zM16.5,9.5c0,3.82 -2.66,5.86 -3.77,6.5H5.27C4.16,15.36 1.5,13.32 1.5,9.5C1.5,5.36 4.86,2 9,2S16.5,5.36 16.5,9.5zM21.37,7.37L20,8l1.37,0.63L22,10l0.63,-1.37L24,8l-1.37,-0.63L22,6L21.37,7.37zM19,6l0.94,-2.06L22,3l-2.06,-0.94L19,0l-0.94,2.06L16,3l2.06,0.94L19,6z"/>
-</vector>
diff --git a/android/app/src/main/res/drawable/ic_baseline_touch_app_24.xml b/android/app/src/main/res/drawable/ic_baseline_touch_app_24.xml
deleted file mode 100644
index 27f451658..000000000
--- a/android/app/src/main/res/drawable/ic_baseline_touch_app_24.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="24dp"
-    android:height="24dp"
-    android:viewportWidth="24"
-    android:viewportHeight="24"
-    android:tint="?attr/colorControlNormal">
-  <path
-      android:fillColor="@android:color/white"
-      android:pathData="M9,11.24V7.5C9,6.12 10.12,5 11.5,5S14,6.12 14,7.5v3.74c1.21,-0.81 2,-2.18 2,-3.74C16,5.01 13.99,3 11.5,3S7,5.01 7,7.5C7,9.06 7.79,10.43 9,11.24zM18.84,15.87l-4.54,-2.26c-0.17,-0.07 -0.35,-0.11 -0.54,-0.11H13v-6C13,6.67 12.33,6 11.5,6S10,6.67 10,7.5v10.74c-3.6,-0.76 -3.54,-0.75 -3.67,-0.75c-0.31,0 -0.59,0.13 -0.79,0.33l-0.79,0.8l4.94,4.94C9.96,23.83 10.34,24 10.75,24h6.79c0.75,0 1.33,-0.55 1.44,-1.28l0.75,-5.27c0.01,-0.07 0.02,-0.14 0.02,-0.2C19.75,16.63 19.37,16.09 18.84,15.87z"/>
-</vector>
diff --git a/android/app/src/main/res/drawable/ic_baseline_trophy_24.xml b/android/app/src/main/res/drawable/ic_baseline_trophy_24.xml
deleted file mode 100644
index dbf6358f8..000000000
--- a/android/app/src/main/res/drawable/ic_baseline_trophy_24.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="24dp"
-    android:height="24dp"
-    android:viewportWidth="24"
-    android:viewportHeight="24"
-    android:tint="?attr/colorControlNormal">
-  <path
-      android:fillColor="@android:color/white"
-      android:pathData="M19,5h-2V3H7v2H5C3.9,5 3,5.9 3,7v1c0,2.55 1.92,4.63 4.39,4.94c0.63,1.5 1.98,2.63 3.61,2.96V19H7v2h10v-2h-4v-3.1c1.63,-0.33 2.98,-1.46 3.61,-2.96C19.08,12.63 21,10.55 21,8V7C21,5.9 20.1,5 19,5zM5,8V7h2v3.82C5.84,10.4 5,9.3 5,8zM19,8c0,1.3 -0.84,2.4 -2,2.82V7h2V8z"/>
-</vector>
diff --git a/android/app/src/main/res/drawable/ic_baseline_vibration_24.xml b/android/app/src/main/res/drawable/ic_baseline_vibration_24.xml
deleted file mode 100644
index a9600b74e..000000000
--- a/android/app/src/main/res/drawable/ic_baseline_vibration_24.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="24dp"
-    android:height="24dp"
-    android:viewportWidth="24"
-    android:viewportHeight="24"
-    android:tint="?attr/colorControlNormal">
-  <path
-      android:fillColor="@android:color/white"
-      android:pathData="M0,15h2L2,9L0,9v6zM3,17h2L5,7L3,7v10zM22,9v6h2L24,9h-2zM19,17h2L21,7h-2v10zM16.5,3h-9C6.67,3 6,3.67 6,4.5v15c0,0.83 0.67,1.5 1.5,1.5h9c0.83,0 1.5,-0.67 1.5,-1.5v-15c0,-0.83 -0.67,-1.5 -1.5,-1.5zM16,19L8,19L8,5h8v14z"/>
-</vector>
diff --git a/android/app/src/main/res/drawable/ic_baseline_view_list_24.xml b/android/app/src/main/res/drawable/ic_baseline_view_list_24.xml
deleted file mode 100644
index 9884aeb83..000000000
--- a/android/app/src/main/res/drawable/ic_baseline_view_list_24.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="24dp"
-    android:height="24dp"
-    android:viewportWidth="24"
-    android:viewportHeight="24"
-    android:tint="?attr/colorControlNormal">
-  <path
-      android:fillColor="@android:color/white"
-      android:pathData="M4,14h4v-4L4,10v4zM4,19h4v-4L4,15v4zM4,9h4L8,5L4,5v4zM9,14h12v-4L9,10v4zM9,19h12v-4L9,15v4zM9,5v4h12L21,5L9,5z"/>
-</vector>
diff --git a/android/app/src/main/res/drawable/ic_controller_a_button.xml b/android/app/src/main/res/drawable/ic_controller_a_button.xml
deleted file mode 100644
index 74124b194..000000000
--- a/android/app/src/main/res/drawable/ic_controller_a_button.xml
+++ /dev/null
@@ -1,17 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="100dp"
-    android:height="100dp"
-    android:viewportWidth="100"
-    android:viewportHeight="100">
-  <path
-      android:pathData="M99.279,49.946A49.271,49.236 0,0 1,50.009 99.182,49.271 49.236,0 0,1 0.738,49.946 49.271,49.236 0,0 1,50.009 0.711,49.271 49.236,0 0,1 99.279,49.946Z"
-      android:strokeWidth="1.5"
-      android:fillColor="#000000"
-      android:strokeColor="#c8c8c8"
-      android:fillType="evenOdd"
-      android:fillAlpha="0"/>
-  <path
-      android:pathData="m61.587,68.222 l-4.369,-11.227h-14.376l-4.318,11.227h-4.623l14.173,-36.424h4.115l14.122,36.424zM55.846,52.931 L51.782,41.958q-0.152,-0.406 -0.508,-1.473 -0.356,-1.067 -0.711,-2.184 -0.305,-1.168 -0.508,-1.778 -0.356,1.575 -0.813,3.099 -0.457,1.473 -0.762,2.337l-4.115,10.973z"
-      android:fillColor="#c8c8c8"
-      android:strokeColor="#00000000"/>
-</vector>
diff --git a/android/app/src/main/res/drawable/ic_controller_a_button_pressed.xml b/android/app/src/main/res/drawable/ic_controller_a_button_pressed.xml
deleted file mode 100644
index 302d83cce..000000000
--- a/android/app/src/main/res/drawable/ic_controller_a_button_pressed.xml
+++ /dev/null
@@ -1,16 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="100dp"
-    android:height="100dp"
-    android:viewportWidth="100"
-    android:viewportHeight="100">
-  <path
-      android:pathData="M99.279,49.946A49.271,49.236 0,0 1,50.009 99.182,49.271 49.236,0 0,1 0.738,49.946 49.271,49.236 0,0 1,50.009 0.711,49.271 49.236,0 0,1 99.279,49.946Z"
-      android:strokeWidth="1.5"
-      android:fillColor="#969696"
-      android:strokeColor="#c8c8c8"
-      android:fillType="evenOdd"/>
-  <path
-      android:pathData="m61.587,68.222 l-4.369,-11.227h-14.376l-4.318,11.227h-4.623l14.173,-36.424h4.115l14.122,36.424zM55.846,52.931 L51.782,41.958q-0.152,-0.406 -0.508,-1.473 -0.356,-1.067 -0.711,-2.184 -0.305,-1.168 -0.508,-1.778 -0.356,1.575 -0.813,3.099 -0.457,1.473 -0.762,2.337l-4.115,10.973z"
-      android:fillColor="#c8c8c8"
-      android:strokeColor="#00000000"/>
-</vector>
diff --git a/android/app/src/main/res/drawable/ic_controller_analog_base.xml b/android/app/src/main/res/drawable/ic_controller_analog_base.xml
deleted file mode 100644
index 85168053b..000000000
--- a/android/app/src/main/res/drawable/ic_controller_analog_base.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="194.89dp"
-    android:height="194.89dp"
-    android:viewportWidth="194.89"
-    android:viewportHeight="194.89">
-    <path
-        android:pathData="M194.89,97.445A97.445,97.445 0,0 1,97.445 194.89,97.445 97.445,0 0,1 0,97.445 97.445,97.445 0,0 1,97.445 0,97.445 97.445,0 0,1 194.89,97.445Z"
-        android:strokeAlpha="0.50645"
-        android:fillColor="#1a1a1a"
-        android:fillAlpha="0.504414" />
-    <path
-        android:pathData="M178.82,97.445A81.381,81.381 0,0 1,97.439 178.826,81.381 81.381,0 0,1 16.058,97.445 81.381,81.381 0,0 1,97.439 16.064,81.381 81.381,0 0,1 178.82,97.445Z"
-        android:strokeAlpha="0.50645"
-        android:fillColor="#333333"
-        android:fillAlpha="0.504414" />
-    <path
-        android:pathData="M159.05,97.445A61.609,61.609 0,0 1,97.441 159.054,61.609 61.609,0 0,1 35.832,97.445 61.609,61.609 0,0 1,97.441 35.836,61.609 61.609,0 0,1 159.05,97.445Z"
-        android:strokeAlpha="0.50645"
-        android:fillColor="#1a1a1a"
-        android:fillAlpha="0.504414" />
-</vector>
diff --git a/android/app/src/main/res/drawable/ic_controller_analog_button.xml b/android/app/src/main/res/drawable/ic_controller_analog_button.xml
deleted file mode 100644
index fec0a0a6e..000000000
--- a/android/app/src/main/res/drawable/ic_controller_analog_button.xml
+++ /dev/null
@@ -1,17 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="24dp"
-    android:height="24dp"
-    android:viewportWidth="24"
-    android:viewportHeight="24">
-  <path
-      android:pathData="M0.6615,0.6614L23.7969,0.6614v23.0L0.6615,23.7969Z"
-      android:strokeAlpha="1"
-      android:strokeLineJoin="round"
-      android:strokeWidth="0.26458332"
-      android:fillColor="#00000000"
-      android:strokeColor="#e6e6e6"
-      android:strokeLineCap="round" />
-  <path
-      android:fillColor="#e6e6e6"
-      android:pathData="M12,2C6.49,2 2,6.49 2,12s4.49,10 10,10 10,-4.49 10,-10S17.51,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8 8,3.59 8,8 -3.59,8 -8,8zM15,12c0,1.66 -1.34,3 -3,3s-3,-1.34 -3,-3 1.34,-3 3,-3 3,1.34 3,3z"/>
-</vector>
diff --git a/android/app/src/main/res/drawable/ic_controller_analog_button_pressed.xml b/android/app/src/main/res/drawable/ic_controller_analog_button_pressed.xml
deleted file mode 100644
index b08bd5e16..000000000
--- a/android/app/src/main/res/drawable/ic_controller_analog_button_pressed.xml
+++ /dev/null
@@ -1,17 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="24dp"
-    android:height="24dp"
-    android:viewportWidth="24"
-    android:viewportHeight="24">
-  <path
-      android:pathData="M0.6615,0.6614L23.7969,0.6614v23.0L0.6615,23.7969Z"
-      android:strokeAlpha="1"
-      android:strokeLineJoin="round"
-      android:strokeWidth="0.26458332"
-      android:fillColor="#4d4d4d"
-      android:strokeColor="#e6e6e6"
-      android:strokeLineCap="round" />
-  <path
-      android:fillColor="#e6e6e6"
-      android:pathData="M12,2C6.49,2 2,6.49 2,12s4.49,10 10,10 10,-4.49 10,-10S17.51,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8 8,3.59 8,8 -3.59,8 -8,8zM15,12c0,1.66 -1.34,3 -3,3s-3,-1.34 -3,-3 1.34,-3 3,-3 3,1.34 3,3z"/>
-</vector>
diff --git a/android/app/src/main/res/drawable/ic_controller_analog_stick_pressed.xml b/android/app/src/main/res/drawable/ic_controller_analog_stick_pressed.xml
deleted file mode 100644
index 7304ff569..000000000
--- a/android/app/src/main/res/drawable/ic_controller_analog_stick_pressed.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="191.756dp"
-    android:height="191.756dp"
-    android:viewportWidth="191.756"
-    android:viewportHeight="191.756">
-    <path
-        android:pathData="M191.756,95.878A95.878,95.878 0,0 1,95.878 191.756,95.878 95.878,0 0,1 0,95.878 95.878,95.878 0,0 1,95.878 0,95.878 95.878,0 0,1 191.756,95.878Z"
-        android:strokeAlpha="0.8"
-        android:fillColor="#666666"
-        android:fillAlpha="0.796784" />
-</vector>
diff --git a/android/app/src/main/res/drawable/ic_controller_analog_stick_unpressed.xml b/android/app/src/main/res/drawable/ic_controller_analog_stick_unpressed.xml
deleted file mode 100644
index 121c376ba..000000000
--- a/android/app/src/main/res/drawable/ic_controller_analog_stick_unpressed.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="191.756dp"
-    android:height="191.756dp"
-    android:viewportWidth="191.756"
-    android:viewportHeight="191.756">
-    <path
-        android:pathData="M191.756,95.878A95.878,95.878 0,0 1,95.878 191.756,95.878 95.878,0 0,1 0,95.878 95.878,95.878 0,0 1,95.878 0,95.878 95.878,0 0,1 191.756,95.878Z"
-        android:strokeAlpha="0.50645"
-        android:fillColor="#666666"
-        android:fillAlpha="0.504414" />
-</vector>
diff --git a/android/app/src/main/res/drawable/ic_controller_b_button.xml b/android/app/src/main/res/drawable/ic_controller_b_button.xml
deleted file mode 100644
index 8f25810d9..000000000
--- a/android/app/src/main/res/drawable/ic_controller_b_button.xml
+++ /dev/null
@@ -1,17 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="100dp"
-    android:height="100dp"
-    android:viewportWidth="100"
-    android:viewportHeight="100">
-  <path
-      android:pathData="M99.279,49.946A49.271,49.236 0,0 1,50.009 99.182,49.271 49.236,0 0,1 0.738,49.946 49.271,49.236 0,0 1,50.009 0.711,49.271 49.236,0 0,1 99.279,49.946Z"
-      android:strokeWidth="1.5"
-      android:fillColor="#000000"
-      android:strokeColor="#c8c8c8"
-      android:fillType="evenOdd"
-      android:fillAlpha="0"/>
-  <path
-      android:pathData="m37.431,31.811h10.363q6.807,0 10.262,2.032 3.505,1.981 3.505,6.96 0,3.2 -1.778,5.334 -1.778,2.083 -5.131,2.692v0.254q2.286,0.356 4.115,1.321 1.88,0.965 2.946,2.743 1.067,1.778 1.067,4.623 0,4.928 -3.404,7.62 -3.353,2.692 -9.195,2.692h-12.751zM42.003,47.254h6.706q4.674,0 6.401,-1.473 1.727,-1.524 1.727,-4.47 0,-2.997 -2.134,-4.267 -2.083,-1.321 -6.706,-1.321h-5.994zM42.003,51.064v13.157h7.315q4.826,0 6.706,-1.88 1.88,-1.88 1.88,-4.928 0,-2.845 -1.981,-4.572 -1.93,-1.778 -6.96,-1.778z"
-      android:fillColor="#c8c8c8"
-      android:strokeColor="#00000000"/>
-</vector>
diff --git a/android/app/src/main/res/drawable/ic_controller_b_button_pressed.xml b/android/app/src/main/res/drawable/ic_controller_b_button_pressed.xml
deleted file mode 100644
index 353d7e5f2..000000000
--- a/android/app/src/main/res/drawable/ic_controller_b_button_pressed.xml
+++ /dev/null
@@ -1,16 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="100dp"
-    android:height="100dp"
-    android:viewportWidth="100"
-    android:viewportHeight="100">
-  <path
-      android:pathData="M99.279,49.946A49.271,49.236 0,0 1,50.009 99.182,49.271 49.236,0 0,1 0.738,49.946 49.271,49.236 0,0 1,50.009 0.711,49.271 49.236,0 0,1 99.279,49.946Z"
-      android:strokeWidth="1.5"
-      android:fillColor="#969696"
-      android:strokeColor="#c8c8c8"
-      android:fillType="evenOdd"/>
-  <path
-      android:pathData="m37.431,31.811h10.363q6.807,0 10.262,2.032 3.505,1.981 3.505,6.96 0,3.2 -1.778,5.334 -1.778,2.083 -5.131,2.692v0.254q2.286,0.356 4.115,1.321 1.88,0.965 2.946,2.743 1.067,1.778 1.067,4.623 0,4.928 -3.404,7.62 -3.353,2.692 -9.195,2.692h-12.751zM42.003,47.254h6.706q4.674,0 6.401,-1.473 1.727,-1.524 1.727,-4.47 0,-2.997 -2.134,-4.267 -2.083,-1.321 -6.706,-1.321h-5.994zM42.003,51.064v13.157h7.315q4.826,0 6.706,-1.88 1.88,-1.88 1.88,-4.928 0,-2.845 -1.981,-4.572 -1.93,-1.778 -6.96,-1.778z"
-      android:fillColor="#c8c8c8"
-      android:strokeColor="#00000000"/>
-</vector>
diff --git a/android/app/src/main/res/drawable/ic_controller_circle_button.xml b/android/app/src/main/res/drawable/ic_controller_circle_button.xml
deleted file mode 100644
index d9fa460c6..000000000
--- a/android/app/src/main/res/drawable/ic_controller_circle_button.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="100dp"
-    android:height="100dp"
-    android:viewportWidth="26.458332"
-    android:viewportHeight="26.45833">
-    <path
-        android:pathData="M13.2292,13.2292m-12.5677,0a12.5677,12.5677 0,1 1,25.1354 0a12.5677,12.5677 0,1 1,-25.1354 0"
-        android:strokeWidth="0.26458332"
-        android:fillColor="#00000000"
-        android:strokeColor="#ffffff" />
-    <path
-        android:pathData="M13.2292,13.2292m-10.5833,0a10.5833,10.5833 0,1 1,21.1667 0a10.5833,10.5833 0,1 1,-21.1667 0"
-        android:strokeLineJoin="round"
-        android:strokeWidth="1.05833328"
-        android:fillColor="#00000000"
-        android:strokeColor="#ff0000"
-        android:fillAlpha="1"
-        android:strokeLineCap="butt" />
-</vector>
diff --git a/android/app/src/main/res/drawable/ic_controller_circle_button_pressed.xml b/android/app/src/main/res/drawable/ic_controller_circle_button_pressed.xml
deleted file mode 100644
index 47953d0c1..000000000
--- a/android/app/src/main/res/drawable/ic_controller_circle_button_pressed.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="100dp"
-    android:height="100dp"
-    android:viewportWidth="26.458332"
-    android:viewportHeight="26.45833">
-    <path
-        android:pathData="M13.2292,13.2292m-12.5677,0a12.5677,12.5677 0,1 1,25.1354 0a12.5677,12.5677 0,1 1,-25.1354 0"
-        android:strokeWidth="0.26458332"
-        android:fillColor="#4d4d4d"
-        android:strokeColor="#ffffff" />
-    <path
-        android:pathData="M13.2292,13.2292m-10.5833,0a10.5833,10.5833 0,1 1,21.1667 0a10.5833,10.5833 0,1 1,-21.1667 0"
-        android:strokeLineJoin="round"
-        android:strokeWidth="1.05833328"
-        android:fillColor="#00000000"
-        android:strokeColor="#ff0000"
-        android:fillAlpha="1"
-        android:strokeLineCap="butt" />
-</vector>
diff --git a/android/app/src/main/res/drawable/ic_controller_cross_button.xml b/android/app/src/main/res/drawable/ic_controller_cross_button.xml
deleted file mode 100644
index b133bd616..000000000
--- a/android/app/src/main/res/drawable/ic_controller_cross_button.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="100dp"
-    android:height="100dp"
-    android:viewportWidth="26.458332"
-    android:viewportHeight="26.45833">
-    <path
-        android:pathData="M13.2292,13.2292m-12.5677,0a12.5677,12.5677 0,1 1,25.1354 0a12.5677,12.5677 0,1 1,-25.1354 0"
-        android:strokeWidth="0.26458332"
-        android:fillColor="#00000000"
-        android:strokeColor="#ffffff" />
-    <path
-        android:pathData="m5.2917,5.2917 l15.875,15.875"
-        android:strokeAlpha="1"
-        android:strokeLineJoin="miter"
-        android:strokeWidth="1.05833333"
-        android:fillColor="#ffffff"
-        android:strokeColor="#008080"
-        android:strokeLineCap="butt" />
-    <path
-        android:pathData="m5.2917,21.1667 l15.875,-15.875"
-        android:strokeAlpha="1"
-        android:strokeLineJoin="miter"
-        android:strokeWidth="1.05833333"
-        android:fillColor="#00000000"
-        android:strokeColor="#008080"
-        android:strokeLineCap="butt" />
-</vector>
diff --git a/android/app/src/main/res/drawable/ic_controller_cross_button_pressed.xml b/android/app/src/main/res/drawable/ic_controller_cross_button_pressed.xml
deleted file mode 100644
index b00988473..000000000
--- a/android/app/src/main/res/drawable/ic_controller_cross_button_pressed.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="100dp"
-    android:height="100dp"
-    android:viewportWidth="26.458332"
-    android:viewportHeight="26.45833">
-    <path
-        android:pathData="M13.2292,13.2292m-12.5677,0a12.5677,12.5677 0,1 1,25.1354 0a12.5677,12.5677 0,1 1,-25.1354 0"
-        android:strokeWidth="0.26458332"
-        android:fillColor="#4d4d4d"
-        android:strokeColor="#ffffff" />
-    <path
-        android:pathData="m5.2917,5.2917 l15.875,15.875"
-        android:strokeAlpha="1"
-        android:strokeLineJoin="miter"
-        android:strokeWidth="1.05833333"
-        android:fillColor="#ffffff"
-        android:strokeColor="#008080"
-        android:strokeLineCap="butt" />
-    <path
-        android:pathData="m5.2917,21.1667 l15.875,-15.875"
-        android:strokeAlpha="1"
-        android:strokeLineJoin="miter"
-        android:strokeWidth="1.05833333"
-        android:fillColor="#00000000"
-        android:strokeColor="#008080"
-        android:strokeLineCap="butt" />
-</vector>
diff --git a/android/app/src/main/res/drawable/ic_controller_down_button.xml b/android/app/src/main/res/drawable/ic_controller_down_button.xml
deleted file mode 100644
index 898f2c54f..000000000
--- a/android/app/src/main/res/drawable/ic_controller_down_button.xml
+++ /dev/null
@@ -1,14 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="100dp"
-    android:height="100dp"
-    android:viewportWidth="26.458332"
-    android:viewportHeight="26.458332">
-    <path
-        android:pathData="m5.2917,10.5833 l7.9375,-7.9375 7.9375,7.9375v14.5521L5.2917,25.1354Z"
-        android:strokeAlpha="1"
-        android:strokeLineJoin="miter"
-        android:strokeWidth="0.26458332"
-        android:fillColor="#00000000"
-        android:strokeColor="#e6e6e6"
-        android:strokeLineCap="butt" />
-</vector>
diff --git a/android/app/src/main/res/drawable/ic_controller_down_button_pressed.xml b/android/app/src/main/res/drawable/ic_controller_down_button_pressed.xml
deleted file mode 100644
index 4e7d5a35e..000000000
--- a/android/app/src/main/res/drawable/ic_controller_down_button_pressed.xml
+++ /dev/null
@@ -1,14 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="100dp"
-    android:height="100dp"
-    android:viewportWidth="26.458332"
-    android:viewportHeight="26.458332">
-    <path
-        android:pathData="m5.2917,10.5833 l7.9375,-7.9375 7.9375,7.9375v14.5521L5.2917,25.1354Z"
-        android:strokeAlpha="1"
-        android:strokeLineJoin="miter"
-        android:strokeWidth="0.26458332"
-        android:fillColor="#4d4d4d"
-        android:strokeColor="#e6e6e6"
-        android:strokeLineCap="butt" />
-</vector>
diff --git a/android/app/src/main/res/drawable/ic_controller_fast_forward.xml b/android/app/src/main/res/drawable/ic_controller_fast_forward.xml
deleted file mode 100644
index 37e89e29b..000000000
--- a/android/app/src/main/res/drawable/ic_controller_fast_forward.xml
+++ /dev/null
@@ -1,17 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="24dp"
-    android:height="24dp"
-    android:viewportWidth="24"
-    android:viewportHeight="24">
-  <path
-      android:pathData="M0.6615,0.6614L23.7969,0.6614v23.0L0.6615,23.7969Z"
-      android:strokeAlpha="1"
-      android:strokeLineJoin="round"
-      android:strokeWidth="0.26458332"
-      android:fillColor="#00000000"
-      android:strokeColor="#e6e6e6"
-      android:strokeLineCap="round" />
-  <path
-      android:fillColor="#e6e6e6"
-      android:pathData="M4,18l8.5,-6L4,6v12zM13,6v12l8.5,-6L13,6z"/>
-</vector>
diff --git a/android/app/src/main/res/drawable/ic_controller_fast_forward_pressed.xml b/android/app/src/main/res/drawable/ic_controller_fast_forward_pressed.xml
deleted file mode 100644
index 2a505aad8..000000000
--- a/android/app/src/main/res/drawable/ic_controller_fast_forward_pressed.xml
+++ /dev/null
@@ -1,17 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="24dp"
-    android:height="24dp"
-    android:viewportWidth="24"
-    android:viewportHeight="24">
-  <path
-      android:pathData="M0.6615,0.6614L23.7969,0.6614v23.0L0.6615,23.7969Z"
-      android:strokeAlpha="1"
-      android:strokeLineJoin="round"
-      android:strokeWidth="0.26458332"
-      android:fillColor="#4d4d4d"
-      android:strokeColor="#e6e6e6"
-      android:strokeLineCap="round" />
-  <path
-      android:fillColor="#e6e6e6"
-      android:pathData="M4,18l8.5,-6L4,6v12zM13,6v12l8.5,-6L13,6z"/>
-</vector>
diff --git a/android/app/src/main/res/drawable/ic_controller_l1_button.xml b/android/app/src/main/res/drawable/ic_controller_l1_button.xml
deleted file mode 100644
index 9f3ab7240..000000000
--- a/android/app/src/main/res/drawable/ic_controller_l1_button.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="100dp"
-    android:height="50dp"
-    android:viewportWidth="26.458332"
-    android:viewportHeight="13.229165">
-    <path
-        android:pathData="M0.6615,0.6614L25.7969,0.6614v11.9063L0.6615,12.5677Z"
-        android:strokeAlpha="1"
-        android:strokeLineJoin="round"
-        android:strokeWidth="0.26458332"
-        android:fillColor="#00000000"
-        android:strokeColor="#e6e6e6"
-        android:strokeLineCap="round" />
-    <path
-        android:pathData="m9.6928,4.0428h0.6959v4.5579h2.5046v0.5857L9.6928,9.1863Z"
-        android:strokeAlpha="1"
-        android:strokeWidth="0.13229167"
-        android:fillColor="#000000"
-        android:strokeColor="#e6e6e6"
-        android:fillAlpha="0" />
-    <path
-        android:pathData="m13.8028,8.6007h1.1369v-3.924l-1.2368,0.2481v-0.6339l1.2299,-0.248h0.6959v4.5579h1.1369v0.5857h-2.9628z"
-        android:strokeAlpha="1"
-        android:strokeWidth="0.13229167"
-        android:fillColor="#000000"
-        android:strokeColor="#e6e6e6"
-        android:fillAlpha="0" />
-</vector>
diff --git a/android/app/src/main/res/drawable/ic_controller_l1_button_pressed.xml b/android/app/src/main/res/drawable/ic_controller_l1_button_pressed.xml
deleted file mode 100644
index 06d625fe5..000000000
--- a/android/app/src/main/res/drawable/ic_controller_l1_button_pressed.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="100dp"
-    android:height="50dp"
-    android:viewportWidth="26.458332"
-    android:viewportHeight="13.229165">
-    <path
-        android:pathData="M0.6615,0.6614L25.7969,0.6614v11.9063L0.6615,12.5677Z"
-        android:strokeAlpha="1"
-        android:strokeLineJoin="round"
-        android:strokeWidth="0.26458332"
-        android:fillColor="#4d4d4d"
-        android:strokeColor="#e6e6e6"
-        android:strokeLineCap="round" />
-    <path
-        android:pathData="m9.6928,4.0428h0.6959v4.5579h2.5046v0.5857L9.6928,9.1863Z"
-        android:strokeAlpha="1"
-        android:strokeWidth="0.13229167"
-        android:fillColor="#1a1a1a"
-        android:strokeColor="#000000"
-        android:fillAlpha="1" />
-    <path
-        android:pathData="m13.8028,8.6007h1.1369v-3.924l-1.2368,0.2481v-0.6339l1.2299,-0.248h0.6959v4.5579h1.1369v0.5857h-2.9628z"
-        android:strokeAlpha="1"
-        android:strokeWidth="0.13229167"
-        android:fillColor="#1a1a1a"
-        android:strokeColor="#000000"
-        android:fillAlpha="1" />
-</vector>
diff --git a/android/app/src/main/res/drawable/ic_controller_l2_button.xml b/android/app/src/main/res/drawable/ic_controller_l2_button.xml
deleted file mode 100644
index 3853d103f..000000000
--- a/android/app/src/main/res/drawable/ic_controller_l2_button.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="100dp"
-    android:height="50dp"
-    android:viewportWidth="26.458332"
-    android:viewportHeight="13.229165">
-    <path
-        android:pathData="M0.6615,0.6614L25.7969,0.6614v11.9063L0.6615,12.5677Z"
-        android:strokeAlpha="1"
-        android:strokeLineJoin="round"
-        android:strokeWidth="0.26458332"
-        android:fillColor="#00000000"
-        android:strokeColor="#e6e6e6"
-        android:strokeLineCap="round" />
-    <path
-        android:pathData="m9.6928,4.0428h0.6959v4.5579h2.5046v0.5857L9.6928,9.1863Z"
-        android:strokeAlpha="1"
-        android:strokeWidth="0.13229167"
-        android:fillColor="#000000"
-        android:strokeColor="#e6e6e6"
-        android:fillAlpha="0" />
-    <path
-        android:pathData="m14.2816,8.6007h2.4288v0.5857h-3.2659v-0.5857q0.3962,-0.41 1.0783,-1.099 0.6856,-0.6925 0.8613,-0.8923 0.3342,-0.3755 0.4651,-0.6339 0.1344,-0.2618 0.1344,-0.5133 0,-0.41 -0.2894,-0.6683 -0.2859,-0.2584 -0.7476,-0.2584 -0.3273,0 -0.6925,0.1137 -0.3617,0.1137 -0.7751,0.3445v-0.7028q0.4203,-0.1688 0.7855,-0.2549 0.3652,-0.0861 0.6683,-0.0861 0.7993,0 1.2747,0.3996 0.4754,0.3996 0.4754,1.068 0,0.3169 -0.1206,0.6029 -0.1171,0.2825 -0.4306,0.6683 -0.0861,0.0999 -0.5478,0.5788 -0.4616,0.4754 -1.3022,1.3333z"
-        android:strokeAlpha="1"
-        android:strokeWidth="0.13229167"
-        android:fillColor="#000000"
-        android:strokeColor="#e6e6e6"
-        android:fillAlpha="0" />
-</vector>
diff --git a/android/app/src/main/res/drawable/ic_controller_l2_button_pressed.xml b/android/app/src/main/res/drawable/ic_controller_l2_button_pressed.xml
deleted file mode 100644
index eeaefb18b..000000000
--- a/android/app/src/main/res/drawable/ic_controller_l2_button_pressed.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="100dp"
-    android:height="50dp"
-    android:viewportWidth="26.458332"
-    android:viewportHeight="13.229165">
-    <path
-        android:pathData="M0.6615,0.6614L25.7969,0.6614v11.9063L0.6615,12.5677Z"
-        android:strokeAlpha="1"
-        android:strokeLineJoin="round"
-        android:strokeWidth="0.26458332"
-        android:fillColor="#4d4d4d"
-        android:strokeColor="#e6e6e6"
-        android:strokeLineCap="round" />
-    <path
-        android:pathData="m9.6928,4.0428h0.6959v4.5579h2.5046v0.5857L9.6928,9.1863Z"
-        android:strokeAlpha="1"
-        android:strokeWidth="0.13229167"
-        android:fillColor="#1a1a1a"
-        android:strokeColor="#000000"
-        android:fillAlpha="1" />
-    <path
-        android:pathData="m14.2816,8.6007h2.4288v0.5857h-3.2659v-0.5857q0.3962,-0.41 1.0783,-1.099 0.6856,-0.6925 0.8613,-0.8923 0.3342,-0.3755 0.4651,-0.6339 0.1344,-0.2618 0.1344,-0.5133 0,-0.41 -0.2894,-0.6683 -0.2859,-0.2584 -0.7476,-0.2584 -0.3273,0 -0.6925,0.1137 -0.3617,0.1137 -0.7751,0.3445v-0.7028q0.4203,-0.1688 0.7855,-0.2549 0.3652,-0.0861 0.6683,-0.0861 0.7993,0 1.2747,0.3996 0.4754,0.3996 0.4754,1.068 0,0.3169 -0.1206,0.6029 -0.1171,0.2825 -0.4306,0.6683 -0.0861,0.0999 -0.5478,0.5788 -0.4616,0.4754 -1.3022,1.3333z"
-        android:strokeAlpha="1"
-        android:strokeWidth="0.13229167"
-        android:fillColor="#1a1a1a"
-        android:strokeColor="#000000"
-        android:fillAlpha="1" />
-</vector>
diff --git a/android/app/src/main/res/drawable/ic_controller_left_button.xml b/android/app/src/main/res/drawable/ic_controller_left_button.xml
deleted file mode 100644
index ccd46c3cc..000000000
--- a/android/app/src/main/res/drawable/ic_controller_left_button.xml
+++ /dev/null
@@ -1,14 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="100dp"
-    android:height="100dp"
-    android:viewportWidth="26.458332"
-    android:viewportHeight="26.458332">
-    <path
-        android:pathData="m16.5365,5.9531 l7.9375,7.9375 -7.9375,7.9375L1.9844,21.8281v-15.875z"
-        android:strokeAlpha="1"
-        android:strokeLineJoin="miter"
-        android:strokeWidth="0.26458332"
-        android:fillColor="#00000000"
-        android:strokeColor="#e6e6e6"
-        android:strokeLineCap="butt" />
-</vector>
diff --git a/android/app/src/main/res/drawable/ic_controller_left_button_pressed.xml b/android/app/src/main/res/drawable/ic_controller_left_button_pressed.xml
deleted file mode 100644
index 39c1de9e1..000000000
--- a/android/app/src/main/res/drawable/ic_controller_left_button_pressed.xml
+++ /dev/null
@@ -1,14 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="100dp"
-    android:height="100dp"
-    android:viewportWidth="26.458332"
-    android:viewportHeight="26.458332">
-    <path
-        android:pathData="m16.5365,5.9531 l7.9375,7.9375 -7.9375,7.9375L1.9844,21.8281v-15.875z"
-        android:strokeAlpha="1"
-        android:strokeLineJoin="miter"
-        android:strokeWidth="0.26458332"
-        android:fillColor="#4d4d4d"
-        android:strokeColor="#e6e6e6"
-        android:strokeLineCap="butt" />
-</vector>
diff --git a/android/app/src/main/res/drawable/ic_controller_pause_button.xml b/android/app/src/main/res/drawable/ic_controller_pause_button.xml
deleted file mode 100644
index 9b64f42b0..000000000
--- a/android/app/src/main/res/drawable/ic_controller_pause_button.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="24dp"
-    android:height="24dp"
-    android:viewportWidth="24"
-    android:viewportHeight="24">
-  <path
-      android:fillColor="#4d4d4d"
-      android:pathData="M9,16h2L11,8L9,8v8zM12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8 8,3.59 8,8 -3.59,8 -8,8zM13,16h2L15,8h-2v8z"/>
-</vector>
diff --git a/android/app/src/main/res/drawable/ic_controller_quick_load_button.xml b/android/app/src/main/res/drawable/ic_controller_quick_load_button.xml
deleted file mode 100644
index f4197876c..000000000
--- a/android/app/src/main/res/drawable/ic_controller_quick_load_button.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="24dp"
-    android:height="24dp"
-    android:viewportWidth="24"
-    android:viewportHeight="24">
-  <path
-      android:fillColor="#4d4d4d"
-      android:pathData="M14,12c0,-1.1 -0.9,-2 -2,-2s-2,0.9 -2,2 0.9,2 2,2 2,-0.9 2,-2zM12,3c-4.97,0 -9,4.03 -9,9L0,12l4,4 4,-4L5,12c0,-3.87 3.13,-7 7,-7s7,3.13 7,7 -3.13,7 -7,7c-1.51,0 -2.91,-0.49 -4.06,-1.3l-1.42,1.44C8.04,20.3 9.94,21 12,21c4.97,0 9,-4.03 9,-9s-4.03,-9 -9,-9z"/>
-</vector>
diff --git a/android/app/src/main/res/drawable/ic_controller_quick_save_button.xml b/android/app/src/main/res/drawable/ic_controller_quick_save_button.xml
deleted file mode 100644
index 2a81bac25..000000000
--- a/android/app/src/main/res/drawable/ic_controller_quick_save_button.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="24dp"
-    android:height="24dp"
-    android:viewportWidth="24"
-    android:viewportHeight="24">
-  <path
-      android:fillColor="#4d4d4d"
-      android:pathData="M17,3L5,3c-1.11,0 -2,0.9 -2,2v14c0,1.1 0.89,2 2,2h14c1.1,0 2,-0.9 2,-2L21,7l-4,-4zM12,19c-1.66,0 -3,-1.34 -3,-3s1.34,-3 3,-3 3,1.34 3,3 -1.34,3 -3,3zM15,9L5,9L5,5h10v4z"/>
-</vector>
diff --git a/android/app/src/main/res/drawable/ic_controller_r1_button.xml b/android/app/src/main/res/drawable/ic_controller_r1_button.xml
deleted file mode 100644
index 3130def38..000000000
--- a/android/app/src/main/res/drawable/ic_controller_r1_button.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="100dp"
-    android:height="50dp"
-    android:viewportWidth="26.458332"
-    android:viewportHeight="13.229165">
-    <path
-        android:pathData="M0.6615,0.6614L25.7969,0.6614v11.9063L0.6615,12.5677Z"
-        android:strokeAlpha="1"
-        android:strokeLineJoin="round"
-        android:strokeWidth="0.26458332"
-        android:fillColor="#00000000"
-        android:strokeColor="#e6e6e6"
-        android:strokeLineCap="round" />
-    <path
-        android:pathData="m11.6703,6.8213q0.2239,0.0758 0.4341,0.3238 0.2136,0.248 0.4272,0.6821l0.7062,1.4056h-0.7476l-0.658,-1.3195q-0.2549,-0.5168 -0.4961,-0.6856 -0.2377,-0.1688 -0.6511,-0.1688L9.927,7.059v2.1739L9.2311,9.2329v-5.1435h1.571q0.8819,0 1.316,0.3686 0.4341,0.3686 0.4341,1.1128 0,0.4858 -0.2274,0.8062 -0.2239,0.3204 -0.6546,0.4444zM9.927,4.6612v1.8259h0.8751q0.503,0 0.7579,-0.2308 0.2584,-0.2343 0.2584,-0.6856 0,-0.4513 -0.2584,-0.6787 -0.2549,-0.2308 -0.7579,-0.2308z"
-        android:strokeAlpha="1"
-        android:strokeWidth="0.13229167"
-        android:fillColor="#000000"
-        android:strokeColor="#e6e6e6"
-        android:fillAlpha="0" />
-    <path
-        android:pathData="m14.3195,8.6472h1.1369v-3.924l-1.2368,0.2481v-0.6339l1.2299,-0.248h0.6959v4.5579h1.1369v0.5857h-2.9628z"
-        android:strokeAlpha="1"
-        android:strokeWidth="0.13229167"
-        android:fillColor="#000000"
-        android:strokeColor="#e6e6e6"
-        android:fillAlpha="0" />
-</vector>
diff --git a/android/app/src/main/res/drawable/ic_controller_r1_button_pressed.xml b/android/app/src/main/res/drawable/ic_controller_r1_button_pressed.xml
deleted file mode 100644
index 352ddbc6a..000000000
--- a/android/app/src/main/res/drawable/ic_controller_r1_button_pressed.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="100dp"
-    android:height="50dp"
-    android:viewportWidth="26.458332"
-    android:viewportHeight="13.229165">
-    <path
-        android:pathData="M0.6615,0.6614L25.7969,0.6614v11.9063L0.6615,12.5677Z"
-        android:strokeAlpha="1"
-        android:strokeLineJoin="round"
-        android:strokeWidth="0.26458332"
-        android:fillColor="#4d4d4d"
-        android:strokeColor="#e6e6e6"
-        android:strokeLineCap="round" />
-    <path
-        android:pathData="m11.6703,6.8213q0.2239,0.0758 0.4341,0.3238 0.2136,0.248 0.4272,0.6821l0.7062,1.4056h-0.7476l-0.658,-1.3195q-0.2549,-0.5168 -0.4961,-0.6856 -0.2377,-0.1688 -0.6511,-0.1688L9.927,7.059v2.1739L9.2311,9.2329v-5.1435h1.571q0.8819,0 1.316,0.3686 0.4341,0.3686 0.4341,1.1128 0,0.4858 -0.2274,0.8062 -0.2239,0.3204 -0.6546,0.4444zM9.927,4.6612v1.8259h0.8751q0.503,0 0.7579,-0.2308 0.2584,-0.2343 0.2584,-0.6856 0,-0.4513 -0.2584,-0.6787 -0.2549,-0.2308 -0.7579,-0.2308z"
-        android:strokeAlpha="1"
-        android:strokeWidth="0.13229167"
-        android:fillColor="#1a1a1a"
-        android:strokeColor="#000000"
-        android:fillAlpha="1" />
-    <path
-        android:pathData="m14.3195,8.6472h1.1369v-3.924l-1.2368,0.2481v-0.6339l1.2299,-0.248h0.6959v4.5579h1.1369v0.5857h-2.9628z"
-        android:strokeAlpha="1"
-        android:strokeWidth="0.13229167"
-        android:fillColor="#1a1a1a"
-        android:strokeColor="#000000"
-        android:fillAlpha="1" />
-</vector>
diff --git a/android/app/src/main/res/drawable/ic_controller_r2_button.xml b/android/app/src/main/res/drawable/ic_controller_r2_button.xml
deleted file mode 100644
index 195fbe85d..000000000
--- a/android/app/src/main/res/drawable/ic_controller_r2_button.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="100dp"
-    android:height="50dp"
-    android:viewportWidth="26.458332"
-    android:viewportHeight="13.229165">
-    <path
-        android:pathData="M0.6615,0.6614L25.7969,0.6614v11.9063L0.6615,12.5677Z"
-        android:strokeAlpha="1"
-        android:strokeLineJoin="round"
-        android:strokeWidth="0.26458332"
-        android:fillColor="#00000000"
-        android:strokeColor="#e6e6e6"
-        android:strokeLineCap="round" />
-    <path
-        android:pathData="m11.6703,6.8213q0.2239,0.0758 0.4341,0.3238 0.2136,0.248 0.4272,0.6821l0.7062,1.4056h-0.7476l-0.658,-1.3195q-0.2549,-0.5168 -0.4961,-0.6856 -0.2377,-0.1688 -0.6511,-0.1688L9.927,7.059v2.1739L9.2311,9.2329v-5.1435h1.571q0.8819,0 1.316,0.3686 0.4341,0.3686 0.4341,1.1128 0,0.4858 -0.2274,0.8062 -0.2239,0.3204 -0.6546,0.4444zM9.927,4.6612v1.8259h0.8751q0.503,0 0.7579,-0.2308 0.2584,-0.2343 0.2584,-0.6856 0,-0.4513 -0.2584,-0.6787 -0.2549,-0.2308 -0.7579,-0.2308z"
-        android:strokeAlpha="1"
-        android:strokeWidth="0.13229167"
-        android:fillColor="#000000"
-        android:strokeColor="#e6e6e6"
-        android:fillAlpha="0" />
-    <path
-        android:pathData="m14.7984,8.6472h2.4288v0.5857h-3.2659v-0.5857q0.3962,-0.41 1.0783,-1.099 0.6856,-0.6925 0.8613,-0.8923 0.3342,-0.3755 0.4651,-0.6339 0.1344,-0.2618 0.1344,-0.5133 0,-0.41 -0.2894,-0.6683 -0.2859,-0.2584 -0.7476,-0.2584 -0.3273,0 -0.6925,0.1137 -0.3617,0.1137 -0.7751,0.3445v-0.7028q0.4203,-0.1688 0.7855,-0.2549 0.3652,-0.0861 0.6683,-0.0861 0.7993,0 1.2747,0.3996 0.4754,0.3996 0.4754,1.068 0,0.3169 -0.1206,0.6029 -0.1171,0.2825 -0.4306,0.6683 -0.0861,0.0999 -0.5478,0.5788 -0.4616,0.4754 -1.3022,1.3333z"
-        android:strokeAlpha="1"
-        android:strokeWidth="0.13229167"
-        android:fillColor="#000000"
-        android:strokeColor="#e6e6e6"
-        android:fillAlpha="0" />
-</vector>
diff --git a/android/app/src/main/res/drawable/ic_controller_r2_button_pressed.xml b/android/app/src/main/res/drawable/ic_controller_r2_button_pressed.xml
deleted file mode 100644
index 640c36863..000000000
--- a/android/app/src/main/res/drawable/ic_controller_r2_button_pressed.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="100dp"
-    android:height="50dp"
-    android:viewportWidth="26.458332"
-    android:viewportHeight="13.229165">
-    <path
-        android:pathData="M0.6615,0.6614L25.7969,0.6614v11.9063L0.6615,12.5677Z"
-        android:strokeAlpha="1"
-        android:strokeLineJoin="round"
-        android:strokeWidth="0.26458332"
-        android:fillColor="#4d4d4d"
-        android:strokeColor="#e6e6e6"
-        android:strokeLineCap="round" />
-    <path
-        android:pathData="m11.6703,6.8213q0.2239,0.0758 0.4341,0.3238 0.2136,0.248 0.4272,0.6821l0.7062,1.4056h-0.7476l-0.658,-1.3195q-0.2549,-0.5168 -0.4961,-0.6856 -0.2377,-0.1688 -0.6511,-0.1688L9.927,7.059v2.1739L9.2311,9.2329v-5.1435h1.571q0.8819,0 1.316,0.3686 0.4341,0.3686 0.4341,1.1128 0,0.4858 -0.2274,0.8062 -0.2239,0.3204 -0.6546,0.4444zM9.927,4.6612v1.8259h0.8751q0.503,0 0.7579,-0.2308 0.2584,-0.2343 0.2584,-0.6856 0,-0.4513 -0.2584,-0.6787 -0.2549,-0.2308 -0.7579,-0.2308z"
-        android:strokeAlpha="1"
-        android:strokeWidth="0.13229167"
-        android:fillColor="#1a1a1a"
-        android:strokeColor="#000000"
-        android:fillAlpha="1" />
-    <path
-        android:pathData="m14.7984,8.6472h2.4288v0.5857h-3.2659v-0.5857q0.3962,-0.41 1.0783,-1.099 0.6856,-0.6925 0.8613,-0.8923 0.3342,-0.3755 0.4651,-0.6339 0.1344,-0.2618 0.1344,-0.5133 0,-0.41 -0.2894,-0.6683 -0.2859,-0.2584 -0.7476,-0.2584 -0.3273,0 -0.6925,0.1137 -0.3617,0.1137 -0.7751,0.3445v-0.7028q0.4203,-0.1688 0.7855,-0.2549 0.3652,-0.0861 0.6683,-0.0861 0.7993,0 1.2747,0.3996 0.4754,0.3996 0.4754,1.068 0,0.3169 -0.1206,0.6029 -0.1171,0.2825 -0.4306,0.6683 -0.0861,0.0999 -0.5478,0.5788 -0.4616,0.4754 -1.3022,1.3333z"
-        android:strokeAlpha="1"
-        android:strokeWidth="0.13229167"
-        android:fillColor="#1a1a1a"
-        android:strokeColor="#000000"
-        android:fillAlpha="1" />
-</vector>
diff --git a/android/app/src/main/res/drawable/ic_controller_right_button.xml b/android/app/src/main/res/drawable/ic_controller_right_button.xml
deleted file mode 100644
index 8545a61ce..000000000
--- a/android/app/src/main/res/drawable/ic_controller_right_button.xml
+++ /dev/null
@@ -1,14 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="100dp"
-    android:height="100dp"
-    android:viewportWidth="26.458332"
-    android:viewportHeight="26.458332">
-    <path
-        android:pathData="m9.9219,21.8281 l-7.9375,-7.9375 7.9375,-7.9375L24.474,5.9531v15.875z"
-        android:strokeAlpha="1"
-        android:strokeLineJoin="miter"
-        android:strokeWidth="0.26458332"
-        android:fillColor="#00000000"
-        android:strokeColor="#e6e6e6"
-        android:strokeLineCap="butt" />
-</vector>
diff --git a/android/app/src/main/res/drawable/ic_controller_right_button_pressed.xml b/android/app/src/main/res/drawable/ic_controller_right_button_pressed.xml
deleted file mode 100644
index f0cff05ba..000000000
--- a/android/app/src/main/res/drawable/ic_controller_right_button_pressed.xml
+++ /dev/null
@@ -1,14 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="100dp"
-    android:height="100dp"
-    android:viewportWidth="26.458332"
-    android:viewportHeight="26.458332">
-    <path
-        android:pathData="m9.9219,21.8281 l-7.9375,-7.9375 7.9375,-7.9375L24.474,5.9531v15.875z"
-        android:strokeAlpha="1"
-        android:strokeLineJoin="miter"
-        android:strokeWidth="0.26458332"
-        android:fillColor="#4d4d4d"
-        android:strokeColor="#e6e6e6"
-        android:strokeLineCap="butt" />
-</vector>
diff --git a/android/app/src/main/res/drawable/ic_controller_select_button.xml b/android/app/src/main/res/drawable/ic_controller_select_button.xml
deleted file mode 100644
index bea56389c..000000000
--- a/android/app/src/main/res/drawable/ic_controller_select_button.xml
+++ /dev/null
@@ -1,14 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="100dp"
-    android:height="50dp"
-    android:viewportWidth="26.458332"
-    android:viewportHeight="13.229165">
-    <path
-        android:pathData="m0.6615,0.6614v11.9063L25.7969,12.5677v-11.9063z"
-        android:strokeAlpha="1"
-        android:strokeLineJoin="miter"
-        android:strokeWidth="0.26458332"
-        android:fillColor="#00000000"
-        android:strokeColor="#6e6e6f"
-        android:strokeLineCap="butt" />
-</vector>
diff --git a/android/app/src/main/res/drawable/ic_controller_select_button_pressed.xml b/android/app/src/main/res/drawable/ic_controller_select_button_pressed.xml
deleted file mode 100644
index a34a925d4..000000000
--- a/android/app/src/main/res/drawable/ic_controller_select_button_pressed.xml
+++ /dev/null
@@ -1,14 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="100dp"
-    android:height="50dp"
-    android:viewportWidth="26.458332"
-    android:viewportHeight="13.229165">
-    <path
-        android:pathData="m0.6615,0.6614v11.9063L25.7969,12.5677v-11.9063z"
-        android:strokeAlpha="1"
-        android:strokeLineJoin="miter"
-        android:strokeWidth="0.26458332"
-        android:fillColor="#4d4d4d"
-        android:strokeColor="#6e6e6f"
-        android:strokeLineCap="butt" />
-</vector>
diff --git a/android/app/src/main/res/drawable/ic_controller_square_button.xml b/android/app/src/main/res/drawable/ic_controller_square_button.xml
deleted file mode 100644
index 0da658c01..000000000
--- a/android/app/src/main/res/drawable/ic_controller_square_button.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="100dp"
-    android:height="100dp"
-    android:viewportWidth="26.458332"
-    android:viewportHeight="26.45833">
-    <path
-        android:pathData="M13.2292,13.2292m-12.5677,0a12.5677,12.5677 0,1 1,25.1354 0a12.5677,12.5677 0,1 1,-25.1354 0"
-        android:strokeWidth="0.26458332"
-        android:fillColor="#00000000"
-        android:strokeColor="#ffffff" />
-    <path
-        android:pathData="M5.2917,5.2917L21.1667,5.2917v15.875L5.2917,21.1667v-15.875"
-        android:strokeAlpha="1"
-        android:strokeLineJoin="miter"
-        android:strokeWidth="1.05833333"
-        android:fillColor="#00000000"
-        android:fillAlpha="1"
-        android:strokeColor="#ff00ff"
-        android:strokeLineCap="square" />
-</vector>
diff --git a/android/app/src/main/res/drawable/ic_controller_square_button_pressed.xml b/android/app/src/main/res/drawable/ic_controller_square_button_pressed.xml
deleted file mode 100644
index 248a1d400..000000000
--- a/android/app/src/main/res/drawable/ic_controller_square_button_pressed.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="100dp"
-    android:height="100dp"
-    android:viewportWidth="26.458332"
-    android:viewportHeight="26.45833">
-    <path
-        android:pathData="M13.2292,13.2292m-12.5677,0a12.5677,12.5677 0,1 1,25.1354 0a12.5677,12.5677 0,1 1,-25.1354 0"
-        android:strokeWidth="0.26458332"
-        android:fillColor="#4d4d4d"
-        android:strokeColor="#ffffff" />
-    <path
-        android:pathData="M5.2917,5.2917L21.1667,5.2917v15.875L5.2917,21.1667v-15.875"
-        android:strokeAlpha="1"
-        android:strokeLineJoin="miter"
-        android:strokeWidth="1.05833333"
-        android:fillColor="#00000000"
-        android:fillAlpha="1"
-        android:strokeColor="#ff00ff"
-        android:strokeLineCap="square" />
-</vector>
diff --git a/android/app/src/main/res/drawable/ic_controller_start_button.xml b/android/app/src/main/res/drawable/ic_controller_start_button.xml
deleted file mode 100644
index 7247bbcd7..000000000
--- a/android/app/src/main/res/drawable/ic_controller_start_button.xml
+++ /dev/null
@@ -1,14 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="100dp"
-    android:height="50dp"
-    android:viewportWidth="26.458332"
-    android:viewportHeight="13.229165">
-    <path
-        android:pathData="m0.6615,0.6614v11.9063l25.1354,-5.9531z"
-        android:strokeAlpha="0.94117647"
-        android:strokeLineJoin="miter"
-        android:strokeWidth="0.265"
-        android:fillColor="#00000000"
-        android:strokeColor="#6e6e6f"
-        android:strokeLineCap="butt" />
-</vector>
diff --git a/android/app/src/main/res/drawable/ic_controller_start_button_pressed.xml b/android/app/src/main/res/drawable/ic_controller_start_button_pressed.xml
deleted file mode 100644
index 5a8255577..000000000
--- a/android/app/src/main/res/drawable/ic_controller_start_button_pressed.xml
+++ /dev/null
@@ -1,14 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="100dp"
-    android:height="50dp"
-    android:viewportWidth="26.458332"
-    android:viewportHeight="13.229165">
-    <path
-        android:pathData="m0.6615,0.6614v11.9063l25.1354,-5.9531z"
-        android:strokeAlpha="0.94117647"
-        android:strokeLineJoin="miter"
-        android:strokeWidth="0.265"
-        android:fillColor="#4d4d4d"
-        android:strokeColor="#6e6e6f"
-        android:strokeLineCap="butt" />
-</vector>
diff --git a/android/app/src/main/res/drawable/ic_controller_t1_button.xml b/android/app/src/main/res/drawable/ic_controller_t1_button.xml
deleted file mode 100644
index 2f342f01c..000000000
--- a/android/app/src/main/res/drawable/ic_controller_t1_button.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="100dp"
-    android:height="100dp"
-    android:viewportWidth="100"
-    android:viewportHeight="100">
-  <path
-      android:pathData="M1.086,50.028a48.94,48.712 0,1 0,97.88 0a48.94,48.712 0,1 0,-97.88 0z"
-      android:strokeWidth="1.5"
-      android:fillColor="#000000"
-      android:fillAlpha="0"
-      android:strokeColor="#c8c8c8"/>
-  <path
-      android:pathData="M40.04,63.464H36.23V36.582H26.79V33.238H49.438v3.344h-9.398z"
-      android:fillColor="#ffffff"
-      android:strokeColor="#00000000"/>
-  <path
-      android:pathData="M64.932,63.464H61.291V42.339q0,-1.82 0.042,-2.921 0.042,-1.101 0.127,-2.286 -0.677,0.677 -1.228,1.143 -0.55,0.466 -1.397,1.185l-3.217,2.625 -1.947,-2.498 8.17,-6.35h3.09z"
-      android:fillColor="#ffffff"
-      android:strokeColor="#00000000"/>
-</vector>
diff --git a/android/app/src/main/res/drawable/ic_controller_t1_button_pressed.xml b/android/app/src/main/res/drawable/ic_controller_t1_button_pressed.xml
deleted file mode 100644
index bf3ffaf35..000000000
--- a/android/app/src/main/res/drawable/ic_controller_t1_button_pressed.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="100dp"
-    android:height="100dp"
-    android:viewportWidth="100"
-    android:viewportHeight="100">
-  <path
-      android:pathData="M1.086,50.028a48.94,48.712 0,1 0,97.88 0a48.94,48.712 0,1 0,-97.88 0z"
-      android:strokeWidth="1.5"
-      android:fillColor="#c9c9c9"
-      android:strokeColor="#c8c8c8"/>
-  <path
-      android:pathData="M40.04,63.464H36.23V36.582H26.79V33.238H49.438v3.344h-9.398z"
-      android:fillColor="#ffffff"
-      android:strokeColor="#00000000"/>
-  <path
-      android:pathData="M64.932,63.464H61.291V42.339q0,-1.82 0.042,-2.921 0.042,-1.101 0.127,-2.286 -0.677,0.677 -1.228,1.143 -0.55,0.466 -1.397,1.185l-3.217,2.625 -1.947,-2.498 8.17,-6.35h3.09z"
-      android:fillColor="#ffffff"
-      android:strokeColor="#00000000"/>
-</vector>
diff --git a/android/app/src/main/res/drawable/ic_controller_t2_button.xml b/android/app/src/main/res/drawable/ic_controller_t2_button.xml
deleted file mode 100644
index abddf7071..000000000
--- a/android/app/src/main/res/drawable/ic_controller_t2_button.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="100dp"
-    android:height="100dp"
-    android:viewportWidth="100"
-    android:viewportHeight="100">
-  <path
-      android:pathData="M1.086,50.028a48.94,48.712 0,1 0,97.88 0a48.94,48.712 0,1 0,-97.88 0z"
-      android:strokeWidth="1.5"
-      android:fillColor="#000000"
-      android:fillAlpha="0"
-      android:strokeColor="#c8c8c8"/>
-  <path
-      android:pathData="M40.04,63.464H36.23V36.582H26.79V33.238H49.438v3.344h-9.398z"
-      android:fillColor="#ffffff"
-      android:strokeColor="#00000000"/>
-  <path
-      android:pathData="M71.917,63.464H51.936v-3.09l7.916,-8.001q2.286,-2.286 3.852,-4.064 1.566,-1.778 2.371,-3.471 0.804,-1.736 0.804,-3.768 0,-2.498 -1.482,-3.768 -1.482,-1.312 -3.852,-1.312 -2.201,0 -3.895,0.762 -1.651,0.762 -3.387,2.117l-1.99,-2.498q1.778,-1.482 4.064,-2.498 2.328,-1.058 5.207,-1.058 4.233,0 6.689,2.159 2.455,2.117 2.455,5.884 0,2.371 -0.974,4.445 -0.974,2.074 -2.709,4.106 -1.736,1.99 -4.064,4.276l-6.308,6.223v0.169h15.282z"
-      android:fillColor="#ffffff"
-      android:strokeColor="#00000000"/>
-</vector>
diff --git a/android/app/src/main/res/drawable/ic_controller_t2_button_pressed.xml b/android/app/src/main/res/drawable/ic_controller_t2_button_pressed.xml
deleted file mode 100644
index 2b07da75f..000000000
--- a/android/app/src/main/res/drawable/ic_controller_t2_button_pressed.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="100dp"
-    android:height="100dp"
-    android:viewportWidth="100"
-    android:viewportHeight="100">
-  <path
-      android:pathData="M1.086,50.028a48.94,48.712 0,1 0,97.88 0a48.94,48.712 0,1 0,-97.88 0z"
-      android:strokeWidth="1.5"
-      android:fillColor="#c9c9c9"
-      android:strokeColor="#c8c8c8"/>
-  <path
-      android:pathData="M40.04,63.464H36.23V36.582H26.79V33.238H49.438v3.344h-9.398z"
-      android:fillColor="#ffffff"
-      android:strokeColor="#00000000"/>
-  <path
-      android:pathData="M71.917,63.464H51.936v-3.09l7.916,-8.001q2.286,-2.286 3.852,-4.064 1.566,-1.778 2.371,-3.471 0.804,-1.736 0.804,-3.768 0,-2.498 -1.482,-3.768 -1.482,-1.312 -3.852,-1.312 -2.201,0 -3.895,0.762 -1.651,0.762 -3.387,2.117l-1.99,-2.498q1.778,-1.482 4.064,-2.498 2.328,-1.058 5.207,-1.058 4.233,0 6.689,2.159 2.455,2.117 2.455,5.884 0,2.371 -0.974,4.445 -0.974,2.074 -2.709,4.106 -1.736,1.99 -4.064,4.276l-6.308,6.223v0.169h15.282z"
-      android:fillColor="#ffffff"
-      android:strokeColor="#00000000"/>
-</vector>
diff --git a/android/app/src/main/res/drawable/ic_controller_t3_button.xml b/android/app/src/main/res/drawable/ic_controller_t3_button.xml
deleted file mode 100644
index d9b001f00..000000000
--- a/android/app/src/main/res/drawable/ic_controller_t3_button.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="100dp"
-    android:height="100dp"
-    android:viewportWidth="100"
-    android:viewportHeight="100">
-  <path
-      android:pathData="M1.086,50.028a48.94,48.712 0,1 0,97.88 0a48.94,48.712 0,1 0,-97.88 0z"
-      android:strokeWidth="1.5"
-      android:fillColor="#000000"
-      android:fillAlpha="0"
-      android:strokeColor="#c8c8c8"/>
-  <path
-      android:pathData="M40.04,63.464H36.23V36.582H26.79V33.238H49.438v3.344h-9.398z"
-      android:fillColor="#ffffff"
-      android:strokeColor="#00000000"/>
-  <path
-      android:pathData="m70.774,40.307q0,3.048 -1.693,4.868 -1.693,1.778 -4.572,2.371v0.169q3.641,0.423 5.419,2.286 1.778,1.863 1.778,4.868 0,2.625 -1.228,4.699 -1.228,2.032 -3.81,3.175 -2.54,1.143 -6.562,1.143 -2.371,0 -4.403,-0.381 -2.032,-0.339 -3.895,-1.27v-3.471q1.905,0.931 4.106,1.482 2.201,0.508 4.233,0.508 4.064,0 5.842,-1.566 1.82,-1.609 1.82,-4.403 0,-2.836 -2.244,-4.064 -2.201,-1.27 -6.223,-1.27h-2.921v-3.175h2.963q3.725,0 5.63,-1.566 1.947,-1.566 1.947,-4.149 0,-2.201 -1.482,-3.387 -1.482,-1.228 -4.022,-1.228 -2.455,0 -4.191,0.72 -1.736,0.72 -3.429,1.82l-1.863,-2.54q1.609,-1.27 3.979,-2.201 2.413,-0.931 5.461,-0.931 4.741,0 7.027,2.117 2.328,2.117 2.328,5.376z"
-      android:fillColor="#ffffff"
-      android:strokeColor="#00000000"/>
-</vector>
diff --git a/android/app/src/main/res/drawable/ic_controller_t3_button_pressed.xml b/android/app/src/main/res/drawable/ic_controller_t3_button_pressed.xml
deleted file mode 100644
index 78465f7fd..000000000
--- a/android/app/src/main/res/drawable/ic_controller_t3_button_pressed.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="100dp"
-    android:height="100dp"
-    android:viewportWidth="100"
-    android:viewportHeight="100">
-  <path
-      android:pathData="M1.086,50.028a48.94,48.712 0,1 0,97.88 0a48.94,48.712 0,1 0,-97.88 0z"
-      android:strokeWidth="1.5"
-      android:fillColor="#c9c9c9"
-      android:strokeColor="#c8c8c8"/>
-  <path
-      android:pathData="M40.04,63.464H36.23V36.582H26.79V33.238H49.438v3.344h-9.398z"
-      android:fillColor="#ffffff"
-      android:strokeColor="#00000000"/>
-  <path
-      android:pathData="m70.774,40.307q0,3.048 -1.693,4.868 -1.693,1.778 -4.572,2.371v0.169q3.641,0.423 5.419,2.286 1.778,1.863 1.778,4.868 0,2.625 -1.228,4.699 -1.228,2.032 -3.81,3.175 -2.54,1.143 -6.562,1.143 -2.371,0 -4.403,-0.381 -2.032,-0.339 -3.895,-1.27v-3.471q1.905,0.931 4.106,1.482 2.201,0.508 4.233,0.508 4.064,0 5.842,-1.566 1.82,-1.609 1.82,-4.403 0,-2.836 -2.244,-4.064 -2.201,-1.27 -6.223,-1.27h-2.921v-3.175h2.963q3.725,0 5.63,-1.566 1.947,-1.566 1.947,-4.149 0,-2.201 -1.482,-3.387 -1.482,-1.228 -4.022,-1.228 -2.455,0 -4.191,0.72 -1.736,0.72 -3.429,1.82l-1.863,-2.54q1.609,-1.27 3.979,-2.201 2.413,-0.931 5.461,-0.931 4.741,0 7.027,2.117 2.328,2.117 2.328,5.376z"
-      android:fillColor="#ffffff"
-      android:strokeColor="#00000000"/>
-</vector>
diff --git a/android/app/src/main/res/drawable/ic_controller_t4_button.xml b/android/app/src/main/res/drawable/ic_controller_t4_button.xml
deleted file mode 100644
index 87f5e6726..000000000
--- a/android/app/src/main/res/drawable/ic_controller_t4_button.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="100dp"
-    android:height="100dp"
-    android:viewportWidth="100"
-    android:viewportHeight="100">
-  <path
-      android:pathData="M1.086,50.028a48.94,48.712 0,1 0,97.88 0a48.94,48.712 0,1 0,-97.88 0z"
-      android:strokeWidth="1.5"
-      android:fillColor="#000000"
-      android:fillAlpha="0"
-      android:strokeColor="#c8c8c8"/>
-  <path
-      android:pathData="M40.04,63.464H36.23V36.582H26.79V33.238H49.438v3.344h-9.398z"
-      android:fillColor="#ffffff"
-      android:strokeColor="#00000000"/>
-  <path
-      android:pathData="m73.272,56.606h-4.403v6.858h-3.598V56.606h-14.478v-3.175l14.224,-20.362h3.852V53.261h4.403zM65.271,43.736q0,-2.201 0.085,-3.725 0.085,-1.566 0.127,-2.963h-0.169q-0.339,0.804 -0.847,1.736 -0.508,0.931 -0.974,1.566L54.433,53.261h10.837z"
-      android:fillColor="#ffffff"
-      android:strokeColor="#00000000"/>
-</vector>
diff --git a/android/app/src/main/res/drawable/ic_controller_t4_button_pressed.xml b/android/app/src/main/res/drawable/ic_controller_t4_button_pressed.xml
deleted file mode 100644
index b7da1f1b2..000000000
--- a/android/app/src/main/res/drawable/ic_controller_t4_button_pressed.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="100dp"
-    android:height="100dp"
-    android:viewportWidth="100"
-    android:viewportHeight="100">
-  <path
-      android:pathData="M1.086,50.028a48.94,48.712 0,1 0,97.88 0a48.94,48.712 0,1 0,-97.88 0z"
-      android:strokeWidth="1.5"
-      android:fillColor="#c9c9c9"
-      android:strokeColor="#c8c8c8"/>
-  <path
-      android:pathData="M40.04,63.464H36.23V36.582H26.79V33.238H49.438v3.344h-9.398z"
-      android:fillColor="#ffffff"
-      android:strokeColor="#00000000"/>
-  <path
-      android:pathData="m73.272,56.606h-4.403v6.858h-3.598V56.606h-14.478v-3.175l14.224,-20.362h3.852V53.261h4.403zM65.271,43.736q0,-2.201 0.085,-3.725 0.085,-1.566 0.127,-2.963h-0.169q-0.339,0.804 -0.847,1.736 -0.508,0.931 -0.974,1.566L54.433,53.261h10.837z"
-      android:fillColor="#ffffff"
-      android:strokeColor="#00000000"/>
-</vector>
diff --git a/android/app/src/main/res/drawable/ic_controller_triangle_button.xml b/android/app/src/main/res/drawable/ic_controller_triangle_button.xml
deleted file mode 100644
index 9a1392988..000000000
--- a/android/app/src/main/res/drawable/ic_controller_triangle_button.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="100dp"
-    android:height="100dp"
-    android:viewportWidth="26.458332"
-    android:viewportHeight="26.45833">
-    <path
-        android:pathData="M13.2292,13.2292m-12.5677,0a12.5677,12.5677 0,1 1,25.1354 0a12.5677,12.5677 0,1 1,-25.1354 0"
-        android:strokeWidth="0.26458332"
-        android:fillColor="#00000000"
-        android:strokeColor="#ffffff" />
-    <path
-        android:pathData="M5.2917,19.0398L21.1667,19.0398l-7.9375,-13.7481 -7.8548,13.6049"
-        android:strokeAlpha="1"
-        android:strokeLineJoin="round"
-        android:strokeWidth="1.05833328"
-        android:fillColor="#00000000"
-        android:strokeColor="#00ff00"
-        android:strokeLineCap="round" />
-</vector>
diff --git a/android/app/src/main/res/drawable/ic_controller_triangle_button_pressed.xml b/android/app/src/main/res/drawable/ic_controller_triangle_button_pressed.xml
deleted file mode 100644
index be10c7a85..000000000
--- a/android/app/src/main/res/drawable/ic_controller_triangle_button_pressed.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="100dp"
-    android:height="100dp"
-    android:viewportWidth="26.458332"
-    android:viewportHeight="26.45833">
-    <path
-        android:pathData="M13.2292,13.2292m-12.5677,0a12.5677,12.5677 0,1 1,25.1354 0a12.5677,12.5677 0,1 1,-25.1354 0"
-        android:strokeWidth="0.26458332"
-        android:fillColor="#4d4d4d"
-        android:strokeColor="#ffffff" />
-    <path
-        android:pathData="M5.2917,19.0398L21.1667,19.0398l-7.9375,-13.7481 -7.8548,13.6049"
-        android:strokeAlpha="1"
-        android:strokeLineJoin="round"
-        android:strokeWidth="1.05833328"
-        android:fillColor="#00000000"
-        android:strokeColor="#00ff00"
-        android:strokeLineCap="round" />
-</vector>
diff --git a/android/app/src/main/res/drawable/ic_controller_up_button.xml b/android/app/src/main/res/drawable/ic_controller_up_button.xml
deleted file mode 100644
index e8b5a4064..000000000
--- a/android/app/src/main/res/drawable/ic_controller_up_button.xml
+++ /dev/null
@@ -1,14 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="100dp"
-    android:height="100dp"
-    android:viewportWidth="26.458332"
-    android:viewportHeight="26.458332">
-    <path
-        android:pathData="m21.1667,17.1979 l-7.9375,7.9375 -7.9375,-7.9375L5.2917,2.6458L21.1667,2.6458Z"
-        android:strokeAlpha="1"
-        android:strokeLineJoin="miter"
-        android:strokeWidth="0.26458332"
-        android:fillColor="#00000000"
-        android:strokeColor="#e6e6e6"
-        android:strokeLineCap="butt" />
-</vector>
diff --git a/android/app/src/main/res/drawable/ic_controller_up_button_pressed.xml b/android/app/src/main/res/drawable/ic_controller_up_button_pressed.xml
deleted file mode 100644
index d17013321..000000000
--- a/android/app/src/main/res/drawable/ic_controller_up_button_pressed.xml
+++ /dev/null
@@ -1,14 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="100dp"
-    android:height="100dp"
-    android:viewportWidth="26.458332"
-    android:viewportHeight="26.458332">
-    <path
-        android:pathData="m21.1667,17.1979 l-7.9375,7.9375 -7.9375,-7.9375L5.2917,2.6458L21.1667,2.6458Z"
-        android:strokeAlpha="1"
-        android:strokeLineJoin="miter"
-        android:strokeWidth="0.26458332"
-        android:fillColor="#4d4d4d"
-        android:strokeColor="#e6e6e6"
-        android:strokeLineCap="butt" />
-</vector>
diff --git a/android/app/src/main/res/drawable/ic_emblem_system.xml b/android/app/src/main/res/drawable/ic_emblem_system.xml
deleted file mode 100644
index 4be483cfc..000000000
--- a/android/app/src/main/res/drawable/ic_emblem_system.xml
+++ /dev/null
@@ -1,45 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:aapt="http://schemas.android.com/aapt"
-    android:width="48dp"
-    android:height="48dp"
-    android:viewportWidth="48"
-    android:viewportHeight="48">
-    <path
-        android:pathData="M44.1942,41.636A19.6222,6.1872 0,1 1,4.9497 41.636A19.6222,6.1872 0,1 1,44.1942 41.636z"
-        android:strokeAlpha="0.40909088"
-        android:strokeLineJoin="miter"
-        android:strokeWidth="1"
-        android:strokeColor="#00000000"
-        android:fillType="nonZero"
-        android:fillAlpha="0.40909088"
-        android:strokeLineCap="butt"></path>
-    <path
-        android:pathData="M23.25,0.4688C22.7846,0.5006 22.3322,0.5727 21.875,0.625L21.8438,0.625L20.75,6.5938C18.9673,6.9997 17.2901,7.6887 15.7813,8.625L10.875,5.0938C9.5487,6.1234 8.3418,7.3243 7.2813,8.625L10.6875,13.5938C9.6533,15.1743 8.8755,16.979 8.4375,18.875C8.4374,18.884 8.4374,18.9047 8.4375,18.9063L2.5,19.8438C2.3914,20.7304 2.3438,21.6467 2.3438,22.5625C2.3438,23.3118 2.3644,24.0511 2.4375,24.7813L8.375,25.8438C8.7973,27.9056 9.5995,29.8313 10.7188,31.5313L7.1875,36.375C8.1988,37.6305 9.3664,38.7736 10.625,39.7813L15.625,36.3438C17.3724,37.4585 19.3231,38.2401 21.4375,38.625L22.375,44.5313C23.0412,44.5919 23.7243,44.5938 24.4063,44.5938C25.3689,44.5938 26.2885,44.5573 27.2188,44.4375L28.3438,38.4063C30.3513,37.9067 32.2372,37.04 33.875,35.875L38.6875,39.375C39.9355,38.3132 41.0768,37.0927 42.0625,35.7813L38.5625,30.7188C39.5104,29.0818 40.1671,27.2756 40.5,25.3438L46.4063,24.4063C46.458,23.7899 46.4688,23.1922 46.4688,22.5625C46.4688,21.4683 46.3416,20.3954 46.1875,19.3438L40.1875,18.25C39.7173,16.5138 38.9458,14.8939 37.9688,13.4375L41.5,8.5938C40.4054,7.2551 39.1568,6.0186 37.7813,4.9688L32.6875,8.4688C31.2235,7.6029 29.648,6.9386 27.9375,6.5625L27,0.625C26.1467,0.5246 25.2864,0.4688 24.4063,0.4688C24.1684,0.4688 23.9236,0.4613 23.6875,0.4688C23.5724,0.4724 23.4585,0.4621 23.3438,0.4688C23.3127,0.4706 23.281,0.4666 23.25,0.4688zM24.0625,15.6563C24.1767,15.6505 24.2907,15.6563 24.4063,15.6563C28.1054,15.6563 31.125,18.6759 31.125,22.375C31.125,26.0741 28.1054,29.0625 24.4063,29.0625C20.7071,29.0625 17.7188,26.0741 17.7188,22.375C17.7188,18.7915 20.5233,15.8358 24.0625,15.6563z"
-        android:strokeAlpha="1"
-        android:strokeLineJoin="miter"
-        android:strokeWidth="1"
-        android:strokeColor="#808080"
-        android:fillType="nonZero"
-        android:fillAlpha="1"
-        android:strokeLineCap="butt"></path>
-    <path
-        android:pathData="M32.13,22.3608A7.7197,7.7197 45,1 1,16.6905 22.3608A7.7197,7.7197 135,1 1,32.13 22.3608z"
-        android:strokeAlpha="0.64772725"
-        android:strokeLineJoin="miter"
-        android:strokeWidth="1.64875567"
-        android:fillColor="#00000000"
-        android:strokeColor="#ffffff"
-        android:fillType="nonZero"
-        android:fillAlpha="0.64772725"
-        android:strokeLineCap="butt" />
-    <path
-        android:pathData="M22.5578,1.6501L21.6796,7.4291C20.0086,7.8097 16.9349,8.9735 15.5206,9.8511L10.8486,6.3639C9.6054,7.3291 9.5201,7.3945 8.5261,8.6137L11.9041,13.6236C10.9347,15.1051 9.7703,17.7451 9.3522,19.6317C9.3522,19.6317 3.4328,20.6296 3.4328,20.6296C3.3311,21.4606 3.38,23.2394 3.4485,23.9238L9.1027,24.9423C9.4985,26.875 10.9797,29.9859 12.0289,31.5794L8.4533,36.3034C9.4012,37.4803 9.591,37.5879 10.7707,38.5324L15.5519,35.0296C17.1898,36.0745 20.4409,37.3455 22.4228,37.7063L23.2075,43.4125C23.8319,43.4693 25.557,43.6288 26.4289,43.5165L27.3071,37.5764C29.1889,37.1081 32.4403,35.7734 33.9754,34.6815L38.7515,38.1323C39.9213,37.137 39.9318,36.9871 40.8557,35.7578L37.3165,30.7271C38.205,29.1927 39.3537,26.1918 39.6657,24.381L45.4604,23.4196C45.5089,22.8419 45.5113,21.2308 45.3669,20.245L39.4631,19.2264C39.0224,17.599 37.5099,14.6665 36.5941,13.3013L40.3464,8.5773C39.3204,7.3226 38.939,7.1504 37.6496,6.1664L32.7073,9.7056C31.335,8.894 28.5987,7.6569 26.9953,7.3044L26.1223,1.6501C25.3224,1.556 23.0149,1.5978 22.5578,1.6501z"
-        android:strokeAlpha="0.34659088"
-        android:strokeLineJoin="miter"
-        android:strokeWidth="0.9999997"
-        android:fillColor="#00000000"
-        android:strokeColor="#ffffff"
-        android:fillType="nonZero"
-        android:fillAlpha="0.34659088"
-        android:strokeLineCap="butt" />
-</vector>
diff --git a/android/app/src/main/res/drawable/ic_launcher_background.xml b/android/app/src/main/res/drawable/ic_launcher_background.xml
deleted file mode 100644
index 0d025f9bf..000000000
--- a/android/app/src/main/res/drawable/ic_launcher_background.xml
+++ /dev/null
@@ -1,170 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="108dp"
-    android:height="108dp"
-    android:viewportWidth="108"
-    android:viewportHeight="108">
-    <path
-        android:fillColor="#008577"
-        android:pathData="M0,0h108v108h-108z" />
-    <path
-        android:fillColor="#00000000"
-        android:pathData="M9,0L9,108"
-        android:strokeWidth="0.8"
-        android:strokeColor="#33FFFFFF" />
-    <path
-        android:fillColor="#00000000"
-        android:pathData="M19,0L19,108"
-        android:strokeWidth="0.8"
-        android:strokeColor="#33FFFFFF" />
-    <path
-        android:fillColor="#00000000"
-        android:pathData="M29,0L29,108"
-        android:strokeWidth="0.8"
-        android:strokeColor="#33FFFFFF" />
-    <path
-        android:fillColor="#00000000"
-        android:pathData="M39,0L39,108"
-        android:strokeWidth="0.8"
-        android:strokeColor="#33FFFFFF" />
-    <path
-        android:fillColor="#00000000"
-        android:pathData="M49,0L49,108"
-        android:strokeWidth="0.8"
-        android:strokeColor="#33FFFFFF" />
-    <path
-        android:fillColor="#00000000"
-        android:pathData="M59,0L59,108"
-        android:strokeWidth="0.8"
-        android:strokeColor="#33FFFFFF" />
-    <path
-        android:fillColor="#00000000"
-        android:pathData="M69,0L69,108"
-        android:strokeWidth="0.8"
-        android:strokeColor="#33FFFFFF" />
-    <path
-        android:fillColor="#00000000"
-        android:pathData="M79,0L79,108"
-        android:strokeWidth="0.8"
-        android:strokeColor="#33FFFFFF" />
-    <path
-        android:fillColor="#00000000"
-        android:pathData="M89,0L89,108"
-        android:strokeWidth="0.8"
-        android:strokeColor="#33FFFFFF" />
-    <path
-        android:fillColor="#00000000"
-        android:pathData="M99,0L99,108"
-        android:strokeWidth="0.8"
-        android:strokeColor="#33FFFFFF" />
-    <path
-        android:fillColor="#00000000"
-        android:pathData="M0,9L108,9"
-        android:strokeWidth="0.8"
-        android:strokeColor="#33FFFFFF" />
-    <path
-        android:fillColor="#00000000"
-        android:pathData="M0,19L108,19"
-        android:strokeWidth="0.8"
-        android:strokeColor="#33FFFFFF" />
-    <path
-        android:fillColor="#00000000"
-        android:pathData="M0,29L108,29"
-        android:strokeWidth="0.8"
-        android:strokeColor="#33FFFFFF" />
-    <path
-        android:fillColor="#00000000"
-        android:pathData="M0,39L108,39"
-        android:strokeWidth="0.8"
-        android:strokeColor="#33FFFFFF" />
-    <path
-        android:fillColor="#00000000"
-        android:pathData="M0,49L108,49"
-        android:strokeWidth="0.8"
-        android:strokeColor="#33FFFFFF" />
-    <path
-        android:fillColor="#00000000"
-        android:pathData="M0,59L108,59"
-        android:strokeWidth="0.8"
-        android:strokeColor="#33FFFFFF" />
-    <path
-        android:fillColor="#00000000"
-        android:pathData="M0,69L108,69"
-        android:strokeWidth="0.8"
-        android:strokeColor="#33FFFFFF" />
-    <path
-        android:fillColor="#00000000"
-        android:pathData="M0,79L108,79"
-        android:strokeWidth="0.8"
-        android:strokeColor="#33FFFFFF" />
-    <path
-        android:fillColor="#00000000"
-        android:pathData="M0,89L108,89"
-        android:strokeWidth="0.8"
-        android:strokeColor="#33FFFFFF" />
-    <path
-        android:fillColor="#00000000"
-        android:pathData="M0,99L108,99"
-        android:strokeWidth="0.8"
-        android:strokeColor="#33FFFFFF" />
-    <path
-        android:fillColor="#00000000"
-        android:pathData="M19,29L89,29"
-        android:strokeWidth="0.8"
-        android:strokeColor="#33FFFFFF" />
-    <path
-        android:fillColor="#00000000"
-        android:pathData="M19,39L89,39"
-        android:strokeWidth="0.8"
-        android:strokeColor="#33FFFFFF" />
-    <path
-        android:fillColor="#00000000"
-        android:pathData="M19,49L89,49"
-        android:strokeWidth="0.8"
-        android:strokeColor="#33FFFFFF" />
-    <path
-        android:fillColor="#00000000"
-        android:pathData="M19,59L89,59"
-        android:strokeWidth="0.8"
-        android:strokeColor="#33FFFFFF" />
-    <path
-        android:fillColor="#00000000"
-        android:pathData="M19,69L89,69"
-        android:strokeWidth="0.8"
-        android:strokeColor="#33FFFFFF" />
-    <path
-        android:fillColor="#00000000"
-        android:pathData="M19,79L89,79"
-        android:strokeWidth="0.8"
-        android:strokeColor="#33FFFFFF" />
-    <path
-        android:fillColor="#00000000"
-        android:pathData="M29,19L29,89"
-        android:strokeWidth="0.8"
-        android:strokeColor="#33FFFFFF" />
-    <path
-        android:fillColor="#00000000"
-        android:pathData="M39,19L39,89"
-        android:strokeWidth="0.8"
-        android:strokeColor="#33FFFFFF" />
-    <path
-        android:fillColor="#00000000"
-        android:pathData="M49,19L49,89"
-        android:strokeWidth="0.8"
-        android:strokeColor="#33FFFFFF" />
-    <path
-        android:fillColor="#00000000"
-        android:pathData="M59,19L59,89"
-        android:strokeWidth="0.8"
-        android:strokeColor="#33FFFFFF" />
-    <path
-        android:fillColor="#00000000"
-        android:pathData="M69,19L69,89"
-        android:strokeWidth="0.8"
-        android:strokeColor="#33FFFFFF" />
-    <path
-        android:fillColor="#00000000"
-        android:pathData="M79,19L79,89"
-        android:strokeWidth="0.8"
-        android:strokeColor="#33FFFFFF" />
-</vector>
diff --git a/android/app/src/main/res/drawable/ic_media_cdrom.xml b/android/app/src/main/res/drawable/ic_media_cdrom.xml
deleted file mode 100644
index 9269ea16f..000000000
--- a/android/app/src/main/res/drawable/ic_media_cdrom.xml
+++ /dev/null
@@ -1,97 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:aapt="http://schemas.android.com/aapt"
-    android:width="48dp"
-    android:height="48dp"
-    android:viewportWidth="48"
-    android:viewportHeight="48">
-    <path
-        android:pathData="M46.9619,41.511A6.0319,22.6274 90,1 1,1.7071 41.511A6.0319,22.6274 90,1 1,46.9619 41.511z"
-        android:strokeAlpha="0.55"
-        android:strokeLineJoin="miter"
-        android:strokeWidth="2"
-        android:strokeColor="#00000000"
-        android:fillType="evenOdd"
-        android:fillAlpha="0.55"
-        android:strokeLineCap="butt"></path>
-    <path
-        android:pathData="M24.347,4.1667C12.7994,4.1667 3.5137,13.4524 3.5137,25C3.5137,36.5476 12.7994,45.8333 24.347,45.8333C35.8946,45.8333 45.1803,36.5476 45.1803,25C45.1803,13.4524 35.8946,4.1667 24.347,4.1667L24.347,4.1667zM24.347,30C21.6089,30 19.347,27.7381 19.347,25C19.347,22.2619 21.6089,20 24.347,20C27.0851,20 29.347,22.2619 29.347,25C29.347,27.7381 27.0851,30 24.347,30z"
-        android:strokeColor="#00000000"
-        android:fillType="nonZero"></path>
-    <path
-        android:strokeWidth="1"
-        android:pathData="M24.347,4.1667C12.7994,4.1667 3.5137,13.4524 3.5137,25C3.5137,36.5476 12.7994,45.8333 24.347,45.8333C35.8946,45.8333 45.1803,36.5476 45.1803,25C45.1803,13.4524 35.8946,4.1667 24.347,4.1667L24.347,4.1667zM24.347,30C21.6089,30 19.347,27.7381 19.347,25C19.347,22.2619 21.6089,20 24.347,20C27.0851,20 29.347,22.2619 29.347,25C29.347,27.7381 27.0851,30 24.347,30z"
-        android:strokeAlpha="1"
-        android:strokeColor="#808080"
-        android:fillType="nonZero"></path>
-    <path
-        android:fillColor="#FF000000"
-        android:pathData="M24.347,14.8958C18.7044,14.8958 14.2428,19.4886 14.2428,25C14.2428,30.6426 18.8356,35.1042 24.347,35.1042C29.9896,35.1042 34.4512,30.5114 34.4512,25C34.4512,19.3574 29.8584,14.8958 24.347,14.8958L24.347,14.8958zM24.347,30.5114C21.3289,30.5114 18.8356,28.0181 18.8356,25C18.8356,21.9819 21.3289,19.4886 24.347,19.4886C27.3651,19.4886 29.8584,21.9819 29.8584,25C29.8584,28.0181 27.3651,30.5114 24.347,30.5114z"
-        android:strokeAlpha="0.10999995"
-        android:strokeColor="#00000000"
-        android:fillType="nonZero"
-        android:fillAlpha="0.10999995" />
-    <path
-        android:pathData="M29.9221,5.6692L26.3255,19.6639C27.4502,19.9634 28.3497,20.6594 28.9606,21.6224L41.3529,14.0732C38.8176,9.9434 34.7487,6.9051 29.9221,5.6692z"
-        android:strokeAlpha="1"
-        android:strokeColor="#00000000"
-        android:fillType="nonZero"
-        android:fillAlpha="1"></path>
-    <path
-        android:pathData="M17.3078,43.7661L22.0431,30.1146C20.9468,29.7236 20.1077,28.956 19.5779,27.946L6.6069,34.4506C8.7939,38.7748 12.5993,42.1375 17.3078,43.7661z"
-        android:strokeAlpha="1"
-        android:strokeColor="#00000000"
-        android:fillType="nonZero"
-        android:fillAlpha="1"></path>
-    <path
-        android:strokeWidth="1"
-        android:pathData="M24.347,5.2024C13.3735,5.2024 4.5494,14.0265 4.5494,25C4.5494,35.9735 13.3735,44.7976 24.347,44.7976C35.3205,44.7976 44.1446,35.9735 44.1446,25C44.1446,14.0265 35.3205,5.2024 24.347,5.2024L24.347,5.2024z"
-        android:strokeAlpha="0.5464481"
-        android:fillColor="#00000000"
-        android:fillType="nonZero"
-        android:fillAlpha="0.5464481"></path>
-    <path
-        android:pathData="M30.494,25.019A6.0988,6.0988 0,1 1,18.2964 25.019A6.0988,6.0988 0,1 1,30.494 25.019z"
-        android:strokeAlpha="0.6721311"
-        android:strokeLineJoin="miter"
-        android:strokeWidth="0.93053865"
-        android:fillColor="#00000000"
-        android:fillType="nonZero"
-        android:fillAlpha="0.21265164"
-        android:strokeLineCap="butt"></path>
-    <path
-        android:pathData="M24.347,4.1667C12.7994,4.1667 3.5137,13.4524 3.5137,25C3.5137,36.5476 12.7994,45.8333 24.347,45.8333C35.8946,45.8333 45.1803,36.5476 45.1803,25C45.1803,13.4524 35.8946,4.1667 24.347,4.1667L24.347,4.1667zM24.347,30C21.6089,30 19.347,27.7381 19.347,25C19.347,22.2619 21.6089,20 24.347,20C27.0851,20 29.347,22.2619 29.347,25C29.347,27.7381 27.0851,30 24.347,30z"
-        android:strokeAlpha="0.1142857"
-        android:strokeColor="#00000000"
-        android:fillType="nonZero"
-        android:fillAlpha="0.1142857"></path>
-    <path
-        android:pathData="M24.347,4.1667C12.7994,4.1667 3.5137,13.4524 3.5137,25C3.5137,36.5476 12.7994,45.8333 24.347,45.8333C35.8946,45.8333 45.1803,36.5476 45.1803,25C45.1803,13.4524 35.8946,4.1667 24.347,4.1667L24.347,4.1667zM24.347,30C21.6089,30 19.347,27.7381 19.347,25C19.347,22.2619 21.6089,20 24.347,20C27.0851,20 29.347,22.2619 29.347,25C29.347,27.7381 27.0851,30 24.347,30z"
-        android:strokeAlpha="0.09714284"
-        android:strokeColor="#00000000"
-        android:fillType="nonZero"
-        android:fillAlpha="0.09714284"></path>
-    <path
-        android:pathData="M24.347,4.1667C12.7994,4.1667 3.5137,13.4524 3.5137,25C3.5137,36.5476 12.7994,45.8333 24.347,45.8333C35.8946,45.8333 45.1803,36.5476 45.1803,25C45.1803,13.4524 35.8946,4.1667 24.347,4.1667L24.347,4.1667zM24.347,30C21.6089,30 19.347,27.7381 19.347,25C19.347,22.2619 21.6089,20 24.347,20C27.0851,20 29.347,22.2619 29.347,25C29.347,27.7381 27.0851,30 24.347,30z"
-        android:strokeAlpha="0.71428573"
-        android:strokeColor="#00000000"
-        android:fillType="nonZero"
-        android:fillAlpha="0.71428573"></path>
-    <path
-        android:pathData="M24.347,4.1667C12.7994,4.1667 3.5137,13.4524 3.5137,25C3.5137,36.5476 12.7994,45.8333 24.347,45.8333C35.8946,45.8333 45.1803,36.5476 45.1803,25C45.1803,13.4524 35.8946,4.1667 24.347,4.1667L24.347,4.1667zM24.347,30C21.6089,30 19.347,27.7381 19.347,25C19.347,22.2619 21.6089,20 24.347,20C27.0851,20 29.347,22.2619 29.347,25C29.347,27.7381 27.0851,30 24.347,30z"
-        android:strokeAlpha="0.62285715"
-        android:strokeColor="#00000000"
-        android:fillType="nonZero"
-        android:fillAlpha="0.62285715"></path>
-    <path
-        android:pathData="M24.347,4.1667C12.7994,4.1667 3.5137,13.4524 3.5137,25C3.5137,36.5476 12.7994,45.8333 24.347,45.8333C35.8946,45.8333 45.1803,36.5476 45.1803,25C45.1803,13.4524 35.8946,4.1667 24.347,4.1667L24.347,4.1667zM24.347,30C21.6089,30 19.347,27.7381 19.347,25C19.347,22.2619 21.6089,20 24.347,20C27.0851,20 29.347,22.2619 29.347,25C29.347,27.7381 27.0851,30 24.347,30z"
-        android:strokeAlpha="0.3714286"
-        android:strokeColor="#00000000"
-        android:fillType="nonZero"
-        android:fillAlpha="0.3714286"></path>
-    <path
-        android:pathData="M24.347,4.1667C12.7994,4.1667 3.5137,13.4524 3.5137,25C3.5137,36.5476 12.7994,45.8333 24.347,45.8333C35.8946,45.8333 45.1803,36.5476 45.1803,25C45.1803,13.4524 35.8946,4.1667 24.347,4.1667L24.347,4.1667zM24.347,30C21.6089,30 19.347,27.7381 19.347,25C19.347,22.2619 21.6089,20 24.347,20C27.0851,20 29.347,22.2619 29.347,25C29.347,27.7381 27.0851,30 24.347,30z"
-        android:strokeAlpha="0.23428573"
-        android:strokeColor="#00000000"
-        android:fillType="nonZero"
-        android:fillAlpha="0.23428573"></path>
-</vector>
diff --git a/android/app/src/main/res/drawable/ic_star_0.png b/android/app/src/main/res/drawable/ic_star_0.png
deleted file mode 100644
index e5b56db70..000000000
Binary files a/android/app/src/main/res/drawable/ic_star_0.png and /dev/null differ
diff --git a/android/app/src/main/res/drawable/ic_star_1.png b/android/app/src/main/res/drawable/ic_star_1.png
deleted file mode 100644
index ae91a29ac..000000000
Binary files a/android/app/src/main/res/drawable/ic_star_1.png and /dev/null differ
diff --git a/android/app/src/main/res/drawable/ic_star_2.png b/android/app/src/main/res/drawable/ic_star_2.png
deleted file mode 100644
index f7bee9b1d..000000000
Binary files a/android/app/src/main/res/drawable/ic_star_2.png and /dev/null differ
diff --git a/android/app/src/main/res/drawable/ic_star_3.png b/android/app/src/main/res/drawable/ic_star_3.png
deleted file mode 100644
index 330aefbac..000000000
Binary files a/android/app/src/main/res/drawable/ic_star_3.png and /dev/null differ
diff --git a/android/app/src/main/res/drawable/ic_star_4.png b/android/app/src/main/res/drawable/ic_star_4.png
deleted file mode 100644
index 4e9f58dfa..000000000
Binary files a/android/app/src/main/res/drawable/ic_star_4.png and /dev/null differ
diff --git a/android/app/src/main/res/drawable/ic_star_5.png b/android/app/src/main/res/drawable/ic_star_5.png
deleted file mode 100644
index aa5707ea7..000000000
Binary files a/android/app/src/main/res/drawable/ic_star_5.png and /dev/null differ
diff --git a/android/app/src/main/res/layout/activity_controller_mapping.xml b/android/app/src/main/res/layout/activity_controller_mapping.xml
deleted file mode 100644
index de6591a20..000000000
--- a/android/app/src/main/res/layout/activity_controller_mapping.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent">
-
-    <FrameLayout
-        android:id="@+id/settings"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent" />
-</LinearLayout>
\ No newline at end of file
diff --git a/android/app/src/main/res/layout/activity_emulation.xml b/android/app/src/main/res/layout/activity_emulation.xml
deleted file mode 100644
index 12493cbca..000000000
--- a/android/app/src/main/res/layout/activity_emulation.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:tools="http://schemas.android.com/tools"
-    android:id="@+id/frameLayout"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:background="#0099cc"
-    tools:context=".EmulationActivity">
-
-    <!-- The primary full-screen view. This can be replaced with whatever view
-         is needed to present your content, e.g. VideoView, SurfaceView,
-         TextureView, etc. -->
-    <com.github.stenzek.duckstation.EmulationSurfaceView
-        android:id="@+id/fullscreen_content"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:gravity="center"
-        android:keepScreenOn="true" />
-
-</FrameLayout>
\ No newline at end of file
diff --git a/android/app/src/main/res/layout/activity_game_directories.xml b/android/app/src/main/res/layout/activity_game_directories.xml
deleted file mode 100644
index 54bfc2181..000000000
--- a/android/app/src/main/res/layout/activity_game_directories.xml
+++ /dev/null
@@ -1,47 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:app="http://schemas.android.com/apk/res-auto"
-    xmlns:tools="http://schemas.android.com/tools"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    tools:context=".GameDirectoriesActivity">
-
-    <com.google.android.material.appbar.AppBarLayout
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:theme="@style/AppTheme.AppBarOverlay">
-
-        <androidx.appcompat.widget.Toolbar
-            android:id="@+id/toolbar"
-            android:layout_width="match_parent"
-            android:layout_height="?attr/actionBarSize"
-            android:background="?attr/colorPrimary"
-            app:popupTheme="@style/AppTheme.PopupOverlay" />
-
-    </com.google.android.material.appbar.AppBarLayout>
-
-    <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
-        xmlns:app="http://schemas.android.com/apk/res-auto"
-        xmlns:tools="http://schemas.android.com/tools"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        app:layout_behavior="@string/appbar_scrolling_view_behavior"
-        tools:context=".MainActivity"
-        tools:showIn="@layout/activity_main">
-
-        <androidx.recyclerview.widget.RecyclerView
-            android:id="@+id/recycler_view"
-            android:layout_width="match_parent"
-            android:layout_height="match_parent" />
-    </androidx.constraintlayout.widget.ConstraintLayout>
-
-    <com.google.android.material.floatingactionbutton.FloatingActionButton
-        android:id="@+id/fab"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_gravity="bottom|end"
-        android:layout_margin="@dimen/fab_margin"
-        app:backgroundTint="@color/fab_background"
-        app:srcCompat="@android:drawable/ic_input_add" />
-
-</androidx.coordinatorlayout.widget.CoordinatorLayout>
\ No newline at end of file
diff --git a/android/app/src/main/res/layout/activity_main.xml b/android/app/src/main/res/layout/activity_main.xml
deleted file mode 100644
index c9dc2d100..000000000
--- a/android/app/src/main/res/layout/activity_main.xml
+++ /dev/null
@@ -1,53 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:app="http://schemas.android.com/apk/res-auto"
-    xmlns:tools="http://schemas.android.com/tools"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    tools:context=".MainActivity">
-
-    <com.google.android.material.appbar.AppBarLayout
-        android:layout_height="wrap_content"
-        android:layout_width="match_parent"
-        android:theme="@style/AppTheme.AppBarOverlay">
-
-        <LinearLayout
-            android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            android:orientation="horizontal">
-
-            <ImageView
-                android:id="@+id/imageView2"
-                android:layout_width="32dp"
-                android:layout_height="match_parent"
-                android:layout_marginStart="16dp"
-                app:srcCompat="@drawable/duck" />
-
-            <androidx.appcompat.widget.Toolbar
-                android:id="@+id/toolbar"
-                android:layout_width="match_parent"
-                android:layout_height="?attr/actionBarSize"
-                android:background="?attr/colorPrimary"
-                app:popupTheme="@style/AppTheme.PopupOverlay" />
-
-        </LinearLayout>
-
-    </com.google.android.material.appbar.AppBarLayout>
-
-    <FrameLayout
-        android:id="@+id/content_fragment"
-        android:layout_width="fill_parent"
-        android:layout_height="fill_parent"
-        android:layout_weight="1"
-        app:layout_behavior="@string/appbar_scrolling_view_behavior" />
-
-    <com.google.android.material.floatingactionbutton.FloatingActionButton
-        android:id="@+id/fab_resume"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_gravity="bottom|end"
-        android:layout_margin="@dimen/fab_margin"
-        app:backgroundTint="@color/fab_background"
-        app:srcCompat="@drawable/ic_baseline_play_arrow_24" />
-
-</androidx.coordinatorlayout.widget.CoordinatorLayout>
\ No newline at end of file
diff --git a/android/app/src/main/res/layout/activity_memory_card_editor.xml b/android/app/src/main/res/layout/activity_memory_card_editor.xml
deleted file mode 100644
index fa471163a..000000000
--- a/android/app/src/main/res/layout/activity_memory_card_editor.xml
+++ /dev/null
@@ -1,65 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:app="http://schemas.android.com/apk/res-auto"
-    xmlns:tools="http://schemas.android.com/tools"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    tools:context=".MainActivity">
-
-    <com.google.android.material.appbar.AppBarLayout
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:theme="@style/AppTheme.AppBarOverlay">
-
-        <androidx.appcompat.widget.Toolbar
-            android:id="@+id/toolbar"
-            android:layout_width="match_parent"
-            android:layout_height="?attr/actionBarSize"
-            android:background="?attr/colorPrimary"
-            app:popupTheme="@style/AppTheme.PopupOverlay" />
-
-    </com.google.android.material.appbar.AppBarLayout>
-
-    <LinearLayout
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:layout_weight="1"
-        android:orientation="vertical"
-        app:layout_behavior="@string/appbar_scrolling_view_behavior">
-
-        <com.google.android.material.tabs.TabLayout
-            android:id="@+id/tab_layout"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            app:tabTextAppearance="@style/TabTextAppearance"
-            app:tabMinWidth="150dp"
-            app:tabMode="scrollable"  />
-
-        <androidx.viewpager2.widget.ViewPager2
-            android:id="@+id/view_pager"
-            android:layout_width="match_parent"
-            android:layout_height="0dp"
-            android:layout_weight="1" />
-
-    </LinearLayout>
-
-    <com.google.android.material.floatingactionbutton.FloatingActionButton
-        android:id="@+id/open_card"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_gravity="bottom|end"
-        android:layout_marginBottom="@dimen/fab_margin"
-        android:layout_marginRight="96dp"
-        app:backgroundTint="@color/fab_background"
-        app:srcCompat="@drawable/ic_baseline_folder_open_24" />
-
-    <com.google.android.material.floatingactionbutton.FloatingActionButton
-        android:id="@+id/close_card"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_gravity="bottom|end"
-        android:layout_margin="@dimen/fab_margin"
-        app:backgroundTint="@color/fab_background"
-        app:srcCompat="@drawable/ic_baseline_close_24" />
-
-</androidx.coordinatorlayout.widget.CoordinatorLayout>
\ No newline at end of file
diff --git a/android/app/src/main/res/layout/fragment_achievement_list.xml b/android/app/src/main/res/layout/fragment_achievement_list.xml
deleted file mode 100644
index d1a64a0de..000000000
--- a/android/app/src/main/res/layout/fragment_achievement_list.xml
+++ /dev/null
@@ -1,74 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:app="http://schemas.android.com/apk/res-auto"
-    xmlns:tools="http://schemas.android.com/tools"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent">
-
-    <RelativeLayout
-        android:id="@+id/navigation_header_container"
-        android:layout_width="fill_parent"
-        android:layout_height="wrap_content"
-        android:padding="10dp"
-        android:layout_alignParentTop="true"
-        android:layout_alignParentStart="true">
-
-        <ImageView
-            android:id="@+id/icon"
-            android:layout_width="70dp"
-            android:layout_height="70dp"
-            android:foregroundGravity="center_vertical"
-            android:layout_alignParentTop="true"
-            android:layout_alignParentStart="true"
-            tools:srcCompat="@drawable/ic_media_cdrom" />
-
-        <TextView
-            android:id="@+id/title"
-            android:layout_width="0dp"
-            android:layout_height="wrap_content"
-            android:layout_marginLeft="10dp"
-            android:focusable="false"
-            android:focusableInTouchMode="false"
-            android:text="Game Title"
-            android:textAppearance="@style/TextAppearance.AppCompat.Large"
-            android:layout_alignParentTop="true"
-            android:layout_toRightOf="@+id/icon"
-            android:layout_alignParentEnd="true" />
-
-        <TextView
-            android:id="@+id/summary"
-            android:layout_width="0dp"
-            android:layout_height="wrap_content"
-            android:layout_marginLeft="10dp"
-            android:focusable="false"
-            android:focusableInTouchMode="false"
-            android:text="You have unlocked %d of %d achievements, earning %d of %d possible points."
-            android:textAppearance="@style/TextAppearance.AppCompat.Small"
-            android:layout_below="@+id/title"
-            android:layout_toRightOf="@+id/icon"
-            android:layout_alignParentEnd="true" />
-
-        <ProgressBar
-            android:id="@+id/progressBar"
-            style="?android:attr/progressBarStyleHorizontal"
-            android:layout_width="0dp"
-            android:layout_height="16dp"
-            android:layout_marginLeft="10dp"
-            android:layout_marginRight="10dp"
-            android:layout_below="@+id/summary"
-            android:layout_toRightOf="@+id/icon"
-            android:layout_alignParentEnd="true" />
-
-    </RelativeLayout>
-
-    <androidx.recyclerview.widget.RecyclerView
-        android:id="@+id/recyclerView"
-        android:layout_width="match_parent"
-        android:layout_height="fill_parent"
-        android:scrollbars="vertical"
-        android:layout_below="@+id/navigation_header_container"
-        android:layout_alignParentBottom="true"
-        android:layout_alignParentLeft="true"
-        android:layout_alignParentEnd="true" />
-
-</RelativeLayout>
\ No newline at end of file
diff --git a/android/app/src/main/res/layout/fragment_achievements_login.xml b/android/app/src/main/res/layout/fragment_achievements_login.xml
deleted file mode 100644
index 5ab32fd3c..000000000
--- a/android/app/src/main/res/layout/fragment_achievements_login.xml
+++ /dev/null
@@ -1,133 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:tools="http://schemas.android.com/tools"
-    android:layout_width="match_parent"
-    android:layout_height="wrap_content"
-    android:minWidth="280dp"
-    >
-    <LinearLayout
-        android:id="@+id/panel"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:orientation="vertical"
-        >
-
-        <LinearLayout
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:orientation="vertical"
-            android:padding="20dp"
-            >
-
-        <TextView
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:layout_marginLeft="8dp"
-            android:layout_marginRight="8dp"
-            android:text="@string/achievement_settings_login_title"
-            android:textAppearance="@style/TextAppearance.AppCompat.Large" />
-
-        <TextView
-            android:id="@+id/title"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:layout_marginBottom="4dp"
-            android:layout_marginLeft="8dp"
-            android:layout_marginRight="8dp"
-            android:layout_marginTop="4dp"
-            android:text="@string/achievement_settings_login_help"
-            />
-        <EditText
-            android:id="@+id/username"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:layout_marginLeft="8dp"
-            android:layout_marginRight="8dp"
-            android:inputType="textVisiblePassword"
-            android:nextFocusDown="@+id/password"
-            android:imeOptions="actionNext"
-            android:singleLine="true"
-            android:hint="@string/achievement_settings_login_username_hint"
-            />
-        <EditText
-            android:id="@+id/password"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:layout_marginLeft="8dp"
-            android:layout_marginRight="8dp"
-            android:inputType="textPassword"
-            android:imeOptions="actionDone"
-            android:singleLine="true"
-            android:hint="@string/achievement_settings_login_password_hint"
-            />
-
-            <TextView
-                android:id="@+id/error"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:layout_marginLeft="8dp"
-                android:layout_marginTop="4dp"
-                android:layout_marginRight="8dp"
-                android:layout_marginBottom="4dp"
-                android:visibility="visible" />
-        </LinearLayout>
-        <LinearLayout
-            android:id="@+id/buttonPanel"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:divider="?android:attr/dividerHorizontal"
-            android:dividerPadding="0dip"
-            android:minHeight="48dp"
-            android:orientation="vertical"
-            android:showDividers="beginning"
-            android:padding="5dp"
-            >
-            <LinearLayout
-                style="?android:attr/buttonBarStyle"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:layoutDirection="locale"
-                android:orientation="horizontal"
-                tools:ignore="UselessParent"
-                >
-                <Space
-                    android:layout_width="wrap_content"
-                    android:layout_height="wrap_content"
-                    android:layout_weight="1" />
-
-                <Button
-                    android:id="@+id/cancel"
-                    style="?android:attr/buttonBarButtonStyle"
-                    android:layout_width="wrap_content"
-                    android:layout_height="wrap_content"
-                    android:layout_gravity="end"
-                    android:focusable="true"
-                    android:maxLines="2"
-                    android:minHeight="48dp"
-                    android:text="@string/achievement_settings_login_cancel_button"
-                    android:textSize="14sp" />
-
-                <Button
-                    android:id="@+id/login"
-                    style="?android:attr/buttonBarButtonStyle"
-                    android:layout_width="wrap_content"
-                    android:layout_height="wrap_content"
-                    android:layout_gravity="end"
-                    android:focusable="true"
-                    android:maxLines="2"
-                    android:minHeight="48dp"
-                    android:text="@string/achievement_settings_login_login_button"
-                    android:textSize="14sp" />
-            </LinearLayout>
-        </LinearLayout>
-    </LinearLayout>
-    <ProgressBar
-        android:id="@+id/progressBar"
-        style="?android:attr/progressBarStyleLarge"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:layout_gravity="center"
-        android:indeterminateOnly="true"
-        android:visibility="gone"
-        />
-</FrameLayout>
\ No newline at end of file
diff --git a/android/app/src/main/res/layout/fragment_controller_settings.xml b/android/app/src/main/res/layout/fragment_controller_settings.xml
deleted file mode 100644
index a47a49de4..000000000
--- a/android/app/src/main/res/layout/fragment_controller_settings.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:app="http://schemas.android.com/apk/res-auto"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:orientation="vertical">
-
-    <com.google.android.material.tabs.TabLayout
-        android:id="@+id/tab_layout"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        app:tabTextAppearance="@style/TabTextAppearance"
-        app:tabMinWidth="150dp"
-        app:tabMode="scrollable"  />
-
-    <androidx.viewpager2.widget.ViewPager2
-        android:id="@+id/view_pager"
-        android:layout_width="match_parent"
-        android:layout_height="0dp"
-        android:layout_weight="1" />
-
-</LinearLayout>
\ No newline at end of file
diff --git a/android/app/src/main/res/layout/fragment_empty_game_list.xml b/android/app/src/main/res/layout/fragment_empty_game_list.xml
deleted file mode 100644
index 55f8fd607..000000000
--- a/android/app/src/main/res/layout/fragment_empty_game_list.xml
+++ /dev/null
@@ -1,44 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:app="http://schemas.android.com/apk/res-auto"
-    xmlns:tools="http://schemas.android.com/tools"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent">
-
-
-    <TextView
-        android:id="@+id/title"
-        android:layout_width="320dp"
-        android:layout_height="wrap_content"
-        android:text="@string/main_activity_empty_game_list_title"
-        app:layout_constraintBottom_toBottomOf="parent"
-        app:layout_constraintEnd_toEndOf="parent"
-        app:layout_constraintHorizontal_bias="0.496"
-        app:layout_constraintStart_toStartOf="parent"
-        app:layout_constraintTop_toTopOf="parent"
-        app:layout_constraintVertical_bias="0.171" />
-
-    <TextView
-        android:id="@+id/supported_formats"
-        android:layout_width="320dp"
-        android:layout_height="wrap_content"
-        android:layout_marginTop="20dp"
-        android:text="@string/main_activity_empty_game_list_supported_formats"
-        app:layout_constraintEnd_toEndOf="parent"
-        app:layout_constraintHorizontal_bias="0.498"
-        app:layout_constraintStart_toStartOf="parent"
-        app:layout_constraintTop_toBottomOf="@id/title" />
-
-    <Button
-        android:id="@+id/add_game_directory"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_marginTop="20dp"
-        android:text="@string/main_activity_empty_game_list_add_directory"
-        style="@style/Widget.AppCompat.Button.Borderless.Colored"
-        app:layout_constraintEnd_toEndOf="parent"
-        app:layout_constraintHorizontal_bias="0.5"
-        app:layout_constraintStart_toStartOf="parent"
-        app:layout_constraintTop_toBottomOf="@id/supported_formats" />
-
-</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
diff --git a/android/app/src/main/res/layout/fragment_emulation_activity_overlay.xml b/android/app/src/main/res/layout/fragment_emulation_activity_overlay.xml
deleted file mode 100644
index 2cdd354d2..000000000
--- a/android/app/src/main/res/layout/fragment_emulation_activity_overlay.xml
+++ /dev/null
@@ -1,113 +0,0 @@
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:app="http://schemas.android.com/apk/res-auto"
-    xmlns:tools="http://schemas.android.com/tools"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:orientation="vertical">
-
-    <androidx.constraintlayout.widget.ConstraintLayout
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:background="@color/colorPrimary"
-        android:orientation="horizontal">
-
-        <ImageView
-            android:id="@+id/cover_image"
-            android:layout_width="60dp"
-            android:layout_height="60dp"
-            android:background="?android:attr/selectableItemBackground"
-            app:layout_constraintStart_toStartOf="parent"
-            app:layout_constraintTop_toTopOf="parent" />
-
-        <TextView
-            android:id="@+id/title"
-            android:layout_width="0dp"
-            android:layout_height="wrap_content"
-            android:layout_marginStart="10dp"
-            android:layout_marginEnd="4dp"
-            android:layout_marginTop="4dp"
-            android:text="Title"
-            android:textAppearance="@style/TextAppearance.AppCompat.Large"
-            android:textColor="?android:textColorPrimary"
-            android:scrollHorizontally="true"
-            android:ellipsize="end"
-            android:maxLines="1"
-            app:layout_constraintEnd_toStartOf="@id/button_container"
-            app:layout_constraintStart_toEndOf="@id/cover_image"
-            app:layout_constraintTop_toTopOf="parent" />
-
-        <TextView
-            android:id="@+id/subtitle"
-            android:layout_width="0dp"
-            android:layout_height="wrap_content"
-            android:layout_marginStart="10dp"
-            android:layout_marginEnd="4dp"
-            android:layout_marginBottom="4dp"
-            android:text="Code - Path"
-            android:textColor="?android:textColorPrimary"
-            android:scrollHorizontally="true"
-            android:ellipsize="end"
-            android:maxLines="1"
-            android:textAppearance="@style/TextAppearance.AppCompat.Small"
-            app:layout_constraintEnd_toStartOf="@id/button_container"
-            app:layout_constraintStart_toEndOf="@id/cover_image"
-            app:layout_constraintTop_toBottomOf="@id/title" />
-
-        <LinearLayout
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:orientation="horizontal"
-            android:id="@+id/button_container"
-            app:layout_constraintBottom_toBottomOf="parent"
-            app:layout_constraintEnd_toEndOf="parent"
-            app:layout_constraintTop_toTopOf="parent">
-
-            <ImageButton
-                android:id="@+id/menu"
-                android:layout_width="40dp"
-                android:layout_height="60dp"
-                android:layout_marginEnd="5dp"
-                android:background="?android:attr/selectableItemBackground"
-                android:tint="?android:textColorPrimary"
-                android:contentDescription="Pause Menu"
-                android:src="@drawable/ic_baseline_menu_24" />
-
-            <ImageButton
-                android:id="@+id/controller_settings"
-                android:layout_width="40dp"
-                android:layout_height="60dp"
-                android:layout_marginEnd="5dp"
-                android:background="?android:attr/selectableItemBackground"
-                android:tint="?android:textColorPrimary"
-                android:contentDescription="Controller Settings"
-                android:src="@drawable/ic_baseline_gamepad_24" />
-
-            <ImageButton
-                android:id="@+id/settings"
-                android:layout_width="40dp"
-                android:layout_height="60dp"
-                android:layout_marginEnd="5dp"
-                android:background="?android:attr/selectableItemBackground"
-                android:tint="?android:textColorPrimary"
-                android:contentDescription="Settings"
-                android:src="@drawable/ic_baseline_settings_24" />
-
-            <ImageButton
-                android:id="@+id/close"
-                android:layout_width="40dp"
-                android:layout_height="60dp"
-                android:layout_marginEnd="5dp"
-                android:background="?android:attr/selectableItemBackground"
-                android:tint="?android:textColorPrimary"
-                android:contentDescription="Close"
-                android:src="@drawable/ic_baseline_close_24" />
-
-        </LinearLayout>
-
-    </androidx.constraintlayout.widget.ConstraintLayout>
-
-    <FrameLayout
-        android:id="@+id/content"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent" />
-</LinearLayout>
\ No newline at end of file
diff --git a/android/app/src/main/res/layout/fragment_game_grid.xml b/android/app/src/main/res/layout/fragment_game_grid.xml
deleted file mode 100644
index 26ce3e703..000000000
--- a/android/app/src/main/res/layout/fragment_game_grid.xml
+++ /dev/null
@@ -1,18 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<androidx.constraintlayout.widget.ConstraintLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:app="http://schemas.android.com/apk/res-auto"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent">
-
-    <androidx.recyclerview.widget.RecyclerView
-        android:id="@+id/game_list_view"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:scrollbars="vertical"
-        app:layout_constraintBottom_toBottomOf="parent"
-        app:layout_constraintLeft_toLeftOf="parent"
-        app:layout_constraintRight_toRightOf="parent"
-        app:layout_constraintTop_toTopOf="parent" />
-
-</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
diff --git a/android/app/src/main/res/layout/fragment_game_list.xml b/android/app/src/main/res/layout/fragment_game_list.xml
deleted file mode 100644
index 0d320dc6e..000000000
--- a/android/app/src/main/res/layout/fragment_game_list.xml
+++ /dev/null
@@ -1,17 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:app="http://schemas.android.com/apk/res-auto"
-    xmlns:tools="http://schemas.android.com/tools"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent">
-
-    <androidx.recyclerview.widget.RecyclerView
-        android:id="@+id/game_list_view"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:scrollbars="vertical"
-        app:layout_constraintBottom_toBottomOf="parent"
-        app:layout_constraintLeft_toLeftOf="parent"
-        app:layout_constraintRight_toRightOf="parent"
-        app:layout_constraintTop_toTopOf="parent" />
-</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
diff --git a/android/app/src/main/res/layout/fragment_memory_card_file.xml b/android/app/src/main/res/layout/fragment_memory_card_file.xml
deleted file mode 100644
index 49d14e2e5..000000000
--- a/android/app/src/main/res/layout/fragment_memory_card_file.xml
+++ /dev/null
@@ -1,14 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:app="http://schemas.android.com/apk/res-auto"
-    xmlns:tools="http://schemas.android.com/tools"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:orientation="vertical">
-
-    <androidx.recyclerview.widget.RecyclerView
-        android:id="@+id/recyclerView"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent" />
-
-</LinearLayout>
\ No newline at end of file
diff --git a/android/app/src/main/res/layout/fragment_settings_collection.xml b/android/app/src/main/res/layout/fragment_settings_collection.xml
deleted file mode 100644
index 49bc94180..000000000
--- a/android/app/src/main/res/layout/fragment_settings_collection.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:app="http://schemas.android.com/apk/res-auto"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:orientation="vertical">
-
-    <com.google.android.material.tabs.TabLayout
-        android:id="@+id/tab_layout"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        app:tabTextAppearance="@style/TabTextAppearance"
-        app:tabMinWidth="150dp"
-        app:tabMode="scrollable" />
-
-    <androidx.viewpager2.widget.ViewPager2
-        android:id="@+id/view_pager"
-        android:layout_width="match_parent"
-        android:layout_height="0dp"
-        android:layout_weight="1" />
-
-</LinearLayout>
\ No newline at end of file
diff --git a/android/app/src/main/res/layout/layout_achievement_entry.xml b/android/app/src/main/res/layout/layout_achievement_entry.xml
deleted file mode 100644
index 861689833..000000000
--- a/android/app/src/main/res/layout/layout_achievement_entry.xml
+++ /dev/null
@@ -1,79 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:app="http://schemas.android.com/apk/res-auto"
-    xmlns:tools="http://schemas.android.com/tools"
-    android:id="@+id/linearLayout"
-    android:layout_width="fill_parent"
-    android:layout_height="wrap_content"
-    android:paddingTop="8dp"
-    android:paddingBottom="8dp"
-    android:background="?android:attr/selectableItemBackground">
-
-    <ImageView
-        android:id="@+id/icon"
-        android:layout_width="48dp"
-        android:layout_height="48dp"
-        android:layout_marginStart="8dp"
-        android:foregroundGravity="center_vertical"
-        app:layout_constraintStart_toStartOf="parent"
-        app:layout_constraintTop_toTopOf="parent"
-        tools:srcCompat="@drawable/ic_media_cdrom" />
-
-    <TextView
-        android:id="@+id/title"
-        android:layout_width="0dp"
-        android:layout_height="wrap_content"
-        android:layout_marginLeft="10dp"
-        android:layout_marginRight="80dp"
-        android:focusable="false"
-        android:focusableInTouchMode="false"
-        android:text="Achievement Title"
-        android:textAppearance="@style/TextAppearance.AppCompat.Large"
-        app:layout_constraintEnd_toEndOf="parent"
-        app:layout_constraintStart_toEndOf="@+id/icon"
-        app:layout_constraintTop_toTopOf="parent" />
-
-    <TextView
-        android:id="@+id/description"
-        android:layout_width="0dp"
-        android:layout_height="wrap_content"
-        android:layout_marginLeft="10dp"
-        android:layout_marginRight="80dp"
-        android:focusable="false"
-        android:focusableInTouchMode="false"
-        android:paddingBottom="8px"
-        android:text="Achievement Description"
-        android:textAppearance="@style/TextAppearance.AppCompat.Small"
-        app:layout_constraintEnd_toEndOf="parent"
-        app:layout_constraintStart_toEndOf="@+id/icon"
-        app:layout_constraintTop_toBottomOf="@+id/title" />
-
-    <ImageView
-        android:id="@+id/locked_icon"
-        android:layout_width="32dp"
-        android:layout_height="28dp"
-        android:layout_marginTop="4dp"
-        android:layout_marginEnd="24dp"
-        android:focusable="false"
-        android:focusableInTouchMode="false"
-        android:paddingBottom="8px"
-        app:layout_constraintEnd_toEndOf="parent"
-        app:layout_constraintTop_toTopOf="parent"
-        app:srcCompat="@drawable/ic_baseline_lock_24" />
-
-    <TextView
-        android:id="@+id/points"
-        android:layout_width="64dp"
-        android:layout_height="16dp"
-        android:layout_marginEnd="8dp"
-        android:focusable="false"
-        android:focusableInTouchMode="false"
-        android:text="5 Points"
-        android:textAlignment="center"
-        android:textAppearance="@style/TextAppearance.AppCompat.Small"
-        app:srcCompat="@drawable/ic_star_5"
-        app:layout_constraintEnd_toEndOf="parent"
-        app:layout_constraintTop_toBottomOf="@+id/locked_icon" />
-
-
-</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
diff --git a/android/app/src/main/res/layout/layout_controller_binding_preference.xml b/android/app/src/main/res/layout/layout_controller_binding_preference.xml
deleted file mode 100644
index 6d9488150..000000000
--- a/android/app/src/main/res/layout/layout_controller_binding_preference.xml
+++ /dev/null
@@ -1,39 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:app="http://schemas.android.com/apk/res-auto"
-    xmlns:tools="http://schemas.android.com/tools"
-    android:id="@+id/linearLayout"
-    android:layout_width="match_parent"
-    android:layout_height="wrap_content"
-    android:orientation="vertical">
-
-    <ImageView
-        android:id="@+id/controller_binding_icon"
-        android:layout_width="48dp"
-        android:layout_height="48dp"
-        android:layout_marginTop="0dp"
-        android:layout_alignParentTop="true"
-        tools:srcCompat="@drawable/ic_media_cdrom" />
-
-    <TextView
-        android:id="@+id/controller_binding_name"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:layout_marginStart="16dp"
-        android:layout_marginTop="0dp"
-        android:text="Up"
-        android:textAppearance="@style/TextAppearance.AppCompat.Medium"
-        android:layout_alignParentTop="true"
-        android:layout_toRightOf="@id/controller_binding_icon" />
-
-    <TextView
-        android:id="@+id/controller_binding_value"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:layout_marginStart="16dp"
-        android:text="Controller0/Button0"
-        android:textAppearance="@style/TextAppearance.AppCompat.Small"
-        android:layout_toRightOf="@id/controller_binding_icon"
-        android:layout_below="@id/controller_binding_name" />
-
-</RelativeLayout>
\ No newline at end of file
diff --git a/android/app/src/main/res/layout/layout_game_directory_entry.xml b/android/app/src/main/res/layout/layout_game_directory_entry.xml
deleted file mode 100644
index d190b6f61..000000000
--- a/android/app/src/main/res/layout/layout_game_directory_entry.xml
+++ /dev/null
@@ -1,53 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:app="http://schemas.android.com/apk/res-auto"
-    android:layout_width="wrap_content"
-    android:layout_height="wrap_content">
-
-    <TextView
-        android:id="@+id/path"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:layout_alignParentStart="true"
-        android:layout_alignParentTop="true"
-        android:layout_marginStart="10dp"
-        android:layout_marginEnd="100dp"
-        android:layout_marginTop="4dp"
-        android:text="TextView"
-        android:textAppearance="?android:attr/textAppearanceMedium" />
-
-    <TextView
-        android:id="@+id/recursive"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:layout_marginStart="10dp"
-        android:layout_marginEnd="100dp"
-        android:layout_marginTop="4dp"
-        android:layout_marginBottom="4dp"
-        android:layout_below="@id/path"
-        android:layout_alignParentStart="true"
-        android:textAppearance="?android:attr/textAppearanceSmall"
-        android:text="TextView" />
-
-    <ImageButton
-        android:id="@+id/remove"
-        android:layout_width="30dp"
-        android:layout_height="30dp"
-        android:layout_alignParentEnd="true"
-        android:layout_alignParentTop="true"
-        android:layout_marginTop="15dp"
-        android:layout_marginEnd="15dp"
-        android:background="?android:selectableItemBackground"
-        app:srcCompat="@drawable/ic_baseline_delete_24" />
-
-    <ImageButton
-        android:id="@+id/toggle_recursive"
-        android:layout_width="30dp"
-        android:layout_height="30dp"
-        android:layout_alignParentTop="true"
-        android:layout_marginTop="15dp"
-        android:layout_marginEnd="15dp"
-        android:layout_toStartOf="@id/remove"
-        android:background="?android:selectableItemBackground"
-        app:srcCompat="@drawable/ic_baseline_folder_24" />
-</RelativeLayout>
\ No newline at end of file
diff --git a/android/app/src/main/res/layout/layout_game_grid_entry.xml b/android/app/src/main/res/layout/layout_game_grid_entry.xml
deleted file mode 100644
index 6faa52b57..000000000
--- a/android/app/src/main/res/layout/layout_game_grid_entry.xml
+++ /dev/null
@@ -1,17 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:app="http://schemas.android.com/apk/res-auto"
-    xmlns:tools="http://schemas.android.com/tools"
-    android:layout_width="160dp"
-    android:layout_height="160dp"
-    android:layout_margin="25dp">
-
-    <ImageView
-        android:id="@+id/imageView"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:foreground="?android:attr/selectableItemBackground"
-        app:srcCompat="@drawable/ic_media_cdrom"
-        tools:layout_editor_absoluteX="1dp"
-        tools:layout_editor_absoluteY="1dp" />
-</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
diff --git a/android/app/src/main/res/layout/layout_game_list_entry.xml b/android/app/src/main/res/layout/layout_game_list_entry.xml
deleted file mode 100644
index 8c450af31..000000000
--- a/android/app/src/main/res/layout/layout_game_list_entry.xml
+++ /dev/null
@@ -1,76 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:app="http://schemas.android.com/apk/res-auto"
-    xmlns:tools="http://schemas.android.com/tools"
-    android:id="@+id/linearLayout"
-    android:layout_width="match_parent"
-    android:layout_height="wrap_content"
-    android:paddingTop="8dp"
-    android:paddingBottom="8dp"
-    android:background="?android:attr/selectableItemBackground">
-
-    <ImageView
-        android:id="@+id/game_list_view_entry_type_icon"
-        android:layout_width="48dp"
-        android:layout_height="48dp"
-        android:layout_marginStart="8dp"
-        android:foregroundGravity="center_vertical"
-        app:layout_constraintStart_toStartOf="parent"
-        app:layout_constraintTop_toTopOf="parent"
-        tools:srcCompat="@drawable/ic_media_cdrom" />
-
-    <TextView
-        android:id="@+id/game_list_view_entry_title"
-        android:layout_width="0dp"
-        android:layout_height="wrap_content"
-        android:layout_marginLeft="10dp"
-        android:layout_marginRight="80dp"
-        android:focusable="false"
-        android:focusableInTouchMode="false"
-        android:text="Game Title"
-        android:textAppearance="@style/TextAppearance.AppCompat.Large"
-        app:layout_constraintEnd_toEndOf="parent"
-        app:layout_constraintStart_toEndOf="@+id/game_list_view_entry_type_icon"
-        app:layout_constraintTop_toTopOf="parent" />
-
-    <TextView
-        android:id="@+id/game_list_view_entry_subtitle"
-        android:layout_width="0dp"
-        android:layout_height="wrap_content"
-        android:layout_marginLeft="10dp"
-        android:layout_marginRight="80dp"
-        android:focusable="false"
-        android:focusableInTouchMode="false"
-        android:paddingBottom="8px"
-        android:text="Game Path"
-        android:textAppearance="@style/TextAppearance.AppCompat.Small"
-        app:layout_constraintEnd_toEndOf="parent"
-        app:layout_constraintStart_toEndOf="@+id/game_list_view_entry_type_icon"
-        app:layout_constraintTop_toBottomOf="@+id/game_list_view_entry_title" />
-
-    <ImageView
-        android:id="@+id/game_list_view_compatibility_icon"
-        android:layout_width="64dp"
-        android:layout_height="16dp"
-        android:layout_marginEnd="8dp"
-        android:focusable="false"
-        android:focusableInTouchMode="false"
-        android:textAppearance="@style/TextAppearance.AppCompat.Small"
-        app:srcCompat="@drawable/ic_star_5"
-        app:layout_constraintEnd_toEndOf="parent"
-        app:layout_constraintTop_toTopOf="parent" />
-
-    <ImageView
-        android:id="@+id/game_list_view_entry_region_icon"
-        android:layout_width="32dp"
-        android:layout_height="28dp"
-        android:layout_marginTop="4dp"
-        android:layout_marginEnd="24dp"
-        android:focusable="false"
-        android:focusableInTouchMode="false"
-        android:paddingBottom="8px"
-        app:layout_constraintEnd_toEndOf="parent"
-        app:layout_constraintTop_toBottomOf="@+id/game_list_view_compatibility_icon"
-        app:srcCompat="@drawable/flag_jp" />
-
-</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
diff --git a/android/app/src/main/res/layout/layout_game_property_entry.xml b/android/app/src/main/res/layout/layout_game_property_entry.xml
deleted file mode 100644
index 47ede3ee3..000000000
--- a/android/app/src/main/res/layout/layout_game_property_entry.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent">
-
-    <TextView
-        android:id="@+id/property_title"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_marginTop="4dp"
-        android:layout_marginStart="10dp"
-        android:layout_alignParentTop="true"
-        android:text="TextView"
-        android:textAppearance="?android:attr/textAppearanceMedium" />
-
-    <TextView
-        android:id="@+id/property_value"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_marginStart="10dp"
-        android:layout_marginTop="4dp"
-        android:layout_marginBottom="4dp"
-        android:layout_below="@id/property_title"
-        android:textAppearance="?android:attr/textAppearanceSmall"
-        android:text="TextView" />
-</RelativeLayout>
\ No newline at end of file
diff --git a/android/app/src/main/res/layout/layout_memory_card_save.xml b/android/app/src/main/res/layout/layout_memory_card_save.xml
deleted file mode 100644
index caab01ec7..000000000
--- a/android/app/src/main/res/layout/layout_memory_card_save.xml
+++ /dev/null
@@ -1,82 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:app="http://schemas.android.com/apk/res-auto"
-    xmlns:tools="http://schemas.android.com/tools"
-    android:id="@+id/linearLayout"
-    android:layout_width="fill_parent"
-    android:layout_height="wrap_content"
-    android:paddingTop="8dp"
-    android:paddingBottom="8dp"
-    android:background="?android:attr/selectableItemBackground">
-
-    <ImageView
-        android:id="@+id/icon"
-        android:layout_width="48dp"
-        android:layout_height="48dp"
-        android:layout_marginStart="8dp"
-        android:foregroundGravity="center_vertical"
-        app:layout_constraintStart_toStartOf="parent"
-        app:layout_constraintTop_toTopOf="parent"
-        tools:srcCompat="@drawable/ic_media_cdrom" />
-
-    <TextView
-        android:id="@+id/title"
-        android:layout_width="0dp"
-        android:layout_height="wrap_content"
-        android:layout_marginLeft="10dp"
-        android:layout_marginRight="80dp"
-        android:focusable="false"
-        android:focusableInTouchMode="false"
-        android:text="Save Title"
-        android:textAppearance="@style/TextAppearance.AppCompat.Large"
-        app:layout_constraintEnd_toEndOf="parent"
-        app:layout_constraintStart_toEndOf="@+id/icon"
-        app:layout_constraintTop_toTopOf="parent" />
-
-    <TextView
-        android:id="@+id/filename"
-        android:layout_width="0dp"
-        android:layout_height="wrap_content"
-        android:layout_marginLeft="10dp"
-        android:layout_marginRight="80dp"
-        android:focusable="false"
-        android:focusableInTouchMode="false"
-        android:paddingBottom="8px"
-        android:text="Save Filename"
-        android:textAppearance="@style/TextAppearance.AppCompat.Small"
-        app:layout_constraintEnd_toEndOf="parent"
-        app:layout_constraintStart_toEndOf="@+id/icon"
-        app:layout_constraintTop_toBottomOf="@+id/title" />
-
-    <TextView
-        android:id="@+id/block_size"
-        android:layout_width="64dp"
-        android:layout_height="20dp"
-        android:layout_marginTop="4dp"
-        android:layout_marginEnd="8dp"
-        android:focusable="false"
-        android:focusableInTouchMode="false"
-        android:paddingBottom="8px"
-        android:text="1 Block"
-        android:textAlignment="viewEnd"
-        android:textAppearance="@style/TextAppearance.AppCompat.Small"
-        app:layout_constraintEnd_toEndOf="parent"
-        app:layout_constraintTop_toTopOf="parent"
-        app:srcCompat="@drawable/ic_baseline_lock_24" />
-
-    <TextView
-        android:id="@+id/file_size"
-        android:layout_width="64dp"
-        android:layout_height="20dp"
-        android:layout_marginEnd="8dp"
-        android:focusable="false"
-        android:focusableInTouchMode="false"
-        android:text="16KB"
-        android:textAlignment="viewEnd"
-        android:textAppearance="@style/TextAppearance.AppCompat.Small"
-        app:srcCompat="@drawable/ic_star_5"
-        app:layout_constraintEnd_toEndOf="parent"
-        app:layout_constraintTop_toBottomOf="@+id/block_size" />
-
-
-</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
diff --git a/android/app/src/main/res/layout/layout_ratio_preference.xml b/android/app/src/main/res/layout/layout_ratio_preference.xml
deleted file mode 100644
index 1191b62f0..000000000
--- a/android/app/src/main/res/layout/layout_ratio_preference.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:app="http://schemas.android.com/apk/res-auto"
-    xmlns:tools="http://schemas.android.com/tools"
-    android:layout_width="wrap_content"
-    android:layout_height="wrap_content"
-    android:orientation="horizontal">
-
-    <Spinner
-        android:id="@+id/numerator"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_gravity="center_vertical" />
-
-    <TextView
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_gravity="center_vertical"
-        android:text=":" />
-
-    <Spinner
-        android:id="@+id/denominator"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_gravity="center_vertical" />
-</LinearLayout>
\ No newline at end of file
diff --git a/android/app/src/main/res/layout/layout_touchscreen_controller_analog_stick.xml b/android/app/src/main/res/layout/layout_touchscreen_controller_analog_stick.xml
deleted file mode 100644
index ac7ffb4af..000000000
--- a/android/app/src/main/res/layout/layout_touchscreen_controller_analog_stick.xml
+++ /dev/null
@@ -1,255 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:app="http://schemas.android.com/apk/res-auto"
-    xmlns:tools="http://schemas.android.com/tools"
-    android:id="@+id/constraintLayout"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:orientation="vertical"
-    android:clipChildren="false">
-
-    <View
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:translationZ="-10px"
-        app:layout_constraintBottom_toBottomOf="parent"
-        app:layout_constraintEnd_toEndOf="parent"
-        app:layout_constraintStart_toStartOf="parent"
-        app:layout_constraintTop_toTopOf="parent" />
-
-    <com.github.stenzek.duckstation.TouchscreenControllerButtonView
-        android:id="@+id/controller_button_r2"
-        android:layout_width="70dp"
-        android:layout_height="35dp"
-        android:layout_marginEnd="60dp"
-        android:layout_marginBottom="280dp"
-        app:layout_constraintBottom_toBottomOf="parent"
-        app:layout_constraintEnd_toEndOf="parent"
-        app:pressedDrawable="@drawable/ic_controller_r2_button_pressed"
-        app:unpressedDrawable="@drawable/ic_controller_r2_button" />
-
-    <com.github.stenzek.duckstation.TouchscreenControllerButtonView
-        android:id="@+id/controller_button_r1"
-        android:layout_width="70dp"
-        android:layout_height="35dp"
-        android:layout_marginEnd="60dp"
-        android:layout_marginBottom="220dp"
-        app:layout_constraintBottom_toBottomOf="parent"
-        app:layout_constraintEnd_toEndOf="parent"
-        app:pressedDrawable="@drawable/ic_controller_r1_button_pressed"
-        app:unpressedDrawable="@drawable/ic_controller_r1_button" />
-
-    <com.github.stenzek.duckstation.TouchscreenControllerButtonView
-        android:id="@+id/controller_button_l1"
-        android:layout_width="70dp"
-        android:layout_height="35dp"
-        android:layout_marginStart="60dp"
-        android:layout_marginBottom="220dp"
-        app:layout_constraintBottom_toBottomOf="parent"
-        app:layout_constraintStart_toStartOf="parent"
-        app:pressedDrawable="@drawable/ic_controller_l1_button_pressed"
-        app:unpressedDrawable="@drawable/ic_controller_l1_button" />
-
-    <com.github.stenzek.duckstation.TouchscreenControllerButtonView
-        android:id="@+id/controller_button_l2"
-        android:layout_width="70dp"
-        android:layout_height="35dp"
-        android:layout_marginStart="60dp"
-        android:layout_marginBottom="280dp"
-        app:layout_constraintBottom_toBottomOf="parent"
-        app:layout_constraintStart_toStartOf="parent"
-        app:pressedDrawable="@drawable/ic_controller_l2_button_pressed"
-        app:unpressedDrawable="@drawable/ic_controller_l2_button" />
-
-    <com.github.stenzek.duckstation.TouchscreenControllerButtonView
-        android:id="@+id/controller_button_start"
-        android:layout_width="40dp"
-        android:layout_height="25dp"
-        android:layout_marginStart="70dp"
-        android:layout_marginBottom="8dp"
-        app:layout_constraintBottom_toBottomOf="parent"
-        app:layout_constraintEnd_toEndOf="parent"
-        app:layout_constraintHorizontal_bias="0.5"
-        app:layout_constraintStart_toStartOf="parent"
-        app:pressedDrawable="@drawable/ic_controller_start_button_pressed"
-        app:unpressedDrawable="@drawable/ic_controller_start_button" />
-
-    <com.github.stenzek.duckstation.TouchscreenControllerButtonView
-        android:id="@+id/controller_button_select"
-        android:layout_width="40dp"
-        android:layout_height="25dp"
-        android:layout_marginEnd="70dp"
-        android:layout_marginBottom="8dp"
-        app:layout_constraintBottom_toBottomOf="parent"
-        app:layout_constraintEnd_toEndOf="parent"
-        app:layout_constraintHorizontal_bias="0.5"
-        app:layout_constraintStart_toStartOf="parent"
-        app:pressedDrawable="@drawable/ic_controller_select_button_pressed"
-        app:unpressedDrawable="@drawable/ic_controller_select_button" />
-
-    <com.github.stenzek.duckstation.TouchscreenControllerButtonView
-        android:id="@+id/controller_button_cross"
-        android:layout_width="50dp"
-        android:layout_height="50dp"
-        android:layout_marginEnd="70dp"
-        android:layout_marginBottom="30dp"
-        app:layout_constraintBottom_toBottomOf="parent"
-        app:layout_constraintEnd_toEndOf="parent"
-        app:pressedDrawable="@drawable/ic_controller_cross_button_pressed"
-        app:unpressedDrawable="@drawable/ic_controller_cross_button" />
-
-    <com.github.stenzek.duckstation.TouchscreenControllerButtonView
-        android:id="@+id/controller_button_square"
-        android:layout_width="50dp"
-        android:layout_height="50dp"
-        android:layout_marginEnd="120dp"
-        android:layout_marginBottom="80dp"
-        app:layout_constraintBottom_toBottomOf="parent"
-        app:layout_constraintEnd_toEndOf="parent"
-        app:pressedDrawable="@drawable/ic_controller_square_button_pressed"
-        app:unpressedDrawable="@drawable/ic_controller_square_button" />
-
-    <com.github.stenzek.duckstation.TouchscreenControllerButtonView
-        android:id="@+id/controller_button_triangle"
-        android:layout_width="50dp"
-        android:layout_height="50dp"
-        android:layout_marginEnd="70dp"
-        android:layout_marginBottom="130dp"
-        app:layout_constraintBottom_toBottomOf="parent"
-        app:layout_constraintEnd_toEndOf="parent"
-        app:pressedDrawable="@drawable/ic_controller_triangle_button_pressed"
-        app:unpressedDrawable="@drawable/ic_controller_triangle_button" />
-
-    <com.github.stenzek.duckstation.TouchscreenControllerButtonView
-        android:id="@+id/controller_button_circle"
-        android:layout_width="50dp"
-        android:layout_height="50dp"
-        android:layout_marginEnd="20dp"
-        android:layout_marginBottom="80dp"
-        app:layout_constraintBottom_toBottomOf="parent"
-        app:layout_constraintEnd_toEndOf="parent"
-        app:pressedDrawable="@drawable/ic_controller_circle_button_pressed"
-        app:unpressedDrawable="@drawable/ic_controller_circle_button" />
-
-    <com.github.stenzek.duckstation.TouchscreenControllerAxisView
-        android:id="@+id/controller_axis_left"
-        android:layout_width="150dp"
-        android:layout_height="150dp"
-        android:layout_marginStart="20dp"
-        android:layout_marginBottom="30dp"
-        android:paddingTop="20dp"
-        android:paddingBottom="20dp"
-        android:paddingLeft="20dp"
-        android:paddingRight="20dp"
-        app:layout_constraintBottom_toBottomOf="parent"
-        app:layout_constraintStart_toStartOf="parent" />
-
-    <com.github.stenzek.duckstation.TouchscreenControllerButtonView
-        android:id="@+id/controller_button_fast_forward"
-        android:layout_width="35dp"
-        android:layout_height="35dp"
-        android:layout_marginBottom="50dp"
-        app:layout_constraintBottom_toBottomOf="parent"
-        app:layout_constraintEnd_toEndOf="parent"
-        app:layout_constraintHorizontal_bias="0.5"
-        app:layout_constraintStart_toStartOf="parent"
-        app:pressedDrawable="@drawable/ic_controller_fast_forward_pressed"
-        app:unpressedDrawable="@drawable/ic_controller_fast_forward" />
-
-    <com.github.stenzek.duckstation.TouchscreenControllerButtonView
-        android:id="@+id/controller_button_analog"
-        android:layout_width="35dp"
-        android:layout_height="35dp"
-        android:layout_marginBottom="95dp"
-        app:layout_constraintBottom_toBottomOf="parent"
-        app:layout_constraintEnd_toEndOf="parent"
-        app:layout_constraintHorizontal_bias="0.5"
-        app:layout_constraintStart_toStartOf="parent"
-        app:pressedDrawable="@drawable/ic_controller_analog_button_pressed"
-        app:unpressedDrawable="@drawable/ic_controller_analog_button" />
-
-    <com.github.stenzek.duckstation.TouchscreenControllerButtonView
-        android:id="@+id/controller_button_pause"
-        android:layout_width="35dp"
-        android:layout_height="35dp"
-        android:layout_marginTop="20dp"
-        android:layout_marginRight="20dp"
-        app:layout_constraintTop_toTopOf="parent"
-        app:layout_constraintEnd_toEndOf="parent"
-        app:pressedDrawable="@drawable/ic_controller_pause_button"
-        app:unpressedDrawable="@drawable/ic_controller_pause_button" />
-
-    <com.github.stenzek.duckstation.TouchscreenControllerButtonView
-        android:id="@+id/controller_button_quick_load"
-        android:layout_width="35dp"
-        android:layout_height="35dp"
-        android:layout_marginTop="20dp"
-        android:layout_marginLeft="20dp"
-        app:layout_constraintTop_toTopOf="parent"
-        app:layout_constraintStart_toStartOf="parent"
-        app:pressedDrawable="@drawable/ic_controller_quick_load_button"
-        app:unpressedDrawable="@drawable/ic_controller_quick_load_button" />
-
-    <com.github.stenzek.duckstation.TouchscreenControllerButtonView
-        android:id="@+id/controller_button_quick_save"
-        android:layout_width="35dp"
-        android:layout_height="35dp"
-        android:layout_marginTop="20dp"
-        android:layout_marginLeft="75dp"
-        app:layout_constraintTop_toTopOf="parent"
-        app:layout_constraintStart_toStartOf="parent"
-        app:pressedDrawable="@drawable/ic_controller_quick_save_button"
-        app:unpressedDrawable="@drawable/ic_controller_quick_save_button" />
-
-    <com.github.stenzek.duckstation.TouchscreenControllerButtonView
-        android:id="@+id/controller_button_autofire_1"
-        android:layout_width="35dp"
-        android:layout_height="35dp"
-        android:layout_marginEnd="60dp"
-        android:layout_marginBottom="220dp"
-        app:layout_constraintBottom_toBottomOf="parent"
-        app:layout_constraintEnd_toEndOf="parent"
-        app:layout_constraintHorizontal_bias="0.5"
-        app:layout_constraintStart_toStartOf="parent"
-        app:pressedDrawable="@drawable/ic_controller_t1_button_pressed"
-        app:unpressedDrawable="@drawable/ic_controller_t1_button" />
-
-    <com.github.stenzek.duckstation.TouchscreenControllerButtonView
-        android:id="@+id/controller_button_autofire_2"
-        android:layout_width="35dp"
-        android:layout_height="35dp"
-        android:layout_marginStart="60dp"
-        android:layout_marginBottom="220dp"
-        app:layout_constraintBottom_toBottomOf="parent"
-        app:layout_constraintEnd_toEndOf="parent"
-        app:layout_constraintHorizontal_bias="0.5"
-        app:layout_constraintStart_toStartOf="parent"
-        app:pressedDrawable="@drawable/ic_controller_t2_button_pressed"
-        app:unpressedDrawable="@drawable/ic_controller_t2_button" />
-
-    <com.github.stenzek.duckstation.TouchscreenControllerButtonView
-        android:id="@+id/controller_button_autofire_3"
-        android:layout_width="35dp"
-        android:layout_height="35dp"
-        android:layout_marginEnd="60dp"
-        android:layout_marginBottom="280dp"
-        app:layout_constraintBottom_toBottomOf="parent"
-        app:layout_constraintEnd_toEndOf="parent"
-        app:layout_constraintHorizontal_bias="0.5"
-        app:layout_constraintStart_toStartOf="parent"
-        app:pressedDrawable="@drawable/ic_controller_t3_button_pressed"
-        app:unpressedDrawable="@drawable/ic_controller_t3_button" />
-
-    <com.github.stenzek.duckstation.TouchscreenControllerButtonView
-        android:id="@+id/controller_button_autofire_4"
-        android:layout_width="35dp"
-        android:layout_height="35dp"
-        android:layout_marginStart="60dp"
-        android:layout_marginBottom="280dp"
-        app:layout_constraintBottom_toBottomOf="parent"
-        app:layout_constraintEnd_toEndOf="parent"
-        app:layout_constraintHorizontal_bias="0.5"
-        app:layout_constraintStart_toStartOf="parent"
-        app:pressedDrawable="@drawable/ic_controller_t4_button_pressed"
-        app:unpressedDrawable="@drawable/ic_controller_t4_button" />
-</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
diff --git a/android/app/src/main/res/layout/layout_touchscreen_controller_analog_sticks.xml b/android/app/src/main/res/layout/layout_touchscreen_controller_analog_sticks.xml
deleted file mode 100644
index 3af81d8bf..000000000
--- a/android/app/src/main/res/layout/layout_touchscreen_controller_analog_sticks.xml
+++ /dev/null
@@ -1,277 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:app="http://schemas.android.com/apk/res-auto"
-    xmlns:tools="http://schemas.android.com/tools"
-    android:id="@+id/constraintLayout"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:orientation="vertical"
-    android:clipChildren="false">
-
-    <View
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:translationZ="-10px"
-        app:layout_constraintBottom_toBottomOf="parent"
-        app:layout_constraintEnd_toEndOf="parent"
-        app:layout_constraintStart_toStartOf="parent"
-        app:layout_constraintTop_toTopOf="parent" />
-
-    <com.github.stenzek.duckstation.TouchscreenControllerButtonView
-        android:id="@+id/controller_button_r2"
-        android:layout_width="70dp"
-        android:layout_height="35dp"
-        android:layout_marginEnd="60dp"
-        android:layout_marginBottom="260dp"
-        app:layout_constraintBottom_toBottomOf="parent"
-        app:layout_constraintEnd_toEndOf="parent"
-        app:pressedDrawable="@drawable/ic_controller_r2_button_pressed"
-        app:unpressedDrawable="@drawable/ic_controller_r2_button" />
-
-    <com.github.stenzek.duckstation.TouchscreenControllerButtonView
-        android:id="@+id/controller_button_r1"
-        android:layout_width="70dp"
-        android:layout_height="35dp"
-        android:layout_marginEnd="60dp"
-        android:layout_marginBottom="200dp"
-        app:layout_constraintBottom_toBottomOf="parent"
-        app:layout_constraintEnd_toEndOf="parent"
-        app:pressedDrawable="@drawable/ic_controller_r1_button_pressed"
-        app:unpressedDrawable="@drawable/ic_controller_r1_button" />
-
-    <com.github.stenzek.duckstation.TouchscreenControllerButtonView
-        android:id="@+id/controller_button_l1"
-        android:layout_width="70dp"
-        android:layout_height="35dp"
-        android:layout_marginStart="60dp"
-        android:layout_marginBottom="200dp"
-        app:layout_constraintBottom_toBottomOf="parent"
-        app:layout_constraintStart_toStartOf="parent"
-        app:pressedDrawable="@drawable/ic_controller_l1_button_pressed"
-        app:unpressedDrawable="@drawable/ic_controller_l1_button" />
-
-    <com.github.stenzek.duckstation.TouchscreenControllerButtonView
-        android:id="@+id/controller_button_l2"
-        android:layout_width="70dp"
-        android:layout_height="35dp"
-        android:layout_marginStart="60dp"
-        android:layout_marginBottom="260dp"
-        app:layout_constraintBottom_toBottomOf="parent"
-        app:layout_constraintStart_toStartOf="parent"
-        app:pressedDrawable="@drawable/ic_controller_l2_button_pressed"
-        app:unpressedDrawable="@drawable/ic_controller_l2_button" />
-
-    <com.github.stenzek.duckstation.TouchscreenControllerButtonView
-        android:id="@+id/controller_button_start"
-        android:layout_width="40dp"
-        android:layout_height="25dp"
-        android:layout_marginStart="70dp"
-        android:layout_marginBottom="8dp"
-        app:layout_constraintBottom_toBottomOf="parent"
-        app:layout_constraintEnd_toEndOf="parent"
-        app:layout_constraintHorizontal_bias="0.5"
-        app:layout_constraintStart_toStartOf="parent"
-        app:pressedDrawable="@drawable/ic_controller_start_button_pressed"
-        app:unpressedDrawable="@drawable/ic_controller_start_button" />
-
-    <com.github.stenzek.duckstation.TouchscreenControllerButtonView
-        android:id="@+id/controller_button_select"
-        android:layout_width="40dp"
-        android:layout_height="25dp"
-        android:layout_marginEnd="70dp"
-        android:layout_marginBottom="8dp"
-        app:layout_constraintBottom_toBottomOf="parent"
-        app:layout_constraintEnd_toEndOf="parent"
-        app:layout_constraintHorizontal_bias="0.5"
-        app:layout_constraintStart_toStartOf="parent"
-        app:pressedDrawable="@drawable/ic_controller_select_button_pressed"
-        app:unpressedDrawable="@drawable/ic_controller_select_button" />
-
-    <com.github.stenzek.duckstation.TouchscreenControllerButtonView
-        android:id="@+id/controller_button_cross"
-        android:layout_width="50dp"
-        android:layout_height="50dp"
-        android:layout_marginEnd="70dp"
-        android:layout_marginBottom="30dp"
-        app:layout_constraintBottom_toBottomOf="parent"
-        app:layout_constraintEnd_toEndOf="parent"
-        app:pressedDrawable="@drawable/ic_controller_cross_button_pressed"
-        app:unpressedDrawable="@drawable/ic_controller_cross_button" />
-
-    <com.github.stenzek.duckstation.TouchscreenControllerButtonView
-        android:id="@+id/controller_button_square"
-        android:layout_width="50dp"
-        android:layout_height="50dp"
-        android:layout_marginEnd="120dp"
-        android:layout_marginBottom="80dp"
-        app:layout_constraintBottom_toBottomOf="parent"
-        app:layout_constraintEnd_toEndOf="parent"
-        app:pressedDrawable="@drawable/ic_controller_square_button_pressed"
-        app:unpressedDrawable="@drawable/ic_controller_square_button" />
-
-    <com.github.stenzek.duckstation.TouchscreenControllerButtonView
-        android:id="@+id/controller_button_triangle"
-        android:layout_width="50dp"
-        android:layout_height="50dp"
-        android:layout_marginEnd="70dp"
-        android:layout_marginBottom="130dp"
-        app:layout_constraintBottom_toBottomOf="parent"
-        app:layout_constraintEnd_toEndOf="parent"
-        app:pressedDrawable="@drawable/ic_controller_triangle_button_pressed"
-        app:unpressedDrawable="@drawable/ic_controller_triangle_button" />
-
-    <com.github.stenzek.duckstation.TouchscreenControllerButtonView
-        android:id="@+id/controller_button_circle"
-        android:layout_width="50dp"
-        android:layout_height="50dp"
-        android:layout_marginEnd="20dp"
-        android:layout_marginBottom="80dp"
-        app:layout_constraintBottom_toBottomOf="parent"
-        app:layout_constraintEnd_toEndOf="parent"
-        app:pressedDrawable="@drawable/ic_controller_circle_button_pressed"
-        app:unpressedDrawable="@drawable/ic_controller_circle_button" />
-
-    <com.github.stenzek.duckstation.TouchscreenControllerAxisView
-        android:id="@+id/controller_axis_left"
-        android:layout_width="150dp"
-        android:layout_height="150dp"
-        android:layout_marginStart="20dp"
-        android:layout_marginBottom="30dp"
-        android:paddingTop="20dp"
-        android:paddingBottom="20dp"
-        android:paddingLeft="20dp"
-        android:paddingRight="20dp"
-        app:layout_constraintBottom_toBottomOf="parent"
-        app:layout_constraintStart_toStartOf="parent" />
-
-    <com.github.stenzek.duckstation.TouchscreenControllerAxisView
-        android:id="@+id/controller_axis_right"
-        android:layout_width="150dp"
-        android:layout_height="150dp"
-        android:layout_marginEnd="20dp"
-        android:layout_marginBottom="300dp"
-        android:paddingLeft="20dp"
-        android:paddingTop="20dp"
-        android:paddingRight="20dp"
-        android:paddingBottom="20dp"
-        app:layout_constraintBottom_toBottomOf="parent"
-        app:layout_constraintEnd_toEndOf="parent" />
-
-    <com.github.stenzek.duckstation.TouchscreenControllerDPadView
-        android:id="@+id/controller_dpad"
-        android:layout_width="150dp"
-        android:layout_height="150dp"
-        android:layout_marginStart="20dp"
-        android:layout_marginBottom="300dp"
-        app:layout_constraintBottom_toBottomOf="parent"
-        app:layout_constraintStart_toStartOf="parent" />
-
-    <com.github.stenzek.duckstation.TouchscreenControllerButtonView
-        android:id="@+id/controller_button_fast_forward"
-        android:layout_width="35dp"
-        android:layout_height="35dp"
-        android:layout_marginBottom="50dp"
-        app:layout_constraintBottom_toBottomOf="parent"
-        app:layout_constraintEnd_toEndOf="parent"
-        app:layout_constraintHorizontal_bias="0.5"
-        app:layout_constraintStart_toStartOf="parent"
-        app:pressedDrawable="@drawable/ic_controller_fast_forward_pressed"
-        app:unpressedDrawable="@drawable/ic_controller_fast_forward" />
-
-    <com.github.stenzek.duckstation.TouchscreenControllerButtonView
-        android:id="@+id/controller_button_analog"
-        android:layout_width="35dp"
-        android:layout_height="35dp"
-        android:layout_marginBottom="95dp"
-        app:layout_constraintBottom_toBottomOf="parent"
-        app:layout_constraintEnd_toEndOf="parent"
-        app:layout_constraintHorizontal_bias="0.5"
-        app:layout_constraintStart_toStartOf="parent"
-        app:pressedDrawable="@drawable/ic_controller_analog_button_pressed"
-        app:unpressedDrawable="@drawable/ic_controller_analog_button" />
-
-    <com.github.stenzek.duckstation.TouchscreenControllerButtonView
-        android:id="@+id/controller_button_pause"
-        android:layout_width="35dp"
-        android:layout_height="35dp"
-        android:layout_marginTop="20dp"
-        android:layout_marginRight="20dp"
-        app:layout_constraintTop_toTopOf="parent"
-        app:layout_constraintEnd_toEndOf="parent"
-        app:pressedDrawable="@drawable/ic_controller_pause_button"
-        app:unpressedDrawable="@drawable/ic_controller_pause_button" />
-
-    <com.github.stenzek.duckstation.TouchscreenControllerButtonView
-        android:id="@+id/controller_button_quick_load"
-        android:layout_width="35dp"
-        android:layout_height="35dp"
-        android:layout_marginTop="20dp"
-        android:layout_marginLeft="20dp"
-        app:layout_constraintTop_toTopOf="parent"
-        app:layout_constraintStart_toStartOf="parent"
-        app:pressedDrawable="@drawable/ic_controller_quick_load_button"
-        app:unpressedDrawable="@drawable/ic_controller_quick_load_button" />
-
-    <com.github.stenzek.duckstation.TouchscreenControllerButtonView
-        android:id="@+id/controller_button_quick_save"
-        android:layout_width="35dp"
-        android:layout_height="35dp"
-        android:layout_marginTop="20dp"
-        android:layout_marginLeft="75dp"
-        app:layout_constraintTop_toTopOf="parent"
-        app:layout_constraintStart_toStartOf="parent"
-        app:pressedDrawable="@drawable/ic_controller_quick_save_button"
-        app:unpressedDrawable="@drawable/ic_controller_quick_save_button" />
-
-    <com.github.stenzek.duckstation.TouchscreenControllerButtonView
-        android:id="@+id/controller_button_autofire_1"
-        android:layout_width="35dp"
-        android:layout_height="35dp"
-        android:layout_marginEnd="60dp"
-        android:layout_marginBottom="220dp"
-        app:layout_constraintBottom_toBottomOf="parent"
-        app:layout_constraintEnd_toEndOf="parent"
-        app:layout_constraintHorizontal_bias="0.5"
-        app:layout_constraintStart_toStartOf="parent"
-        app:pressedDrawable="@drawable/ic_controller_t1_button_pressed"
-        app:unpressedDrawable="@drawable/ic_controller_t1_button" />
-
-    <com.github.stenzek.duckstation.TouchscreenControllerButtonView
-        android:id="@+id/controller_button_autofire_2"
-        android:layout_width="35dp"
-        android:layout_height="35dp"
-        android:layout_marginStart="60dp"
-        android:layout_marginBottom="220dp"
-        app:layout_constraintBottom_toBottomOf="parent"
-        app:layout_constraintEnd_toEndOf="parent"
-        app:layout_constraintHorizontal_bias="0.5"
-        app:layout_constraintStart_toStartOf="parent"
-        app:pressedDrawable="@drawable/ic_controller_t2_button_pressed"
-        app:unpressedDrawable="@drawable/ic_controller_t2_button" />
-
-    <com.github.stenzek.duckstation.TouchscreenControllerButtonView
-        android:id="@+id/controller_button_autofire_3"
-        android:layout_width="35dp"
-        android:layout_height="35dp"
-        android:layout_marginEnd="60dp"
-        android:layout_marginBottom="280dp"
-        app:layout_constraintBottom_toBottomOf="parent"
-        app:layout_constraintEnd_toEndOf="parent"
-        app:layout_constraintHorizontal_bias="0.5"
-        app:layout_constraintStart_toStartOf="parent"
-        app:pressedDrawable="@drawable/ic_controller_t3_button_pressed"
-        app:unpressedDrawable="@drawable/ic_controller_t3_button" />
-
-    <com.github.stenzek.duckstation.TouchscreenControllerButtonView
-        android:id="@+id/controller_button_autofire_4"
-        android:layout_width="35dp"
-        android:layout_height="35dp"
-        android:layout_marginStart="60dp"
-        android:layout_marginBottom="280dp"
-        app:layout_constraintBottom_toBottomOf="parent"
-        app:layout_constraintEnd_toEndOf="parent"
-        app:layout_constraintHorizontal_bias="0.5"
-        app:layout_constraintStart_toStartOf="parent"
-        app:pressedDrawable="@drawable/ic_controller_t4_button_pressed"
-        app:unpressedDrawable="@drawable/ic_controller_t4_button" />
-</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
diff --git a/android/app/src/main/res/layout/layout_touchscreen_controller_digital.xml b/android/app/src/main/res/layout/layout_touchscreen_controller_digital.xml
deleted file mode 100644
index 163a07b4f..000000000
--- a/android/app/src/main/res/layout/layout_touchscreen_controller_digital.xml
+++ /dev/null
@@ -1,239 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:app="http://schemas.android.com/apk/res-auto"
-    xmlns:tools="http://schemas.android.com/tools"
-    android:id="@+id/constraintLayout"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:orientation="vertical"
-    android:clipChildren="false">
-
-    <View
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:translationZ="-10px"
-        app:layout_constraintBottom_toBottomOf="parent"
-        app:layout_constraintEnd_toEndOf="parent"
-        app:layout_constraintStart_toStartOf="parent"
-        app:layout_constraintTop_toTopOf="parent" />
-
-    <com.github.stenzek.duckstation.TouchscreenControllerButtonView
-        android:id="@+id/controller_button_r2"
-        android:layout_width="70dp"
-        android:layout_height="35dp"
-        android:layout_marginEnd="60dp"
-        android:layout_marginBottom="280dp"
-        app:layout_constraintBottom_toBottomOf="parent"
-        app:layout_constraintEnd_toEndOf="parent"
-        app:pressedDrawable="@drawable/ic_controller_r2_button_pressed"
-        app:unpressedDrawable="@drawable/ic_controller_r2_button" />
-
-    <com.github.stenzek.duckstation.TouchscreenControllerButtonView
-        android:id="@+id/controller_button_r1"
-        android:layout_width="70dp"
-        android:layout_height="35dp"
-        android:layout_marginEnd="60dp"
-        android:layout_marginBottom="220dp"
-        app:layout_constraintBottom_toBottomOf="parent"
-        app:layout_constraintEnd_toEndOf="parent"
-        app:pressedDrawable="@drawable/ic_controller_r1_button_pressed"
-        app:unpressedDrawable="@drawable/ic_controller_r1_button" />
-
-    <com.github.stenzek.duckstation.TouchscreenControllerDPadView
-        android:id="@+id/controller_dpad"
-        android:layout_width="150dp"
-        android:layout_height="150dp"
-        android:layout_marginStart="20dp"
-        android:layout_marginBottom="30dp"
-        app:layout_constraintBottom_toBottomOf="parent"
-        app:layout_constraintStart_toStartOf="parent" />
-
-    <com.github.stenzek.duckstation.TouchscreenControllerButtonView
-        android:id="@+id/controller_button_l1"
-        android:layout_width="70dp"
-        android:layout_height="35dp"
-        android:layout_marginStart="60dp"
-        android:layout_marginBottom="220dp"
-        app:layout_constraintBottom_toBottomOf="parent"
-        app:layout_constraintStart_toStartOf="parent"
-        app:pressedDrawable="@drawable/ic_controller_l1_button_pressed"
-        app:unpressedDrawable="@drawable/ic_controller_l1_button" />
-
-    <com.github.stenzek.duckstation.TouchscreenControllerButtonView
-        android:id="@+id/controller_button_l2"
-        android:layout_width="70dp"
-        android:layout_height="35dp"
-        android:layout_marginStart="60dp"
-        android:layout_marginBottom="280dp"
-        app:layout_constraintBottom_toBottomOf="parent"
-        app:layout_constraintStart_toStartOf="parent"
-        app:pressedDrawable="@drawable/ic_controller_l2_button_pressed"
-        app:unpressedDrawable="@drawable/ic_controller_l2_button" />
-
-    <com.github.stenzek.duckstation.TouchscreenControllerButtonView
-        android:id="@+id/controller_button_start"
-        android:layout_width="40dp"
-        android:layout_height="25dp"
-        android:layout_marginStart="70dp"
-        android:layout_marginBottom="8dp"
-        app:layout_constraintBottom_toBottomOf="parent"
-        app:layout_constraintEnd_toEndOf="parent"
-        app:layout_constraintHorizontal_bias="0.5"
-        app:layout_constraintStart_toStartOf="parent"
-        app:pressedDrawable="@drawable/ic_controller_start_button_pressed"
-        app:unpressedDrawable="@drawable/ic_controller_start_button" />
-
-    <com.github.stenzek.duckstation.TouchscreenControllerButtonView
-        android:id="@+id/controller_button_select"
-        android:layout_width="40dp"
-        android:layout_height="25dp"
-        android:layout_marginEnd="70dp"
-        android:layout_marginBottom="8dp"
-        app:layout_constraintBottom_toBottomOf="parent"
-        app:layout_constraintEnd_toEndOf="parent"
-        app:layout_constraintHorizontal_bias="0.5"
-        app:layout_constraintStart_toStartOf="parent"
-        app:pressedDrawable="@drawable/ic_controller_select_button_pressed"
-        app:unpressedDrawable="@drawable/ic_controller_select_button" />
-
-    <com.github.stenzek.duckstation.TouchscreenControllerButtonView
-        android:id="@+id/controller_button_cross"
-        android:layout_width="50dp"
-        android:layout_height="50dp"
-        android:layout_marginEnd="70dp"
-        android:layout_marginBottom="30dp"
-        app:layout_constraintBottom_toBottomOf="parent"
-        app:layout_constraintEnd_toEndOf="parent"
-        app:pressedDrawable="@drawable/ic_controller_cross_button_pressed"
-        app:unpressedDrawable="@drawable/ic_controller_cross_button" />
-
-    <com.github.stenzek.duckstation.TouchscreenControllerButtonView
-        android:id="@+id/controller_button_square"
-        android:layout_width="50dp"
-        android:layout_height="50dp"
-        android:layout_marginEnd="120dp"
-        android:layout_marginBottom="80dp"
-        app:layout_constraintBottom_toBottomOf="parent"
-        app:layout_constraintEnd_toEndOf="parent"
-        app:pressedDrawable="@drawable/ic_controller_square_button_pressed"
-        app:unpressedDrawable="@drawable/ic_controller_square_button" />
-
-    <com.github.stenzek.duckstation.TouchscreenControllerButtonView
-        android:id="@+id/controller_button_triangle"
-        android:layout_width="50dp"
-        android:layout_height="50dp"
-        android:layout_marginEnd="70dp"
-        android:layout_marginBottom="130dp"
-        app:layout_constraintBottom_toBottomOf="parent"
-        app:layout_constraintEnd_toEndOf="parent"
-        app:pressedDrawable="@drawable/ic_controller_triangle_button_pressed"
-        app:unpressedDrawable="@drawable/ic_controller_triangle_button" />
-
-    <com.github.stenzek.duckstation.TouchscreenControllerButtonView
-        android:id="@+id/controller_button_circle"
-        android:layout_width="50dp"
-        android:layout_height="50dp"
-        android:layout_marginEnd="20dp"
-        android:layout_marginBottom="80dp"
-        app:layout_constraintBottom_toBottomOf="parent"
-        app:layout_constraintEnd_toEndOf="parent"
-        app:pressedDrawable="@drawable/ic_controller_circle_button_pressed"
-        app:unpressedDrawable="@drawable/ic_controller_circle_button" />
-
-    <com.github.stenzek.duckstation.TouchscreenControllerButtonView
-        android:id="@+id/controller_button_fast_forward"
-        android:layout_width="35dp"
-        android:layout_height="35dp"
-        android:layout_marginBottom="50dp"
-        app:layout_constraintBottom_toBottomOf="parent"
-        app:layout_constraintEnd_toEndOf="parent"
-        app:layout_constraintHorizontal_bias="0.5"
-        app:layout_constraintStart_toStartOf="parent"
-        app:pressedDrawable="@drawable/ic_controller_fast_forward_pressed"
-        app:unpressedDrawable="@drawable/ic_controller_fast_forward" />
-
-    <com.github.stenzek.duckstation.TouchscreenControllerButtonView
-        android:id="@+id/controller_button_pause"
-        android:layout_width="35dp"
-        android:layout_height="35dp"
-        android:layout_marginTop="20dp"
-        android:layout_marginRight="20dp"
-        app:layout_constraintTop_toTopOf="parent"
-        app:layout_constraintEnd_toEndOf="parent"
-        app:pressedDrawable="@drawable/ic_controller_pause_button"
-        app:unpressedDrawable="@drawable/ic_controller_pause_button" />
-
-    <com.github.stenzek.duckstation.TouchscreenControllerButtonView
-        android:id="@+id/controller_button_quick_load"
-        android:layout_width="35dp"
-        android:layout_height="35dp"
-        android:layout_marginTop="20dp"
-        android:layout_marginLeft="20dp"
-        app:layout_constraintTop_toTopOf="parent"
-        app:layout_constraintStart_toStartOf="parent"
-        app:pressedDrawable="@drawable/ic_controller_quick_load_button"
-        app:unpressedDrawable="@drawable/ic_controller_quick_load_button" />
-
-    <com.github.stenzek.duckstation.TouchscreenControllerButtonView
-        android:id="@+id/controller_button_quick_save"
-        android:layout_width="35dp"
-        android:layout_height="35dp"
-        android:layout_marginTop="20dp"
-        android:layout_marginLeft="75dp"
-        app:layout_constraintTop_toTopOf="parent"
-        app:layout_constraintStart_toStartOf="parent"
-        app:pressedDrawable="@drawable/ic_controller_quick_save_button"
-        app:unpressedDrawable="@drawable/ic_controller_quick_save_button" />
-
-    <com.github.stenzek.duckstation.TouchscreenControllerButtonView
-        android:id="@+id/controller_button_autofire_1"
-        android:layout_width="35dp"
-        android:layout_height="35dp"
-        android:layout_marginEnd="60dp"
-        android:layout_marginBottom="220dp"
-        app:layout_constraintBottom_toBottomOf="parent"
-        app:layout_constraintEnd_toEndOf="parent"
-        app:layout_constraintHorizontal_bias="0.5"
-        app:layout_constraintStart_toStartOf="parent"
-        app:pressedDrawable="@drawable/ic_controller_t1_button_pressed"
-        app:unpressedDrawable="@drawable/ic_controller_t1_button" />
-
-    <com.github.stenzek.duckstation.TouchscreenControllerButtonView
-        android:id="@+id/controller_button_autofire_2"
-        android:layout_width="35dp"
-        android:layout_height="35dp"
-        android:layout_marginStart="60dp"
-        android:layout_marginBottom="220dp"
-        app:layout_constraintBottom_toBottomOf="parent"
-        app:layout_constraintEnd_toEndOf="parent"
-        app:layout_constraintHorizontal_bias="0.5"
-        app:layout_constraintStart_toStartOf="parent"
-        app:pressedDrawable="@drawable/ic_controller_t2_button_pressed"
-        app:unpressedDrawable="@drawable/ic_controller_t2_button" />
-
-    <com.github.stenzek.duckstation.TouchscreenControllerButtonView
-        android:id="@+id/controller_button_autofire_3"
-        android:layout_width="35dp"
-        android:layout_height="35dp"
-        android:layout_marginEnd="60dp"
-        android:layout_marginBottom="280dp"
-        app:layout_constraintBottom_toBottomOf="parent"
-        app:layout_constraintEnd_toEndOf="parent"
-        app:layout_constraintHorizontal_bias="0.5"
-        app:layout_constraintStart_toStartOf="parent"
-        app:pressedDrawable="@drawable/ic_controller_t3_button_pressed"
-        app:unpressedDrawable="@drawable/ic_controller_t3_button" />
-
-    <com.github.stenzek.duckstation.TouchscreenControllerButtonView
-        android:id="@+id/controller_button_autofire_4"
-        android:layout_width="35dp"
-        android:layout_height="35dp"
-        android:layout_marginStart="60dp"
-        android:layout_marginBottom="280dp"
-        app:layout_constraintBottom_toBottomOf="parent"
-        app:layout_constraintEnd_toEndOf="parent"
-        app:layout_constraintHorizontal_bias="0.5"
-        app:layout_constraintStart_toStartOf="parent"
-        app:pressedDrawable="@drawable/ic_controller_t4_button_pressed"
-        app:unpressedDrawable="@drawable/ic_controller_t4_button" />
-</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
diff --git a/android/app/src/main/res/layout/layout_touchscreen_controller_edit.xml b/android/app/src/main/res/layout/layout_touchscreen_controller_edit.xml
deleted file mode 100644
index 0dea1ecd9..000000000
--- a/android/app/src/main/res/layout/layout_touchscreen_controller_edit.xml
+++ /dev/null
@@ -1,18 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:app="http://schemas.android.com/apk/res-auto"
-    xmlns:tools="http://schemas.android.com/tools"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent">
-
-    <Button
-        android:id="@+id/options"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_marginTop="16dp"
-        android:text="@string/touchscreen_controller_edit_menu"
-        app:layout_constraintEnd_toEndOf="parent"
-        app:layout_constraintHorizontal_bias="0.5"
-        app:layout_constraintStart_toStartOf="parent"
-        app:layout_constraintTop_toTopOf="parent" />
-</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
diff --git a/android/app/src/main/res/layout/layout_touchscreen_controller_lightgun.xml b/android/app/src/main/res/layout/layout_touchscreen_controller_lightgun.xml
deleted file mode 100644
index bd83243d8..000000000
--- a/android/app/src/main/res/layout/layout_touchscreen_controller_lightgun.xml
+++ /dev/null
@@ -1,138 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:app="http://schemas.android.com/apk/res-auto"
-    xmlns:tools="http://schemas.android.com/tools"
-    android:id="@+id/constraintLayout"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:orientation="vertical"
-    android:clipChildren="false">
-
-    <View
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:translationZ="-10px"
-        app:layout_constraintBottom_toBottomOf="parent"
-        app:layout_constraintEnd_toEndOf="parent"
-        app:layout_constraintStart_toStartOf="parent"
-        app:layout_constraintTop_toTopOf="parent" />
-
-    <com.github.stenzek.duckstation.TouchscreenControllerButtonView
-        android:id="@+id/controller_button_a"
-        android:layout_width="50dp"
-        android:layout_height="50dp"
-        android:layout_marginEnd="30dp"
-        android:layout_marginBottom="30dp"
-        app:layout_constraintBottom_toBottomOf="parent"
-        app:layout_constraintEnd_toEndOf="parent"
-        app:pressedDrawable="@drawable/ic_controller_a_button_pressed"
-        app:unpressedDrawable="@drawable/ic_controller_a_button" />
-
-    <com.github.stenzek.duckstation.TouchscreenControllerButtonView
-        android:id="@+id/controller_button_b"
-        android:layout_width="50dp"
-        android:layout_height="50dp"
-        android:layout_marginEnd="80dp"
-        android:layout_marginBottom="80dp"
-        app:layout_constraintBottom_toBottomOf="parent"
-        app:layout_constraintEnd_toEndOf="parent"
-        app:pressedDrawable="@drawable/ic_controller_b_button_pressed"
-        app:unpressedDrawable="@drawable/ic_controller_b_button" />
-
-    <com.github.stenzek.duckstation.TouchscreenControllerButtonView
-        android:id="@+id/controller_button_fast_forward"
-        android:layout_width="35dp"
-        android:layout_height="35dp"
-        android:layout_marginBottom="50dp"
-        app:layout_constraintBottom_toBottomOf="parent"
-        app:layout_constraintEnd_toEndOf="parent"
-        app:layout_constraintHorizontal_bias="0.5"
-        app:layout_constraintStart_toStartOf="parent"
-        app:pressedDrawable="@drawable/ic_controller_fast_forward_pressed"
-        app:unpressedDrawable="@drawable/ic_controller_fast_forward" />
-
-    <com.github.stenzek.duckstation.TouchscreenControllerButtonView
-        android:id="@+id/controller_button_pause"
-        android:layout_width="35dp"
-        android:layout_height="35dp"
-        android:layout_marginTop="20dp"
-        android:layout_marginRight="20dp"
-        app:layout_constraintTop_toTopOf="parent"
-        app:layout_constraintEnd_toEndOf="parent"
-        app:pressedDrawable="@drawable/ic_controller_pause_button"
-        app:unpressedDrawable="@drawable/ic_controller_pause_button" />
-
-    <com.github.stenzek.duckstation.TouchscreenControllerButtonView
-        android:id="@+id/controller_button_quick_load"
-        android:layout_width="35dp"
-        android:layout_height="35dp"
-        android:layout_marginTop="20dp"
-        android:layout_marginLeft="20dp"
-        app:layout_constraintTop_toTopOf="parent"
-        app:layout_constraintStart_toStartOf="parent"
-        app:pressedDrawable="@drawable/ic_controller_quick_load_button"
-        app:unpressedDrawable="@drawable/ic_controller_quick_load_button" />
-
-    <com.github.stenzek.duckstation.TouchscreenControllerButtonView
-        android:id="@+id/controller_button_quick_save"
-        android:layout_width="35dp"
-        android:layout_height="35dp"
-        android:layout_marginTop="20dp"
-        android:layout_marginLeft="75dp"
-        app:layout_constraintTop_toTopOf="parent"
-        app:layout_constraintStart_toStartOf="parent"
-        app:pressedDrawable="@drawable/ic_controller_quick_save_button"
-        app:unpressedDrawable="@drawable/ic_controller_quick_save_button" />
-
-    <com.github.stenzek.duckstation.TouchscreenControllerButtonView
-        android:id="@+id/controller_button_autofire_1"
-        android:layout_width="35dp"
-        android:layout_height="35dp"
-        android:layout_marginEnd="60dp"
-        android:layout_marginBottom="220dp"
-        app:layout_constraintBottom_toBottomOf="parent"
-        app:layout_constraintEnd_toEndOf="parent"
-        app:layout_constraintHorizontal_bias="0.5"
-        app:layout_constraintStart_toStartOf="parent"
-        app:pressedDrawable="@drawable/ic_controller_t1_button_pressed"
-        app:unpressedDrawable="@drawable/ic_controller_t1_button" />
-
-    <com.github.stenzek.duckstation.TouchscreenControllerButtonView
-        android:id="@+id/controller_button_autofire_2"
-        android:layout_width="35dp"
-        android:layout_height="35dp"
-        android:layout_marginStart="60dp"
-        android:layout_marginBottom="220dp"
-        app:layout_constraintBottom_toBottomOf="parent"
-        app:layout_constraintEnd_toEndOf="parent"
-        app:layout_constraintHorizontal_bias="0.5"
-        app:layout_constraintStart_toStartOf="parent"
-        app:pressedDrawable="@drawable/ic_controller_t2_button_pressed"
-        app:unpressedDrawable="@drawable/ic_controller_t2_button" />
-
-    <com.github.stenzek.duckstation.TouchscreenControllerButtonView
-        android:id="@+id/controller_button_autofire_3"
-        android:layout_width="35dp"
-        android:layout_height="35dp"
-        android:layout_marginEnd="60dp"
-        android:layout_marginBottom="280dp"
-        app:layout_constraintBottom_toBottomOf="parent"
-        app:layout_constraintEnd_toEndOf="parent"
-        app:layout_constraintHorizontal_bias="0.5"
-        app:layout_constraintStart_toStartOf="parent"
-        app:pressedDrawable="@drawable/ic_controller_t3_button_pressed"
-        app:unpressedDrawable="@drawable/ic_controller_t3_button" />
-
-    <com.github.stenzek.duckstation.TouchscreenControllerButtonView
-        android:id="@+id/controller_button_autofire_4"
-        android:layout_width="35dp"
-        android:layout_height="35dp"
-        android:layout_marginStart="60dp"
-        android:layout_marginBottom="280dp"
-        app:layout_constraintBottom_toBottomOf="parent"
-        app:layout_constraintEnd_toEndOf="parent"
-        app:layout_constraintHorizontal_bias="0.5"
-        app:layout_constraintStart_toStartOf="parent"
-        app:pressedDrawable="@drawable/ic_controller_t4_button_pressed"
-        app:unpressedDrawable="@drawable/ic_controller_t4_button" />
-</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
diff --git a/android/app/src/main/res/layout/save_state_view_entry.xml b/android/app/src/main/res/layout/save_state_view_entry.xml
deleted file mode 100644
index eaaff4f7a..000000000
--- a/android/app/src/main/res/layout/save_state_view_entry.xml
+++ /dev/null
@@ -1,66 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:app="http://schemas.android.com/apk/res-auto"
-    xmlns:tools="http://schemas.android.com/tools"
-    android:id="@+id/linearLayout"
-    android:layout_width="match_parent"
-    android:layout_height="wrap_content"
-    android:orientation="vertical">
-
-    <ImageView
-        android:id="@+id/image"
-        android:layout_width="80dp"
-        android:layout_height="60dp"
-        android:layout_marginTop="20dp"
-        android:layout_marginBottom="4dp"
-        android:layout_marginLeft="15dp"
-        android:layout_alignParentTop="true"
-        android:scaleType="fitXY"
-        tools:srcCompat="@drawable/ic_media_cdrom" />
-
-    <TextView
-        android:id="@+id/summary"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:layout_marginStart="15dp"
-        android:layout_marginTop="8dp"
-        android:text="Game Slot 1"
-        android:textAppearance="@style/TextAppearance.AppCompat.Medium"
-        android:layout_alignParentTop="true"
-        android:layout_toRightOf="@id/image" />
-
-    <TextView
-        android:id="@+id/game"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:layout_marginStart="15dp"
-        android:layout_marginTop="0dp"
-        android:text="SCES-0000 - Game Name"
-        android:textAppearance="@style/TextAppearance.AppCompat.Small"
-        android:layout_below="@id/summary"
-        android:layout_toRightOf="@id/image" />
-
-    <TextView
-        android:id="@+id/path"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:layout_marginStart="15dp"
-        android:layout_marginTop="0dp"
-        android:text="Dump Name.chd"
-        android:textAppearance="@style/TextAppearance.AppCompat.Small"
-        android:layout_below="@id/game"
-        android:layout_toRightOf="@id/image" />
-
-    <TextView
-        android:id="@+id/timestamp"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:layout_marginStart="15dp"
-        android:layout_marginTop="0dp"
-        android:layout_marginBottom="14dp"
-        android:text="Saved at Timestamp"
-        android:textAppearance="@style/TextAppearance.AppCompat.Small"
-        android:layout_below="@id/path"
-        android:layout_toRightOf="@id/image" />
-
-</RelativeLayout>
\ No newline at end of file
diff --git a/android/app/src/main/res/layout/settings_activity.xml b/android/app/src/main/res/layout/settings_activity.xml
deleted file mode 100644
index de6591a20..000000000
--- a/android/app/src/main/res/layout/settings_activity.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent">
-
-    <FrameLayout
-        android:id="@+id/settings"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent" />
-</LinearLayout>
\ No newline at end of file
diff --git a/android/app/src/main/res/menu/menu_controller_mapping.xml b/android/app/src/main/res/menu/menu_controller_mapping.xml
deleted file mode 100644
index 2521ee5e1..000000000
--- a/android/app/src/main/res/menu/menu_controller_mapping.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<menu xmlns:app="http://schemas.android.com/apk/res-auto"
-    xmlns:android="http://schemas.android.com/apk/res/android">
-
-    <item
-        android:id="@+id/action_load_profile"
-        android:title="Load Profile"
-        android:icon="@drawable/ic_baseline_folder_open_24"
-        app:showAsAction="ifRoom" />
-
-    <item
-        android:id="@+id/action_save_profile"
-        android:title="Save Profile"
-        android:icon="@drawable/ic_baseline_save_24"
-        app:showAsAction="ifRoom" />
-
-    <item
-        android:id="@+id/action_clear_bindings"
-        android:title="Clear Bindings" />
-</menu>
\ No newline at end of file
diff --git a/android/app/src/main/res/menu/menu_edit_game_directories.xml b/android/app/src/main/res/menu/menu_edit_game_directories.xml
deleted file mode 100644
index 06192fbb8..000000000
--- a/android/app/src/main/res/menu/menu_edit_game_directories.xml
+++ /dev/null
@@ -1,15 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<menu xmlns:app="http://schemas.android.com/apk/res-auto"
-    xmlns:android="http://schemas.android.com/apk/res/android">
-
-    <item
-        android:id="@+id/add_directory"
-        android:title="@string/menu_edit_game_directories_add_directory" />
-    <item
-        android:id="@+id/add_path"
-        android:title="@string/menu_edit_game_directories_add_path" />
-    <item
-        android:id="@+id/force_saf"
-        android:checkable="true"
-        android:title="@string/menu_edit_game_directories_force_saf" />
-</menu>
\ No newline at end of file
diff --git a/android/app/src/main/res/menu/menu_game_list_entry.xml b/android/app/src/main/res/menu/menu_game_list_entry.xml
deleted file mode 100644
index e1ce8dab3..000000000
--- a/android/app/src/main/res/menu/menu_game_list_entry.xml
+++ /dev/null
@@ -1,16 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<menu xmlns:app="http://schemas.android.com/apk/res-auto"
-    xmlns:android="http://schemas.android.com/apk/res/android">
-    <item
-        android:id="@+id/game_list_entry_menu_start_game"
-        android:title="@string/menu_game_list_entry_start_game" />
-    <item
-        android:id="@+id/game_list_entry_menu_resume_game"
-        android:title="@string/menu_game_list_entry_resume_game" />
-    <item
-        android:id="@+id/game_list_entry_menu_properties"
-        android:title="@string/menu_game_list_entry_game_properties" />
-    <item
-        android:id="@+id/game_list_entry_menu_choose_cover_image"
-        android:title="@string/menu_game_list_entry_choose_cover_image" />
-</menu>
\ No newline at end of file
diff --git a/android/app/src/main/res/menu/menu_main.xml b/android/app/src/main/res/menu/menu_main.xml
deleted file mode 100644
index 3b82f7748..000000000
--- a/android/app/src/main/res/menu/menu_main.xml
+++ /dev/null
@@ -1,67 +0,0 @@
-<menu xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:app="http://schemas.android.com/apk/res-auto"
-    xmlns:tools="http://schemas.android.com/tools"
-    tools:context="com.github.stenzek.duckstation.MainActivity">
-    <group android:id="@+id/start_menu">
-        <item
-            android:id="@+id/action_start_file"
-            android:title="@string/menu_main_start_file" />
-        <item
-            android:id="@+id/action_start_bios"
-            android:title="@string/menu_main_start_bios" />
-    </group>
-    <group android:id="@+id/settings">
-        <item
-            android:id="@+id/action_settings"
-            android:icon="@drawable/ic_baseline_settings_24"
-            android:orderInCategory="103"
-            android:title="@string/action_settings"
-            app:showAsAction="always" />
-        <item
-            android:id="@+id/action_switch_view"
-            android:icon="@drawable/ic_baseline_settings_24"
-            android:orderInCategory="99"
-            android:title="@string/action_switch_view"
-            app:showAsAction="always" />
-        <item
-            android:id="@+id/action_controller_settings"
-            android:icon="@drawable/ic_baseline_gamepad_24"
-            android:orderInCategory="102"
-            android:title="@string/action_controller_mapping"
-            app:showAsAction="always" />
-        <item
-            android:id="@+id/action_memory_card_editor"
-            android:icon="@drawable/ic_baseline_sd_card_24"
-            android:orderInCategory="100"
-            android:title="@string/action_memory_card_editor"
-            app:showAsAction="always" />
-        <item
-            android:id="@+id/action_edit_game_directories"
-            android:icon="@drawable/ic_baseline_folder_open_24"
-            android:title="@string/menu_main_edit_game_directories"
-            android:orderInCategory="101"
-            app:showAsAction="always"/>
-        <item
-            android:id="@+id/action_import_bios"
-            android:title="@string/menu_main_import_bios" />
-    </group>
-    <group android:id="@+id/game_list">
-        <item
-            android:id="@+id/action_scan_for_new_games"
-            android:title="@string/menu_main_scan_for_new_games" />
-        <item
-            android:id="@+id/action_rescan_all_games"
-            android:title="@string/menu_main_rescan_all_games" />
-    </group>
-    <group android:id="@+id/support">
-        <item
-            android:id="@+id/action_show_version"
-            android:title="@string/menu_main_show_version" />
-        <item
-            android:id="@+id/action_github_respository"
-            android:title="@string/menu_main_github_repository" />
-        <item
-            android:id="@+id/action_discord_server"
-            android:title="@string/menu_main_discord_server" />
-    </group>
-</menu>
diff --git a/android/app/src/main/res/menu/menu_memory_card_editor.xml b/android/app/src/main/res/menu/menu_memory_card_editor.xml
deleted file mode 100644
index 9411e9cde..000000000
--- a/android/app/src/main/res/menu/menu_memory_card_editor.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<menu xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto">
-    <item
-        android:id="@+id/action_new_card"
-        android:title="@string/action_memory_card_editor_new_card"
-        android:enabled="false"
-        android:icon="@drawable/ic_baseline_create_new_folder_24" />
-    <item
-        android:id="@+id/action_import_card"
-        android:title="@string/action_memory_card_editor_import_card"
-        android:icon="@drawable/ic_baseline_import_contacts_24"
-        app:showAsAction="ifRoom" />
-    <item
-        android:id="@+id/action_format_card"
-        android:title="@string/action_memory_card_editor_format_card"
-        android:enabled="false"
-        android:icon="@drawable/ic_baseline_delete_sweep_24" />
-    <item
-        android:id="@+id/action_delete_card"
-        android:title="@string/action_memory_card_editor_delete_card"
-        android:icon="@drawable/ic_baseline_delete_24"
-        app:showAsAction="ifRoom"
-    />
-</menu>
\ No newline at end of file
diff --git a/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
deleted file mode 100644
index c9ad5f98f..000000000
--- a/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
-    <background android:drawable="@color/ic_launcher_background" />
-    <foreground android:drawable="@mipmap/ic_launcher_foreground" />
-</adaptive-icon>
\ No newline at end of file
diff --git a/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
deleted file mode 100644
index c9ad5f98f..000000000
--- a/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
-    <background android:drawable="@color/ic_launcher_background" />
-    <foreground android:drawable="@mipmap/ic_launcher_foreground" />
-</adaptive-icon>
\ No newline at end of file
diff --git a/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
deleted file mode 100644
index d64d76803..000000000
Binary files a/android/app/src/main/res/mipmap-hdpi/ic_launcher.png and /dev/null differ
diff --git a/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png b/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png
deleted file mode 100644
index 9b6b70411..000000000
Binary files a/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png and /dev/null differ
diff --git a/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png b/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
deleted file mode 100644
index 7d7817be6..000000000
Binary files a/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png and /dev/null differ
diff --git a/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
deleted file mode 100644
index d5aa43caa..000000000
Binary files a/android/app/src/main/res/mipmap-mdpi/ic_launcher.png and /dev/null differ
diff --git a/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png b/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png
deleted file mode 100644
index 3b3c14850..000000000
Binary files a/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png and /dev/null differ
diff --git a/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png b/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
deleted file mode 100644
index 2dc2434af..000000000
Binary files a/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png and /dev/null differ
diff --git a/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
deleted file mode 100644
index b260a7956..000000000
Binary files a/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png and /dev/null differ
diff --git a/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png b/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png
deleted file mode 100644
index e31c4c180..000000000
Binary files a/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png and /dev/null differ
diff --git a/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
deleted file mode 100644
index 37c92a904..000000000
Binary files a/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png and /dev/null differ
diff --git a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
deleted file mode 100644
index 633789a6c..000000000
Binary files a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png and /dev/null differ
diff --git a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png
deleted file mode 100644
index 9e64e9588..000000000
Binary files a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png and /dev/null differ
diff --git a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
deleted file mode 100644
index 9e2f73b53..000000000
Binary files a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png and /dev/null differ
diff --git a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
deleted file mode 100644
index 7c9848832..000000000
Binary files a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png and /dev/null differ
diff --git a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png
deleted file mode 100644
index 988afe5cf..000000000
Binary files a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png and /dev/null differ
diff --git a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
deleted file mode 100644
index 9b9c6f683..000000000
Binary files a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png and /dev/null differ
diff --git a/android/app/src/main/res/values-es/arrays.xml b/android/app/src/main/res/values-es/arrays.xml
deleted file mode 100644
index d74fb6b1b..000000000
--- a/android/app/src/main/res/values-es/arrays.xml
+++ /dev/null
@@ -1,220 +0,0 @@
-<resources>
-    <string-array name="settings_console_region_entries">
-        <item>Auto-Detectar</item>
-        <item>NTSC-J (Japón)</item>
-        <item>NTSC-U (US)</item>
-        <item>PAL (Europa, Australia)</item>
-    </string-array>
-    <string-array name="settings_cpu_execution_mode_entries">
-        <item>Intérprete (El más lento)</item>
-        <item>Intérprete en Caché (Rápido)</item>
-        <item>Recompilador (Más rápido)</item>
-    </string-array>
-    <string-array name="settings_cpu_fastmem_mode_entries">
-        <item>Deshabilitado (El más lento)</item>
-        <item>MMap (Hardware, Más rápido, 64-Bit Solamente)</item>
-        <item>LUT (Rápido)</item>
-    </string-array>
-    <string-array name="gpu_renderer_entries">
-        <item>Hardware (OpenGL)</item>
-        <item>Hardware (Vulkan)</item>
-        <item>Software</item>
-    </string-array>
-    <string-array name="settings_gpu_resolution_scale_entries">
-        <item>1x</item>
-        <item>2x</item>
-        <item>3x (para 720p)</item>
-        <item>4x</item>
-        <item>5x (para 1080p)</item>
-        <item>6x (para 1440p)</item>
-        <item>7x</item>
-        <item>8x</item>
-        <item>9x (para 4K)</item>
-        <item>10x</item>
-        <item>11x</item>
-        <item>12x</item>
-        <item>13x</item>
-        <item>14x</item>
-        <item>15x</item>
-        <item>16x</item>
-    </string-array>
-    <string-array name="settings_display_crop_mode_entries">
-        <item>Ninguno</item>
-        <item>Sólo área de sobreescaneo</item>
-        <item>Todos los bordes</item>
-    </string-array>
-    <string-array name="settings_display_aspect_ratio_names">
-        <item>Auto (Nativo del juego)</item>
-        <item>Auto (Match Display)</item>
-        <item>Custom</item>
-        <item>4:3</item>
-        <item>16:9</item>
-        <item>19:9</item>
-        <item>20:9</item>
-        <item>PAR 1:1</item>
-    </string-array>
-    <string-array name="settings_gpu_texture_filter_names">
-        <item>Nearest-Neighbor</item>
-        <item>Bilinear</item>
-        <item>Bilinear (Sin unión de bordes)</item>
-        <item>JINC2</item>
-        <item>JINC2 (Sin unión de bordes)</item>
-        <item>xBR</item>
-        <item>xBR (Sin unión de bordes)</item>
-    </string-array>
-    <string-array name="settings_controller_type_entries">
-        <item>None</item>
-        <item>Control Digital (Mando)</item>
-        <item>Control Analógico (DualShock)</item>
-        <item>Analog Joystick</item>
-        <item>NeGcon</item>
-        <item>GunCon</item>
-    </string-array>
-    <string-array name="settings_memory_card_mode_entries">
-        <item>Sin tarjeta de memoria</item>
-        <item>Compartido entre todos los juegos</item>
-        <item>Tarjeta separada por juego (Código)</item>
-        <item>Tarjeta separada por juego (Título)</item>
-    </string-array>
-    <string-array name="settings_cdrom_read_speedup_entries">
-        <item>Ninguno (Velocidad doble)</item>
-        <item>2x (Velocidad cuádruple)</item>
-        <item>3x (6x Velocidad)</item>
-        <item>4x (8x Velocidad)</item>
-        <item>5x (10x Velocidad)</item>
-        <item>6x (12x Velocidad)</item>
-        <item>7x (14x Velocidad)</item>
-        <item>8x (16x Velocidad)</item>
-        <item>9x (18x Velocidad)</item>
-        <item>10x (20x Velocidad)</item>
-    </string-array>
-    <string-array name="settings_touchscreen_controller_view_entries">
-        <item>Ninguno</item>
-        <item>Mando digital</item>
-        <item>Mando analógico unico</item>
-        <item>Mando analógico dual</item>
-        <item>Lightgun</item>
-    </string-array>
-    <string-array name="settings_audio_backend_entries">
-        <item>Nulo (Sin Salida)</item>
-        <item>Cubeb</item>
-        <item>OpenSL ES (Recomendado)</item>
-    </string-array>
-    <string-array name="settings_audio_buffer_size_entries">
-        <item>1024 Fotogramas (23.22ms)</item>
-        <item>2048 Fotogramas (46.44ms, Recomendado)</item>
-        <item>3072 Fotogramas (69.66ms)</item>
-        <item>4096 Fotogramas (92.88ms)</item>
-    </string-array>
-    <string-array name="settings_log_level_entries">
-        <item>Ninguno</item>
-        <item>Error</item>
-        <item>Alerta</item>
-        <item>Alertas de Rendimiento</item>
-        <item>Información</item>
-        <item>Detalles</item>
-        <item>Desarrollador</item>
-        <item>Perfil</item>
-        <item>Depurar</item>
-        <item>Seguimiento</item>
-    </string-array>
-    <string-array name="settings_tabs">
-        <item>General</item>
-        <item>Pantalla</item>
-        <item>Audio</item>
-        <item>Mejoras</item>
-        <item>Logros</item>
-        <item>Avanzado</item>
-    </string-array>
-    <string-array name="settings_gpu_msaa_entries">
-        <item>Deshabilitado</item>
-        <item>2x MSAA</item>
-        <item>4x MSAA</item>
-        <item>8x MSAA</item>
-        <item>2x SSAA</item>
-        <item>4x SSAA</item>
-        <item>8x SSAA</item>
-    </string-array>
-    <string-array name="settings_advanced_display_fps_limit_entries">
-        <item>Ilimitado (Mostrar fotogramas)</item>
-        <item>10 FPS</item>
-        <item>15 FPS</item>
-        <item>30 FPS</item>
-        <item>45 FPS</item>
-        <item>60 FPS</item>
-        <item>75 FPS</item>
-        <item>90 FPS</item>
-    </string-array>
-    <string-array name="settings_emulation_speed_entries">
-        <item>Ilimitado</item>
-        <item>10% [6 FPS (NTSC) / 5 FPS (PAL)]</item>
-        <item>20% [12 FPS (NTSC) / 10 FPS (PAL)]</item>
-        <item>30% [18 FPS (NTSC) / 15 FPS (PAL)]</item>
-        <item>40% [24 FPS (NTSC) / 20 FPS (PAL)]</item>
-        <item>50% [30 FPS (NTSC) / 25 FPS (PAL)]</item>
-        <item>60% [36 FPS (NTSC) / 30 FPS (PAL)]</item>
-        <item>70% [42 FPS (NTSC) / 35 FPS (PAL)]</item>
-        <item>80% [48 FPS (NTSC) / 40 FPS (PAL)]</item>
-        <item>90% [54 FPS (NTSC) / 45 FPS (PAL)]</item>
-        <item>100% [60 FPS (NTSC) / 50 FPS (PAL), Defecto]</item>
-        <item>125% [75 FPS (NTSC) / 62 FPS (PAL)]</item>
-        <item>150% [90 FPS (NTSC) / 75 FPS (PAL)]</item>
-        <item>175% [105 FPS (NTSC) / 87 FPS (PAL)]</item>
-        <item>200% [120 FPS (NTSC) / 100 FPS (PAL)]</item>
-        <item>250% [150 FPS (NTSC) / 125 FPS (PAL)]</item>
-        <item>300% [180 FPS (NTSC) / 150 FPS (PAL)]</item>
-        <item>350% [210 FPS (NTSC) / 175 FPS (PAL)]</item>
-        <item>400% [240 FPS (NTSC) / 200 FPS (PAL)]</item>
-        <item>450% [270 FPS (NTSC) / 225 FPS (PAL)]</item>
-        <item>500% [300 FPS (NTSC) / 250 FPS (PAL)]</item>
-        <item>600% [360 FPS (NTSC) / 300 FPS (PAL)]</item>
-        <item>700% [420 FPS (NTSC) / 350 FPS (PAL)]</item>
-        <item>800% [480 FPS (NTSC) / 400 FPS (PAL)]</item>
-        <item>900% [540 FPS (NTSC) / 450 FPS (PAL)]</item>
-        <item>1000% [600 FPS (NTSC) / 500 FPS (PAL)]</item>
-    </string-array>
-    <string-array name="settings_advanced_cpu_overclock_entries">
-        <item>25% (8MHz)</item>
-        <item>50% (16MHz)</item>
-        <item>75% (24MHz)</item>
-        <item>100% (33MHz, Defecto)</item>
-        <item>125% (41MHz)</item>
-        <item>150% (49MHz)</item>
-        <item>175% (57MHz)</item>
-        <item>200% (66MHz)</item>
-        <item>225% (74MHz)</item>
-        <item>250% (82MHz)</item>
-        <item>275% (90MHz)</item>
-        <item>300% (99MHz)</item>
-        <item>350% (115MHz)</item>
-        <item>400% (132MHz)</item>
-        <item>450% (148MHz)</item>
-        <item>500% (165MHz)</item>
-        <item>500% (165MHz)</item>
-        <item>600% (198MHz)</item>
-        <item>700% (231MHz)</item>
-        <item>800% (264MHz)</item>
-        <item>900% (297MHz)</item>
-        <item>1000% (330MHz)</item>
-    </string-array>
-    <string-array name="settings_emulation_screen_orientation_entries">
-        <item>Usar configuración del dipositivo</item>
-        <item>Vertical</item>
-        <item>Horizontal</item>
-        <item>Sensor Based</item>
-    </string-array>
-    <string-array name="settings_theme_entries">
-        <item>Usar configuración del Sistema</item>
-        <item>Claro</item>
-        <item>Oscuro</item>
-    </string-array>
-    <string-array name="settings_downsample_mode_entries">
-        <item>Deshabilitado</item>
-        <item>Cuadro (Reducir Resolución 3D/Suavizar todo)</item>
-        <item>Adaptable (Preservar 3D/Suavizar 2D)</item>
-    </string-array>
-    <string-array name="settings_boolean_entries">
-        <item>Deshabilitado</item>
-        <item>Habilitado</item>
-    </string-array>
-</resources>
diff --git a/android/app/src/main/res/values-es/strings.xml b/android/app/src/main/res/values-es/strings.xml
deleted file mode 100644
index 7543266ad..000000000
--- a/android/app/src/main/res/values-es/strings.xml
+++ /dev/null
@@ -1,346 +0,0 @@
-<resources>
-    <string name="app_name">DuckStation</string>
-    <string name="action_settings">Configuraciones</string>
-    <string name="action_controller_mapping">Mapeado del Control</string>
-    <string name="title_activity_settings">Configuraciones</string>
-    <string name="settings_console_region">Región de Consola</string>
-    <string name="settings_console_tty_output">Habilitar Salida TTY</string>
-    <string name="settings_console_fast_boot">Inicio Rápido</string>
-    <string name="settings_osd_show_messages">Mostrar Mensajes</string>
-    <string name="settings_osd_show_speed">Mostrar Velocidad de Emulación</string>
-    <string name="settings_osd_show_show_fps">Mostrar velocidad de fotogramas del juego</string>
-    <string name="settings_osd_show_show_vps">Mostrar pantalla FPS</string>
-    <string name="settings_cpu_execution_mode">Modo de Ejecución de CPU</string>
-    <string name="settings_gpu_renderer">Renderizador de GPU</string>
-    <string name="settings_gpu_resolution_scale">Escala de Resolución</string>
-    <string name="title_activity_emulation">Actividad de Emulación</string>
-    <string name="settings_emulation_speed">Velocidad de Emulación</string>
-    <string name="settings_fast_forward_speed">Velocidad de Avance Rápido</string>
-    <string name="settings_save_state_on_exit">Guardar Estado al Salir</string>
-    <string name="settings_emulation_screen_orientation">Orientación de pantalla del Emulador</string>
-    <string name="settings_load_patch_codes">Cargar Códigos de Parche</string>
-    <string name="settings_summary_save_state_on_exit">Guarda automáticamente el estado del emulador al apagar o salir. Después puedes continuar desde donde lo dejaste la última vez.</string>
-    <string name="settings_summary_load_patch_codes"><![CDATA[Cargar Códigos de Parche de trucos/<game name>.cht en formato PCSXR. Los códigos pueden ser activados dentro del juego.]]></string>
-    <string name="settings_apply_compatibility_settings">Aplicar configuración de compatiblidad</string>
-    <string name="settings_summary_apply_compatibility_settings">Desactiva las mejoras automáticamente cuando no son compatibles con los juegos.</string>
-    <string name="settings_summary_video_sync">Habilita esta opción para coincidir la tasa de refresco de DuckStation con la de tu pantalla. La VSync se deshabilita automáticamente cuando no sea posible (ejemplo, no llegar al 100% de la velocidad).</string>
-    <string name="settings_video_sync">Sincronizar Video</string>
-    <string name="settings_cpu_overclocking">CPU Overclocking</string>
-    <string name="settings_cdrom_region_check">Chequeo Regional de CD-ROM</string>
-    <string name="settings_summary_cdrom_region_check">Evita que el emulador lea discos de regiones incorrectas. Comúnmente es seguro desactivarlo.</string>
-    <string name="settings_cdrom_preload_image_to_ram">Precargar imagen a RAM de CD-ROM</string>
-    <string name="settings_summary_preload_image_to_ram">Carga la imagen del juego en la RAM. Útil para cuando se usan directorios a través de una red. En algunas ocasiones puede eliminar las pausas que se generan cuando el juego inicia la reproducción de una pista de audio.</string>
-    <string name="settings_pgxp_vertex_cache">Caché de vértices PGXP</string>
-    <string name="settings_summary_pgxp_vertex_cache">Utiliza las coordenadas de la pantalla como respaldo cuando falla el seguimiento de vértices a través de la memoria. Puede mejorar la compatibilidad con PGXP.</string>
-    <string name="settings_pgxp_cpu_mode">Modo PGXP CPU</string>
-    <string name="settings_summary_pgxp_cpu_mode">Intenta rastrear la manipulación de vértices a través del CPU. Algunos juegos requieren esta opción para que PGXP sea efectivo. Muy lento e incompatible con el recompilador.</string>
-    <string name="settings_cpu_recompiler_icache">CPU Recompilado ICache</string>
-    <string name="settings_summary_cpu_recompiler_icache">Determina si la caché de instrucciones del CPU se simula en el recompilador. Mejora la precisión con un pequeño coste de rendimiento. Si los juegos corren demasiado rápido, intenta habilitar esta opción.</string>
-    <string name="settings_cpu_recompiler_fastmem">CPU Recompilador de acceso rápido a la memoria</string>
-    <string name="settings_summary_cpu_recompiler_fastmem">Hace que el acceso de memoria de los invitados sea más eficiente mediante el uso de errores de página y parches. Desactívalo si es inestable en tu dispositivo.</string>
-    <string name="settings_presented_frame_limit">Límite de fotogramas presentados</string>
-    <string name="settings_logging_level">Nivel de Registro</string>
-    <string name="settings_log_to_file">Registrar en Archivo</string>
-    <string name="settings_summary_log_to_file">Escribe los mensajes de registros duckstation.log en tu directorio de Usuario. Usarlo solamente para depurar, ya que ralentiza la emulación.</string>
-    <string name="settings_log_to_logcat">Registrar en Logcat</string>
-    <string name="settings_summary_log_to_logcat">Escribe los mensajes de registros en el registrador de mensajes de Android. Solo es útil cuando se conecta a una computadora con adb.</string>
-    <string name="settings_volume">Volumen</string>
-    <string name="settings_summary_volume">Controla el volumen de salida de audio del emulador.</string>
-    <string name="settings_fast_forward_volume">Volumen de Avance Rápido</string>
-    <string name="settings_summary_fast_forward_volume">Controla el volumen de salida de audio del emulador que durante el avance rápido.</string>
-    <string name="settings_mute_all_sound">Silenciar todo</string>
-    <string name="settings_summary_mute_all_sound">Evita que el emulador emita cualquier sonido.</string>
-    <string name="settings_mute_cd_audio">Silenciar audio de CD</string>
-    <string name="settings_summary_mute_cd_audio">Silecia a la fuerza el audio CD-DA y XA del CD-ROM. Puede usarse para deshabilitar la música de fondo en algunos juegos.</string>
-    <string name="settings_audio_backend">Motor de Audio</string>
-    <string name="settings_audio_buffer_size">Tamaño del Búfer de Audio</string>
-    <string name="settings_summary_audio_buffer_size">Determina la latencia entre el audio que se genera y de salida por altavoces. Los valores más pequeños reducen la latencia, pero las variaciones en la velocidad de emulación causarán problemas.</string>
-    <string name="settings_audio_sync">Sincronizar Audio</string>
-    <string name="settings_summary_audio_sync">Acelera la velocidad de la emulación basado en los fotogramas de audio enviados por el motor de audio. Esto ayuda a eliminar ruidos o distorsiones si la emulación es muy rápida. La sincronización se desabilitará automáticamente si la velocidad no es del 100%.</string>
-    <string name="settings_controller_type">Tipo de Control</string>
-    <string name="settings_enable_analog_mode_on_reset">Habilitar el Modo Analógico al Reiniciar</string>
-    <string name="settings_touchscreen_controller_view">Vista de Control de Pantalla Táctil</string>
-    <string name="settings_auto_hide_touchscreen_controller">Auto-Ocultar el control de pantalla táctil​</string>
-    <string name="settings_summary_auto_hide_touchscreen_controller">Oculta el control de pantalla táctil cuando un control externo es detectado.</string>
-    <string name="settings_vibrate_on_press">Vibrar al presionar</string>
-    <string name="settings_summary_vibrate_on_press">Permite una vibración corta cuando un botón en la pantalla táctil es presionado. Requiere que \"Vibrar al presionar\" esté habilitado en tu dispositivo.</string>
-    <string name="settings_enable_vibration">Activar Vibración</string>
-    <string name="settings_summary_enable_vibration">Reenvía el ruido del juego al motor de vibración del teléfono..</string>
-    <string name="settings_memory_card_1_type">Tarjeta de Memoria Tipo 1</string>
-    <string name="settings_memory_card_2_type">Tarjeta de Memoria Tipo 2</string>
-    <string name="settings_crop_mode">Modo de recorte</string>
-    <string name="settings_aspect_ratio">Relación de Aspecto</string>
-    <string name="settings_linear_upscaling">Escalado Lineal</string>
-    <string name="settings_integer_upscaling">Escalado Entero</string>
-    <string name="settings_summary_linear_upscaling">Suaviza la imagen al escalar la consola a la pantalla.</string>
-    <string name="settings_summary_integer_upscaling">Añade relleno en la pantalla para asegurarse que la relación entre los pixeles de la consola y del anfitrión es un número entero. Puede resultar en una imagen más nítida en algunos juegos 2D.</string>
-    <string name="settings_summary_osd_show_messages">Muestra mensajes en pantalla cuando ocurren eventos como crear o cargar estados guardados, tomar capturas, etc.</string>
-    <string name="settings_summary_osd_show_speed">Establece la velocidad de emulación de destino. No se asegura que esa velocidad se vaya a alcanzar, y de no hacerlo, el emulador va a correr lo más rápido que pueda.</string>
-    <string name="settings_summary_osd_show_fps">Muestra la velocidad de fotogramas interna del juego en la esquina superior derecha de la pantalla.</string>
-    <string name="settings_summary_osd_show_vps">Muestra el número de fotogramas (o sincronizaciones verticales) mostradas por segundo por el sistema en la esquina superior derecha de la pantalla.</string>
-    <string name="settings_cdrom_read_speedup">CD-ROM Aceleración de lectura</string>
-    <string name="settings_summary_cdrom_read_speedup">Acelera la lectura del CD-ROM para el valor especificado. Sólo se aplica a lecturas de doble velocidad, y se ignora cuando se está reproduciendo audio. Puede mejorar las velocidades de carga en algunos juegos, mientras que puede interrumpir otros.</string>
-    <string name="settings_summary_console_fast_boot">Omite el BIOS shell/intro, iniciando directamente en el juego. Normalmente es seguro habilitarlo, pero algunos juegos se tildan.</string>
-    <string name="settings_msaa">Anti-aliasing de muestreo múltiple</string>
-    <string name="settings_true_color">Renderizado de color verdadero (24-bit, deshabilita el tramado)</string>
-    <string name="settings_summary_true_color">Esto produce mejores gradientes al costo de hacer algunos colores diferentes. Deshabilitar esta opción también activa el tramado. La mayoría de los juegos son compatibles con esta opción.</string>
-    <string name="settings_scaled_dithering">Escalado de tramado (escalar patrón de tramado a resolución)</string>
-    <string name="settings_summary_scaled_dithering">Escala el patrón del tramado a la escala de resolución de la GPU emulada. Esto disimula el tramado en altas resoluciones. Usualmente es seguro habilitarlo, y sólo está soportado por los renderizadores de hardware.</string>
-    <string name="settings_disable_interlacing">Deshabilitar tramado (fuerza progresivamente renderizado/escaneo)</string>
-    <string name="settings_summary_disable_interlacing">Fuerza el renderizado y visualización de fotogramas en modo progresivo. Esto elimina el efecto \"peine\" visto en juegos con 480i renderizándolos en 480p. Normalmente es seguro habilitarlo.</string>
-    <string name="settings_texture_filtering">Filtrado de textura</string>
-    <string name="settings_force_ntsc_timings">Forzar tiempos NTSC (60hz en PAL)</string>
-    <string name="settings_summary_force_ntsc_timings">Usa los tiempos de fotograma del modo NTSC cuando la consola está en modo PAL, forzando los juegos PAL a correr a 60Hz.</string>
-    <string name="settings_widescreen_hack">Hack de Pantalla Panorámica</string>
-    <string name="settings_summary_widescreen_hack">Escala las posiciones de vértices en pantalla a una relación de aspecto panorámica, incrementando el campo de visión de 4:3 a 16:9 en juegos 3D. Tal vez no sea compatible con todos los juegos.</string>
-    <string name="settings_force_4_3_for_24bit">Forzar 4:3 para escenas 24-bit</string>
-    <string name="settings_summary_force_4_3_for_24bit">Cambia al modo de pantalla 4:3 cuando se muestra contenido de 24-bit, generalmente FMVs.</string>
-    <string name="settings_chroma_smoothing_24bit">Suavizado de croma para escenas 24-bit</string>
-    <string name="settings_summary_chrome_smoothing_24bit">Suaviza el efecto pixelado que se produce entre las transiciones de colores en contenido de 24-bit, generalmente en FMVs. Sólo se aplica a los renderizadores de hardware.</string>
-    <string name="settings_pgxp_geometry_correction">PGXP Corrección de Geometría</string>
-    <string name="settings_summary_pgxp_geometry_correction"><![CDATA[Reduce los polígonos \"temblorosos\" y las texturas \"deformadas\" que son comunes en juegos de PS1. >Solo funciona con los renderizadores de hardware. Tal vez no sea compatible con todos los juegos.]]></string>
-    <string name="settings_pgxp_culling_correction">PGXP Correción de Culling</string>
-    <string name="settings_summary_pgxp_culling_correction">Incrementa la precisión del culling de polígonos, reduciendo el número de huecos en la geometría. Requiere la correción de geometría activada.</string>
-    <string name="settings_pgxp_texture_correction">PGXP Corrección de Texturas</string>
-    <string name="settings_summary_pgxp_texture_correction">Usa interpolación con perspectiva correcta para las coordenadas de texturas y colores, enderezando texturas deformadas. Requiere la correción de geometría activada.</string>
-    <string name="settings_pgxp_preserve_projection_precision">PGXP Conservar la precisión de proyección</string>
-    <string name="settings_summary_pgxp_preserve_projection_precision">Permite precisión adicional para PGXP. Puede mejorar las imágenes en algunos juegos pero fallar en otros.</string>
-    <string name="settings_pgxp_depth_buffer">PGXP Búfer de Profundidad</string>
-    <string name="settings_summary_pgxp_depth_buffer">Intenta reducir los polígonos en el eje Z probando píxeles con los valores de profundidad de PGXP. Tiene baja compatibilidad, pero puede funcionar bien en algunos juegos.</string>
-    <string name="menu_main_resume_last_session">Reanudar la última sesión</string>
-    <string name="menu_main_start_file">Iniciar Archivo</string>
-    <string name="menu_main_start_bios">Iniciar BIOS</string>
-    <string name="menu_main_edit_game_directories">Editar Directorios de Juego</string>
-    <string name="menu_main_scan_for_new_games">Escanear para juegos nuevos</string>
-    <string name="menu_main_rescan_all_games">Reescanear todos los juegos</string>
-    <string name="menu_main_import_bios">Importar BIOS</string>
-    <string name="menu_main_show_version">Mostrar Versión</string>
-    <string name="menu_main_github_repository">Repositorio de GitHub</string>
-    <string name="menu_main_discord_server">Servidor de Discord</string>
-    <string name="menu_game_list_entry_start_game">Iniciar Juego</string>
-    <string name="menu_game_list_entry_resume_game">Reanudar Juego</string>
-    <string name="android_progress_callback_please_wait">Cargando...</string>
-    <string name="android_progress_callback_ok">OK</string>
-    <string name="android_progress_callback_information">Información</string>
-    <string name="android_progress_callback_confirmation">Confirmación</string>
-    <string name="android_progress_callback_yes">Si</string>
-    <string name="android_progress_callback_no">No</string>
-    <string name="emulation_activity_error">Error</string>
-    <string name="emulation_activity_ok">OK</string>
-    <string name="emulation_activity_import_patch_codes">Importar códigos de parche...</string>
-    <string name="emulation_activity_patch_on">(ENCENDIDO)</string>
-    <string name="emulation_activity_patch_off">(APAGADO)</string>
-    <string name="emulation_activity_choose_patch_code_file">Seleccionar Archivo con Códigos de Parche</string>
-    <string name="emulation_activity_failed_to_import_patch_codes">Fallo al importar códigos de parche. Asegúrese de seleccionar un archivo con formato PCSXR o Libretro.</string>
-    <string name="main_activity_choose_directory">Elegir Directorio</string>
-    <string name="main_activity_error">Error</string>
-    <string name="main_activity_get_path_from_file_error">No se pudo obtener la ruta del archivo seleccionado. Asegúrese de que el archivo esté un almacenamiento interno/externo.\n\nToque el botón que sobresale en el selector de directorio.\nSeleccione "Mostrar Almacenamiento Interno".\nToque el botón de menú y seleccione el nombre de su dispositivo o tarjeta SD .</string>
-    <string name="main_activity_ok">OK</string>
-    <string name="main_activity_get_path_from_directory_error">No se pudo obtener la ruta del directorio seleccionado. Asegúrese de que el directorio esté un almacenamiento interno/externo.\n\nToque el botón que sobresale en el selector de directorio.\nSeleccione \"Mostrar Almacenamiento Interno\".\nToque el botón de menú y seleccione el nombre de su dispositivo o tarjeta SD .</string>
-    <string name="main_activity_external_storage_permissions_error">Se requieren permisos de almacenamiento externo para usar DuckStation.</string>
-    <string name="main_activity_choose_disc_image">Seleccionar Imagen de Disco</string>
-    <string name="main_activity_missing_bios_image_prompt">No se encontró ninguna imagen de BIOS en el directorio BIOS de DuckStation. ¿Quiere localizar e importar una imagen de BIOS ahora?</string>
-    <string name="main_activity_missing_bios_image">Imagen BIOS Ausente</string>
-    <string name="main_activity_yes">Si</string>
-    <string name="main_activity_no">No</string>
-    <string name="main_activity_choose_bios_image">Elegir Imagen BIOS</string>
-    <string name="main_activity_failed_to_open_bios_image">Fallo al cargar la imagen BIOS.</string>
-    <string name="main_activity_failed_to_read_bios_image_prefix">\"Fallo al leer la imagen BIOS: \"</string>
-    <string name="main_activity_bios_image_too_large">La imagen de BIOS es demasiado grande. Debes seleccionar una imagen de BIOS, no un juego, y debe tener un tamaño de 512 KB.</string>
-    <string name="main_activity_invalid_error">Esta Imagen BIOS es incorrecta, o ya ha sido importado.</string>
-    <string name="main_activity_show_version_title">Version</string>
-    <string name="main_activity_copy">Copiar</string>
-    <string name="settings_gpu_thread">Renderizado de GPU con Hilos</string>
-    <string name="settings_summary_gpu_thread">Usa un segundo hilo para dibujar los gráficos. Actualmente solo está disponible para el renderizador por software, pero puede dar un aumento significante de velocidad, y es seguro de usar.</string>
-    <string name="settings_gpu_threaded_presentation">Presentación de GPU con subprocesos</string>
-    <string name="settings_summary_gpu_threaded_presentation">Presenta fotogramas en un hilo de fondo cuando el Avance Rápido o VSync está desactivado. Esto puede mejorar considerablemente el rendimiento en el renderizador Vulkan.</string>
-    <string name="settings_language">Idioma (reiniciar para aplicar)</string>
-    <string name="touchscreen_controller_stop_editing">Dejar de editar</string>
-    <string name="touchscreen_controller_reset_layout">Reiniciar Modelo</string>
-    <string name="emulation_activity_touchscreen_controller_not_active">El control de pantalla táctil no está activo.</string>
-    <string name="settings_theme">Tema</string>
-    <string name="settings_controller_mapping_summary">Permite asignar botones/ejes del control externo al controlador emulado.</string>
-    <string name="settings_controller_mapping">Mapeado de Control</string>
-    <string name="controller_binding_dialog_message">Presiona un botón del control para seleccionar una nueva asignación.\n\nAsignación Actual: %s</string>
-    <string name="controller_binding_dialog_no_binding"><![CDATA[<Sin Asignar>]]></string>
-    <string name="controller_binding_dialog_cancel">Cancelar</string>
-    <string name="controller_binding_dialog_clear">Limpiar</string>
-    <string name="controller_mapping_activity_title">Mapeado de Control</string>
-    <string name="controller_mapping_activity_no_profiles_found">No se encontraron perfiles.</string>
-    <string name="controller_mapping_activity_select_input_profile">Seleccionar perfil de control</string>
-    <string name="controller_mapping_activity_failed_to_load_profile">Fallo al cargar el perfil \'%s\'</string>
-    <string name="controller_mapping_activity_input_profile_name">Ingrese Nombre de Perfil:</string>
-    <string name="controller_mapping_activity_save">Guardar</string>
-    <string name="controller_mapping_activity_name_must_be_provided">Debe proporcionarse un nombre.</string>
-    <string name="controller_mapping_activity_failed_to_save_input_profile">Fallo al guardar perfil de control.</string>
-    <string name="controller_mapping_activity_input_profile_saved">Perfil de control \'%s\' guardado.</string>
-    <string name="controller_mapping_activity_cancel">Cancelar</string>
-    <string name="settings_use_analog_sticks_for_dpad">Usar las palancas analógicas como cruceta en el modo digital</string>
-    <string name="settings_summary_enable_analog_mode_on_reset">Fuerza el control al modo analógico cuando la consola se reinicia/enciende</string>
-    <string name="settings_summary_use_analog_sticks_for_dpad">Te permite usar las palancas analógicas para controlar la cruceta y los botones en modo digital.</string>
-    <string name="settings_disable_all_enhancements">Desactiva todas las mejoras</string>
-    <string name="settings_summary_disable_all_enhancements">Temporalmente desactiva todas las mejoras, el cual puede ser útil al depurar problemas.</string>
-    <string name="settings_downsample_mode">Submuestreo</string>
-    <string name="activity_game_properties">Propiedades del Juego</string>
-    <string name="game_properties_preference_use_global_setting">Usar configuración global</string>
-    <string name="settings_input_profile">Perfil de Control</string>
-    <string name="game_properties_tab_summary">Resumen</string>
-    <string name="game_properties_tab_game_settings">Configuraciones de juego</string>
-    <string name="game_properties_tab_controller_settings">Configuraciones de Control</string>
-    <string name="settings_audio_resampling">Remuestreo de Audio</string>
-    <string name="settings_summary_audio_resampling">Cuando se ejecuta por encima del 100% de velocidad, vuelve a muestrear el audio de la velocidad objetivo en lugar de eliminar fotogramas. Produce un audio de avance/desaceleración mucho más agradable a un pequeño costo del rendimiento.</string>
-    <string name="settings_general_sync_to_host_refresh_rate">Sincronizar con la velocidad de actualización del anfitrión</string>
-    <string name="settings_summary_general_sync_to_host_refresh_rate">Ajusta la velocidad de emulación para que la frecuencia de actualización de la consola coincida con la frecuencia de actualización del anfitrión cuando las configuraciones de VSync y Remuestreo de audio estén habilitados. Esto da como resultado las animaciones más suaves posibles, a costa de aumentar potencialmente la velocidad de emulación en menos del 1%.</string>
-    <string name="settings_sustained_performance_mode">Modo de Rendimiento Sostenido</string>
-    <string name="settings_summary_sustained_performance_mode">Habilita el Modo de Rendimiento Sostenido por Android. Puede resultar en velocidades de fotogramas más consistentes para sesiones largas en algunos dispositivos.</string>
-    <string name="title_activity_game_directories">Editar Directorio de juegos</string>
-    <string name="settings_game_directories">Directorio de juegos</string>
-    <string name="settings_summary_game_directories">Cambia la lista de directorio que se utiliza para buscar juegos.</string>
-    <string name="game_directories_scanning_subdirectories">Escaneo de subdirectorios.</string>
-    <string name="game_directories_not_scanning_subdirectories">No escanear subdirectorios.</string>
-    <string name="settings_display_all_frames">Optimizar Frame Pacing</string>
-    <string name="settings_summary_display_all_frames">Habilitar esta opción asegurará que cada fotograma que la consola renderice se muestre en la pantalla, para un ritmo de fotograma óptimo. Si tiene dificultades para mantener la velocidad máxima o problemas de audio, intente desactivar esta opción.</string>
-    <string name="menu_edit_game_directories_add_directory">Agregar directorio</string>
-    <string name="menu_edit_game_directories_add_path">Agregar ruta</string>
-    <string name="edit_game_directories_add_path">Agregar ruta</string>
-    <string name="edit_game_directories_add_path_summary">Ingrese la ruta completa al directorio con juegos. \n\nEsto lo puedes obtener de un administrador de archivos.\n\nEjemplo: /storage/emulated/0/games</string>
-    <string name="save_state_info_slot_is_empty">Ranura vacia</string>
-    <string name="save_state_info_game_save_n">Juego guardado en %d</string>
-    <string name="save_state_info_global_save_n">Guardado global %d</string>
-    <string name="save_state_info_quick_save">Guardado rápido</string>
-    <string name="settings_osd_show_show_resolution">Mostrar resolución</string>
-    <string name="settings_summary_osd_show_resolution">Muestra la resolución a la que se está corriendo el juego en la esquina superior derecha de la pantalla.</string>
-    <string name="settings_summary_display_stretch">Estira la pantalla activa para llenar la pantalla.</string>
-    <string name="settings_display_stretch">Estirar para rellenar</string>
-    <string name="settings_category_global">Configuración Global</string>
-    <string name="settings_category_display">Mostrar configuración en Pantalla</string>
-    <string name="settings_category_audio">Configuración de Audio</string>
-    <string name="settings_category_console">Configuración de consola</string>
-    <string name="settings_category_cpu">Configuración de CPU</string>
-    <string name="settings_category_gpu">Configuración de GPU</string>
-    <string name="settings_category_logging">Configuración de registro</string>
-    <string name="dialog_done">Terminado</string>
-    <string name="dialog_touchscreen_controller_type">Tipo de control de pantalla táctil</string>
-    <string name="dialog_touchscreen_controller_opacity">Opacidad del control de pantalla táctil</string>
-    <string name="dialog_touchscreen_controller_buttons">Botones del control de pantalla táctil</string>
-    <string name="dialog_touchscreen_controller_settings">Configuración del control de pantalla táctil</string>
-    <string name="settings_summary_console_tty_output">Registra mensajes de depuración de los juegos.</string>
-    <string name="action_show_game_list">Vista por lista</string>
-    <string name="action_show_game_grid">Vista por grilla</string>
-    <string name="settings_touch_gliding">Toque deslizamiento</string>
-    <string name="settings_summary_touch_gliding">Le permite presionar varios botones frontales del control arrastrando el dedo por la pantalla. </string>
-    <string name="menu_game_list_entry_game_properties">Propiedades del Juego</string>
-    <string name="emulation_activity_change_disc_select_new_file">Seleccionar nuevo archivo...</string>
-    <string name="settings_achievements_enable">Habilitar RetroAchievements</string>
-    <string name="settings_summary_achievements_enable">Cuando está habilitado y logueado, DuckStation buscará logros al iniciarse.</string>
-    <string name="settings_achievements_challenge_mode">Habilitar modo Hardcore</string>
-    <string name="settings_summary_achievements_challenge_mode">Modo de Desafío. Desactiva el estado de guardado, los trucos y las funciones de ralentización, pero recibes el doble de puntos de logros. No se puede alternar en el juego.</string>
-    <string name="settings_achievements_rich_presence">Habilitar Rich Presence</string>
-    <string name="settings_summary_achievements_rich_presence">La información de Rich presence se recopilará y enviará información al servidor donde sea compatible</string>
-    <string name="settings_achievements_username">Nombre de Usuario</string>
-    <string name="settings_achievements_token_generation_time">Tiempo de generación del Token</string>
-    <string name="settings_achievements_login">Inicio de sesión</string>
-    <string name="settings_summary_achievements_login">Inicia sesión en tu cuenta para registrar logros.</string>
-    <string name="settings_achievements_register">Registro</string>
-    <string name="settings_summary_achievements_register">Abre un enlace para crear una nueva cuenta.</string>
-    <string name="settings_achievements_logout">Cerrar sesión</string>
-    <string name="settings_summary_achievements_logout">Cierra sesión en su cuenta. No se registrarán nuevos logros.</string>
-    <string name="settings_achievements_view_profile">Ver Perfil</string>
-    <string name="settings_summary_achievements_view_profile">Abre un enlace a tu perfil.</string>
-    <string name="settings_achievements_test_mode">Habilitar el modo Test</string>
-    <string name="settings_summary_achievements_test_mode">Cuando está habilitado, DuckStation asumirá que todos los logros están bloqueados y no enviará notificaciones de desbloqueo al servidor.</string>
-    <string name="settings_achievements_use_first_disc_from_playlist">Usar el primer disco de la Lista</string>
-    <string name="settings_summary_achievements_use_first_disc_from_playlist">Cuando está habilitado, el primer disco de una lista se utilizará para los logros, independientemente del disco que esté activo.</string>
-    <string name="achievement_settings_login_title">Inicio de sesión en RetroAchievements</string>
-    <string name="achievement_settings_login_help">Ingrese el nombre de usuario y password de retroachievements.org. Su contraseña no será guardada en DuckStation, en su lugar se generará y se utilizará un token de acceso.</string>
-    <string name="achievement_settings_login_username_hint">Usuario</string>
-    <string name="achievement_settings_login_password_hint">Contraseña</string>
-    <string name="achievement_settings_login_login_button">Loguearse</string>
-    <string name="achievement_settings_login_cancel_button">Cancelar</string>
-    <string name="achievement_settings_login_failed">Fallo al iniciar sesión. Chequear que el nombre de usuario y contraseña estén bien escritos e intentelo nuevamente.</string>
-    <string name="achievement_points_format_string">%d puntos</string>
-    <string name="achievement_summary_format_string">Has desbloqueado %1$d de %2$d logros y has obtenido %3$d de %4$d puntos posibles.</string>
-    <string name="achievement_title_challenge_mode_format_string">%s (Modo Hardcore)</string>
-    <string name="settings_achievements_disclaimer">DuckStation utiliza RetroAchievements (retroachievements.org) como base de datos de logros y para realizar un seguimiento del progreso.</string>
-    <string name="settings_achievements_confirm_logout_title">Confirmar cierre de sesión</string>
-    <string name="settings_achievements_confirm_logout_message">Después de cerrar la sesión, no se desbloquearán más logros hasta que vuelva a iniciar sesión. Los logros desbloqueados no se perderán.</string>
-    <string name="controller_binding_device_for_vibration">Dispositivo para vibración</string>
-    <string name="controller_settings_tab_settings">Configuración</string>
-    <string name="controller_settings_tab_hotkeys">Hotkeys</string>
-    <string name="controller_settings_category_button_bindings">Asignación de botones</string>
-    <string name="controller_settings_category_axis_bindings">Asignación de ejes</string>
-    <string name="controller_settings_category_settings">Configuración</string>
-    <string name="controller_settings_category_touchscreen_controller">Control de pantalla táctil</string>
-    <string name="controller_settings_category_ports">Puertos</string>
-    <string name="controller_settings_main_port_format">Puerto %d</string>
-    <string name="controller_settings_sub_port_format">Puerto %1$d%2$c</string>
-    <string name="action_switch_view">Cambiar vista</string>
-    <string name="title_activity_memory_card_editor">Editor de Tarjeta de Memoria</string>
-    <string name="action_memory_card_editor">Editar Tarjeta de Memoria</string>
-    <string name="action_memory_card_editor_import_card">Importar Tarjeta</string>
-    <string name="action_memory_card_editor_open_card">Abrir Tarjeta</string>
-    <string name="action_memory_card_editor_new_card">Nueva Tarjeta</string>
-    <string name="action_memory_card_editor_format_card">Formatear Tarjeta</string>
-    <string name="action_memory_card_editor_delete_card">Borrar Tarjeta</string>
-    <string name="memory_card_editor_no_cards_found">No se encontraron tarjetas de memoria.</string>
-    <string name="memory_card_editor_card_already_open">Esta tarjeta ya está abierta.</string>
-    <string name="memory_card_editor_failed_to_open_card">Error al abrir o leer la tarjeta de memoria.</string>
-    <string name="memory_card_editor_must_have_at_least_two_cards_to_copy">Debe tener al menos dos tarjetas abiertas para copiar.</string>
-    <string name="memory_card_editor_copy_save_to">Copiar %s a...</string>
-    <string name="memory_card_editor_select_card">Seleccionar tarjeta</string>
-    <string name="memory_card_editor_error">Error</string>
-    <string name="memory_card_editor_copy_insufficient_blocks">Este archivo requiere %1$d bloques, pero solo tiene %2$d bloques libres.</string>
-    <string name="memory_card_editor_copy_already_exists">El archivo \'%s\' ya existe en la tarjeta de destino.</string>
-    <string name="memory_card_editor_copy_read_failed">Error al leer el archivo \'%s\' de la tarjeta seleccionada.</string>
-    <string name="memory_card_editor_copy_write_failed">Error al escribir el archivo \'%s\' en la tarjeta de destino.</string>
-    <string name="memory_card_editor_copy_success">Copiado \'%1$s\' a \'%2$s\'.</string>
-    <string name="memory_card_editor_delete_confirm">¿Estás seguro de borrar el estado guardado \'%s\'?</string>
-    <string name="memory_card_editor_delete_success">Borrado estado guardado \'%s\'.</string>
-    <string name="memory_card_editor_delete_failed">Error al eliminar el archivo \'%s\'.</string>
-    <string name="memory_card_editor_no_card_selected">No se ha seleccionado una tarjeta.</string>
-    <string name="memory_card_editor_import_failed">Error al importar la tarjeta de memoria. Puede que no sea un formato compatible.</string>
-    <string name="memory_card_editor_delete_card_confirm_message">La tarjeta de memoria \'%s\' se eliminará y no se podra recuperar. ¿Estás seguro de eliminarlo?</string>
-    <string name="memory_card_editor_delete_card_failed">Fallo al borrar \'%s\'.</string>
-    <string name="memory_card_editor_delete_card_success">Tarjeta borrada \'%s\'.</string>
-    <string name="memory_card_editor_format_card_confirm_message">La tarjeta de memoria \'%s\' será formateada borrando todos los estados guardados. ¿Estás seguro de formatearlo?</string>
-    <string name="memory_card_editor_format_card_failed">Error al formatear \'%s\'.</string>
-    <string name="memory_card_editor_format_card_success">Tarjeta formateada \'%s\'.</string>
-    <string name="memory_card_editor_import_card_confirm_message">La importación de \'%1$s\' eliminará todos los archivos guardados en \'%2$s\'. ¿Deseas continuar?</string>
-    <string name="memory_card_editor_import_card_read_failed">Error al leer \'%s\'.</string>
-    <string name="memory_card_editor_import_card_failed">Error al importar la tarjeta \'%s\'. Puede que no sea un formato compatible.</string>
-    <string name="memory_card_editor_import_card_success">Tarjeta importada \'%s\'.</string>
-    <string name="menu_game_list_entry_choose_cover_image">Selecciona una imagen de tapa</string>
-    <string name="controller_settings_vibration_unsupported">El dispositivo seleccionado no soporta vibración.</string>
-    <string name="controller_settings_automatic_mapping">Realizar mapeo automático</string>
-    <string name="controller_settings_summary_automatic_mapping">Intenta vincular automáticamente todos los botones/ejes a un control conectado.</string>
-    <string name="controller_settings_clear_controller_bindings">Limpiar asignaciones</string>
-    <string name="controller_settings_summary_clear_controller_bindings">Desvincula todos los botones/ejes de este control.</string>
-    <string name="controller_settings_clear_controller_bindings_confirm">¿Está seguro de que desea borrar todas las asignaciones? Esto no se puede revertir.</string>
-    <string name="controller_settings_clear_controller_bindings_done">Todas las asignaciones fueron borradas para el control %d.</string>
-    <string name="controller_auto_mapping_no_devices">No se encontraron dispositivos adecuados. La asignación automática solo admite dispositivos de mando, pero aún puede vincular otros tipos de dispositivos manualmente.</string>
-    <string name="controller_auto_mapping_select_device">Seleccione el dispositivo</string>
-    <string name="controller_auto_mapping_results">Resultados de asignación automática</string>
-    <string name="main_activity_empty_game_list_title">No se encontraron juegos. Agregue un directorio con juegos o seleccione manualmente un archivo.</string>
-    <string name="main_activity_empty_game_list_supported_formats">Formatos admitidos: %s</string>
-    <string name="main_activity_empty_game_list_add_directory">Añadir directorio de juegos</string>
-    <string name="main_activity_empty_game_list_start_file">Iniciar archivo</string>
-    <string name="update_notes_title">Notas de actualización</string>
-    <string name="update_notes_message_version_controller_update">Esta actualización de DuckStation incluye soporte para múltiples controles con vibración y dispositivos vinculantes como teclados/botones de volumen.\n\nDebe volver a re-asignar sus controles, de lo contrario dejarán de funcionar. ¿Quieres hacer esto ahora?</string>
-    <string name="settings_osd_show_show_inputs">Mostrar entrada del control</string>
-    <string name="settings_summary_osd_show_inputs">Muestra el estado actual del control del sistema en la esquina inferior izquierda de la pantalla.</string>
-    <string name="touchscreen_controller_edit_menu">Editar menu</string>
-    <string name="settings_achievements_category">Cuenta</string>
-    <string name="settings_achievements_global_settings">Configuración global</string>
-    <string name="settings_category_achievements">Configuración de logros</string>
-    <string name="settings_multitap_mode">Modo Multitap</string>
-    <string name="emulation_menu_load_state">Cargar partida</string>
-    <string name="emulation_menu_save_state">Guardar partida</string>
-    <string name="emulation_menu_toggle_fast_forward">Activar avance rápido</string>
-    <string name="emulation_menu_achievements">Logros</string>
-    <string name="emulation_menu_patch_codes">Códigos de parche</string>
-    <string name="emulation_menu_change_disc">Cambiar disco</string>
-    <string name="emulation_menu_touchscreen_controller_settings">Configuración del control de pantalla táctil</string>
-    <string name="emulation_menu_toggle_analog_mode">Activar modo de control analógico</string>
-    <string name="emulation_menu_reset_console">Reiniciar consola</string>
-    <string name="emulation_menu_exit_game">Salir del juego</string>
-</resources>
diff --git a/android/app/src/main/res/values-it/arrays.xml b/android/app/src/main/res/values-it/arrays.xml
deleted file mode 100644
index 1fef79048..000000000
--- a/android/app/src/main/res/values-it/arrays.xml
+++ /dev/null
@@ -1,206 +0,0 @@
-<resources>
-    <string-array name="settings_console_region_entries">
-        <item>Auto-Rileva</item>
-        <item>NTSC-J (Giappone)</item>
-        <item>NTSC-U (US, Canada)</item>
-        <item>PAL (Europa, Australia)</item>
-    </string-array>
-    <string-array name="settings_cpu_execution_mode_entries">
-        <item>Interprete (Il più lento)</item>
-        <item>Cached Interpreter (Più veloce)</item>
-        <item>Recompiler (Il più veloce)</item>
-    </string-array>
-    <string-array name="settings_cpu_fastmem_mode_entries">
-        <item>Disabilitato (Il più lento)</item>
-        <item>MMap (Hardware, il più veloce, Solo 64-Bit)</item>
-        <item>LUT (Più veloce)</item>
-    </string-array>
-    <string-array name="gpu_renderer_entries">
-        <item>Hardware (OpenGL)</item>
-        <item>Hardware (Vulkan)</item>
-        <item>Software</item>
-    </string-array>
-    <string-array name="settings_gpu_resolution_scale_entries">
-        <item>1x</item>
-        <item>2x</item>
-        <item>3x (per 720p)</item>
-        <item>4x</item>
-        <item>5x (per 1080p)</item>
-        <item>6x (per 1440p)</item>
-        <item>7x</item>
-        <item>8x</item>
-        <item>9x (per 4K)</item>
-        <item>10x</item>
-        <item>11x</item>
-        <item>12x</item>
-        <item>13x</item>
-        <item>14x</item>
-        <item>15x</item>
-        <item>16x</item>
-    </string-array>
-    <string-array name="settings_display_crop_mode_entries">
-        <item>None</item>
-        <item>Solo area di Overscan</item>
-        <item>Tutti i bordi</item>
-    </string-array>
-    <string-array name="settings_display_aspect_ratio_names">
-        <item>Auto (Game Native)</item>
-        <item>Auto (Match Display)</item>
-        <item>Custom</item>
-        <item>4:3</item>
-        <item>16:9</item>
-        <item>19:9</item>
-        <item>20:9</item>
-        <item>PAR 1:1</item>
-    </string-array>
-    <string-array name="settings_gpu_texture_filter_names">
-        <item>Nearest-Neighbor</item>
-        <item>Bilineare</item>
-        <item>Bilineare (No Blending Bordi)</item>
-        <item>JINC2</item>
-        <item>JINC2 (No Blending Bordi)</item>
-        <item>xBR</item>
-        <item>xBR (No Blending Bordi)</item>
-    </string-array>
-    <string-array name="settings_controller_type_entries">
-        <item>None</item>
-        <item>Controller Digitale (Gamepad)</item>
-        <item>Controller Analogico (DualShock)</item>
-        <item>Analog Joystick</item>
-        <item>NeGcon</item>
-        <item>GunCon</item>
-    </string-array>
-    <string-array name="settings_memory_card_mode_entries">
-        <item>No Memory Card</item>
-        <item>Condivisa fra tutti i giochi</item>
-        <item>MC separata per ogni gioco (Codice Gioco)</item>
-        <item>MC separata per ogni gioco (Titolo Gioco)</item>
-    </string-array>
-    <string-array name="settings_cdrom_read_speedup_entries">
-        <item>Nessuna Velocità Doppia)</item>
-        <item>2x (Velocità Quadrupla</item>
-        <item>3x (Velocità 6x)</item>
-        <item>4x (Velocità 8x)</item>
-        <item>5x (Velocità 10x)</item>
-        <item>6x (Velocità 12x)</item>
-        <item>7x (Velocità 14x)</item>
-        <item>8x (Velocità 16x)</item>
-        <item>9x (Velocità 18x)</item>
-        <item>10x (Velocità 20x)</item>
-    </string-array>
-    <string-array name="settings_touchscreen_controller_view_entries">
-        <item>Nessuno</item>
-        <item>Pad Digitale</item>
-        <item>Pad Analogico Singolo</item>
-        <item>Pad Analogico Doppio</item>
-        <item>Lightgun</item>
-    </string-array>
-    <string-array name="settings_audio_backend_entries">
-        <item>Null (No Output)</item>
-        <item>Cubeb</item>
-        <item>OpenSL ES (Raccomandato)</item>
-    </string-array>
-    <string-array name="settings_audio_buffer_size_entries">
-        <item>1024 Fotogrammi (23.22ms)</item>
-        <item>2048 Fotogrammi (46.44ms, Raccomandato)</item>
-        <item>3072 Fotogrammi (69.66ms)</item>
-        <item>4096 Fotogrammi (92.88ms)</item>
-    </string-array>
-    <string-array name="settings_log_level_entries">
-        <item>None</item>
-        <item>Error</item>
-        <item>Warning</item>
-        <item>Performance Warnings</item>
-        <item>Information</item>
-        <item>Verbose</item>
-        <item>Developer</item>
-        <item>Profile</item>
-        <item>Debug</item>
-        <item>Trace</item>
-    </string-array>
-    <string-array name="settings_tabs">
-        <item>Generali</item>
-        <item>Display</item>
-        <item>Audio</item>
-        <item>Miglioramenti</item>
-        <item>Achievements</item>
-        <item>Avanzate</item>
-    </string-array>
-    <string-array name="settings_gpu_msaa_entries">
-        <item>Disabilitato</item>
-        <item>2x MSAA</item>
-        <item>4x MSAA</item>
-        <item>8x MSAA</item>
-        <item>2x SSAA</item>
-        <item>4x SSAA</item>
-        <item>8x SSAA</item>
-    </string-array>
-    <string-array name="settings_advanced_display_fps_limit_entries">
-        <item>Senza Limite (Mostra tutti i fotogrammi)</item>
-        <item>10 FPS</item>
-        <item>15 FPS</item>
-        <item>30 FPS</item>
-        <item>45 FPS</item>
-        <item>60 FPS</item>
-        <item>75 FPS</item>
-        <item>90 FPS</item>
-    </string-array>
-    <string-array name="settings_emulation_speed_entries">
-        <item>Senza Limite</item>
-        <item>10% [6 FPS (NTSC) / 5 FPS (PAL)]</item>
-        <item>20% [12 FPS (NTSC) / 10 FPS (PAL)]</item>
-        <item>30% [18 FPS (NTSC) / 15 FPS (PAL)]</item>
-        <item>40% [24 FPS (NTSC) / 20 FPS (PAL)]</item>
-        <item>50% [30 FPS (NTSC) / 25 FPS (PAL)]</item>
-        <item>60% [36 FPS (NTSC) / 30 FPS (PAL)]</item>
-        <item>70% [42 FPS (NTSC) / 35 FPS (PAL)]</item>
-        <item>80% [48 FPS (NTSC) / 40 FPS (PAL)]</item>
-        <item>90% [54 FPS (NTSC) / 45 FPS (PAL)]</item>
-        <item>100% [60 FPS (NTSC) / 50 FPS (PAL), Default]</item>
-        <item>125% [75 FPS (NTSC) / 62 FPS (PAL)]</item>
-        <item>150% [90 FPS (NTSC) / 75 FPS (PAL)]</item>
-        <item>175% [105 FPS (NTSC) / 87 FPS (PAL)]</item>
-        <item>200% [120 FPS (NTSC) / 100 FPS (PAL)]</item>
-        <item>250% [150 FPS (NTSC) / 125 FPS (PAL)]</item>
-        <item>300% [180 FPS (NTSC) / 150 FPS (PAL)]</item>
-        <item>350% [210 FPS (NTSC) / 175 FPS (PAL)]</item>
-        <item>400% [240 FPS (NTSC) / 200 FPS (PAL)]</item>
-        <item>450% [270 FPS (NTSC) / 225 FPS (PAL)]</item>
-        <item>500% [300 FPS (NTSC) / 250 FPS (PAL)]</item>
-        <item>600% [360 FPS (NTSC) / 300 FPS (PAL)]</item>
-        <item>700% [420 FPS (NTSC) / 350 FPS (PAL)]</item>
-        <item>800% [480 FPS (NTSC) / 400 FPS (PAL)]</item>
-        <item>900% [540 FPS (NTSC) / 450 FPS (PAL)]</item>
-        <item>1000% [600 FPS (NTSC) / 500 FPS (PAL)]</item>
-    </string-array>
-    <string-array name="settings_advanced_cpu_overclock_entries">
-        <item>25% (8MHz)</item>
-        <item>50% (16MHz)</item>
-        <item>75% (24MHz)</item>
-        <item>100% (33MHz, Default)</item>
-        <item>125% (41MHz)</item>
-        <item>150% (49MHz)</item>
-        <item>175% (57MHz)</item>
-        <item>200% (66MHz)</item>
-        <item>225% (74MHz)</item>
-        <item>250% (82MHz)</item>
-        <item>275% (90MHz)</item>
-        <item>300% (99MHz)</item>
-        <item>350% (115MHz)</item>
-        <item>400% (132MHz)</item>
-        <item>450% (148MHz)</item>
-        <item>500% (165MHz)</item>
-        <item>500% (165MHz)</item>
-        <item>600% (198MHz)</item>
-        <item>700% (231MHz)</item>
-        <item>800% (264MHz)</item>
-        <item>900% (297MHz)</item>
-        <item>1000% (330MHz)</item>
-    </string-array>
-    <string-array name="settings_emulation_screen_orientation_entries">
-        <item>Usa Impostazione Dispositivo</item>
-        <item>Verticale</item>
-        <item>Orizzontale</item>
-        <item>Sensor Based</item>
-    </string-array>
-</resources>
diff --git a/android/app/src/main/res/values-it/strings.xml b/android/app/src/main/res/values-it/strings.xml
deleted file mode 100644
index edcd29639..000000000
--- a/android/app/src/main/res/values-it/strings.xml
+++ /dev/null
@@ -1,16 +0,0 @@
-<resources>
-    <string name="app_name">DuckStation</string>
-    <string name="action_settings">Impostazioni</string>
-    <string name="title_activity_settings">Impostazioni</string>
-    <string name="settings_console_region">Regione Console</string>
-    <string name="settings_console_tty_output">Abilita TTY Output</string>
-    <string name="settings_console_fast_boot">Avvio Rapido</string>
-    <string name="settings_osd_show_messages">Mostra Messaggi</string>
-    <string name="settings_osd_show_speed">Mostra Velocità Emulazione</string>
-    <string name="settings_osd_show_show_fps">Mostra la frequenza dei fotogrammi del gioco</string>
-    <string name="settings_osd_show_show_vps">Mostra FPS di visualizzazione</string>
-    <string name="settings_cpu_execution_mode">Modalità di Esecuzione CPU</string>
-    <string name="settings_gpu_renderer">GPU Renderer</string>
-    <string name="settings_gpu_resolution_scale">Scala di Risoluzione</string>
-    <string name="title_activity_emulation">EmulationActivity</string>
-</resources>
diff --git a/android/app/src/main/res/values-night/colors.xml b/android/app/src/main/res/values-night/colors.xml
deleted file mode 100644
index 6801baa94..000000000
--- a/android/app/src/main/res/values-night/colors.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<resources>
-    <color name="colorPrimary">#000000</color>
-    <color name="colorPrimaryDark">#000000</color>
-    <color name="colorAccent">#03A9F4</color>
-    <color name="colorNavigation">#000000</color>
-
-    <color name="black_overlay">#66000000</color>
-    <color name="fab_background">#222222</color>
-
-    <color name="emulationActivityPauseBackground">#cc000000</color>
-</resources>
diff --git a/android/app/src/main/res/values-nl/arrays.xml b/android/app/src/main/res/values-nl/arrays.xml
deleted file mode 100644
index 4f0cdfedb..000000000
--- a/android/app/src/main/res/values-nl/arrays.xml
+++ /dev/null
@@ -1,206 +0,0 @@
-<resources>
-    <string-array name="settings_console_region_entries">
-        <item>Automatisch Detecteren</item>
-        <item>NTSC-J (Japan)</item>
-        <item>NTSC-U (VS)</item>
-        <item>PAL (Europa, Australië)</item>
-    </string-array>
-    <string-array name="settings_cpu_execution_mode_entries">
-        <item>Interpreter (Langzaamst)</item>
-        <item>Cached Interpreter (Sneller)</item>
-        <item>Recompiler (Snelst)</item>
-    </string-array>
-    <string-array name="settings_cpu_fastmem_mode_entries">
-        <item>Uitgeschakeld (Langzaamst)</item>
-        <item>MMap (Hardware, Snelst, Alleen 64-Bit)</item>
-        <item>LUT (Sneller)</item>
-    </string-array>
-    <string-array name="gpu_renderer_entries">
-        <item>Hardware (OpenGL)</item>
-        <item>Hardware (Vulkan)</item>
-        <item>Software</item>
-    </string-array>
-    <string-array name="settings_gpu_resolution_scale_entries">
-        <item>1x</item>
-        <item>2x</item>
-        <item>3x (voor 720p)</item>
-        <item>4x</item>
-        <item>5x (voor 1080p)</item>
-        <item>6x (voor 1440p)</item>
-        <item>7x</item>
-        <item>8x</item>
-        <item>9x (voor 4K)</item>
-        <item>10x</item>
-        <item>11x</item>
-        <item>12x</item>
-        <item>13x</item>
-        <item>14x</item>
-        <item>15x</item>
-        <item>16x</item>
-    </string-array>
-    <string-array name="settings_display_crop_mode_entries">
-        <item>Geen</item>
-        <item>Alleen Overscangebied</item>
-        <item>Alle Randen</item>
-    </string-array>
-    <string-array name="settings_display_aspect_ratio_names">
-        <item>Auto (Game Native)</item>
-        <item>Auto (Match Display)</item>
-        <item>Custom</item>
-        <item>4:3</item>
-        <item>16:9</item>
-        <item>19:9</item>
-        <item>20:9</item>
-        <item>PAR 1:1</item>
-    </string-array>
-    <string-array name="settings_gpu_texture_filter_names">
-        <item>Dichtstbijzijde</item>
-        <item>Bilineair</item>
-        <item>Bilineair (Geen Edge Blending)</item>
-        <item>JINC2</item>
-        <item>JINC2 (Geen Edge Blending)</item>
-        <item>xBR</item>
-        <item>xBR (Geen Edge Blending)</item>
-    </string-array>
-    <string-array name="settings_controller_type_entries">
-        <item>None</item>
-        <item>Digitale Controller (Gamepad)</item>
-        <item>Analoge Controller (DualShock)</item>
-        <item>Analog Joystick</item>
-        <item>NeGcon</item>
-        <item>GunCon</item>
-    </string-array>
-    <string-array name="settings_memory_card_mode_entries">
-        <item>Geen Geheugenkaart</item>
-        <item>Gedeeld Tussen Alle Spellen</item>
-        <item>Aparte Kaart Per Spel (Spelcode)</item>
-        <item>Aparte Kaart Per Spel (Speltitel)</item>
-    </string-array>
-    <string-array name="settings_cdrom_read_speedup_entries">
-        <item>Geen (Dubbele Snelheid)</item>
-        <item>2x (Vierdubbele Snelheid)</item>
-        <item>3x (6x Snelheid)</item>
-        <item>4x (8x Snelheid)</item>
-        <item>5x (10x Snelheid)</item>
-        <item>6x (12x Snelheid)</item>
-        <item>7x (14x Snelheid)</item>
-        <item>8x (16x Snelheid)</item>
-        <item>9x (18x Snelheid)</item>
-        <item>10x (20x Snelheid)</item>
-    </string-array>
-    <string-array name="settings_touchscreen_controller_view_entries">
-        <item>Geen</item>
-        <item>Digitale Pad</item>
-        <item>Enekele Analoge Pad</item>
-        <item>Dubbele Analoge Pad</item>
-        <item>Lightgun</item>
-    </string-array>
-    <string-array name="settings_audio_backend_entries">
-        <item>Null (Geen Output)</item>
-        <item>Cubeb</item>
-        <item>OpenSL ES (Aanbevolen)</item>
-    </string-array>
-    <string-array name="settings_audio_buffer_size_entries">
-        <item>1024 Frames (23.22ms)</item>
-        <item>2048 Frames (46.44ms, Recommended)</item>
-        <item>3072 Frames (69.66ms)</item>
-        <item>4096 Frames (92.88ms)</item>
-    </string-array>
-    <string-array name="settings_log_level_entries">
-        <item>Geen</item>
-        <item>Fout</item>
-        <item>Waarschuwing</item>
-        <item>Uitgebreid</item>
-        <item>Prestatie Waarschuwingen</item>
-        <item>Informatie</item>
-        <item>Ontwikkelaar</item>
-        <item>Profiel</item>
-        <item>Debug</item>
-        <item>Trace</item>
-    </string-array>
-    <string-array name="settings_tabs">
-        <item>Algemeen</item>
-        <item>Weergave</item>
-        <item>Audio</item>
-        <item>Verbeteringen</item>
-        <item>Achievements</item>
-        <item>Geavanceerd</item>
-    </string-array>
-    <string-array name="settings_gpu_msaa_entries">
-        <item>Uitgeschakeld</item>
-        <item>2x MSAA</item>
-        <item>4x MSAA</item>
-        <item>8x MSAA</item>
-        <item>2x SSAA</item>
-        <item>4x SSAA</item>
-        <item>8x SSAA</item>
-    </string-array>
-    <string-array name="settings_advanced_display_fps_limit_entries">
-        <item>Onbegrensd (Alle Frames Weergeven)</item>
-        <item>10 FPS</item>
-        <item>15 FPS</item>
-        <item>30 FPS</item>
-        <item>45 FPS</item>
-        <item>60 FPS</item>
-        <item>75 FPS</item>
-        <item>90 FPS</item>
-    </string-array>
-    <string-array name="settings_emulation_speed_entries">
-        <item>Onbegrensd</item>
-        <item>10% [6 FPS (NTSC) / 5 FPS (PAL)]</item>
-        <item>20% [12 FPS (NTSC) / 10 FPS (PAL)]</item>
-        <item>30% [18 FPS (NTSC) / 15 FPS (PAL)]</item>
-        <item>40% [24 FPS (NTSC) / 20 FPS (PAL)]</item>
-        <item>50% [30 FPS (NTSC) / 25 FPS (PAL)]</item>
-        <item>60% [36 FPS (NTSC) / 30 FPS (PAL)]</item>
-        <item>70% [42 FPS (NTSC) / 35 FPS (PAL)]</item>
-        <item>80% [48 FPS (NTSC) / 40 FPS (PAL)]</item>
-        <item>90% [54 FPS (NTSC) / 45 FPS (PAL)]</item>
-        <item>100% [60 FPS (NTSC) / 50 FPS (PAL), Default]</item>
-        <item>125% [75 FPS (NTSC) / 62 FPS (PAL)]</item>
-        <item>150% [90 FPS (NTSC) / 75 FPS (PAL)]</item>
-        <item>175% [105 FPS (NTSC) / 87 FPS (PAL)]</item>
-        <item>200% [120 FPS (NTSC) / 100 FPS (PAL)]</item>
-        <item>250% [150 FPS (NTSC) / 125 FPS (PAL)]</item>
-        <item>300% [180 FPS (NTSC) / 150 FPS (PAL)]</item>
-        <item>350% [210 FPS (NTSC) / 175 FPS (PAL)]</item>
-        <item>400% [240 FPS (NTSC) / 200 FPS (PAL)]</item>
-        <item>450% [270 FPS (NTSC) / 225 FPS (PAL)]</item>
-        <item>500% [300 FPS (NTSC) / 250 FPS (PAL)]</item>
-        <item>600% [360 FPS (NTSC) / 300 FPS (PAL)]</item>
-        <item>700% [420 FPS (NTSC) / 350 FPS (PAL)]</item>
-        <item>800% [480 FPS (NTSC) / 400 FPS (PAL)]</item>
-        <item>900% [540 FPS (NTSC) / 450 FPS (PAL)]</item>
-        <item>1000% [600 FPS (NTSC) / 500 FPS (PAL)]</item>
-    </string-array>
-    <string-array name="settings_advanced_cpu_overclock_entries">
-        <item>25% (8MHz)</item>
-        <item>50% (16MHz)</item>
-        <item>75% (24MHz)</item>
-        <item>100% (33MHz, Default)</item>
-        <item>125% (41MHz)</item>
-        <item>150% (49MHz)</item>
-        <item>175% (57MHz)</item>
-        <item>200% (66MHz)</item>
-        <item>225% (74MHz)</item>
-        <item>250% (82MHz)</item>
-        <item>275% (90MHz)</item>
-        <item>300% (99MHz)</item>
-        <item>350% (115MHz)</item>
-        <item>400% (132MHz)</item>
-        <item>450% (148MHz)</item>
-        <item>500% (165MHz)</item>
-        <item>500% (165MHz)</item>
-        <item>600% (198MHz)</item>
-        <item>700% (231MHz)</item>
-        <item>800% (264MHz)</item>
-        <item>900% (297MHz)</item>
-        <item>1000% (330MHz)</item>
-    </string-array>
-    <string-array name="settings_emulation_screen_orientation_entries">
-        <item>Apparaatinstellingen Gebruiken</item>
-        <item>Portret</item>
-        <item>Landschap</item>
-        <item>Sensor Based</item>
-    </string-array>
-</resources>
\ No newline at end of file
diff --git a/android/app/src/main/res/values-nl/strings.xml b/android/app/src/main/res/values-nl/strings.xml
deleted file mode 100644
index 8c17c4277..000000000
--- a/android/app/src/main/res/values-nl/strings.xml
+++ /dev/null
@@ -1,152 +0,0 @@
-<resources>
-    <string name="app_name">DuckStation</string>
-    <string name="action_settings">Instellingen</string>
-    <string name="title_activity_settings">Instellingen</string>
-    <string name="settings_console_region">Console Gebied</string>
-    <string name="settings_console_tty_output">TTY Output Aanzetten</string>
-    <string name="settings_console_fast_boot">Snel Starten</string>
-    <string name="settings_osd_show_messages">Toon Berichten</string>
-    <string name="settings_osd_show_speed">Toon Emulatiesnelheid</string>
-    <string name="settings_osd_show_show_fps">Framesnelheid van games weergeven</string>
-    <string name="settings_osd_show_show_vps">Toon weergave FPS</string>
-    <string name="settings_cpu_execution_mode">CPU Executie Modus</string>
-    <string name="settings_gpu_renderer">GPU Renderer</string>
-    <string name="settings_gpu_resolution_scale">Resolutie Schaal</string>
-    <string name="title_activity_emulation">Emulatie Activiteit</string>
-    <string name="settings_emulation_speed">Emulatie Snelheid</string>
-    <string name="settings_fast_forward_speed">Doorspoelsnelheid</string>
-    <string name="settings_save_state_on_exit">Staat Opslaan Bij Afsluiten</string>
-    <string name="settings_emulation_screen_orientation">Emulatie Schermorientatie</string>
-    <string name="settings_load_patch_codes">Laad Patch Codes</string>
-    <string name="settings_summary_save_state_on_exit">Slaat automatisch de emulator staat op bij afsluiten. Je kan dan de volgende keer verder vanaf waar je gebleven was.</string>
-    <string name="settings_summary_load_patch_codes"><![CDATA[Laad patch codes van cheats/<game name>.cht in PCSXR formaat. Codes kunnen aan- en uitgeschakeld worden in-game.]]></string>
-    <string name="settings_apply_compatibility_settings">Pas Compatibiliteitsinstellingen Toe</string>
-    <string name="settings_summary_apply_compatibility_settings">Schakelt automatisch verbeteringen uit wanneer ze niet door spellen ondersteund worden.</string>
-    <string name="settings_summary_video_sync">Schakel deze optie in om DuckStation\'s verversingssnelheid te synchroniseren met je scherm. VSync is automatisch uitegeschakeld wanneer dit niet mogelijk is (bijvoorbeeld wanneer er niet op 100% snelheid gespeeld wordt).</string>
-    <string name="settings_video_sync">Video Sync</string>
-    <string name="settings_cpu_overclocking">CPU Overclocken</string>
-    <string name="settings_cdrom_region_check">CD-ROM Regio Check</string>
-    <string name="settings_summary_cdrom_region_check">Voorkomt dat discs uit incorrecte regio\'s geladen worden door de emulator. Over het algemeen veilig om uit te schakelen.</string>
-    <string name="settings_cdrom_preload_image_to_ram">CD-ROM Image Voorladen naar RAM</string>
-    <string name="settings_summary_preload_image_to_ram">Laadt de image van het spel in RAM. Handig voor netwerkpaden die instabiel kunnen worden tijdens het spelen van het spelen. Kan soms ook haperingen voorkomen wanneer spellen audio instellen.</string>
-    <string name="settings_pgxp_vertex_cache">PGXP Vertex Cache</string>
-    <string name="settings_summary_pgxp_vertex_cache">Gebruikt schermcoordinaten als terugval wanneer vertices niet door het geheugen getraceerd kunnen worden. Kan PGXP compatibiliteit verbeteren.</string>
-    <string name="settings_pgxp_cpu_mode">PGXP CPU Modus</string>
-    <string name="settings_summary_pgxp_cpu_mode">Probeert vertex manupulatie te traceren door de CPU. Sommige spellen vereisen deze optie om PGXP te gebruiken. Heel langzaam, en incompatibel met de recompiler.</string>
-    <string name="settings_cpu_recompiler_icache">CPU Recompiler ICache</string>
-    <string name="settings_summary_cpu_recompiler_icache">Bepaalt of de CPU\'s instructie cache gesimuleerd wordt in de recompiler. Verbetert precisie, maar kost een klein beetje prestatie. Als games te snel afspelen, probeer dan deze optie aan te zetten.</string>
-    <string name="settings_cpu_recompiler_fastmem">CPU Recompiler Fast Memory Access</string>
-    <string name="settings_summary_cpu_recompiler_fastmem">Maakt geheugentoegang van het gesimuleerde systeem meer efficient door page faults en backpatching te gebruiken. Schakel dit uit als het instabiel is op je systeem.</string>
-    <string name="settings_presented_frame_limit">Getoonde Frame Begrenzing</string>
-    <string name="settings_logging_level">Logging Niveau</string>
-    <string name="settings_log_to_file">Log Naar Bestand</string>
-    <string name="settings_summary_log_to_file">Schrijft de log naar duckstation.log in je gebruikersfolder. Gebruik dit alleen voor debuggen, want het kan vertraagt de emulatie.</string>
-    <string name="settings_log_to_logcat">Log Naar Logcat</string>
-    <string name="settings_summary_log_to_logcat">Schrijft logberichten naar de Android berichtenlog. Alleen nuttig wanneer gebruikt in combinatie met een computer met adb.</string>
-    <string name="settings_volume">Volume</string>
-    <string name="settings_summary_volume">Bedient het volume van de emulator.</string>
-    <string name="settings_mute_all_sound">Alles Dempen</string>
-    <string name="settings_summary_mute_all_sound">Voorkomt dat de emulator geluid produceert.</string>
-    <string name="settings_mute_cd_audio">CD Audio Dempen</string>
-    <string name="settings_summary_mute_cd_audio">Dempt zowel CD-DA en XA audio van de CD-ROM. Kan gebruikt worden om achtergrondmuziek uit te schakelen in sommige spellen.</string>
-    <string name="settings_audio_backend">Audio Backend</string>
-    <string name="settings_audio_buffer_size">Audio Buffer Grootte</string>
-    <string name="settings_summary_audio_buffer_size">Bepaald de vertraging tussen de audiogeneratie en de output van de speakers. Kleinere waardes kunnen vertraging verkleinen, maar variaties in emulatiesnelheid kunnen voor haperingen zorgen.</string>
-    <string name="settings_audio_sync">Audio Sync</string>
-    <string name="settings_summary_audio_sync">Beperkt de emulatiesnelheid gebaseerd op hoe snel de audio backend samples opvraagt. Dit helpt om ruis en kraken te voorkomen wanneer de emulator te snel gaat. Wordt automatisch uitgeschakeld wanneer er niet op 100% snelheid afgespeeld wordt.</string>
-    <string name="settings_controller_type">Controller Type</string>
-    <string name="settings_enable_analog_mode_on_reset">Analoge Modus Bij Reset.</string>
-    <string name="settings_touchscreen_controller_view">Touchscreen Controller Beeld</string>
-    <string name="settings_auto_hide_touchscreen_controller">Automatisch Touchscreen Controller Verbergen</string>
-    <string name="settings_summary_auto_hide_touchscreen_controller">Verbergt de touchscreen controller wanneer een externe controller gedetecteerd wordt.</string>
-    <string name="settings_vibrate_on_press">Vibreren Bij Indrukking</string>
-    <string name="settings_summary_vibrate_on_press">Schakelt een kleine trilling in wanneer een touchscreenknop ingedrukt wordt. Vereist dat \"Trillen bij aanraking\" ingeschakeld is op je apparaat.</string>
-    <string name="settings_enable_vibration">Vibratie Inschakelen</string>
-    <string name="settings_summary_enable_vibration">Vibreert de telefoon wanneer de spel dit voor een controller doet.</string>
-    <string name="settings_memory_card_1_type">Geheugenkaart 1 Type</string>
-    <string name="settings_memory_card_2_type">Geheugenkaart 2 Type</string>
-    <string name="settings_crop_mode">Knip Modus</string>
-    <string name="settings_aspect_ratio">Schermverhouding</string>
-    <string name="settings_linear_upscaling">Lineaire Opschaling</string>
-    <string name="settings_integer_upscaling">Integer Opschaling</string>
-    <string name="settings_summary_linear_upscaling">Interpoleert tussen pixels wanneer het beeld opgeschaald wordt naar het apparaat.</string>
-    <string name="settings_summary_integer_upscaling">Voegt randen toe aan het beeld zodat de verhouding tussen pixels op het apparaat, en pixels van de console een geheel getal is. Kan voor een scherper beeld zorgen in sommige 2D games.</string>
-    <string name="settings_summary_osd_show_messages">Toont berichten op het scherm wanneer gebeurtenissen als het opslaan/laden van een spelstatus, schermafbeeldingen maken, etc. gebeuren.</string>
-    <string name="settings_summary_osd_show_speed">Zet een doelsnelheid voor de emulatie. Het is niet gegarandeerd dat deze snelheid behaald wordt. Zo niet, dan gaat de emulator zo snel als hij kan.</string>
-    <string name="settings_summary_osd_show_fps">Toont de interne framesnelheid van het spel in de rechter bovenhoek van het scherm.</string>
-    <string name="settings_summary_osd_show_vps">Toont het aantal frames (of v-syncs) van het systeem in de rechter bovenhoek van het scherm.</string>
-    <string name="settings_cdrom_read_speedup">CD-ROM Leesversnelling</string>
-    <string name="settings_summary_cdrom_read_speedup">Versnelt de CD-ROM leessnelheid met de gegeven factor. Alleen van toepassing op dubbele-snelheids leesoperaties, en genegeerd wanneer audio afspeelt. Kan laadsnelheden vergroten bij sommige spellen, maar kan andere spellen niet goed laten werken.</string>
-    <string name="settings_summary_console_fast_boot">Slaat de BIOS intro over, en start direct het spel. Over het algemeen veilig om in te schakelen, maar sommige spellen werken niet goed meer.</string>
-    <string name="settings_msaa">Multisample Antialiasing</string>
-    <string name="settings_true_color">True Color Rendering (24-bit, schakelt dithering uit)</string>
-    <string name="settings_summary_true_color">Dit produceert mooiere gradienten, maar kan sommige kleuren een klein beetje verkleuren. Uitschakelen schakelt ook dithering uit. De meeste spellen zijn compatibel met deze optie.</string>
-    <string name="settings_scaled_dithering">Geschaalde Dithering (schaal dither patrron naar resolutie)</string>
-    <string name="settings_summary_scaled_dithering">Schaalt het dither patroon naar de resolutieschaal van de geëmuleerde GPU. Dit maakt het ditherpatroon minder duidelijk bij hogere resoluties. Over het algemeen veilig in te schakelen. Werkt alleen bij hardware renderers.</string>
-    <string name="settings_disable_interlacing">Interlacing Uitschakelen(forceer progressieve render/scan)</string>
-    <string name="settings_summary_disable_interlacing">Forceert het renderen en weergeven van frames naar de progressieve modus. Dit verwijdert het \"kam\" effect gezien in 480i spellen door ze in 480p te rendreren. Meestal veilig om in te schakelen.</string>
-    <string name="settings_texture_filtering">Texture Filtering</string>
-    <string name="settings_force_ntsc_timings">Forceer NTSC Timings (60hz-on-PAL)</string>
-    <string name="settings_summary_force_ntsc_timings">Gebruikt NTSC frame timings wanneer de console in PAL modus is. Dwingt PAL spellen om in 60hz af te spelen.</string>
-    <string name="settings_widescreen_hack">Widescreen Hack</string>
-    <string name="settings_summary_widescreen_hack">Schaalt vertex posities in schermruimte op naar een breedbeeldverhouding, wat in essentie het gezichtsveld van 4:3 naar 16:9 verhoogt in 3D spellen. Niet compatibel met alle spellen.</string>
-    <string name="settings_force_4_3_for_24bit">Forceer 4:3 Voor 24-Bit Schermen</string>
-    <string name="settings_summary_force_4_3_for_24bit">Gaat terug naar een 4:3 schermverhouding wanneer 24-bit inhoud weergeven wordt, meestal FMVs.</string>
-    <string name="settings_chroma_smoothing_24bit">Chroma Smoothing Voor 24-Bit Schermen</string>
-    <string name="settings_summary_chrome_smoothing_24bit">Vermindert de blokkerigheid bij kleurtransities van 24-bit inhoud, meestal FMVs. Alleen van toepassing bij hardware renderers.</string>
-    <string name="settings_pgxp_geometry_correction">PGXP Geometry Correction</string>
-    <string name="settings_summary_pgxp_geometry_correction"><![CDATA[Vermindert \"wiebelige\" polygons en \"vervormde\" textures die vaak in PS1 spellen voorkomen. >Werkt alleen met hardware renderers. Mogelijk niet compatibel met alle spellen.]]></string>
-    <string name="settings_pgxp_culling_correction">PGXP Culling Correction</string>
-    <string name="settings_summary_pgxp_culling_correction">Verhoogt de precisie van polygon culling, vermindert het aantal gaten in objecten. Vereist dat \"geometry correction\" ingeschakeld is.</string>
-    <string name="settings_pgxp_texture_correction">PGXP Texture Correction</string>
-    <string name="settings_summary_pgxp_texture_correction">Gebruikt perspectief-correcte interpolatie voor texture coordinaten en kleuren, maakt vervormde textures weer glad. Vereist dat \"geometry correction\" ingeschakeld is.</string>
-    <string name="settings_pgxp_preserve_projection_precision">PGXP Behoud Projectie Precisie</string>
-    <string name="settings_summary_pgxp_preserve_projection_precision">Schakelt extra precisie in voor PGXP. Kan beeld verbeteren in sommige spellen, maar kan andere minder goed laten werken.</string>
-    <string name="menu_main_resume_last_session">Hervat Vorige Sessie</string>
-    <string name="menu_main_start_file">Start Bestand</string>
-    <string name="menu_main_start_bios">Start BIOS</string>
-    <string name="menu_main_edit_game_directories">Bewerk Gamemappen</string>
-    <string name="menu_main_scan_for_new_games">Scan Naar Nieuwe Spellen</string>
-    <string name="menu_main_rescan_all_games">Alle Spellen Opnieuw Scannen</string>
-    <string name="menu_main_import_bios">Importeer BIOS</string>
-    <string name="menu_main_show_version">Toon Versie</string>
-    <string name="menu_main_github_repository">GitHub Repository</string>
-    <string name="menu_main_discord_server">Discord Server</string>
-    <string name="menu_game_list_entry_start_game">Start Spel</string>
-    <string name="menu_game_list_entry_resume_game">Hervat Spel</string>
-    <string name="android_progress_callback_please_wait">Wachten alstublieft...</string>
-    <string name="android_progress_callback_ok">Oké</string>
-    <string name="android_progress_callback_information">Informatie</string>
-    <string name="android_progress_callback_confirmation">Bevestiging</string>
-    <string name="android_progress_callback_yes">Ja</string>
-    <string name="android_progress_callback_no">Nee</string>
-    <string name="emulation_activity_error">Fout</string>
-    <string name="emulation_activity_ok">Oké</string>
-    <string name="emulation_activity_import_patch_codes">Importeer Patch Codes...</string>
-    <string name="emulation_activity_patch_on">(AAN)</string>
-    <string name="emulation_activity_patch_off">(UIT)</string>
-    <string name="emulation_activity_choose_patch_code_file">Kies Een Patch Code Bestand</string>
-    <string name="emulation_activity_failed_to_import_patch_codes">Patch codes importeren mislukt. Selecteer een PCSXR of Libretro formaat bestand.</string>
-    <string name="main_activity_choose_directory">Kies folder</string>
-    <string name="main_activity_error">Fout</string>
-    <string name="main_activity_get_path_from_file_error">Mislukt om het bestand op te halen. Zorg ervoor dat het bestand in de interne/externe opslag is.\n\nTik op de overflow knop in de folderselectie.\nSelecteer "Toon Interne Opslag".\nTik op de menuknop en selecteer uw apparaat of SD kaart.</string>
-    <string name="main_activity_ok">Oké</string>
-    <string name="main_activity_get_path_from_directory_error">Pad van folder ophalen mislukt.Zorg ervoor dat de folder in de interne/externe opslag is.\n\nTik op de overflow knop in de folderselectie.\nSelecteer "Toon Interne Opslag".\nTik op de menuknop en selecteer uw apparaat of SD kaart.</string>
-    <string name="main_activity_external_storage_permissions_error">Toegang tot externe opslag nodig om DuckStation te gebruiken.</string>
-    <string name="main_activity_choose_disc_image">Kies Disc Image</string>
-    <string name="main_activity_missing_bios_image_prompt">Er was geen BIOS image was gevonden in DuckStation\'s bios folder. Wilt u nu een BIOS image importeren?</string>
-    <string name="main_activity_missing_bios_image">Ontbrekende BIOS Image</string>
-    <string name="main_activity_yes">Ja</string>
-    <string name="main_activity_no">Nee</string>
-    <string name="main_activity_choose_bios_image">Kies BIOS Image</string>
-    <string name="main_activity_failed_to_open_bios_image">BIOS image openen mislukt.</string>
-    <string name="main_activity_failed_to_read_bios_image_prefix">\"BIOS image lezen mislukt: \"</string>
-    <string name="main_activity_bios_image_too_large">BIOS-image is te groot. U moet een BIOS-image selecteren, geen game, en deze moet 512 KB groot zijn.</string>
-    <string name="main_activity_invalid_error">Deze BIOS image is ongeldig, of is al geimporteerd.</string>
-    <string name="main_activity_show_version_title">Versie</string>
-    <string name="main_activity_copy">Kopieer</string>
-    <string name="settings_fast_forward_volume">Doorspoel Volume</string>
-    <string name="settings_summary_fast_forward_volume">Bedient het volume van de emulator wanneer het spel sneller afgespeeld wordt.</string>
-    <string name="settings_gpu_thread">Threaded GPU Rendering</string>
-    <string name="settings_summary_gpu_thread">Gebruikt een tweede thread voor het renderen van graphics. Op het moment alleen beschikbaar voor software renderers, maar kan een significante snelheidsverbetering opleveren, en is veilig te gebruiken.</string>
-</resources>
diff --git a/android/app/src/main/res/values-pt-rBR/arrays.xml b/android/app/src/main/res/values-pt-rBR/arrays.xml
deleted file mode 100644
index 21379782a..000000000
--- a/android/app/src/main/res/values-pt-rBR/arrays.xml
+++ /dev/null
@@ -1,264 +0,0 @@
-<resources>
-    <string-array name="settings_console_region_entries">
-        <item>Auto-Detectar</item>
-        <item>NTSC-J (Japão)</item>
-        <item>NTSC-U (US)</item>
-        <item>PAL (Europa, Austrália)</item>
-    </string-array>
-    <string-array name="settings_cpu_execution_mode_entries">
-        <item>Interpretador (Mais Lento)</item>
-        <item>Interpretador Armazenado (Rápido)</item>
-        <item>Recompilador (Mais Rápido)</item>
-    </string-array>
-    <string-array name="settings_cpu_fastmem_mode_entries">
-        <item>Desabilitado (Lento)</item>
-        <item>MMap (Hardware, Mais Rápido, (Dispositivos 64-Bits)</item>
-        <item>LUT (Rápido)</item>
-    </string-array>
-    <string-array name="gpu_renderer_entries">
-        <item>Dedicado (OpenGL)</item>
-        <item>Dedicado (Vulkan)</item>
-        <item>Aplicativo</item>
-    </string-array>
-    <string-array name="settings_gpu_resolution_scale_entries">
-        <item>1x</item>
-        <item>2x</item>
-        <item>3x (para 720p)</item>
-        <item>4x</item>
-        <item>5x (para 1080p)</item>
-        <item>6x (para 1440p)</item>
-        <item>7x</item>
-        <item>8x</item>
-        <item>9x (para 4K)</item>
-        <item>10x</item>
-        <item>11x</item>
-        <item>12x</item>
-        <item>13x</item>
-        <item>14x</item>
-        <item>15x</item>
-        <item>16x</item>
-    </string-array>
-    <string-array name="settings_display_crop_mode_entries">
-        <item>Nenhum</item>
-        <item>Área Renderizada</item>
-        <item>Todas as Bordas</item>
-    </string-array>
-    <string-array name="settings_display_aspect_ratio_names">
-      <item>Auto (Nativo)</item>
-      <item>Auto (Corresponder a Janela)</item>
-      <item>Custom</item>
-      <item>4:3</item>
-      <item>16:9</item>
-      <item>19:9</item>
-      <item>20:9</item>
-      <item>PAR 1:1</item>
-    </string-array>
-    <string-array name="settings_gpu_texture_filter_names">
-        <item>Nearest-Neighbor</item>
-        <item>Bilinear</item>
-        <item>Bilinear (Sem AA)</item>
-        <item>JINC2</item>
-        <item>JINC2 (Sem AA)</item>
-        <item>xBR</item>
-        <item>xBR (Sem AA)</item>
-    </string-array>
-    <string-array name="settings_controller_type_entries">
-        <item>Nenhum</item>
-        <item>Controle Digital (Gamepad)</item>
-        <item>Controle Analógico (DualShock)</item>
-        <item>Joystick Analógico</item>
-        <item>NeGcon</item>
-        <item>GunCon</item>
-    </string-array>
-    <string-array name="settings_memory_card_mode_entries">
-        <item>Sem Cartão de Memória</item>
-        <item>Compartilhada entre Jogos</item>
-        <item>Separado Por Jogo (Cód. Jogo)</item>
-        <item>Separado Por Jogo (Título Jogo)</item>
-    </string-array>
-    <string-array name="emulation_touchscreen_menu">
-		<item>Mudar</item>
-		<item>Ajustar Visibilidade</item>
-		<item>Adicionar/Remover botões</item>
-        <item>Mover Botões</item>
-        <item>Redimensionar Botões</item>
-        </string-array>
-    <string-array name="touchscreen_layout_menu">
-        <item>Mudar Opacidade</item>
-        <item>Adicionar/Remover Botões</item>
-        <item>Mover Botões</item>
-        <item>Redimensionar Botões</item>
-        <item>Redefinir Posição</item>
-        <item>Sair</item>
-    </string-array>
-    <string-array name="settings_cdrom_read_speedup_entries">
-        <item>Nenhum</item>
-        <item>2x (4x Veloz)</item>
-        <item>3x (6x Veloz)</item>
-        <item>4x (8x Veloz)</item>
-        <item>5x (10x Veloz)</item>
-        <item>6x (12x Veloz)</item>
-        <item>7x (14x Veloz)</item>
-        <item>8x (16x Veloz)</item>
-        <item>9x (18x Veloz)</item>
-        <item>10x(20x Veloz)</item>
-    </string-array>
-    <string-array name="settings_touchscreen_controller_view_entries">
-        <item>Nenhum</item>
-        <item>Digital D-Pad</item>
-        <item>1 Analógico</item>
-        <item>2 Analógicos</item>
-        <item>Lightgun</item>
-    </string-array>
-    <string-array name="settings_audio_backend_entries">
-         <item>Mudo</item>
-        <item>Cubeb</item>
-        <item>SLES (Recomendado)</item>
-    </string-array>
-    <string-array name="settings_audio_buffer_size_entries">
-        <item>1024 Quadros (23.22ms)</item>
-        <item>2048 Quadros (46.44ms, Recomendado)</item>
-        <item>3072 Quadros (69.66ms)</item>
-        <item>4096 Quadros (92.88ms)</item>
-    </string-array>
-    <string-array name="settings_log_level_entries">
-        <item>Nenhum</item>
-        <item>Erro</item>
-        <item>Alerta</item>
-        <item>Alertas de Performance</item>
-        <item>Informação</item>
-        <item>Detalhado</item>
-        <item>Desenvolvedor</item>
-        <item>Perfil</item>
-        <item>Depuração</item>
-        <item>Rota</item>
-    </string-array>
-    <string-array name="settings_tabs">
-        <item>Geral</item>
-        <item>Vídeo</item>
-        <item>Áudio</item>
-        <item>Melhorias</item>
-        <item>Conquistas</item>
-        <item>Avançado</item>
-    </string-array>
-    <string-array name="settings_gpu_msaa_entries">
-        <item>Desativado</item>
-        <item>2x MSAA</item>
-        <item>4x MSAA</item>
-        <item>8x MSAA</item>
-        <item>2x SSAA</item>
-        <item>4x SSAA</item>
-        <item>8x SSAA</item>
-    </string-array>
-    <string-array name="settings_advanced_display_fps_limit_entries">
-        <item>Sem limite mostrar quadros)</item>
-        <item>10 FPS</item>
-        <item>15 FPS</item>
-        <item>30 FPS</item>
-        <item>45 FPS</item>
-        <item>60 FPS</item>
-        <item>75 FPS</item>
-        <item>90 FPS</item>
-    </string-array>
-    <string-array name="settings_emulation_speed_entries">
-        <item>Sem Limite</item>
-        <item>10% [6 FPS (NTSC) / 5 FPS (PAL)]</item>
-        <item>20% [12 FPS (NTSC) / 10 FPS (PAL)]</item>
-        <item>30% [18 FPS (NTSC) / 15 FPS (PAL)]</item>
-        <item>40% [24 FPS (NTSC) / 20 FPS (PAL)]</item>
-        <item>50% [30 FPS (NTSC) / 25 FPS (PAL)]</item>
-        <item>60% [36 FPS (NTSC) / 30 FPS (PAL)]</item>
-        <item>70% [42 FPS (NTSC) / 35 FPS (PAL)]</item>
-        <item>80% [48 FPS (NTSC) / 40 FPS (PAL)]</item>
-        <item>90% [54 FPS (NTSC) / 45 FPS (PAL)]</item>
-        <item>100% [60 FPS (NTSC) / 50 FPS (PAL), Padrão]</item>
-        <item>125% [75 FPS (NTSC) / 62 FPS (PAL)]</item>
-        <item>150% [90 FPS (NTSC) / 75 FPS (PAL)]</item>
-        <item>175% [105 FPS (NTSC) / 87 FPS (PAL)]</item>
-        <item>200% [120 FPS (NTSC) / 100 FPS (PAL)]</item>
-        <item>250% [150 FPS (NTSC) / 125 FPS (PAL)]</item>
-        <item>300% [180 FPS (NTSC) / 150 FPS (PAL)]</item>
-        <item>350% [210 FPS (NTSC) / 175 FPS (PAL)]</item>
-        <item>400% [240 FPS (NTSC) / 200 FPS (PAL)]</item>
-        <item>450% [270 FPS (NTSC) / 225 FPS (PAL)]</item>
-        <item>500% [300 FPS (NTSC) / 250 FPS (PAL)]</item>
-        <item>600% [360 FPS (NTSC) / 300 FPS (PAL)]</item>
-        <item>700% [420 FPS (NTSC) / 350 FPS (PAL)]</item>
-        <item>800% [480 FPS (NTSC) / 400 FPS (PAL)]</item>
-        <item>900% [540 FPS (NTSC) / 450 FPS (PAL)]</item>
-        <item>1000% [600 FPS (NTSC) / 500 FPS (PAL)]</item>
-    </string-array>
-    <string-array name="settings_advanced_cpu_overclock_entries">
-        <item>25% (8MHz)</item>
-        <item>50% (16MHz)</item>
-        <item>75% (24MHz)</item>
-        <item>100% (33MHz, Padrão)</item>
-        <item>125% (41MHz)</item>
-        <item>150% (49MHz)</item>
-        <item>175% (57MHz)</item>
-        <item>200% (66MHz)</item>
-        <item>225% (74MHz)</item>
-        <item>250% (82MHz)</item>
-        <item>275% (90MHz)</item>
-        <item>300% (99MHz)</item>
-        <item>350% (115MHz)</item>
-        <item>400% (132MHz)</item>
-        <item>450% (148MHz)</item>
-        <item>500% (165MHz)</item>
-        <item>500% (165MHz)</item>
-        <item>600% (198MHz)</item>
-        <item>700% (231MHz)</item>
-        <item>800% (264MHz)</item>
-        <item>900% (297MHz)</item>
-        <item>1000% (330MHz)</item>
-    </string-array>
-    <string-array name="settings_emulation_screen_orientation_entries">
-        <item>Padrão do Dispositivo</item>
-        <item>Retrato</item>
-        <item>Paisagem</item>
-        <item>Baseado no sensor de movimento</item>
-    </string-array>
-	<string-array name="settings_language_entries">
-        	<item>Mesmo do sistema</item>
-        	<item>Inglês</item>
-			<item>Português (Brasil)</item>
-        	<item>Italiano</item>
-        	<item>Holandês</item>
-        	<item>Espanhol</item>
-        	<item>Russo</item>
- 	</string-array>
-    <string-array name="settings_theme_entries">
-        <item>Padrão do Sistema</item>
-		<item>Claro</item>
-        <item>Escuro</item>
-    </string-array>
-    <string-array name="settings_downsample_mode_entries">
-        <item>Desabilitado</item>
-		<item>Misto (Reduz 3D / Suaviza Tudo)</item>
-        <item>Adaptativo (Preserva o 3D / Suaviza 2D)</item>
-    </string-array>
-	<string-array name="settings_boolean_entries">
-		<item>Desligado</item>
-		<item>Ligado</item>
-	</string-array>
-	<string-array name="settings_multitap_mode_entries">
-        	<item>Desativado</item>
-        	<item>Conectado à porta 1</item>
-        	<item>Conectado à porta 2</item>
-        	<item>Conectado à porta 1 e 2</item>
-    	</string-array>
-		<string-array name="memory_card_editor_save_menu">
-     		<item>Copiar salvar</item>
-     		<item>Excluir salvar</item>
-        </string-array>
-		<string-array name="settings_touchscreen_controller_port_entries">
-               <item>Porta 1</item>
-               <item>Porta 2</item>
-               <item>Multitap 3</item>
-               <item>Multitap 4</item>
-               <item>Multitap 5</item>
-               <item>Multitap 6</item>
-               <item>Multitap 7</item>
-               <item>Multitap 8</item>
-        </string-array>
-</resources>
diff --git a/android/app/src/main/res/values-pt-rBR/strings.xml b/android/app/src/main/res/values-pt-rBR/strings.xml
deleted file mode 100644
index b4c92179f..000000000
--- a/android/app/src/main/res/values-pt-rBR/strings.xml
+++ /dev/null
@@ -1,368 +0,0 @@
-<resources>
-    <string name="app_name">DuckStation</string>
-    <string name="action_settings">Configurações</string>
-    <string name="action_controller_mapping">Configurações de Controle</string>
-    <string name="title_activity_settings">Configurações</string>
-    <string name="settings_console_region">Região do Console</string>
-    <string name="settings_console_tty_output">Ativar saída TTY</string>
-    <string name="settings_console_fast_boot">Inicio Rápido</string>
-    <string name="settings_osd_show_messages">Mostrar Mensagens</string>
-    <string name="settings_osd_show_speed">Mostrar velocidade da emulação</string>
-    <string name="settings_osd_show_show_fps">Mostrar FPS do Jogo</string>
-    <string name="settings_osd_show_show_vps">Mostrar VPS do Jogo</string>
-    <string name="settings_cpu_execution_mode">Modo de execução CPU</string>
-    <string name="settings_gpu_renderer">Renderizado por GPU</string>
-    <string name="settings_gpu_resolution_scale">Escala de Resolução</string>
-    <string name="title_activity_emulation">Atividade da Emulação</string>
-    <string name="settings_emulation_speed">Velocidade da Emulação</string>
-    <string name="settings_fast_forward_speed">Velocidade de Avanço Rápido</string>
-    <string name="settings_save_state_on_exit">Salvar estado ao Sair</string>
-    <string name="settings_emulation_screen_orientation">Orientação de Tela</string>
-    <string name="settings_load_patch_codes">Carregar Trapaças</string>
-    <string name="settings_summary_save_state_on_exit">Salvar automaticamente o estado da emulação ao desligar</string>
-    <string name="settings_summary_load_patch_codes"><![CDATA[Loads Carrega códigos de trapaça no formato .cht e ou PCSXR. Códigos podem ser alternados durante o jogo.]]></string>
-    <string name="settings_apply_compatibility_settings">Aplicar Configurações de Compatibilidade</string>
-    <string name="settings_summary_apply_compatibility_settings">Desativar automaticamente melhorias quando não são suportadas.</string>
-    <string name="settings_summary_video_sync">Ative essa opção para que o emulador sincronize a taxa de FPS de acordo com a taxa do seu aparelho.</string>
-    <string name="settings_video_sync">Sincronização Vertical</string>
-    <string name="settings_cpu_overclocking">Aumento de Velocidade CPU (Overclock)</string>
-    <string name="settings_cdrom_region_check">Checagem de Região do CD-ROM</string>
-    <string name="settings_summary_cdrom_region_check">Previne que discos de regiões incorretas sejam lidos pelo emulador. Pode ser Desligado.</string>
-    <string name="settings_cdrom_preload_image_to_ram">Carregar CD-ROM para memória RAM</string>
-    <string name="settings_summary_preload_image_to_ram">Carrega o jogo todo na RAM. Útil para prevenir instabilidades durante o jogo. Em alguns casos também elimina travamentos durante os carregamentos.</string>
-    <string name="settings_pgxp_vertex_cache">PGXP - Vértice Armazenado</string>
-    <string name="settings_summary_pgxp_vertex_cache">Reduz as oscilações nos poligonos tentando preservar os mesmos na hora da transferência para a RAM.</string>
-    <string name="settings_pgxp_cpu_mode">PGXP - Modo CPU</string>
-    <string name="settings_summary_pgxp_cpu_mode">Tenta reduzir oscilações nos poligonos preservando-os na hora da transferência para o CPU. Alguns jogos se beneficiam com esta opção junto com o PGXP para que funcione corretamente. Muito lento, e imcompativel com o modo recompilador.</string>
-    <string name="settings_cpu_recompiler_icache">Recompilador CPU Modo ICache</string>
-    <string name="settings_summary_cpu_recompiler_icache">Determina se a instrução enviada ao CPU emulado fica armazenada no recompilador. Melhor a precisão ao pequeno custo de performance. Se os jogos estão rodando muito rápido, tente ativar esta opção.</string>
-    <string name="settings_cpu_recompiler_fastmem">Recompilador CPU Modo FASTMEM</string>
-    <string name="settings_summary_cpu_recompiler_fastmem">Torna o acesso à memória mais eficiente. Desative se estiver instável em seu aparelho.</string>
-    <string name="settings_presented_frame_limit">Limite do quadro Atual</string>
-    <string name="settings_logging_level">Nível de Registro</string>
-    <string name="settings_log_to_file">Registro para Arquivo</string>
-    <string name="settings_summary_log_to_file">Escreve mensagens em um arquivo duckstation.log em seu diretório raiz. Use só para depuração isto deixará o emulador lento.</string>
-    <string name="settings_log_to_logcat">Registro em Linha de Comando</string>
-    <string name="settings_summary_log_to_logcat">Escreve um arquivo de registro em um arquivo no Android. Só útil quando atrelado ao PC com adb.</string>
-    <string name="settings_volume">Volume</string>
-    <string name="settings_summary_volume">Controla o volume do emulador.</string>
-    <string name="settings_fast_forward_volume">Volume do Avanço Rápido</string>
-    <string name="settings_summary_fast_forward_volume">Controla o volume do áudio quando o avanço rápido é usado.</string>
-    <string name="settings_mute_all_sound">Silenciar Tudo</string>
-    <string name="settings_summary_mute_all_sound">Silencia totalmente o emulador.</string>
-    <string name="settings_mute_cd_audio">Silenciar CDs de Áudio</string>
-    <string name="settings_summary_mute_cd_audio">Silencia de forma forçada tanto para CDs de música quanto em jogos.</string>
-    <string name="settings_audio_backend">Opções de Áudio</string>
-    <string name="settings_audio_buffer_size">Latência do Volume</string>
-    <string name="settings_summary_audio_buffer_size">Determina a latência entre o áudio. Valores menores reduzem a latência (atraso), pode causar engasgos quando jogos são acelerados.</string>
-    <string name="settings_audio_sync">Sincronia de Áudio</string>
-    <string name="settings_summary_audio_sync">Limita a velocidade de emulação com base na opção escolhida. Isso ajuda a remover ruídos ou estalos se a emulação for muito rápida. A sincronização será automaticamente desativada se não funcionar a 100%.</string>
-    <string name="settings_controller_type">Tipo de Controle</string>
-    <string name="settings_enable_analog_mode_on_reset">Ativa modo analógico ao reiniciar</string>
-    <string name="settings_touchscreen_controller_view">Visualização do controle em tela</string>
-    <string name="settings_auto_hide_touchscreen_controller">Auto ocultar controles em tela</string>
-    <string name="settings_summary_auto_hide_touchscreen_controller">Esconde controles em tela quando um controle externo é detectado.</string>
-    <string name="settings_vibrate_on_press">Vibrar ao Pressionar</string>
-    <string name="settings_summary_vibrate_on_press">Ativa vibração quando um botão da tela de toque é pressionado. Requer \"Vibrar ao Tocar\" ativado nas opções do seu dispositivo para funcionar.</string>
-    <string name="settings_enable_vibration">Ativa Vibração</string>
-    <string name="settings_summary_enable_vibration">Encaminha vibração do jogo para o motor do aparelho.</string>
-    <string name="settings_memory_card_1_type">Tipo de Cartão de Memória 1</string>
-    <string name="settings_memory_card_2_type">Tipo de Cartão de Memória 2</string>
-    <string name="settings_crop_mode">Modo de Corte</string>
-    <string name="settings_aspect_ratio">Razão de Aspecto</string>
-    <string name="settings_linear_upscaling">Escalonamento Linear</string>
-    <string name="settings_integer_upscaling">Escalonamento Integro</string>
-    <string name="settings_summary_linear_upscaling">Suaviza a imagem ao aumentar a resolução da emulação.</string>
-    <string name="settings_summary_integer_upscaling">Adiciona preenchimento a área exibida para garantir a proporção entre os pixels. Pode resultar em uma imagem mais nítida em jogos 2D.</string>
-    <string name="settings_summary_osd_show_messages">Mostra mensagens em tela ao salvar, carregar, carregar trapaças ou quando eventos e alertas ocorrerem.</string>
-    <string name="settings_summary_osd_show_speed">Mostra a velocidadea atual da emulação no topo superior direito da tela..</string>
-    <string name="settings_summary_osd_show_fps">Mostra a velocidade atual dos quadros FPS no topo da tela.</string>
-    <string name="settings_summary_osd_show_vps">Mostra a velocidade atual dos quadros VPS no topo da tela.</string>
-    <string name="settings_cdrom_read_speedup">Velocidade de leitura CD-Rom</string>
-    <string name="settings_summary_cdrom_read_speedup">Aumenta a velocidade de leitura do CD-Rom. Só se aplica a velocidade de leitura em 2x para cima, configuração será ignorada quando usado para tocar CD\'s de música. Pode aumentar a velocidade de leitura em telas de carregamento em alguns jogos, ao custo de quebrar outros..</string>
-    <string name="settings_summary_console_fast_boot">Pula a tela de abertura clássica da Sony seguro ativar porém alguns raros jogos podem quebrar.</string>
-    <string name="settings_msaa">Filtro Anti-serrilhado</string>
-    <string name="settings_true_color">Renderizar em 24 Cores (desativa dithering)</string>
-    <string name="settings_summary_true_color">Produz gradientes de aparência mais agradável ao custo de fazer algumas cores ficarem ligeiramente diferentes. A maioria dos jogos são compatíveis com esta opção.</string>
-    <string name="settings_scaled_dithering">Efeito Dithering Escalado (escala pontilhados para resolução)</string>
-    <string name="settings_summary_scaled_dithering">Escala o dithering para a resolução da GPU emulada. Torna o padrão do pontilhado muito menos óbvio em resoluções mais altas.</string>
-    <string name="settings_disable_interlacing">Desativar Entrelaçamento (força redenrização progressiva)</string>
-    <string name="settings_summary_disable_interlacing">Força a renderização e exibição de quadros para o modo progressivo. Remove o efeito de \'alisamento\' visto em jogos 480i renderizando sempre em 480, seguro deixar ativo.</string>
-    <string name="settings_texture_filtering">Filtragem de textura</string>
-    <string name="settings_force_ntsc_timings">Força renderização em NTSC (60hz-em-PAL)</string>
-    <string name="settings_summary_force_ntsc_timings">Usa temporizadores de quadro NTSC forçando os jogos PAL vulgo Europeus, a rodarem a 60 Hz.</string>
-    <string name="settings_widescreen_hack">Hack de tela panorâmica</string>
-    <string name="settings_summary_widescreen_hack">Dimensiona as posições dos vértices da tela para a proporção mais larga (Panoramicas), basicamente aumenta o campo de visão de 4:3 para 16:09 em jogos 3D. Não é compatível com todos os jogos.</string>
-    <string name="settings_force_4_3_for_24bit">Forçar 4:3 para telas 24-bits</string>
-    <string name="settings_summary_force_4_3_for_24bit">Volta a tela para 4:3 (Desativa efeito esticado em FMVs).</string>
-    <string name="settings_chroma_smoothing_24bit">Suavização de Croma</string>
-    <string name="settings_summary_chrome_smoothing_24bit">Suavização de Croma (reduz artefatos em cenas FMV).</string>
-    <string name="settings_pgxp_geometry_correction">Correção Geométrica PGXP</string>
-    <string name="settings_summary_pgxp_geometry_correction"><![CDATA[Reduz as "oscilações" nos polígonos tentando preservar os mesmos na hora da transferência para a memória. Funciona apenas se rederizado por hardware e pode não ser compatível com todos os jogos Não compativel com todos os jogos.]]></string>
-    <string name="settings_pgxp_culling_correction">PGXP - Correção de Curvas</string>
-    <string name="settings_summary_pgxp_culling_correction">Aumenta a precisão das curvas nos polígonos, reduzindo o número de buracos na geometria do mesmo. Requer a Correção Geometrica ativada. Requer que a correção geométrica esteja ativada.</string>
-    <string name="settings_pgxp_texture_correction">PGXP - Correção de Textura</string>
-    <string name="settings_summary_pgxp_texture_correction">Utiliza interpolação corretiva em perspetiva para coordenadas e das cores na textura, endireitando as que estiverem distorcidas. Requer que a correção geométrica esteja ativada.</string>
-    <string name="settings_pgxp_preserve_projection_precision">PGXP - Preserva Precisão de Projeção</string>
-    <string name="settings_summary_pgxp_preserve_projection_precision">Permite precisão adicional para PGXP; Pode melhorar o visual em alguns jogos e prejudicar outros.</string>
-    <string name="settings_pgxp_depth_buffer">PGXP - Modo Polimento (Z)</string>
-    <string name="settings_summary_pgxp_depth_buffer">Tenta reduzir os poligonos no eixo Z (parte inferior ou cantos em alguns casos) ajustando os limites dos valores para que não haja conflitos na renderização de poligonos 3D. Gerando um efeito de buracos ou quadrados piscando. Tem pouca compatibilidade no geral, mas pode funcionar bem em alguns jogos. Outros precisam ser ajustados via limitador.</string>
-    <string name="menu_main_resume_last_session">Resumir Jogo</string>
-    <string name="menu_main_start_file">Iniciar Arquivo</string>
-    <string name="menu_main_start_bios">Iniciar BIOS</string>
-    <string name="menu_main_edit_game_directories">Editar Diretórios de Jogos</string>
-    <string name="menu_main_scan_for_new_games">Escanear por Jogos Novos</string>
-    <string name="menu_main_rescan_all_games">Rescanear Tudo</string>
-    <string name="menu_main_import_bios">Importar BIOS</string>
-    <string name="menu_main_show_version">Mostrar Versão</string>
-    <string name="menu_main_github_repository">Repositório no Github</string>
-    <string name="menu_main_discord_server">Servidor no Discord</string>
-    <string name="menu_game_list_entry_start_game">Iniciar Jogo</string>
-    <string name="menu_game_list_entry_resume_game">Resumir Jogo</string>
-    <string name="android_progress_callback_please_wait">Aguarde...</string>
-    <string name="android_progress_callback_ok">OK</string>
-    <string name="android_progress_callback_information">Informação</string>
-    <string name="android_progress_callback_confirmation">Confirmação</string>
-    <string name="android_progress_callback_yes">Sim</string>
-    <string name="android_progress_callback_no">Não</string>
-    <string name="emulation_activity_error">Erro</string>
-    <string name="emulation_activity_ok">OK</string>
-    <string name="emulation_activity_import_patch_codes">Importar Trapaças...</string>
-    <string name="emulation_activity_patch_on">(Ligado)</string>
-    <string name="emulation_activity_patch_off">(Desligado)</string>
-    <string name="emulation_activity_choose_patch_code_file">Escolher Arquivo de Trapaça</string>
-    <string name="emulation_activity_failed_to_import_patch_codes">Falha ao importar trapaça. Tenha certeza de ter escolhido o formato PCSXR ou Libretro CHT.</string>
-    <string name="main_activity_choose_directory">Escolher Diretório</string>
-    <string name="main_activity_error">Erro</string>
-    <string name="main_activity_get_path_from_file_error">Falha ao obter o caminho para o arquivo selecionado. Certifique-se de que o arquivo esteja no armazenamento interno / externo.\n\nTap.\nSelect "Mostrar armazenamento interno".\nTap selecione o nome do seu dispositivo ou cartão SD.</string>
-    <string name="main_activity_ok">OK</string>
-    <string name="main_activity_get_path_from_directory_error">Falha ao obter o caminho para o arquivo selecionado. Certifique-se de que o arquivo esteja no armazenamento interno / externo. \n\nTap the overflow button in the directory selector.\nSelect \"Mostrar armazenamento interno\".\nTap selecione o nome do seu dispositivo ou cartão SD.</string>
-    <string name="main_activity_external_storage_permissions_error">Permissões de armazenamento externo são necessárias para usar o DuckStation.</string>
-    <string name="main_activity_choose_disc_image">Escolha Arquivo de Jogo</string>
-    <string name="main_activity_missing_bios_image_prompt">Nenhum BIOS foi encontrada no diretório de BIOS do DuckStation. Deseja localizar e importar o BIOS agora?</string>
-    <string name="main_activity_missing_bios_image">BIOS ausente</string>
-    <string name="main_activity_yes">Sim</string>
-    <string name="main_activity_no">Não</string>
-    <string name="main_activity_choose_bios_image">Escolher BIOS</string>
-    <string name="main_activity_failed_to_open_bios_image">Falha ao Abrir BIOS</string>
-    <string name="main_activity_failed_to_read_bios_image_prefix">\"Falha ao ler BIOS: \"</string>
-    <string name="main_activity_bios_image_too_large">Aqruivo BIOS muito grande. Você deve selecionar uma imagem do BIOS, não um jogo, e deve ter 512 KB de tamanho.</string>
-    <string name="main_activity_invalid_error">Esse BIOS não é válido, ou já foi importado.</string>
-    <string name="main_activity_show_version_title">Versão</string>
-    <string name="main_activity_copy">Copiar</string>
-    <string name="settings_gpu_thread">Renderização Sequencial - GPU</string>
-    <string name="settings_summary_gpu_thread">Usa um segundo processo para desenhar gráficos em tela. Atualmente só disponível para renderizadores por software, pode fornecer uma melhoria significativa na velocidade, pode ser usado a vontade.</string>
-    <string name="settings_gpu_threaded_presentation">Apresentação Sequencial - GPU</string>
-    <string name="settings_summary_gpu_threaded_presentation">Apresenta quadros sequêncialmente em segundo plano quando o avanço rápido ou sincronizador vertical (Vsync) está desativado Isso pode melhorar o desempenho no renderizador Vulkan.</string>
-    <string name="settings_language">Linguagem (Necessário Reiniciar)</string>
-    <string name="touchscreen_controller_stop_editing">Terminado</string>
-    <string name="touchscreen_controller_reset_layout">Redefinir</string>
-    <string name="emulation_activity_touchscreen_controller_not_active">Controle em tela não Ativado.</string>
-    <string name="settings_theme">Tema</string>
-    <string name="settings_controller_mapping_summary">Permite configurar e atribuir os botões de seu controle externo ao emulador.</string>
-    <string name="settings_controller_mapping">Mapear Controles</string>
-    <string name="controller_binding_dialog_message">Pressione os botões para atribuí-los ao controle.\n\nAtribuição Atual: %s</string>
-    <string name="controller_binding_dialog_no_binding"><![CDATA[<Nenhuma Atribuição>]]></string>
-    <string name="controller_binding_dialog_cancel">Cancelar</string>
-    <string name="controller_binding_dialog_clear">Limpar</string>
-    <string name="controller_mapping_activity_title">Mapear Controle</string>
-    <string name="controller_mapping_activity_no_profiles_found">Perfil não encontrado.</string>
-    <string name="controller_mapping_activity_select_input_profile">Escolha o Perfil de Entrada</string>
-    <string name="controller_mapping_activity_failed_to_load_profile">Falha ao carregar o perfil \'%s\'</string>
-    <string name="controller_mapping_activity_input_profile_name">Nome do Perfil:</string>
-    <string name="controller_mapping_activity_save">Salvar</string>
-    <string name="controller_mapping_activity_name_must_be_provided">Um nome deve ser escolhido.</string>
-    <string name="controller_mapping_activity_failed_to_save_input_profile">Falha ao salvar perfil.</string>
-    <string name="controller_mapping_activity_input_profile_saved">Perfil \'%s\' salvo.</string>
-    <string name="controller_mapping_activity_cancel">Cancelar</string>
-    <string name="settings_use_analog_sticks_for_dpad">Usar Analógicos como D-Pad no Modo Digital</string>
-    <string name="settings_summary_enable_analog_mode_on_reset">Força os controles ao modo analógico quando emulador é reiniciado.</string>
-    <string name="settings_summary_use_analog_sticks_for_dpad">Permite usar os analógicos como um direcional (D-Pad) no modo digital, assim como os botões.</string>
-    <string name="settings_disable_all_enhancements">Desativar todos os aprimoramentos</string>
-    <string name="settings_summary_disable_all_enhancements">Desliga temporariamente todos os aprimoramentos, útil para achar problemas de performance..</string>
-    <string name="settings_downsample_mode">Suavização da Imagem</string>
-    <string name="activity_game_properties">Propriedades do Jogo</string>
-    <string name="game_properties_preference_use_global_setting">Usar configuração global</string>
-    <string name="settings_input_profile">Perfil de controle</string>
-    <string name="game_properties_tab_summary">Sumário</string>
-    <string name="game_properties_tab_game_settings">Configuração de Jogo</string>
-    <string name="game_properties_tab_controller_settings">Configurações de Controle</string>
-    <string name="settings_audio_resampling">Ajuste de Áudio</string>
-    <string name="settings_summary_audio_resampling">Quando estiver rodando fora dos 100% da velocidade, o áudio será ajustado para que não haja queda de quadros. Produz uma melhor qualidade do avanço rápido no áudio ao custo pequeno de perda de performance.</string>
-    <string name="settings_general_sync_to_host_refresh_rate">Sincronizar taxa de atualização</string>
-    <string name="settings_summary_general_sync_to_host_refresh_rate">Ajusta a velocidade da emulação de acordo com a mesma taxa de atualização do dispositivo.</string>
-    <string name="settings_sustained_performance_mode">Desempenho Contínuo</string>
-    <string name="settings_summary_sustained_performance_mode">Ativa o modo contínuo de perfomance do Android. Resulta em um melhor desempenho de quadros e perfomance por longos periodos em alguns dispositivos..</string>
-    <string name="title_activity_game_directories">Editar Diretório de Jogos</string>
-    <string name="settings_game_directories">Diretório de Jogos</string>
-    <string name="settings_summary_game_directories">Altera a lista de diretórios usados ​​para pesquisar jogos.</string>
-    <string name="game_directories_scanning_subdirectories">Ler subdiretórios.</string>
-    <string name="game_directories_not_scanning_subdirectories">Não ler subdiretórios.</string>
-    <string name="settings_display_all_frames">Otimização de Quadros</string>
-    <string name="settings_summary_display_all_frames">Garante que cada quadro renderizado será mostrado em tela, no seu rtimo adequado. Se estiver tendo dificuldades ao manter uma boa velocidade, ou estiver enfrentando algumas falhas de áudio tente desativar esta opção.</string>
-    <string name="menu_edit_game_directories_add_directory">Adicionar Diretório</string>
-    <string name="menu_edit_game_directories_add_path">Adicionar Caminho</string>
-    <string name="edit_game_directories_add_path">Editar Caminho</string>
-    <string name="edit_game_directories_add_path_summary">Insira o caminho completo dos seus jogos.\n\nUse um gerenciador de arquivos para ver o caminho.\n\nExemplo: /storage/emulated/0/games</string>
-    <string name="save_state_info_slot_is_empty">Espaço Vazio</string>
-    <string name="save_state_info_game_save_n">Id do Jogo %d</string>
-    <string name="save_state_info_global_save_n">Espaço Global %d</string>
-    <string name="save_state_info_quick_save">Salvamento Rápido</string>
-    <string name="settings_osd_show_show_resolution">Mostrar Resolução</string>
-    <string name="settings_summary_osd_show_resolution">Mostra resolução do jogo no canto superior direito da tela.</string>
-    <string name="settings_summary_display_stretch">Estica a imagem para preencher toda a tela.</string>
-    <string name="settings_display_stretch">Esticar para Preencher</string>
-    <string name="settings_category_global">Configurações Básicas</string>
-    <string name="settings_category_display">Configurações de Tela</string>
-    <string name="settings_category_audio">Configurações de Áudio</string>
-    <string name="settings_category_console">Configurações do Console</string>
-    <string name="settings_category_cpu">Configurações de CPU</string>
-    <string name="settings_category_gpu">Configurações de GPU</string>
-    <string name="settings_category_logging">Configurações de Rastreio</string>
-    <string name="dialog_done">Salvar</string>
-    <string name="dialog_touchscreen_controller_type">Ver Controle em Tela</string>
-    <string name="dialog_touchscreen_controller_opacity">Visibilidade do Controle</string>
-    <string name="dialog_touchscreen_controller_buttons">Botões do Controle</string>
-    <string name="dialog_touchscreen_controller_settings">Configurações do controle em Tela</string>
-    <string name="settings_summary_console_tty_output">Informações de Depuração.</string>
-    <string name="action_show_game_list">Modo Lista</string>
-    <string name="action_show_game_grid">Modo Grade</string>
-    <string name="settings_touch_gliding">Deslizar por toque</string>
-    <string name="settings_summary_touch_gliding">Permite que você pressione combinações de botões deslizando o dedo pela tela.</string>
-    <string name="menu_game_list_entry_game_properties">Propriedades</string>
-    <string name="emulation_activity_change_disc_select_new_file">Escolha um arquivo...</string>
-    <string name="settings_achievements_enable">Ativar Conquistas</string>
-    <string name="settings_summary_achievements_enable">Quando ativado e logado com sua conta, Ducstation irá procurar e baixar as conquistas se hovuerem ao iniciar o jogo.</string>
-    <string name="settings_achievements_challenge_mode">Modo Dificílimo (Hardcore)</string>
-    <string name="settings_summary_achievements_challenge_mode">Modo Dificílimo (hardcore). Desativa salvamentos rápidos, carregamento de trapaças e funções de velocidade, mas você receberá o dobro de pontos de conquistas em troca.</string>
-    <string name="settings_achievements_rich_presence">Ativar presença Rica (Discord)</string>
-    <string name="settings_summary_achievements_rich_presence">Quando ativado, a informação do que estiver sendo jogado será enviado ao servidor se suportado.</string>
-    <string name="settings_achievements_username">Nome de Usuário</string>
-    <string name="settings_achievements_token_generation_time">Token Gerado</string>
-    <string name="settings_achievements_login">Usuário</string>
-    <string name="settings_summary_achievements_login">Entre para obter Conquistas</string>
-    <string name="settings_achievements_register">Registrar-se</string>
-    <string name="settings_summary_achievements_register">Acesse para registrar-se.</string>
-    <string name="settings_achievements_logout">Sair</string>
-    <string name="settings_summary_achievements_logout">Sair da sua conta. Novas conquistas não serão registradas.</string>
-    <string name="settings_achievements_view_profile">Ver Perfil</string>
-    <string name="settings_summary_achievements_view_profile">Ver Peril...</string>
-    <string name="settings_achievements_test_mode">Ativar Modo Teste</string>
-    <string name="settings_summary_achievements_test_mode">Quando ativado, DuckStation entenderá que todas as Conquistas deverão ficar travadas e não mandará uma notificação para o servidor não marcando a mesma como destravada.</string>
-    <string name="settings_achievements_use_first_disc_from_playlist">Usar primeiro Disco (Playlist)</string>
-    <string name="settings_summary_achievements_use_first_disc_from_playlist">Quando ativado, o primeiro disco em uma lista de reprodução será usado para conquistas, independente de qual disco está ativo.</string>
-    <string name="achievement_settings_login_title">Credenciais do RetroAchievements</string>
-    <string name="achievement_settings_login_help">Por favor entre com um nome de usuário e senha para se autenticar no retroachievements.org conforme abaixo. Suas credenciais não serão salvas no emulador. Será criado um token único de acesso para autenticação.</string>
-    <string name="achievement_settings_login_username_hint">Usuário</string>
-    <string name="achievement_settings_login_password_hint">Senha</string>
-    <string name="achievement_settings_login_login_button">Entrar</string>
-    <string name="achievement_settings_login_cancel_button">Cancelar</string>
-    <string name="achievement_settings_login_failed">Falha na entrada, verifique seu usuário e senha e tente novamente</string>
-    <string name="achievement_points_format_string">%d pontos</string>
-    <string name="achievement_summary_format_string">Você obteve %1$d de %2$d conquistas, ganhando %3$d pontos de %4$d disponiveis.</string>
-    <string name="achievement_title_challenge_mode_format_string">%s (Modo Hardcore)</string>
-    <string name="settings_achievements_disclaimer">DuckStation usa o RetroAchievements como base de dados para as conquistas. Para usar esta função, considere fazer sua conta em:(https://retroachievements.org).</string>
-    <string name="settings_achievements_confirm_logout_title">Confirmar Sair</string>
-    <string name="settings_achievements_confirm_logout_message">O encerramento de uma sessão desabilitará as conquistas até que entre novamente. Conquistas abertas anteriormente não serão perdidas.</string>
-    <string name="controller_binding_device_for_vibration">Vibração do Dispositivo</string>
-    <string name="controller_settings_tab_settings">Configurações</string>
-    <string name="controller_settings_tab_hotkeys">Atalhos</string>
-    <string name="controller_settings_category_button_bindings">Atribuição de Botões</string>
-    <string name="controller_settings_category_axis_bindings">Atribuição de Eixos</string>
-    <string name="controller_settings_category_settings">Configurações</string>
-    <string name="controller_settings_category_touchscreen_controller">Controles de toque</string>
-    <string name="controller_settings_category_ports">Portas</string>
-    <string name="controller_settings_main_port_format">Porta %d</string>
-    <string name="controller_settings_sub_port_format">Porta %1$d%2$c</string>
-    <string name="action_switch_view">Mudar visualização</string>
-    <string name="title_activity_memory_card_editor">Editor de Cartão de Memória</string>
-    <string name="action_memory_card_editor">Editor de Cartão de Memória</string>
-    <string name="action_memory_card_editor_import_card">Importar Cartão</string>
-    <string name="action_memory_card_editor_open_card">Abrir Cartão</string>
-    <string name="action_memory_card_editor_new_card">Novo Cartão</string>
-    <string name="action_memory_card_editor_format_card">Formartar Cartão</string>
-    <string name="action_memory_card_editor_delete_card">Apagar Cartão</string>
-    <string name="memory_card_editor_no_cards_found">Nenhum Cartão de Memória encontrado.</string>
-    <string name="memory_card_editor_card_already_open">Este cartão já está aberto.</string>
-    <string name="memory_card_editor_failed_to_open_card">Falha ao abrir ou ler o cartão de memória.</string>
-    <string name="memory_card_editor_must_have_at_least_two_cards_to_copy">Necessário que tenha pelo menos 2 cartões para abrir e copiar.</string>
-    <string name="memory_card_editor_copy_save_to">Coppiar %s para...</string>
-    <string name="memory_card_editor_select_card">Escolher Cartão</string>
-    <string name="memory_card_editor_error">Erro</string>
-    <string name="memory_card_editor_copy_insufficient_blocks">Este arquivo precisa de %1$d blocos, mas só restam %2$d livres.</string>
-    <string name="memory_card_editor_copy_already_exists">Arquivo \'%s\' já existente no cartão destino.</string>
-    <string name="memory_card_editor_copy_read_failed">Falha ao ler \'%s\' do cartão origem.</string>
-    <string name="memory_card_editor_copy_write_failed">Falha ao escrever \'%s\' no cartão destino.</string>
-    <string name="memory_card_editor_copy_success">Copiado \'%1$s\' para \'%2$s\'.</string>
-    <string name="memory_card_editor_delete_confirm">Tem certeza que quer apagar o save \'%s\'?</string>
-    <string name="memory_card_editor_delete_success">Apagar save \'%s\'.</string>
-    <string name="memory_card_editor_delete_failed">Falha ao apagar arquivo \'%s\'.</string>
-    <string name="memory_card_editor_no_card_selected">Nenhum cartão selecionado.</string>
-    <string name="memory_card_editor_import_failed">Falha ao importar cartão. Pode não ter o formato correto.</string>
-    <string name="memory_card_editor_delete_card_confirm_message">Cartao de Memória \'%s\' será apagado, e não poderá ser recuperado. Tem certeza que quer apagá-lo?</string>
-    <string name="memory_card_editor_delete_card_failed">Falha ao deletar \'%s\'.</string>
-    <string name="memory_card_editor_delete_card_success">Cartão Apagado \'%s\'.</string>
-    <string name="memory_card_editor_format_card_confirm_message">Cartão de Memória \'%s\' será formatado, limpando tudo. Tem certeza que quer formatar?</string>
-    <string name="memory_card_editor_format_card_failed">Falha ao formatar \'%s\'.</string>
-    <string name="memory_card_editor_format_card_success">Cartão formatado \'%s\'.</string>
-    <string name="memory_card_editor_import_card_confirm_message">Importando \'%1$s\' removerá todos os saves \'%2$s\'. Quer mesmo continuar?</string>
-    <string name="memory_card_editor_import_card_read_failed">Falha ao ler \'%s\'.</string>
-    <string name="memory_card_editor_import_card_failed">Falha ao importar cartão \'%s\'. Pode não conter um formato válido.</string>
-    <string name="memory_card_editor_import_card_success">Cartão Importado \'%s\'.</string>
-    <string name="menu_game_list_entry_choose_cover_image">Escolha um arquivo de Capa</string>
-    <string name="controller_settings_vibration_unsupported">O dispositivo escolhido não tem suporte a vibração.</string>
-    <string name="controller_settings_automatic_mapping">Executar mapeamento automático</string>
-    <string name="controller_settings_summary_automatic_mapping">Tentará mapear os botões de forma automática ao controle conectado.</string>
-    <string name="controller_settings_clear_controller_bindings">Limpar atribuições</string>
-    <string name="controller_settings_summary_clear_controller_bindings">Remove todas as atribuições para o controle conectado.</string>
-    <string name="controller_settings_clear_controller_bindings_confirm">Tem certeza de que quer remover as atribuições para o controle, isto não poderá ser desfeito.</string>
-    <string name="controller_settings_clear_controller_bindings_done">Todas as atribuições de botões removidas para o controle %d.</string>
-    <string name="controller_auto_mapping_no_devices">Nenhum controle com suporte disponível encontrado. A atribuição automática não pôde ser feita, mas você pode ainda atribuir os botões manualmente..</string>
-    <string name="controller_auto_mapping_select_device">Escolha o dispositivo</string>
-    <string name="controller_auto_mapping_results">Resultados da atribuição automática</string>
-    <string name="main_activity_empty_game_list_title">Nenhum jogo encontrado. Adicione o diretório contendo jogos para iniciar.</string>
-    <string name="main_activity_empty_game_list_supported_formats">Os formatos suportados são:\n\n%s\n\nJogos no formato .bin precisam obrigatoriamente do arquvio .cue para iniciar.</string>
-    <string name="main_activity_empty_game_list_add_directory">Adicionar diretório de jogos</string>
-    <string name="main_activity_empty_game_list_start_file">Iniciar arquivo</string>
-    <string name="update_notes_title">Atualizar Notas</string>
-    <string name="update_notes_message_version_controller_update">Esta atualização inclui suporte para multiplos controles com vibração, e suporte a atribuição de botões comos os de volume.\n\nVocê deverá reatribuir seus controles, caso contrário eles não irão mais funcionar. Quer continuar ?</string>
-    <string name="settings_osd_show_show_inputs">Mostrar entrada de controle</string>
-    <string name="settings_summary_osd_show_inputs">Mostra quais botões estão sendo pressionados no canto inferior esquerdo da tela.</string>
-    <string name="touchscreen_controller_edit_menu">Editar Menu</string>
-    <string name="settings_achievements_category">Conta</string>
-    <string name="settings_achievements_global_settings">Configuração Global</string>
-    <string name="settings_category_achievements">Configuração de Conquista</string>
-    <string name="settings_multitap_mode">Modo Multitap</string>
-    <string name="settings_touchscreen_controller_port">Porta do controle em tela</string>
-    <string name="emulation_menu_load_state">Carregar Estado</string>
-    <string name="emulation_menu_save_state">Salvar Estado</string>
-    <string name="emulation_menu_toggle_fast_forward">Alternar Avanço Rápido</string>
-    <string name="emulation_menu_achievements">Conquistas</string>
-    <string name="emulation_menu_patch_codes">Trapaças</string>
-    <string name="emulation_menu_change_disc">Mudar Disco</string>
-    <string name="emulation_menu_touchscreen_controller_settings">Configuração do controle em tela</string>
-    <string name="emulation_menu_toggle_analog_mode">Alternar modo analógico do controle</string>
-    <string name="emulation_menu_reset_console">Reiniciar Console</string>
-    <string name="emulation_menu_exit_game">Sair do Jogo</string>
-    <string name="settings_use_software_renderer_for_readbacks">Usar rederizador por software para releituras</string>
-    <string name="settings_summary_use_software_renderer_for_readbacks">Executa o modo software em paralelo para releituras na memória de vídeo. Em alguns sistemas, pode resultar em maior desempenho ao usar aprimoramentos gráficos com o renderizador por hardware..</string>
-    <string name="settings_use_software_renderer">Usar modo Software</string>
-    <string name="settings_disable_widescreen">Desativar Hack de tela panorâmica</string>
-    <string name="settings_cdrom_seek_speedup">Velocidade de busca CD-ROM</string>
-    <string name="settings_summary_cdrom_seek_speedup">Aumenta a velocidade de leitura do CD-Rom. Só se aplica a velocidade de leitura em 2x para cima, configuração será ignorada quando usado para tocar CD\'s de música. Pode aumentar a velocidade de leitura em telas de carregamento em alguns jogos, ao custo de quebrar outros.</string>
-    <string name="settings_custom_aspect_ratio">Proporção da imagem customizada</string>
-    <string name="settings_summary_custom_aspect_ratio">Usada para quando a proporção de imagem é definida como customizada.</string>
-    <string name="controller_settings_category_auto_fire_buttons">Botões de auto disparo</string>
-    <string name="controller_settings_category_auto_fire_bindings">Botões de auto disparo (Gatilho)</string>
-    <string name="controller_settings_auto_fire_n_button">Auto disparo botão %d</string>
-    <string name="controller_settings_auto_fire_n_frequency">Auto disparo botão %d Frequência/Intervalo</string>
-    <string name="controller_binding_auto_fire_n">Auto disparo %d</string>
-    <string name="settings_category_cdrom">Configurações de CD-ROM</string>	
-    <string name="settings_cdrom_read_thread">Usar Leitura Assíncrona</string>	
-    <string name="settings_summary_read_thread">Reduz engasgos na emulação lendo / descomprimindo os arquivos da midia de forma assíncrona.</string>
-    <string name="settings_cdrom_load_image_patches">Aplicar Modificações</string>	
-    <string name="settings_summary_load_image_patches">Aplica automaticamente \'modificações\' em jogos quando presentes no mesmo diretório. Atualmente só são aceitos modificações do tipo PPF.</string>
-    <string name="menu_edit_game_directories_force_saf">Forçar armazenamento com escopo</string>	
-    <string name="settings_expand_to_cutout">Expandir para área cortada</string>
-    <string name="settings_summary_expand_to_cutout">Expande a área de exibição para incluir partes que foram removidas da imagem. Útil para telas curvas em que parte da imagem acaba de perdendo.</string>
-</resources>
diff --git a/android/app/src/main/res/values-ru/arrays.xml b/android/app/src/main/res/values-ru/arrays.xml
deleted file mode 100644
index 522bd81b7..000000000
--- a/android/app/src/main/res/values-ru/arrays.xml
+++ /dev/null
@@ -1,277 +0,0 @@
-<resources>
-	<string-array name="settings_console_region_entries">
-		<item>Автоопределение</item>
-		<item>NTSC-J (Япония)</item>
-		<item>NTSC-U (США)</item>
-		<item>PAL (Европа, Австралия)</item>
-	</string-array>
-	<string-array name="settings_cpu_execution_mode_entries">
-		<item>Интерпретатор (самый медленный)</item>
-		<item>Кэшированный интерпретатор (быстрее)</item>
-		<item>Рекомпилятор (самый быстрый)</item>
-	</string-array>
-	<string-array name="settings_cpu_fastmem_mode_entries">
-		<item>Выключен (самый медленный)</item>
-		<item>MMap (аппаратный, самый быстрый, только для 64-бит)</item>
-		<item>LUT (быстрее)</item>
-	</string-array>
-	<string-array name="gpu_renderer_entries">
-		<item>Аппаратный (OpenGL)</item>
-		<item>Аппаратный (Vulkan)</item>
-		<item>Программный</item>
-	</string-array>
-	<string-array name="settings_gpu_resolution_scale_entries">
-		<item>1x</item>
-		<item>2x</item>
-		<item>3x (720p)</item>
-		<item>4x</item>
-		<item>5x (1080p)</item>
-		<item>6x (1440p)</item>
-		<item>7x</item>
-		<item>8x</item>
-		<item>9x (4K)</item>
-		<item>10x</item>
-		<item>11x</item>
-		<item>12x</item>
-		<item>13x</item>
-		<item>14x</item>
-		<item>15x</item>
-		<item>16x</item>
-	</string-array>
-	<string-array name="settings_display_crop_mode_entries">
-		<item>Нет</item>
-		<item>Только вылеты развёртки</item>
-		<item>Все границы</item>
-	</string-array>
-	<string-array name="settings_display_aspect_ratio_names">
-   		<item>Автонастройка (нативно игре)</item>
-    		<item>Автонастройка (под экран)</item>
-    		<item>Вручную</item>
-    		<item>4:3</item>
-    		<item>16:9</item>
-    		<item>19:9</item>
-    		<item>20:9</item>
-    		<item>PAR 1:1</item>
-	</string-array>
-	<string-array name="settings_gpu_texture_filter_names">
-		<item>Метод ближайшего соседа</item>
-		<item>Билинейная</item>
-		<item>Билинейная (без сглаживания краёв)</item>
-		<item>JINC2</item>
-		<item>JINC2 (без сглаживания краёв)</item>
-		<item>xBR</item>
-		<item>xBR (без сглаживания краёв)</item>
-	</string-array>
-	<string-array name="settings_controller_type_entries">
-		<item>Нет</item>
-		<item>Цифровой</item>
-		<item>Аналоговый (DualShock)</item>
-		<item>Аналоговый джойстик</item>
-		<item>NeGcon</item>
-		<item>GunCon</item>
-	</string-array>
-	<string-array name="settings_memory_card_mode_entries">
-		<item>Без карты памяти</item>
-		<item>Общая для всех игр</item>
-		<item>Своя карта для каждой игры (по коду)</item>
-		<item>Своя карта для каждой игры (по названию)</item>
-	</string-array>
-	<string-array name="emulation_touchscreen_menu">
-		<item>Сменить вид</item>
-		<item>Настроить видимость</item>
-		<item>Добавить/убрать кнопки</item>
-		<item>Положение кнопок</item>
-		<item>Размер кнопок</item>
-	</string-array>
-	<string-array name="touchscreen_layout_menu">
-		<item>Настроить видимость</item>
-		<item>Добавить/убрать кнопки</item>
-		<item>Положение кнопок</item>
-		<item>Размер кнопок</item>
-		<item>Сбросить макет</item>
-		<item>Закрыть редактор</item>
-	</string-array>
-	<string-array name="settings_cdrom_read_speedup_entries">
-		<item>Нет (двойная скорость)</item>
-		<item>2x (скорость 4x)</item>
-		<item>3x (скорость 6x)</item>
-		<item>4x (скорость 8x)</item>
-		<item>5x (скорость 10x)</item>
-		<item>6x (скорость 12x)</item>
-		<item>7x (скорость 14x)</item>
-		<item>8x (скорость 16x)</item>
-		<item>9x (скорость 18x)</item>
-		<item>10x (скорость 20x)</item>
-	</string-array>
-	<string-array name="settings_touchscreen_controller_view_entries">
-		<item>Нет</item>
-		<item>Цифровой</item>
-		<item>Аналоговый, один стик</item>
-		<item>Аналоговый, два стика</item>
-		<item>Световой пистолет</item>
-	</string-array>
-	<string-array name="settings_audio_backend_entries">
-		<item>Нет (без звука)</item>
-		<item>Cubeb</item>
-		<item>OpenSL ES (рекомендовано)</item>
-	</string-array>
-	<string-array name="settings_audio_buffer_size_entries">
-		<item>1024 блока (23.22 мс)</item>
-		<item>2048 блоков (46.44 мс, рекомендовано)</item>
-		<item>3072 блока (69.66 мс)</item>
-		<item>4096 блоков (92.88 мс)</item>
-	</string-array>
-	<string-array name="settings_log_level_entries">
-		<item>Нет</item>
-		<item>Error</item>
-		<item>Warning</item>
-		<item>Performance Warnings</item>
-		<item>Information</item>
-		<item>Verbose</item>
-		<item>Developer</item>
-		<item>Profile</item>
-		<item>Debug</item>
-		<item>Trace</item>
-	</string-array>
-	<string-array name="settings_tabs">
-		<item>Основные</item>
-		<item>Экран</item>
-		<item>Звук</item>
-		<item>Улучшения</item>
-		<item>Достижения</item>
-		<item>Расширенные</item>
-	</string-array>
-	<string-array name="settings_gpu_msaa_entries">
-		<item>Выключен</item>
-		<item>2x MSAA</item>
-		<item>4x MSAA</item>
-		<item>8x MSAA</item>
-		<item>2x SSAA</item>
-		<item>4x SSAA</item>
-		<item>8x SSAA</item>
-	</string-array>
-	<string-array name="settings_advanced_display_fps_limit_entries">
-		<item>Без ограничения (выводить все кадры)</item>
-		<item>10 FPS</item>
-		<item>15 FPS</item>
-		<item>30 FPS</item>
-		<item>45 FPS</item>
-		<item>60 FPS</item>
-		<item>75 FPS</item>
-		<item>90 FPS</item>
-	</string-array>
-	<string-array name="settings_emulation_speed_entries">
-		<item>Без ограничения</item>
-		<item>10% [6 FPS (NTSC) / 5 FPS (PAL)]</item>
-		<item>20% [12 FPS (NTSC) / 10 FPS (PAL)]</item>
-		<item>30% [18 FPS (NTSC) / 15 FPS (PAL)]</item>
-		<item>40% [24 FPS (NTSC) / 20 FPS (PAL)]</item>
-		<item>50% [30 FPS (NTSC) / 25 FPS (PAL)]</item>
-		<item>60% [36 FPS (NTSC) / 30 FPS (PAL)]</item>
-		<item>70% [42 FPS (NTSC) / 35 FPS (PAL)]</item>
-		<item>80% [48 FPS (NTSC) / 40 FPS (PAL)]</item>
-		<item>90% [54 FPS (NTSC) / 45 FPS (PAL)]</item>
-		<item>100% [60 FPS (NTSC) / 50 FPS (PAL), по умолчанию]</item>
-		<item>125% [75 FPS (NTSC) / 62 FPS (PAL)]</item>
-		<item>150% [90 FPS (NTSC) / 75 FPS (PAL)]</item>
-		<item>175% [105 FPS (NTSC) / 87 FPS (PAL)]</item>
-		<item>200% [120 FPS (NTSC) / 100 FPS (PAL)]</item>
-		<item>250% [150 FPS (NTSC) / 125 FPS (PAL)]</item>
-		<item>300% [180 FPS (NTSC) / 150 FPS (PAL)]</item>
-		<item>350% [210 FPS (NTSC) / 175 FPS (PAL)]</item>
-		<item>400% [240 FPS (NTSC) / 200 FPS (PAL)]</item>
-		<item>450% [270 FPS (NTSC) / 225 FPS (PAL)]</item>
-		<item>500% [300 FPS (NTSC) / 250 FPS (PAL)]</item>
-		<item>600% [360 FPS (NTSC) / 300 FPS (PAL)]</item>
-		<item>700% [420 FPS (NTSC) / 350 FPS (PAL)]</item>
-		<item>800% [480 FPS (NTSC) / 400 FPS (PAL)]</item>
-		<item>900% [540 FPS (NTSC) / 450 FPS (PAL)]</item>
-		<item>1000% [600 FPS (NTSC) / 500 FPS (PAL)]</item>
-	</string-array>
-	<string-array name="settings_advanced_cpu_overclock_entries">
-		<item>25% (8 МГц)</item>
-		<item>50% (16 МГц)</item>
-		<item>75% (24 МГц)</item>
-		<item>100% (33 МГц, по умолчанию)</item>
-		<item>125% (41 МГц)</item>
-		<item>150% (49 МГц)</item>
-		<item>175% (57 МГц)</item>
-		<item>200% (66 МГц)</item>
-		<item>225% (74 МГц)</item>
-		<item>250% (82 МГц)</item>
-		<item>275% (90 МГц)</item>
-		<item>300% (99 МГц)</item>
-		<item>350% (115 МГц)</item>
-		<item>400% (132 МГц)</item>
-		<item>450% (148 МГц)</item>
-		<item>500% (165 МГц)</item>
-		<item>500% (165 МГц)</item>
-		<item>600% (198 МГц)</item>
-		<item>700% (231 МГц)</item>
-		<item>800% (264 МГц)</item>
-		<item>900% (297 МГц)</item>
-		<item>1000% (330 МГц)</item>
-	</string-array>
-	<string-array name="settings_emulation_screen_orientation_entries">
-		<item>По выбору системы</item>
-		<item>Портретная</item>
-		<item>Ландшафтная</item>
-		<item>По датчику положения</item>
-	</string-array>
-	<string-array name="settings_language_entries">
-        	<item>По выбору системы</item>
-        	<item>Английский</item>
-		<item>Бразильский португальский</item>
-        	<item>Итальянский</item>
-        	<item>Нидерландский</item>
-        	<item>Испанский</item>
-        	<item>Русский</item>
- 	</string-array>
-	<string-array name="settings_theme_entries">
-		<item>По выбору системы</item>
-		<item>Светлая</item>
-		<item>Тёмная</item>
-	</string-array>
-	<string-array name="settings_downsample_mode_entries">
-		<item>Выключен</item>
-		<item>Прямоугольный (понижать 3D/сглаживать всё)</item>
-		<item>Адаптивный (не понижать 3D/сглаживать 2D)</item>
-	</string-array>
-	<string-array name="settings_boolean_entries">
-		<item>Выключено</item>
-		<item>Включено</item>
-	</string-array>
-	<string-array name="settings_multitap_mode_entries">
-        	<item>Отключен</item>
-        	<item>Подключен к порту 1</item>
-        	<item>Подключен к порту 2</item>
-        	<item>Подключен к портам 1 и 2</item>
-    	</string-array>
- 	<string-array name="memory_card_editor_save_menu">
-     		<item>Скопировать сохранение</item>
-     		<item>Удалить сохранение</item>
-        </string-array>
-        <string-array name="settings_touchscreen_controller_port_entries">
-               <item>Порт 1</item>
-               <item>Порт 2</item>
-               <item>Multitap 3</item>
-               <item>Multitap 4</item>
-               <item>Multitap 5</item>
-               <item>Multitap 6</item>
-               <item>Multitap 7</item>
-               <item>Multitap 8</item>
-        </string-array>
-	<string-array name="settings_cdrom_seek_speedup_entries">
-               <item>Нет (обычная скорость)</item>
-               <item>Без задержки</item>
-               <item>2x</item>
-               <item>3x</item>
-               <item>4x</item>
-               <item>5x</item>
-               <item>6x</item>
-               <item>7x</item>
-               <item>8x</item>
-               <item>9x</item>
-               <item>10x</item>
-        </string-array>
-</resources>
diff --git a/android/app/src/main/res/values-ru/strings.xml b/android/app/src/main/res/values-ru/strings.xml
deleted file mode 100644
index c88009189..000000000
--- a/android/app/src/main/res/values-ru/strings.xml
+++ /dev/null
@@ -1,368 +0,0 @@
-<resources>
-	<string name="app_name">DuckStation</string>
-	<string name="action_settings">Настройки</string>
-	<string name="action_controller_mapping">Настройки управления</string>
-	<string name="title_activity_settings">Настройки</string>
-	<string name="settings_console_region">Регион консоли</string>
-	<string name="settings_console_tty_output">Вывод в TTY</string>
-	<string name="settings_console_fast_boot">Быстрый запуск</string>
-	<string name="settings_osd_show_messages">Показывать сообщения</string>
-	<string name="settings_osd_show_speed">Показывать скорость эмуляции</string>
-	<string name="settings_osd_show_show_fps">Показывать частоту кадров в игре</string>
-	<string name="settings_osd_show_show_vps">Показывать частоту кадров дисплея</string>
-	<string name="settings_cpu_execution_mode">Режим работы CPU</string>
-	<string name="settings_gpu_renderer">Графический движок</string>
-	<string name="settings_gpu_resolution_scale">Масштаб разрешения</string>
-	<string name="title_activity_emulation">EmulationActivity</string>
-	<string name="settings_emulation_speed">Скорость эмуляции</string>
-	<string name="settings_fast_forward_speed">Скорость перемотки</string>
-	<string name="settings_save_state_on_exit">Сохранять при выходе</string>
-	<string name="settings_emulation_screen_orientation">Ориентация экрана эмуляции</string>
-	<string name="settings_load_patch_codes">Загружать чит-коды</string>
-	<string name="settings_summary_save_state_on_exit">Автоматически сохранять состояние эмулятора при выходе. Позволяет продолжить игру с места остановки.</string>
-	<string name="settings_summary_load_patch_codes">Загружать чит-коды из cheats/&lt;название игры&gt;.cht в формате PCSXR или Libretro. Коды можно активировать после запуска игры.</string>
-	<string name="settings_apply_compatibility_settings">Применять настройки совместимости</string>
-	<string name="settings_summary_apply_compatibility_settings">Автоматически отключать улучшения, которые не поддерживаются играми.</string>
-	<string name="settings_summary_video_sync">Включите для синхронизации частоты обновления DuckStation с частотой экрана устройства. Синхронизация автоматически выключится, если скорость эмуляции не равна 100%.</string>
-	<string name="settings_video_sync">Видеосинхронизация</string>
-	<string name="settings_cpu_overclocking">Разгон CPU</string>
-	<string name="settings_cdrom_region_check">Проверка региона CD-ROM</string>
-	<string name="settings_summary_cdrom_region_check">Снижает вероятность некорректного определения региона диска эмулятором. Как правило, не влияет на стабильность.</string>
-	<string name="settings_cdrom_preload_image_to_ram">Предзагрузка образа CD-ROM в ОЗУ</string>
-	<string name="settings_summary_preload_image_to_ram">Загружать образ диска в оперативную память. Полезно при запуске игр с ненадёжных сетевых ресурсов. В некоторых случаях помогает устранить замедления при запуске игрой аудиодорожек.</string>
-	<string name="settings_pgxp_vertex_cache">Вершинный кэш PGXP</string>
-	<string name="settings_summary_pgxp_vertex_cache">Использовать координаты экрана в качестве резервных при отслеживании вершин с помощью отказов памяти. Может улучшать совместимость PGXP.</string>
-	<string name="settings_pgxp_cpu_mode">Режим CPU PGXP</string>
-	<string name="settings_summary_pgxp_cpu_mode">Пытаться отслеживать смещения вершин с помощью CPU. Требуется для правильной работы PGXP в некоторых играх. Существенно влияет на производительность.</string>
-	<string name="settings_cpu_recompiler_icache">Рекомпиляция кэша команд CPU</string>
-	<string name="settings_summary_cpu_recompiler_icache">Включить симуляцию кэша команд CPU в рекомпиляторе. Повышает точность, незначительно снижая производительность. Попробуйте включить, если игры идут слишком быстро.</string>
-	<string name="settings_cpu_recompiler_fastmem">Быстрый доступ к памяти в рекомпиляторе CPU</string>
-	<string name="settings_summary_cpu_recompiler_fastmem">Повышает эффективность доступа к гостевой памяти с помощью бэкпатчей и ошибок страниц. Отключите при нестабильной работе на устройстве.</string>
-	<string name="settings_presented_frame_limit">Ограничение частоты кадров</string>
-	<string name="settings_logging_level">Уровень логирования</string>
-	<string name="settings_log_to_file">Лог в файл</string>
-	<string name="settings_summary_log_to_file">Записывать сообщения лога в duckstation.log в папке эмулятора. Из-за снижения скорости эмуляции используйте только для отладки.</string>
-	<string name="settings_log_to_logcat">Лог в Logcat</string>
-	<string name="settings_summary_log_to_logcat">Записывать сообщения лога в журнал отладки Android. Полезно только при подключении к компьютеру с adb.</string>
-	<string name="settings_volume">Громкость</string>
-	<string name="settings_summary_volume">Изменение громкости звука эмулятора.</string>
-	<string name="settings_fast_forward_volume">Громкость при ускорении</string>
-	<string name="settings_summary_fast_forward_volume">Изменение громкости звука при ускоренной перемотке.</string>
-	<string name="settings_mute_all_sound">Отключить звук</string>
-	<string name="settings_summary_mute_all_sound">Отключает вывод звука в эмуляторе.</string>
-	<string name="settings_mute_cd_audio">Отключить CD аудио</string>
-	<string name="settings_summary_mute_cd_audio">Принудительное отключение CD-DA и XA дорожек диска. Может использоваться для отключения фоновой музыки в играх.</string>
-	<string name="settings_audio_backend">Аудио бэкенд</string>
-	<string name="settings_audio_buffer_size">Размер аудио буфера</string>
-	<string name="settings_summary_audio_buffer_size">Определяет задержку звука между обработкой и выводом. Меньшие значения снижают задержку, но вызывают треск при нестабильной скорости эмуляции.</string>
-	<string name="settings_audio_sync">Аудиосинхронизация</string>
-	<string name="settings_summary_audio_sync">Ускоряет эмуляцию в зависимости от скорости вывода блоков бэкендом. Помогает устранить искажения звука, если эмуляция идёт слишком быстро. Синхронизация автоматически выключается, если скорость эмуляции не равна 100%.</string>
-	<string name="settings_controller_type">Тип контроллера</string>
-	<string name="settings_enable_analog_mode_on_reset">Аналоговый режим при сбросе</string>
-	<string name="settings_touchscreen_controller_view">Вид экранного геймпада</string>
-	<string name="settings_auto_hide_touchscreen_controller">Автоотключение экранного геймпада</string>
-	<string name="settings_summary_auto_hide_touchscreen_controller">Скрывать экранный геймпад при подключении внешнего устройства ввода.</string>
-	<string name="settings_vibrate_on_press">Вибрация при касании</string>
-	<string name="settings_summary_vibrate_on_press">Включить короткую вибрацию при нажатии экранных кнопок. Виброотклик должен быть включен в настройках системы.</string>
-	<string name="settings_enable_vibration">Включить вибрацию</string>
-	<string name="settings_summary_enable_vibration">Перенаправлять отдачу в игре на вибромотор смартфона.</string>
-	<string name="settings_memory_card_1_type">Тип карты памяти 1</string>
-	<string name="settings_memory_card_2_type">Тип карты памяти 2</string>
-	<string name="settings_crop_mode">Режим обрезки</string>
-	<string name="settings_aspect_ratio">Соотношение сторон</string>
-	<string name="settings_linear_upscaling">Линейное масштабирование</string>
-	<string name="settings_integer_upscaling">Целочисленное масштабирование</string>
-	<string name="settings_summary_linear_upscaling">Сглаживает картинку при масштабировании изображения с консоли под экран.</string>
-	<string name="settings_summary_integer_upscaling">Добавляет пустое пространство к изображению, чтобы пиксельное соотношение устройства и консоли равнялось целому числу. Позволяет получить более чёткую картинку в 2D-играх.</string>
-	<string name="settings_summary_osd_show_messages">Выводить на экран сообщения о системных событиях, таких как сохранение/загрузка, снимок экрана и т.д.</string>
-	<string name="settings_summary_osd_show_speed">Показывать скорость эмуляции в процентах в правом верхнем углу экрана.</string>
-	<string name="settings_summary_osd_show_fps">Показывать внутреннюю частоту кадров игры в правом верхнем углу экрана.</string>
-	<string name="settings_summary_osd_show_vps">Показывать количество кадров (синхронизаций) в секунду в правом верхнем углу экрана.</string>
-	<string name="settings_cdrom_read_speedup">Ускорение чтения CD-ROM</string>
-	<string name="settings_summary_cdrom_read_speedup">Повышает скорость считывания диска на заданный множитель. Применяется только в режиме чтения с удвоенной скоростью и не учитывается при воспроизведении аудио. Ускоряет загрузки в некоторых играх, но может приводить к ошибкам.</string>
-	<string name="settings_summary_console_fast_boot">Пропускать заставку BIOS, загружаясь прямо в игру. Как правило, не влияет на стабильность.</string>
-	<string name="settings_msaa">Мультисэмплинг</string>
-	<string name="settings_true_color">Рендеринг в True Color (24-бита, без дизеринга)</string>
-	<string name="settings_summary_true_color">Обеспечивает более качественные градиенты, но меняет отображение некоторых цветов. Отключение опции также включает дизеринг. Совместимо с большинством игр.</string>
-	<string name="settings_scaled_dithering">Масштабировать дизеринг</string>
-	<string name="settings_summary_scaled_dithering">Масштабировать паттерн дизеринга под разрешение эмулируемого GPU, маскируя эффект зашумления на высоких разрешениях. Поддерживается только аппаратными рендерами и обычно не влияет на стабильность.</string>
-	<string name="settings_disable_interlacing">Отключить чересстрочность</string>
-	<string name="settings_summary_disable_interlacing">Принудительный рендеринг и вывод кадров в прогрессивной развёртке. Убирает эффект \"гребёнки\" для игр в 480i. Как правило, не влияет на стабильность.</string>
-	<string name="settings_texture_filtering">Фильтрация текстур</string>
-	<string name="settings_force_ntsc_timings">Принудительный NTSC-тайминг (PAL в 60 Гц)</string>
-	<string name="settings_summary_force_ntsc_timings">Использовать NTSC-тайминги кадра когда консоль в режиме PAL, тем самым принудительно запуская игры PAL в 60 Гц.</string>
-	<string name="settings_widescreen_hack">Широкоформатный хак</string>
-	<string name="settings_summary_widescreen_hack">Масштабировать позиции вершин в пространстве экрана до широкоформатных соотношений сторон, расширяя область обзора в 3D-играх с 4:3 до 16:9. Несовместимо с некоторыми играми.</string>
-	<string name="settings_force_4_3_for_24bit">Использовать 4:3 для 24-бит</string>
-	<string name="settings_summary_force_4_3_for_24bit">Переключаться обратно на соотношение сторон 4:3 при выводе 24-битного контента, например видео.</string>
-	<string name="settings_chroma_smoothing_24bit">Сглаживание цвета для 24-бит</string>
-	<string name="settings_summary_chrome_smoothing_24bit">Сглаживать блочность цветовых переходов в 24-битном контенте, например видео. Поддерживается только аппаратными рендерами.</string>
-	<string name="settings_pgxp_geometry_correction">Коррекция геометрии PGXP</string>
-	<string name="settings_summary_pgxp_geometry_correction">Уменьшает дрожание и неровность текстур, характерные для PS1. Поддерживается только аппаратными рендерами. Несовместимо с некоторыми играми.</string>
-	<string name="settings_pgxp_culling_correction">Коррекция выборки PGXP</string>
-	<string name="settings_summary_pgxp_culling_correction">Повышает точность отбраковки полигонов, снижая количество провалов в геометрии. Требуется включение коррекции геометрии.</string>
-	<string name="settings_pgxp_texture_correction">Коррекция текстур PGXP</string>
-	<string name="settings_summary_pgxp_texture_correction">Использовать перспективно-корректную интерполяцию координат текстур и цветов для выпрямления неровности текстур. Должна быть включена коррекция геометрии.</string>
-	<string name="settings_pgxp_preserve_projection_precision">Точность проекции PGXP</string>
-	<string name="settings_summary_pgxp_preserve_projection_precision">Включает повышенную точность PGXP. Может улучшать графику в некоторых играх, но в других вызывать ошибки.</string>
-	<string name="settings_pgxp_depth_buffer">Буфер глубины PGXP</string>
-	<string name="settings_summary_pgxp_depth_buffer">Пытаться устранять наложения полигонов проверкой пикселей по значениям глубины PGXP. Обладает низкой совместимостью, но в ряде игр даёт хороший эффект.</string>
-	<string name="menu_main_resume_last_session">Продолжить сеанс</string>
-	<string name="menu_main_start_file">Открыть файл</string>
-	<string name="menu_main_start_bios">Запустить BIOS</string>
-	<string name="menu_main_edit_game_directories">Настроить каталоги игр</string>
-	<string name="menu_main_scan_for_new_games">Обновить список игр</string>
-	<string name="menu_main_rescan_all_games">Проверить игры в списке</string>
-	<string name="menu_main_import_bios">Импортировать BIOS</string>
-	<string name="menu_main_show_version">Версия приложения</string>
-	<string name="menu_main_github_repository">Репозиторий GitHub</string>
-	<string name="menu_main_discord_server">Сервер Discord</string>
-	<string name="menu_game_list_entry_start_game">Запустить</string>
-	<string name="menu_game_list_entry_resume_game">Продолжить</string>
-	<string name="android_progress_callback_please_wait">Пожалуйста, подождите...</string>
-	<string name="android_progress_callback_ok">OK</string>
-	<string name="android_progress_callback_information">Информация</string>
-	<string name="android_progress_callback_confirmation">Подтверждение</string>
-	<string name="android_progress_callback_yes">Да</string>
-	<string name="android_progress_callback_no">Нет</string>
-	<string name="emulation_activity_error">Ошибка</string>
-	<string name="emulation_activity_ok">OK</string>
-	<string name="emulation_activity_import_patch_codes">Импорт чит-кодов...</string>
-	<string name="emulation_activity_patch_on">(ВКЛ)</string>
-	<string name="emulation_activity_patch_off">(ВЫКЛ)</string>
-	<string name="emulation_activity_choose_patch_code_file">Выберите файл с чит-кодами</string>
-	<string name="emulation_activity_failed_to_import_patch_codes">Не удалось импортировать чит-коды. Убедитесь, что выбранный файл в формате PCSXR или Libretro.</string>
-	<string name="main_activity_choose_directory">Выберите каталог</string>
-	<string name="main_activity_error">Ошибка</string>
-	<string name="main_activity_get_path_from_file_error">Не удалось получить путь к указанному файлу. Пожалуйста, убедитесь, что файл присутствует во внутреннем/внешнем хранилище. Нажмите значок настроек в окне выбора каталога. Включите отображение внутренней памяти. Нажмите кнопку меню и выберите устройство или SD-карту.</string>
-	<string name="main_activity_ok">OK</string>
-	<string name="main_activity_get_path_from_directory_error">Не удалось получить путь к указанному каталогу. Пожалуйста, убедитесь, что каталог присутствует во внутреннем/внешнем хранилище. Нажмите значок настроек в окне выбора каталога. Включите отображение внутренней памяти. Нажмите кнопку меню и выберите устройство или SD-карту.</string>
-	<string name="main_activity_external_storage_permissions_error">DuckStation требуется разрешение для доступа к внешнему хранилищу.</string>
-	<string name="main_activity_choose_disc_image">Выберите образ диска</string>
-	<string name="main_activity_missing_bios_image_prompt">Не найдены образы BIOS в папке bios эмулятора. Указать путь и импортировать образ BIOS сейчас?</string>
-	<string name="main_activity_missing_bios_image">Отсутствует образ BIOS</string>
-	<string name="main_activity_yes">Да</string>
-	<string name="main_activity_no">Нет</string>
-	<string name="main_activity_choose_bios_image">Выберите образ BIOS</string>
-	<string name="main_activity_failed_to_open_bios_image">Не удалось открыть образ BIOS.</string>
-	<string name="main_activity_failed_to_read_bios_image_prefix">\"Не удалось прочитать образ BIOS: \"</string>
-	<string name="main_activity_bios_image_too_large">Образ BIOS слишком большой. Вы должны выбрать образ BIOS, а не игру, и он должен быть размером 512 KB.</string>
-	<string name="main_activity_invalid_error">Образ BIOS неправильный или уже был импортирован.</string>
-	<string name="main_activity_show_version_title">Версия</string>
-	<string name="main_activity_copy">Копировать</string>
-	<string name="settings_gpu_thread">Рендеринг GPU в отдельном потоке</string>
-	<string name="settings_summary_gpu_thread">Использовать второй поток для отрисовки графики. В настоящее время поддерживается только программным рендерингом, существенно повышая производительность и не влияя на стабильность.</string>
-	<string name="settings_gpu_threaded_presentation">Вывод с GPU в отдельном потоке</string>
-	<string name="settings_summary_gpu_threaded_presentation">Выводить кадры в фоновом потоке когда не используется ускорение или видеосинхронизация. Может значительно повысить производительность при рендеринге на Vulkan.</string>
-	<string name="settings_language">Язык (требуется перезапуск)</string>
-	<string name="touchscreen_controller_stop_editing">Закрыть редактор</string>
-	<string name="touchscreen_controller_reset_layout">Сбросить макет</string>
-	<string name="emulation_activity_touchscreen_controller_not_active">Экранный геймпад неактивен.</string>
-	<string name="settings_theme">Тема</string>
-	<string name="settings_controller_mapping_summary">Настроить привязки подключенного геймпада к кнопкам и осям эмулируемого контроллера.</string>
-	<string name="settings_controller_mapping">Настройка геймпада</string>
-	<string name="controller_binding_dialog_message">Нажмите кнопку геймпада для установки новой привязки.\n\nТекущая привязка: %s</string>
-	<string name="controller_binding_dialog_no_binding">&lt;Нет привязки&gt;</string>
-	<string name="controller_binding_dialog_cancel">Отмена</string>
-	<string name="controller_binding_dialog_clear">Удалить</string>
-	<string name="controller_mapping_activity_title">Управление</string>
-	<string name="controller_mapping_activity_no_profiles_found">Профили не найдены.</string>
-	<string name="controller_mapping_activity_select_input_profile">Профиль устройства ввода</string>
-	<string name="controller_mapping_activity_failed_to_load_profile">Не удалось загрузить профиль \'%s\'</string>
-	<string name="controller_mapping_activity_input_profile_name">Имя профиля ввода:</string>
-	<string name="controller_mapping_activity_save">Сохранить</string>
-	<string name="controller_mapping_activity_name_must_be_provided">Требуется ввести имя.</string>
-	<string name="controller_mapping_activity_failed_to_save_input_profile">Не удалось сохранить профиль ввода.</string>
-	<string name="controller_mapping_activity_input_profile_saved">Профиль ввода \'%s\' сохранён.</string>
-	<string name="controller_mapping_activity_cancel">Отмена</string>
-	<string name="settings_use_analog_sticks_for_dpad">Джойстик как d-pad в цифровом режиме</string>
-	<string name="settings_summary_enable_analog_mode_on_reset">Переключить контроллер в аналоговый режим при включении/перезагрузке консоли.</string>
-	<string name="settings_summary_use_analog_sticks_for_dpad">Использовать аналоговый джойстик как d-pad в цифровом режиме DualShock.</string>
-	<string name="settings_disable_all_enhancements">Отключить улучшения</string>
-	<string name="settings_summary_disable_all_enhancements">Временно отключить все улучшения. Используйте для отладки.</string>
-	<string name="settings_downsample_mode">Даунсэмплинг</string>
-	<string name="activity_game_properties">Свойства</string>
-	<string name="game_properties_preference_use_global_setting">Глобальная настройка</string>
-	<string name="settings_input_profile">Профиль ввода</string>
-	<string name="game_properties_tab_summary">Сведения</string>
-	<string name="game_properties_tab_game_settings">Настройки игры</string>
-	<string name="game_properties_tab_controller_settings">Настройки контроллера</string>
-	<string name="settings_audio_resampling">Аудио ресэмплинг</string>
-	<string name="settings_summary_audio_resampling">Изменять частоту звука вместо пропуска блоков, если скорость эмуляции отличается от 100%. Улучшает звук при ускорении/замедлении, незначительно влияя на производительность.</string>
-	<string name="settings_general_sync_to_host_refresh_rate">Синхронизировать с частотой хоста</string>
-	<string name="settings_summary_general_sync_to_host_refresh_rate">Подстраивать скорость эмуляции для совпадения частоты обновления консоли с частотой хоста, если включены Видеосинхронизация и Аудио ресэмплинг. Обеспечивает наиболее плавную анимацию за счёт возможного завышения скорости менее чем на 1%.</string>
-	<string name="settings_sustained_performance_mode">Режим устойчивой производительности</string>
-	<string name="settings_summary_sustained_performance_mode">Включить режим устойчивой производительности Андроид. Обеспечивает стабильный фреймрейт при продолжительных сеансах игры на некоторых устройствах.</string>
-	<string name="title_activity_game_directories">Настройка каталогов игр</string>
-	<string name="settings_game_directories">Каталоги игр</string>
-	<string name="settings_summary_game_directories">Редактировать список каталогов для поиска игр.</string>
-	<string name="game_directories_scanning_subdirectories">Сканировать подкаталоги.</string>
-	<string name="game_directories_not_scanning_subdirectories">Не сканировать подкаталоги.</string>
-	<string name="settings_display_all_frames">Оптимальное распределение кадров</string>
-	<string name="settings_summary_display_all_frames">Включение настройки гарантирует вывод всех кадров с консоли на экран для оптимального распределения. Попробуйте отключить, если не получается достичь полной скорости или есть проблемы со звуком.</string>
-	<string name="menu_edit_game_directories_add_directory">Добавить каталог</string>
-    	<string name="menu_edit_game_directories_add_path">Добавить путь</string>
-    	<string name="edit_game_directories_add_path">Добавить путь</string>
-    	<string name="edit_game_directories_add_path_summary">Введите полный путь к каталогу с играми.\n\nВы можете уточнить его с помощью файлового менеджера.\n\nПример: /storage/emulated/0/games</string>
-        <string name="save_state_info_slot_is_empty">Свободный слот</string>
-    	<string name="save_state_info_game_save_n">Сохранение %d</string>
-    	<string name="save_state_info_global_save_n">Глобальное сохранение %d</string>
-    	<string name="save_state_info_quick_save">Быстрое сохранение</string>
-	<string name="settings_osd_show_show_resolution">Показывать разрешение</string>
-        <string name="settings_summary_osd_show_resolution">Показывать разрешение рендеринга игры в правом верхнем углу экрана.</string>
-	<string name="settings_summary_display_stretch">Растягивать изображение до границ экрана.</string>
-    	<string name="settings_display_stretch">Растягивать на весь экран</string>
-    	<string name="settings_category_global">Основные настройки</string>
-    	<string name="settings_category_display">Настройки экрана</string>
-    	<string name="settings_category_audio">Настройки звука</string>
-    	<string name="settings_category_console">Настройки консоли</string>
-    	<string name="settings_category_cpu">Настройки CPU</string>
-    	<string name="settings_category_gpu">Настройки GPU</string>
-    	<string name="settings_category_logging">Настройки логирования</string>
-    	<string name="dialog_done">Сохранить</string>
-    	<string name="dialog_touchscreen_controller_type">Вид экранного геймпада</string>
-    	<string name="dialog_touchscreen_controller_opacity">Видимость экранного геймпада</string>
-    	<string name="dialog_touchscreen_controller_buttons">Кнопки экранного геймпада</string>
-	<string name="dialog_touchscreen_controller_settings">Настройки экранного геймпада</string>
-	<string name="settings_summary_console_tty_output">Выводить отладочную информацию по игре в консоль.</string>
-        <string name="action_show_game_list">Вид списка</string>
-        <string name="action_show_game_grid">Вид сетки</string>
-        <string name="settings_touch_gliding">Скольжение касаний</string>
-        <string name="settings_summary_touch_gliding">Позволяет нажимать комбинации кнопок скольжением пальца по экрану.</string>
-	<string name="menu_game_list_entry_game_properties">Свойства</string>
-	<string name="emulation_activity_change_disc_select_new_file">Выбрать файл...</string>
-	<string name="settings_achievements_enable">Включить достижения</string>
-    	<string name="settings_summary_achievements_enable">Если опция включена и выполнен вход в учётную запись, DuckStation будет искать достижения при запуске игр.</string>
-    	<string name="settings_achievements_challenge_mode">Режим хардкора</string>
-    	<string name="settings_summary_achievements_challenge_mode">Соревновательный режим. Отключает сохранение состояния, чит-коды, возможность замедления, но удваивает количество получаемых очков достижений. Нельзя включить во время игры.</string>
-    	<string name="settings_achievements_rich_presence">Расширенный статус</string>
-    	<string name="settings_summary_achievements_rich_presence">Если поддерживается, собирать и отсылать на сервер расширенную информацию.</string>
-    	<string name="settings_achievements_username">Имя пользователя</string>
-    	<string name="settings_achievements_token_generation_time">Время генерации маркера доступа</string>
-    	<string name="settings_achievements_login">Вход</string>
-    	<string name="settings_summary_achievements_login">Войти в учётную запись для получения достижений.</string>
-    	<string name="settings_achievements_register">Регистрация</string>
-    	<string name="settings_summary_achievements_register">Открыть ссылку для создания новой учётной записи.</string>
-    	<string name="settings_achievements_logout">Выход</string>
-    	<string name="settings_summary_achievements_logout">Выйти из аккаунта. Получение достижений будет остановлено.</string>
-    	<string name="settings_achievements_view_profile">Просмотр профиля</string>
-    	<string name="settings_summary_achievements_view_profile">Открыть ссылку на ваш профиль.</string>
-    	<string name="settings_achievements_test_mode">Тестовый режим</string>
-    	<string name="settings_summary_achievements_test_mode">Если включено, DuckStation будет считать, что все достижения закрыты и не будет отправлять уведомления об открытии на сервер.</string>
-    	<string name="settings_achievements_use_first_disc_from_playlist">Использовать первый диск в плейлисте</string>
-    	<string name="settings_summary_achievements_use_first_disc_from_playlist">Если включено, для получения достижений будет использоваться первый диск в плейлисте, независимо от активного диска.</string>
-    	<string name="achievement_settings_login_title">Вход в RetroAchievements</string>
-    	<string name="achievement_settings_login_help">Пожалуйста, введите логин и пароль для retroachievements.org. Ваш пароль не хранится в DuckStation. Вместо этого будет сгенерирован маркер доступа.</string>
-    	<string name="achievement_settings_login_username_hint">Логин</string>
-    	<string name="achievement_settings_login_password_hint">Пароль</string>
-    	<string name="achievement_settings_login_login_button">Вход</string>
- 	<string name="achievement_settings_login_cancel_button">Отмена</string>
-    	<string name="achievement_settings_login_failed">Ошибка входа. Пожалуйста, проверьте логин и пароль и повторите попытку.</string>
-    	<string name="achievement_points_format_string">%d очков</string>
-    	<string name="achievement_summary_format_string">Вы открыли %1$d из %2$d достижений, заработав %3$d очков из %4$d возможных.</string>
-    	<string name="achievement_title_challenge_mode_format_string">%s (Режим хардкора)</string>
-    	<string name="settings_achievements_disclaimer">DuckStation использует RetroAchievements (retroachievements.org) для отслеживания прогресса и получения данных о достижениях.</string>
-    	<string name="settings_achievements_confirm_logout_title">Подтвердите выход</string>
-    	<string name="settings_achievements_confirm_logout_message">Завершение сеанса отключит получение достижений до следующего входа в учётную запись. Открытые ранее достижения не будут утеряны.</string>
-	<string name="controller_binding_device_for_vibration">Вибрация для устройства</string>
-    	<string name="controller_settings_tab_settings">Настройки</string>
-    	<string name="controller_settings_tab_hotkeys">Горячие клавиши</string>
-    	<string name="controller_settings_category_button_bindings">Привязки кнопок</string>
-    	<string name="controller_settings_category_axis_bindings">Привязки осей</string>
-    	<string name="controller_settings_category_settings">Настройки</string>
-    	<string name="controller_settings_category_touchscreen_controller">Экранный геймпад</string>
-    	<string name="controller_settings_category_ports">Порты</string>
-    	<string name="controller_settings_main_port_format">Порт %d</string>
-    	<string name="controller_settings_sub_port_format">Порт %1$d%2$c</string>
-        <string name="action_switch_view">Сменить вид</string>
-	<string name="title_activity_memory_card_editor">Редактор карт памяти</string>
-	<string name="action_memory_card_editor">Редактор карт памяти</string>
-	<string name="action_memory_card_editor_import_card">Импорт карты</string>
-	<string name="action_memory_card_editor_open_card">Открыть карту</string>
-	<string name="action_memory_card_editor_new_card">Новая карта</string>
-	<string name="action_memory_card_editor_format_card">Форматировать</string>
-	<string name="action_memory_card_editor_delete_card">Удалить карту</string>
-	<string name="memory_card_editor_no_cards_found">Карты памяти не найдены.</string>
-	<string name="memory_card_editor_card_already_open">Данная карта уже открыта.</string>
-	<string name="memory_card_editor_failed_to_open_card">Не удалось открыть или прочитать карту памяти.</string>
-	<string name="memory_card_editor_must_have_at_least_two_cards_to_copy">Для копирования требуется открыть минимум две карты памяти.</string>
-	<string name="memory_card_editor_copy_save_to">Скопировать %s в...</string>
-	<string name="memory_card_editor_select_card">Выбор карты</string>
-	<string name="memory_card_editor_error">Ошибка</string>
-	<string name="memory_card_editor_copy_insufficient_blocks">Для данного файла требуется %1$d блока, но свободно только %2$d.</string>
-	<string name="memory_card_editor_copy_already_exists">Файл \'%s\' уже создан на целевой карте памяти.</string>
-	<string name="memory_card_editor_copy_read_failed">Не удалось прочитать файл \'%s\' с исходной карты памяти.</string>
-	<string name="memory_card_editor_copy_write_failed">Не удалось записать файл \'%s\' на целевую карту памяти.</string>
-	<string name="memory_card_editor_copy_success">\'%1$s\' скопировано в \'%2$s\'.</string>
-	<string name="memory_card_editor_delete_confirm">Вы действительно хотите удалить сохранение \'%s\'?</string>
-	<string name="memory_card_editor_delete_success">Сохранение \'%s\' удалено.</string>
-	<string name="memory_card_editor_delete_failed">Не удалось удалить файл \'%s\'.</string>
-	<string name="memory_card_editor_no_card_selected">Карта не выбрана.</string>
-	<string name="memory_card_editor_import_failed">Не удалось импортировать карту памяти. Возможно, формат не поддерживается.</string>
-	<string name="memory_card_editor_delete_card_confirm_message">Карта памяти \'%s\' будет удалена без возможности восстановления. Вы действительно хотите удалить данную карту?</string>
-	<string name="memory_card_editor_delete_card_failed">Не удалось удалить \'%s\'.</string>
-	<string name="memory_card_editor_delete_card_success">Карта \'%s\' удалена.</string>
-	<string name="memory_card_editor_format_card_confirm_message">Карта памяти \'%s\' будет отформатирована с удалением всех сохранений. Вы действительно хотите отформатировать данную карту?</string>
-	<string name="memory_card_editor_format_card_failed">Не удалось отформатировать \'%s\'.</string>
-	<string name="memory_card_editor_format_card_success">Карта \'%s\' отформатирована.</string>
-	<string name="memory_card_editor_import_card_confirm_message">Импортирование \'%1$s\' удалит все сохранения на \'%2$s\'. Продолжить?</string>
-	<string name="memory_card_editor_import_card_read_failed">Не удалось прочитать \'%s\'.</string>
-	<string name="memory_card_editor_import_card_failed">Не удалось импортировать карту \'%s\'. Возможно, формат не поддерживается.</string>
-	<string name="memory_card_editor_import_card_success">Карта \'%s\' импортирована.</string>
-	<string name="menu_game_list_entry_choose_cover_image">Обложка</string>
-	<string name="controller_settings_vibration_unsupported">Данное устройство не поддерживает вибрацию.</string>
-	<string name="controller_settings_automatic_mapping">Выполнить автонастройку</string>
-	<string name="controller_settings_summary_automatic_mapping">Попытаться автоматически привязать все кнопки/оси для подключенного устройства.</string>
-	<string name="controller_settings_clear_controller_bindings">Сброс привязок</string>
-	<string name="controller_settings_summary_clear_controller_bindings">Удалить привязки для всех кнопок и осей текущего устройства.</string>
-	<string name="controller_settings_clear_controller_bindings_confirm">Вы действительно хотите удалить все привязки? Это действие нельзя отменить.</string>
-	<string name="controller_settings_clear_controller_bindings_done">Удалены привязки для устройства %d.</string>
-	<string name="controller_auto_mapping_no_devices">Подходящие устройства не найдены. Автонастройка поддерживается только для геймпадов. Вы можете настроить прочие устройства вручную.</string>
-	<string name="controller_auto_mapping_select_device">Выбор устройства</string>
-	<string name="controller_auto_mapping_results">Результаты автонастройки</string>
-	<string name="main_activity_empty_game_list_title">Игры не найдены. Пожалуйста, добавьте каталог с играми или выберите файл вручную.</string>
-	<string name="main_activity_empty_game_list_supported_formats">Поддерживаемые форматы:\n\n%s\n\nДля игр в формате bin требуется наличие файла разметки (.cue).</string>
-	<string name="main_activity_empty_game_list_add_directory">Добавить каталог с играми</string>
-	<string name="main_activity_empty_game_list_start_file">Открыть файл</string>
-	<string name="update_notes_title">Примечание к обновлению</string>
-	<string name="update_notes_message_version_controller_update">В данном обновлении DuckStation добавлена возможность подключения нескольких геймпадов с поддержкой отдачи, поддержка клавиатур, возможность привязки действий к кнопкам громкости.\n\nТребуется перенастроить привязки геймпадов, иначе они перестанут функционировать. Выполнить это сейчас?</string>
-	<string name="settings_osd_show_show_inputs">Показывать нажатия контроллера</string>
-    	<string name="settings_summary_osd_show_inputs">Показывать системное состояние контроллера в левом нижнем углу экрана.</string>
-	<string name="touchscreen_controller_edit_menu">Меню редактора</string>
-    	<string name="settings_achievements_category">Учётная запись</string>
-    	<string name="settings_achievements_global_settings">Глобальные настройки</string>
-    	<string name="settings_category_achievements">Настройки достижений</string>
-    	<string name="settings_multitap_mode">Режим Multitap</string>
-        <string name="settings_touchscreen_controller_port">Порт экранного геймпада</string>
-	<string name="emulation_menu_load_state">Загрузить состояние</string>
-   	<string name="emulation_menu_save_state">Сохранить состояние</string>
- 	<string name="emulation_menu_toggle_fast_forward">Вкл./выкл. ускорение</string>
-	<string name="emulation_menu_achievements">Достижения</string>
-	<string name="emulation_menu_patch_codes">Чит-коды</string>
-   	<string name="emulation_menu_change_disc">Сменить диск</string>
-  	<string name="emulation_menu_touchscreen_controller_settings">Экранный геймпад</string>
-   	<string name="emulation_menu_toggle_analog_mode">Режим контроллера</string>
-   	<string name="emulation_menu_reset_console">Сброс консоли</string>
-	<string name="emulation_menu_exit_game">Закрыть игру</string>
-	<string name="settings_use_software_renderer_for_readbacks">Софт-рендер для обратных считываний</string>
-	<string name="settings_summary_use_software_renderer_for_readbacks">Запускать параллельно программный рендер для обратных считываний VRAM. На некоторых устройствах может существенно повысить скорость при использовании улучшений на аппаратном рендеринге.</string>
-    	<string name="settings_use_software_renderer">Использовать программный рендер</string>
-    	<string name="settings_disable_widescreen">Отключить широкоформатный режим</string>
-	<string name="settings_cdrom_seek_speedup">Ускорение поиска по CD-ROM</string>
-        <string name="settings_summary_cdrom_seek_speedup">Повышает скорость поиска по диску на указанный множитель. В некоторых играх ускоряет подгрузки, но может приводить к ошибкам.</string>
-	<string name="settings_custom_aspect_ratio">Ручная установка соотношения сторон</string>
-     	<string name="settings_summary_custom_aspect_ratio">Применяется, если для соотношения сторон выбрана ручная настройка.</string>
-    	<string name="controller_settings_category_auto_fire_buttons">Турбо-кнопки</string>
-    	<string name="controller_settings_category_auto_fire_bindings">Активаторы турбо</string>
-    	<string name="controller_settings_auto_fire_n_button">Турбо-кнопка %d</string>
-    	<string name="controller_settings_auto_fire_n_frequency">Частота/интервал турбо %d</string>
-    	<string name="controller_binding_auto_fire_n">Турбо %d</string>
-	<string name="settings_category_cdrom">Настройки CD-ROM</string>
-        <string name="settings_cdrom_read_thread">Производить чтение в потоке (асинхронно)</string>
-        <string name="settings_summary_read_thread">Уменьшает задержки в эмуляции с помощью асинхронного чтения/распаковки данных диска в рабочем потоке.</string>
-        <string name="settings_cdrom_load_image_patches">Применять патчи к образам</string>
-        <string name="settings_summary_load_image_patches">Автоматически применять патчи к образам дисков при их наличии. В настоящее время поддерживается только формат PPF.</string>
-        <string name="menu_edit_game_directories_force_saf">Вкл. Scoped Storage</string>
-	<string name="settings_expand_to_cutout">Добавлять область выреза</string>
-    	<string name="settings_summary_expand_to_cutout">Расширяет изображение, используя область выреза.</string>
-</resources>
diff --git a/android/app/src/main/res/values/arrays.xml b/android/app/src/main/res/values/arrays.xml
deleted file mode 100644
index 4d214c260..000000000
--- a/android/app/src/main/res/values/arrays.xml
+++ /dev/null
@@ -1,525 +0,0 @@
-<resources>
-    <string-array name="settings_console_region_entries">
-        <item>Auto-Detect</item>
-        <item>NTSC-J (Japan)</item>
-        <item>NTSC-U (US)</item>
-        <item>PAL (Europe, Australia)</item>
-    </string-array>
-    <string-array name="settings_console_region_values">
-        <item>Auto</item>
-        <item>NTSC-J</item>
-        <item>NTSC-U</item>
-        <item>PAL</item>
-    </string-array>
-    <string-array name="settings_cpu_execution_mode_entries">
-        <item>Interpreter (Slowest)</item>
-        <item>Cached Interpreter (Faster)</item>
-        <item>Recompiler (Fastest)</item>
-    </string-array>
-    <string-array name="settings_cpu_execution_mode_values">
-        <item>Interpreter</item>
-        <item>CachedInterpreter</item>
-        <item>Recompiler</item>
-    </string-array>
-    <string-array name="settings_cpu_fastmem_mode_entries">
-        <item>Disabled (Slowest)</item>
-        <item>MMap (Hardware, Fastest, 64-Bit Only)</item>
-        <item>LUT (Faster)</item>
-    </string-array>
-    <string-array name="settings_cpu_fastmem_mode_values">
-        <item>Disabled</item>
-        <item>MMap</item>
-        <item>LUT</item>
-    </string-array>
-    <string-array name="gpu_renderer_entries">
-        <item>Hardware (OpenGL)</item>
-        <item>Hardware (Vulkan)</item>
-        <item>Software</item>
-    </string-array>
-    <string-array name="gpu_renderer_values">
-        <item>OpenGL</item>
-        <item>Vulkan</item>
-        <item>Software</item>
-    </string-array>
-    <string-array name="settings_gpu_resolution_scale_entries">
-        <item>1x</item>
-        <item>2x</item>
-        <item>3x (for 720p)</item>
-        <item>4x</item>
-        <item>5x (for 1080p)</item>
-        <item>6x (for 1440p)</item>
-        <item>7x</item>
-        <item>8x</item>
-        <item>9x (for 4K)</item>
-        <item>10x</item>
-        <item>11x</item>
-        <item>12x</item>
-        <item>13x</item>
-        <item>14x</item>
-        <item>15x</item>
-        <item>16x</item>
-    </string-array>
-    <string-array name="settings_gpu_resolution_scale_values">
-        <item>1</item>
-        <item>2</item>
-        <item>3</item>
-        <item>4</item>
-        <item>5</item>
-        <item>6</item>
-        <item>7</item>
-        <item>8</item>
-        <item>9</item>
-        <item>10</item>
-        <item>11</item>
-        <item>12</item>
-        <item>13</item>
-        <item>14</item>
-        <item>15</item>
-        <item>16</item>
-    </string-array>
-    <string-array name="settings_display_crop_mode_entries">
-        <item>None</item>
-        <item>Only Overscan Area</item>
-        <item>All Borders</item>
-    </string-array>
-    <string-array name="settings_display_crop_mode_values">
-        <item>None</item>
-        <item>Overscan</item>
-        <item>Borders</item>
-    </string-array>
-    <string-array name="settings_display_aspect_ratio_names">
-        <item>Auto (Game Native)</item>
-        <item>Auto (Match Display)</item>
-        <item>Custom</item>
-        <item>4:3</item>
-        <item>16:9</item>
-        <item>19:9</item>
-        <item>20:9</item>
-        <item>PAR 1:1</item>
-    </string-array>
-    <string-array name="settings_display_aspect_ratio_values">
-        <item>Auto (Game Native)</item>
-        <item>Auto (Match Window)</item>
-        <item>Custom</item>
-        <item>4:3</item>
-        <item>16:9</item>
-        <item>19:9</item>
-        <item>20:9</item>
-        <item>PAR 1:1</item>
-    </string-array>
-    <string-array name="settings_gpu_texture_filter_names">
-        <item>Nearest-Neighbor</item>
-        <item>Bilinear</item>
-        <item>Bilinear (No Edge Blending)</item>
-        <item>JINC2</item>
-        <item>JINC2 (No Edge Blending)</item>
-        <item>xBR</item>
-        <item>xBR (No Edge Blending)</item>
-    </string-array>
-    <string-array name="settings_gpu_texture_filter_values">
-        <item>Nearest</item>
-        <item>Bilinear</item>
-        <item>BilinearBinAlpha</item>
-        <item>JINC2</item>
-        <item>JINC2BinAlpha</item>
-        <item>xBR</item>
-        <item>xBRBinAlpha</item>
-    </string-array>
-    <string-array name="settings_controller_type_entries">
-        <item>None</item>
-        <item>Digital Controller (Gamepad)</item>
-        <item>Analog Controller (DualShock)</item>
-        <item>Analog Joystick</item>
-        <item>NeGcon</item>
-        <item>GunCon</item>
-    </string-array>
-    <string-array name="settings_controller_type_values">
-        <item>None</item>
-        <item>DigitalController</item>
-        <item>AnalogController</item>
-        <item>AnalogJoystick</item>
-        <item>NeGcon</item>
-        <item>NamcoGunCon</item>
-    </string-array>
-    <string-array name="settings_memory_card_mode_entries">
-        <item>No Memory Card</item>
-        <item>Shared Between All Games</item>
-        <item>Separate Card Per Game (Game Code)</item>
-        <item>Separate Card Per Game (Game Title)</item>
-    </string-array>
-    <string-array name="settings_memory_card_mode_values">
-        <item>None</item>
-        <item>Shared</item>
-        <item>PerGame</item>
-        <item>PerGameTitle</item>
-    </string-array>
-    <string-array name="emulation_touchscreen_menu">
-        <item>Change Type</item>
-        <item>Change Opacity</item>
-        <item>Add/Remove Buttons</item>
-        <item>Move Buttons</item>
-        <item>Resize Buttons</item>
-    </string-array>
-    <string-array name="touchscreen_layout_menu">
-        <item>Change Opacity</item>
-        <item>Add/Remove Buttons</item>
-        <item>Move Buttons</item>
-        <item>Resize Buttons</item>
-        <item>Reset Layout</item>
-        <item>Exit Editor</item>
-    </string-array>
-    <string-array name="settings_cdrom_read_speedup_entries">
-        <item>None (Double Speed)</item>
-        <item>2x (Quad Speed)</item>
-        <item>3x (6x Speed)</item>
-        <item>4x (8x Speed)</item>
-        <item>5x (10x Speed)</item>
-        <item>6x (12x Speed)</item>
-        <item>7x (14x Speed)</item>
-        <item>8x (16x Speed)</item>
-        <item>9x (18x Speed)</item>
-        <item>10x (20x Speed)</item>
-    </string-array>
-    <string-array name="settings_cdrom_read_speedup_values">
-        <item>1</item>
-        <item>2</item>
-        <item>3</item>
-        <item>4</item>
-        <item>5</item>
-        <item>6</item>
-        <item>7</item>
-        <item>8</item>
-        <item>9</item>
-        <item>10</item>
-    </string-array>
-    <string-array name="settings_touchscreen_controller_view_entries">
-        <item>None</item>
-        <item>Digital Pad</item>
-        <item>Single Analog Pad</item>
-        <item>Dual Analog Pad</item>
-        <item>Lightgun</item>
-    </string-array>
-    <string-array name="settings_touchscreen_controller_view_values">
-        <item>none</item>
-        <item>digital</item>
-        <item>analog_stick</item>
-        <item>analog_sticks</item>
-        <item>lightgun</item>
-    </string-array>
-    <string-array name="settings_audio_backend_entries">
-        <item>Null (No Output)</item>
-        <item>Cubeb</item>
-        <item>OpenSL ES (Recommended)</item>
-    </string-array>
-    <string-array name="settings_audio_backend_values">
-        <item>Null</item>
-        <item>Cubeb</item>
-        <item>OpenSLES</item>
-    </string-array>
-    <string-array name="settings_audio_buffer_size_entries">
-        <item>1024 Frames (23.22ms)</item>
-        <item>2048 Frames (46.44ms, Recommended)</item>
-        <item>3072 Frames (69.66ms)</item>
-        <item>4096 Frames (92.88ms)</item>
-    </string-array>
-    <string-array name="settings_audio_buffer_size_values">
-        <item>1024</item>
-        <item>2048</item>
-        <item>3072</item>
-        <item>4096</item>
-    </string-array>
-    <string-array name="settings_log_level_entries">
-        <item>None</item>
-        <item>Error</item>
-        <item>Warning</item>
-        <item>Performance Warnings</item>
-        <item>Information</item>
-        <item>Verbose</item>
-        <item>Developer</item>
-        <item>Profile</item>
-        <item>Debug</item>
-        <item>Trace</item>
-    </string-array>
-    <string-array name="settings_log_level_values">
-        <item>None</item>
-        <item>Error</item>
-        <item>Warning</item>
-        <item>Perf</item>
-        <item>Info</item>
-        <item>Verbose</item>
-        <item>Dev</item>
-        <item>Profile</item>
-        <item>Debug</item>
-        <item>Trace</item>
-    </string-array>
-    <string-array name="settings_tabs">
-        <item>General</item>
-        <item>Display</item>
-        <item>Audio</item>
-        <item>Enhancements</item>
-        <item>Achievements</item>
-        <item>Advanced</item>
-    </string-array>
-    <string-array name="settings_gpu_msaa_entries">
-        <item>Disabled</item>
-        <item>2x MSAA</item>
-        <item>4x MSAA</item>
-        <item>8x MSAA</item>
-        <item>2x SSAA</item>
-        <item>4x SSAA</item>
-        <item>8x SSAA</item>
-    </string-array>
-    <string-array name="settings_gpu_msaa_values">
-        <item>1</item>
-        <item>2</item>
-        <item>4</item>
-        <item>8</item>
-        <item>2-ssaa</item>
-        <item>4-ssaa</item>
-        <item>8-ssaa</item>
-    </string-array>
-    <string-array name="settings_advanced_display_fps_limit_entries">
-        <item>Unlimited (Display All Frames)</item>
-        <item>10 FPS</item>
-        <item>15 FPS</item>
-        <item>30 FPS</item>
-        <item>45 FPS</item>
-        <item>60 FPS</item>
-        <item>75 FPS</item>
-        <item>90 FPS</item>
-    </string-array>
-    <string-array name="settings_advanced_display_fps_limit_values">
-        <item>0</item>
-        <item>10</item>
-        <item>15</item>
-        <item>30</item>
-        <item>45</item>
-        <item>60</item>
-        <item>75</item>
-        <item>90</item>
-    </string-array>
-    <string-array name="settings_emulation_speed_entries">
-        <item>Unlimited</item>
-        <item>10% [6 FPS (NTSC) / 5 FPS (PAL)]</item>
-        <item>20% [12 FPS (NTSC) / 10 FPS (PAL)]</item>
-        <item>30% [18 FPS (NTSC) / 15 FPS (PAL)]</item>
-        <item>40% [24 FPS (NTSC) / 20 FPS (PAL)]</item>
-        <item>50% [30 FPS (NTSC) / 25 FPS (PAL)]</item>
-        <item>60% [36 FPS (NTSC) / 30 FPS (PAL)]</item>
-        <item>70% [42 FPS (NTSC) / 35 FPS (PAL)]</item>
-        <item>80% [48 FPS (NTSC) / 40 FPS (PAL)]</item>
-        <item>90% [54 FPS (NTSC) / 45 FPS (PAL)]</item>
-        <item>100% [60 FPS (NTSC) / 50 FPS (PAL), Default]</item>
-        <item>125% [75 FPS (NTSC) / 62 FPS (PAL)]</item>
-        <item>150% [90 FPS (NTSC) / 75 FPS (PAL)]</item>
-        <item>175% [105 FPS (NTSC) / 87 FPS (PAL)]</item>
-        <item>200% [120 FPS (NTSC) / 100 FPS (PAL)]</item>
-        <item>250% [150 FPS (NTSC) / 125 FPS (PAL)]</item>
-        <item>300% [180 FPS (NTSC) / 150 FPS (PAL)]</item>
-        <item>350% [210 FPS (NTSC) / 175 FPS (PAL)]</item>
-        <item>400% [240 FPS (NTSC) / 200 FPS (PAL)]</item>
-        <item>450% [270 FPS (NTSC) / 225 FPS (PAL)]</item>
-        <item>500% [300 FPS (NTSC) / 250 FPS (PAL)]</item>
-        <item>600% [360 FPS (NTSC) / 300 FPS (PAL)]</item>
-        <item>700% [420 FPS (NTSC) / 350 FPS (PAL)]</item>
-        <item>800% [480 FPS (NTSC) / 400 FPS (PAL)]</item>
-        <item>900% [540 FPS (NTSC) / 450 FPS (PAL)]</item>
-        <item>1000% [600 FPS (NTSC) / 500 FPS (PAL)]</item>
-    </string-array>
-    <string-array name="settings_emulation_speed_values">
-        <item>0.0</item>
-        <item>0.1</item>
-        <item>0.2</item>
-        <item>0.3</item>
-        <item>0.4</item>
-        <item>0.5</item>
-        <item>0.6</item>
-        <item>0.7</item>
-        <item>0.8</item>
-        <item>0.9</item>
-        <item>1.0</item>
-        <item>1.25</item>
-        <item>1.5</item>
-        <item>1.75</item>
-        <item>2.0</item>
-        <item>2.5</item>
-        <item>3.0</item>
-        <item>3.5</item>
-        <item>4.0</item>
-        <item>4.5</item>
-        <item>5.0</item>
-        <item>6.0</item>
-        <item>7.0</item>
-        <item>8.0</item>
-        <item>9.0</item>
-        <item>10.0</item>
-    </string-array>
-    <string-array name="settings_advanced_cpu_overclock_entries">
-        <item>25% (8MHz)</item>
-        <item>50% (16MHz)</item>
-        <item>75% (24MHz)</item>
-        <item>100% (33MHz, Default)</item>
-        <item>125% (41MHz)</item>
-        <item>150% (49MHz)</item>
-        <item>175% (57MHz)</item>
-        <item>200% (66MHz)</item>
-        <item>225% (74MHz)</item>
-        <item>250% (82MHz)</item>
-        <item>275% (90MHz)</item>
-        <item>300% (99MHz)</item>
-        <item>350% (115MHz)</item>
-        <item>400% (132MHz)</item>
-        <item>450% (148MHz)</item>
-        <item>500% (165MHz)</item>
-        <item>500% (165MHz)</item>
-        <item>600% (198MHz)</item>
-        <item>700% (231MHz)</item>
-        <item>800% (264MHz)</item>
-        <item>900% (297MHz)</item>
-        <item>1000% (330MHz)</item>
-    </string-array>
-    <string-array name="settings_advanced_cpu_overclock_values">
-        <item>25</item>
-        <item>50</item>
-        <item>75</item>
-        <item>100</item>
-        <item>125</item>
-        <item>150</item>
-        <item>175</item>
-        <item>200</item>
-        <item>225</item>
-        <item>250</item>
-        <item>275</item>
-        <item>300</item>
-        <item>350</item>
-        <item>400</item>
-        <item>450</item>
-        <item>500</item>
-        <item>500</item>
-        <item>600</item>
-        <item>700</item>
-        <item>800</item>
-        <item>900</item>
-        <item>1000</item>
-    </string-array>
-    <string-array name="settings_emulation_screen_orientation_entries">
-        <item>Use Device Setting</item>
-        <item>Portrait</item>
-        <item>Landscape</item>
-        <item>Sensor Based</item>
-    </string-array>
-    <string-array name="settings_emulation_screen_orientation_values">
-        <item>unspecified</item>
-        <item>portrait</item>
-        <item>landscape</item>
-        <item>sensor</item>
-    </string-array>
-    <string-array name="settings_language_entries">
-        <item>Use Device Setting</item>
-        <item>English</item>
-        <item>Portuguese (pt) in Brazil (BR)</item>
-        <item>Italian (it)</item>
-        <item>Dutch (nl)</item>
-        <item>Spanish (es)</item>
-        <item>Russian (ru)</item>
-    </string-array>
-    <string-array name="settings_language_values">
-        <item>none</item>
-        <item>en-EN</item>
-        <item>pt-rBR</item>
-        <item>it-IT</item>
-        <item>nl-NL</item>
-        <item>es-ES</item>
-        <item>ru-RU</item>
-    </string-array>
-    <string-array name="settings_theme_entries">
-        <item>Follow System</item>
-        <item>Light</item>
-        <item>Dark</item>
-    </string-array>
-    <string-array name="settings_theme_values">
-        <item>follow_system</item>
-        <item>light</item>
-        <item>dark</item>
-    </string-array>
-    <string-array name="settings_downsample_mode_entries">
-        <item>Disabled</item>
-        <item>Box (Downsample 3D/Smooth All)</item>
-        <item>Adaptive (Preserve 3D/Smooth 2D)</item>
-    </string-array>
-    <string-array name="settings_downsample_mode_values">
-        <item>Disabled</item>
-        <item>Box</item>
-        <item>Adaptive</item>
-    </string-array>
-    <string-array name="settings_boolean_entries">
-        <item>Disabled</item>
-        <item>Enabled</item>
-    </string-array>
-    <string-array name="settings_boolean_values">
-        <item>false</item>
-        <item>true</item>
-    </string-array>
-    <string-array name="settings_multitap_mode_entries">
-        <item>Disabled</item>
-        <item>Enable on Port 1 Only</item>
-        <item>Enable on Port 2 Only</item>
-        <item>Enable on Ports 1 and 2</item>
-    </string-array>
-    <string-array name="settings_multitap_mode_values">
-        <item>Disabled</item>
-        <item>Port1Only</item>
-        <item>Port2Only</item>
-        <item>BothPorts</item>
-    </string-array>
-    <string-array name="memory_card_editor_save_menu">
-        <item>Copy Save</item>
-        <item>Delete Save</item>
-    </string-array>
-    <string-array name="settings_touchscreen_controller_port_entries">
-        <item>Port 1</item>
-        <item>Port 2</item>
-        <item>Multitap 3</item>
-        <item>Multitap 4</item>
-        <item>Multitap 5</item>
-        <item>Multitap 6</item>
-        <item>Multitap 7</item>
-        <item>Multitap 8</item>
-    </string-array>
-    <string-array name="settings_touchscreen_controller_port_values">
-        <item>0</item>
-        <item>1</item>
-        <item>2</item>
-        <item>3</item>
-        <item>4</item>
-        <item>5</item>
-        <item>6</item>
-        <item>7</item>
-    </string-array>
-    <string-array name="settings_cdrom_seek_speedup_entries">
-        <item>None (Normal Speed)</item>
-        <item>Infinite/Instantaneous</item>
-        <item>2x</item>
-        <item>3x</item>
-        <item>4x</item>
-        <item>5x</item>
-        <item>6x</item>
-        <item>7x</item>
-        <item>8x</item>
-        <item>9x</item>
-        <item>10x</item>
-    </string-array>
-    <string-array name="settings_cdrom_seek_speedup_values">
-        <item>1</item>
-        <item>0</item>
-        <item>2</item>
-        <item>3</item>
-        <item>4</item>
-        <item>5</item>
-        <item>6</item>
-        <item>7</item>
-        <item>8</item>
-        <item>9</item>
-        <item>10</item>
-    </string-array>
-</resources>
diff --git a/android/app/src/main/res/values/attrs.xml b/android/app/src/main/res/values/attrs.xml
deleted file mode 100644
index 7ce840eb6..000000000
--- a/android/app/src/main/res/values/attrs.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-<resources>
-
-    <!-- Declare custom theme attributes that allow changing which styles are
-         used for button bars depending on the API level.
-         ?android:attr/buttonBarStyle is new as of API 11 so this is
-         necessary to support previous API levels. -->
-    <declare-styleable name="ButtonBarContainerTheme">
-        <attr name="metaButtonBarStyle" format="reference" />
-        <attr name="metaButtonBarButtonStyle" format="reference" />
-    </declare-styleable>
-
-</resources>
diff --git a/android/app/src/main/res/values/attrs_touchscreen_controller_button_view.xml b/android/app/src/main/res/values/attrs_touchscreen_controller_button_view.xml
deleted file mode 100644
index e9dacf26a..000000000
--- a/android/app/src/main/res/values/attrs_touchscreen_controller_button_view.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<resources>
-    <declare-styleable name="TouchscreenControllerButtonView">
-        <attr name="unpressedDrawable" format="color|reference" />
-        <attr name="pressedDrawable" format="color|reference" />
-    </declare-styleable>
-</resources>
diff --git a/android/app/src/main/res/values/colors.xml b/android/app/src/main/res/values/colors.xml
deleted file mode 100644
index a66a016b2..000000000
--- a/android/app/src/main/res/values/colors.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<resources>
-    <color name="colorPrimary">#6200EE</color>
-    <color name="colorPrimaryDark">#3700B3</color>
-    <color name="colorAccent">#D81B60</color>
-    <color name="colorNavigation">#000000</color>
-
-    <color name="black_overlay">#66000000</color>
-    <color name="fab_background">#ffffffff</color>
-
-    <color name="emulationActivityPauseBackground">#eeffffff</color>
-</resources>
diff --git a/android/app/src/main/res/values/dimens.xml b/android/app/src/main/res/values/dimens.xml
deleted file mode 100644
index 59a0b0c4f..000000000
--- a/android/app/src/main/res/values/dimens.xml
+++ /dev/null
@@ -1,3 +0,0 @@
-<resources>
-    <dimen name="fab_margin">16dp</dimen>
-</resources>
diff --git a/android/app/src/main/res/values/ic_launcher_background.xml b/android/app/src/main/res/values/ic_launcher_background.xml
deleted file mode 100644
index c5d5899fd..000000000
--- a/android/app/src/main/res/values/ic_launcher_background.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<resources>
-    <color name="ic_launcher_background">#FFFFFF</color>
-</resources>
\ No newline at end of file
diff --git a/android/app/src/main/res/values/strings.xml b/android/app/src/main/res/values/strings.xml
deleted file mode 100644
index e3ddc5a3a..000000000
--- a/android/app/src/main/res/values/strings.xml
+++ /dev/null
@@ -1,368 +0,0 @@
-<resources>
-    <string name="app_name">DuckStation</string>
-    <string name="action_settings">Settings</string>
-    <string name="action_controller_mapping">Controller Settings</string>
-    <string name="title_activity_settings">Settings</string>
-    <string name="settings_console_region">Console Region</string>
-    <string name="settings_console_tty_output">Enable TTY Output</string>
-    <string name="settings_console_fast_boot">Fast Boot</string>
-    <string name="settings_osd_show_messages">Show Messages</string>
-    <string name="settings_osd_show_speed">Show Emulation Speed</string>
-    <string name="settings_osd_show_show_fps">Show Game Frame Rate</string>
-    <string name="settings_osd_show_show_vps">Show Display FPS</string>
-    <string name="settings_cpu_execution_mode">CPU Execution Mode</string>
-    <string name="settings_gpu_renderer">GPU Renderer</string>
-    <string name="settings_gpu_resolution_scale">Resolution Scale</string>
-    <string name="title_activity_emulation">EmulationActivity</string>
-    <string name="settings_emulation_speed">Emulation Speed</string>
-    <string name="settings_fast_forward_speed">Fast Forward Speed</string>
-    <string name="settings_save_state_on_exit">Save State On Exit</string>
-    <string name="settings_emulation_screen_orientation">Emulation Screen Orientation</string>
-    <string name="settings_load_patch_codes">Load Patch Codes</string>
-    <string name="settings_summary_save_state_on_exit">Automatically saves the emulator state when powering down or exiting. You can then resume directly from where you left off next time.</string>
-    <string name="settings_summary_load_patch_codes"><![CDATA[Loads patch codes from cheats/<game name>.cht in PCSXR format. Codes can be toggled while ingame.]]></string>
-    <string name="settings_apply_compatibility_settings">Apply Compatibility Settings</string>
-    <string name="settings_summary_apply_compatibility_settings">Automatically disable enhancements when they are not supported by games.</string>
-    <string name="settings_summary_video_sync">Enable this option to match DuckStation\'s refresh rate with your current monitor or screen. VSync is automatically disabled when it is not possible (e.g. running at non-100% speed).</string>
-    <string name="settings_video_sync">Video Sync</string>
-    <string name="settings_cpu_overclocking">CPU Overclocking</string>
-    <string name="settings_cdrom_region_check">Region Check</string>
-    <string name="settings_summary_cdrom_region_check">Prevents discs from incorrect regions being read by the emulator. Usually safe to disable.</string>
-    <string name="settings_cdrom_preload_image_to_ram">Preload Image to RAM</string>
-    <string name="settings_summary_preload_image_to_ram">Loads the game image into RAM. Useful for network paths that may become unreliable during gameplay. In some cases also eliminates stutter when games initiate audio track playback.</string>
-    <string name="settings_pgxp_vertex_cache">PGXP Vertex Cache</string>
-    <string name="settings_summary_pgxp_vertex_cache">Uses screen coordinates as a fallback when tracking vertices through memory fails. May improve PGXP compatibility.</string>
-    <string name="settings_pgxp_cpu_mode">PGXP CPU Mode</string>
-    <string name="settings_summary_pgxp_cpu_mode">Tries to track vertex manipulation through the CPU. Some games require this option for PGXP to be effective. Very high performance penalty.</string>
-    <string name="settings_cpu_recompiler_icache">CPU Recompiler ICache</string>
-    <string name="settings_summary_cpu_recompiler_icache">Determines whether the CPU\'s instruction cache is simulated in the recompiler. Improves accuracy at a small cost to performance. If games are running too fast, try enabling this option.</string>
-    <string name="settings_cpu_recompiler_fastmem">CPU Recompiler Fast Memory Access</string>
-    <string name="settings_summary_cpu_recompiler_fastmem">Makes guest memory access more efficient by using page faults and backpatching. Disable if it is unstable on your device.</string>
-    <string name="settings_presented_frame_limit">Presented Frame Limit</string>
-    <string name="settings_logging_level">Logging Level</string>
-    <string name="settings_log_to_file">Log To File</string>
-    <string name="settings_summary_log_to_file">Writes log messages to duckstation.log in your user directory. Only use for debugging as it slows down emulation.</string>
-    <string name="settings_log_to_logcat">Log To Logcat</string>
-    <string name="settings_summary_log_to_logcat">Writes log messages to the Android message logger. Only useful when attached to a computer with adb.</string>
-    <string name="settings_volume">Volume</string>
-    <string name="settings_summary_volume">Controls the volume of the emulator\'s sound output.</string>
-    <string name="settings_fast_forward_volume">Fast Forward Volume</string>
-    <string name="settings_summary_fast_forward_volume">Controls the volume of the emulator\'s sound output when fast forwarding.</string>
-    <string name="settings_mute_all_sound">Mute All Sound</string>
-    <string name="settings_summary_mute_all_sound">Prevents the emulator from emitting any sound.</string>
-    <string name="settings_mute_cd_audio">Mute CD Audio</string>
-    <string name="settings_summary_mute_cd_audio">Forcibly mutes both CD-DA and XA audio from the CD-ROM. Can be used to disable background music in some games.</string>
-    <string name="settings_audio_backend">Audio Backend</string>
-    <string name="settings_audio_buffer_size">Audio Buffer Size</string>
-    <string name="settings_summary_audio_buffer_size">Determines the latency between audio being generated and output to speakers. Smaller values reduce latency, but variations in emulation speed will cause hitches.</string>
-    <string name="settings_audio_sync">Audio Sync</string>
-    <string name="settings_summary_audio_sync">Throttles the emulation speed based on the audio backend pulling audio frames. This helps to remove noises or crackling if emulation is too fast. Sync will automatically be disabled if not running at 100% speed.</string>
-    <string name="settings_controller_type">Controller Type</string>
-    <string name="settings_enable_analog_mode_on_reset">Enable Analog Mode On Reset</string>
-    <string name="settings_touchscreen_controller_view">Touchscreen Controller View</string>
-    <string name="settings_auto_hide_touchscreen_controller">Auto-Hide Touchscreen Controller</string>
-    <string name="settings_summary_auto_hide_touchscreen_controller">Hides the touchscreen controller when an external controller is detected.</string>
-    <string name="settings_vibrate_on_press">Vibrate On Press</string>
-    <string name="settings_summary_vibrate_on_press">Enables a short vibration when a touchscreen button is pressed. Requires \"Vibrate on Touch\" to be enabled on your device.</string>
-    <string name="settings_enable_vibration">Device Vibration</string>
-    <string name="settings_summary_enable_vibration">Forwards rumble from the game to the phone\'s vibration motor.</string>
-    <string name="settings_memory_card_1_type">Memory Card 1 Type</string>
-    <string name="settings_memory_card_2_type">Memory Card 2 Type</string>
-    <string name="settings_crop_mode">Crop Mode</string>
-    <string name="settings_aspect_ratio">Aspect Ratio</string>
-    <string name="settings_linear_upscaling">Linear Upscaling</string>
-    <string name="settings_integer_upscaling">Integer Upscaling</string>
-    <string name="settings_summary_linear_upscaling">Smooths out the image when upscaling the console to the screen.</string>
-    <string name="settings_summary_integer_upscaling">Adds padding to the display area to ensure that the ratio between pixels on the host to pixels in the console is an integer number. May result in a sharper image in some 2D games.</string>
-    <string name="settings_summary_osd_show_messages">Shows on-screen-display messages when events occur such as save states being created/loaded, screenshots being taken, etc.</string>
-    <string name="settings_summary_osd_show_speed">Shows the current emulation speed of the system in the top-right corner of the display as a percentage.</string>
-    <string name="settings_summary_osd_show_fps">Shows the internal frame rate of the game in the top-right corner of the display.</string>
-    <string name="settings_summary_osd_show_vps">Shows the number of frames (or v-syncs) displayed per second by the system in the top-right corner of the display.</string>
-    <string name="settings_cdrom_read_speedup">CD-ROM Read Speedup</string>
-    <string name="settings_summary_cdrom_read_speedup">Speeds up CD-ROM reads by the specified factor. Only applies to double-speed reads, and is ignored when audio is playing. May improve loading speeds in some games, at the cost of breaking others.</string>
-    <string name="settings_summary_console_fast_boot">Skips the BIOS shell/intro, booting directly into the game. Usually safe to enable, but some games break.</string>
-    <string name="settings_msaa">Multisample Antialiasing</string>
-    <string name="settings_true_color">True Color Rendering (24-bit, disables dithering)</string>
-    <string name="settings_summary_true_color">This produces nicer looking gradients at the cost of making some colours look slightly different. Disabling the option also enables dithering. Most games are compatible with this option.</string>
-    <string name="settings_scaled_dithering">Scaled Dithering (scale dither pattern to resolution)</string>
-    <string name="settings_summary_scaled_dithering">Scales the dither pattern to the resolution scale of the emulated GPU. This makes the dither pattern much less obvious at higher resolutions. Usually safe to enable, and only supported by the hardware renderers.</string>
-    <string name="settings_disable_interlacing">Disable Interlacing (force progressive render/scan)</string>
-    <string name="settings_summary_disable_interlacing">Forces the rendering and display of frames to progressive mode. This removes the \"combing\" effect seen in 480i games by rendering them in 480p. Usually safe to enable.</string>
-    <string name="settings_texture_filtering">Texture Filtering</string>
-    <string name="settings_force_ntsc_timings">Force NTSC Timings (60hz-on-PAL)</string>
-    <string name="settings_summary_force_ntsc_timings">Uses NTSC frame timings when the console is in PAL mode, forcing PAL games to run at 60hz.</string>
-    <string name="settings_widescreen_hack">Widescreen Hack</string>
-    <string name="settings_summary_widescreen_hack">Scales vertex positions in screen-space to a widescreen aspect ratio, essentially increasing the field of view from 4:3 to 16:9 in 3D games. Not be compatible with all games.</string>
-    <string name="settings_force_4_3_for_24bit">Force 4:3 For 24-Bit Display</string>
-    <string name="settings_summary_force_4_3_for_24bit">Switches back to 4:3 display aspect ratio when displaying 24-bit content, usually FMVs.</string>
-    <string name="settings_chroma_smoothing_24bit">Chroma Smoothing For 24-Bit Display</string>
-    <string name="settings_summary_chrome_smoothing_24bit">Smooths out blockyness between colour transitions in 24-bit content, usually FMVs. Only applies to the hardware renderers.</string>
-    <string name="settings_pgxp_geometry_correction">PGXP Geometry Correction</string>
-    <string name="settings_summary_pgxp_geometry_correction"><![CDATA[Reduces \"wobbly\" polygons and \"warping\" textures that are common in PS1 games. >Only works with the hardware renderers. May not be compatible with all games.]]></string>
-    <string name="settings_pgxp_culling_correction">PGXP Culling Correction</string>
-    <string name="settings_summary_pgxp_culling_correction">Increases the precision of polygon culling, reducing the number of holes in geometry. Requires geometry correction enabled.</string>
-    <string name="settings_pgxp_texture_correction">PGXP Texture Correction</string>
-    <string name="settings_summary_pgxp_texture_correction">Uses perspective-correct interpolation for texture coordinates and colors, straightening out warped textures. Requires geometry correction enabled.</string>
-    <string name="settings_pgxp_preserve_projection_precision">PGXP Preserve Projection Precision</string>
-    <string name="settings_summary_pgxp_preserve_projection_precision">Enables additional precision for PGXP. May improve visuals in some games but break others.</string>
-    <string name="settings_pgxp_depth_buffer">PGXP Depth Buffer</string>
-    <string name="settings_summary_pgxp_depth_buffer">Attempts to reduce polygon Z-fighting by testing pixels against the depth values from PGXP. Low compatibility, but can work well in some games.</string>
-    <string name="menu_main_resume_last_session">Resume Last Session</string>
-    <string name="menu_main_start_file">Start File</string>
-    <string name="menu_main_start_bios">Start BIOS</string>
-    <string name="menu_main_edit_game_directories">Edit Game Directories</string>
-    <string name="menu_main_scan_for_new_games">Scan For New Games</string>
-    <string name="menu_main_rescan_all_games">Rescan All Games</string>
-    <string name="menu_main_import_bios">Import BIOS</string>
-    <string name="menu_main_show_version">Show Version</string>
-    <string name="menu_main_github_repository">GitHub Repository</string>
-    <string name="menu_main_discord_server">Discord Server</string>
-    <string name="menu_game_list_entry_start_game">Start Game</string>
-    <string name="menu_game_list_entry_resume_game">Resume Game</string>
-    <string name="android_progress_callback_please_wait">Please wait...</string>
-    <string name="android_progress_callback_ok">OK</string>
-    <string name="android_progress_callback_information">Information</string>
-    <string name="android_progress_callback_confirmation">Confirmation</string>
-    <string name="android_progress_callback_yes">Yes</string>
-    <string name="android_progress_callback_no">No</string>
-    <string name="emulation_activity_error">Error</string>
-    <string name="emulation_activity_ok">OK</string>
-    <string name="emulation_activity_import_patch_codes">Import Patch Codes...</string>
-    <string name="emulation_activity_patch_on">(ON)</string>
-    <string name="emulation_activity_patch_off">(OFF)</string>
-    <string name="emulation_activity_choose_patch_code_file">Choose Patch Code File</string>
-    <string name="emulation_activity_failed_to_import_patch_codes">Failed to import patch codes. Make sure you selected a PCSXR or Libretro format file.</string>
-    <string name="main_activity_choose_directory">Choose directory</string>
-    <string name="main_activity_error">Error</string>
-    <string name="main_activity_get_path_from_file_error">Failed to get path for the selected file. Please make sure the file is in internal/external storage.\n\nTap the overflow button in the directory selector.\nSelect "Show Internal Storage".\nTap the menu button and select your device name or SD card.</string>
-    <string name="main_activity_ok">OK</string>
-    <string name="main_activity_get_path_from_directory_error">Failed to get path for the selected directory. Please make sure the directory is in internal/external storage.\n\nTap the overflow button in the directory selector.\nSelect \"Show Internal Storage\".\nTap the menu button and select your device name or SD card.</string>
-    <string name="main_activity_external_storage_permissions_error">External storage permissions are required to use DuckStation.</string>
-    <string name="main_activity_choose_disc_image">Choose Disc Image</string>
-    <string name="main_activity_missing_bios_image_prompt">No BIOS image was found in DuckStation\'s bios directory. Do you wish to locate and import a BIOS image now?</string>
-    <string name="main_activity_missing_bios_image">Missing BIOS Image</string>
-    <string name="main_activity_yes">Yes</string>
-    <string name="main_activity_no">No</string>
-    <string name="main_activity_choose_bios_image">Choose BIOS Image</string>
-    <string name="main_activity_failed_to_open_bios_image">Failed to open BIOS image.</string>
-    <string name="main_activity_failed_to_read_bios_image_prefix">\"Failed to read BIOS image: \"</string>
-    <string name="main_activity_bios_image_too_large">BIOS image is too large. You must select a BIOS image, not a game, and it should be 512KB in size.</string>
-    <string name="main_activity_invalid_error">This BIOS image is invalid, or has already been imported.</string>
-    <string name="main_activity_show_version_title">Version</string>
-    <string name="main_activity_copy">Copy</string>
-    <string name="settings_gpu_thread">Threaded GPU Rendering</string>
-    <string name="settings_summary_gpu_thread">Uses a second thread for drawing graphics. Currently only available for the software renderer, but can provide a significant speed improvement, and is safe to use.</string>
-    <string name="settings_gpu_threaded_presentation">Threaded GPU Presentation</string>
-    <string name="settings_summary_gpu_threaded_presentation">Presents frames on a background thread when fast forwarding or vsync is disabled. This can measurably improve performance in the Vulkan renderer.</string>
-    <string name="settings_language">Language (restart to apply)</string>
-    <string name="touchscreen_controller_stop_editing">Stop Editing</string>
-    <string name="touchscreen_controller_reset_layout">Reset Layout</string>
-    <string name="emulation_activity_touchscreen_controller_not_active">Touchscreen controller is not active.</string>
-    <string name="settings_theme">Theme</string>
-    <string name="settings_controller_mapping_summary">Allows you bind external controller buttons/axises to the emulated controller.</string>
-    <string name="settings_controller_mapping">Controller Mapping</string>
-    <string name="controller_binding_dialog_message">Press button on controller to set new binding.\n\nCurrent Binding: %s</string>
-    <string name="controller_binding_dialog_no_binding"><![CDATA[<No Binding>]]></string>
-    <string name="controller_binding_dialog_cancel">Cancel</string>
-    <string name="controller_binding_dialog_clear">Clear</string>
-    <string name="controller_mapping_activity_title">Controller Settings</string>
-    <string name="controller_mapping_activity_no_profiles_found">No profiles found.</string>
-    <string name="controller_mapping_activity_select_input_profile">Select Input Profile</string>
-    <string name="controller_mapping_activity_failed_to_load_profile">Failed to load profile \'%s\'</string>
-    <string name="controller_mapping_activity_input_profile_name">Input Profile Name:</string>
-    <string name="controller_mapping_activity_save">Save</string>
-    <string name="controller_mapping_activity_name_must_be_provided">A name must be provided.</string>
-    <string name="controller_mapping_activity_failed_to_save_input_profile">Failed to save input profile.</string>
-    <string name="controller_mapping_activity_input_profile_saved">Input profile \'%s\' saved.</string>
-    <string name="controller_mapping_activity_cancel">Cancel</string>
-    <string name="settings_use_analog_sticks_for_dpad">Use Analog Sticks for D-Pad in Digital Mode</string>
-    <string name="settings_summary_enable_analog_mode_on_reset">Forces the controller to analog mode when the console is reset/powered on.</string>
-    <string name="settings_summary_use_analog_sticks_for_dpad">Allows you to use the analog sticks to control the d-pad in digital mode, as well as the buttons.</string>
-    <string name="settings_disable_all_enhancements">Disable All Enhancements</string>
-    <string name="settings_summary_disable_all_enhancements">Temporarily disables all enhancements, which can be useful when debugging issues.</string>
-    <string name="settings_downsample_mode">Downsampling</string>
-    <string name="activity_game_properties">Game Properties</string>
-    <string name="game_properties_preference_use_global_setting">Use Global Setting</string>
-    <string name="settings_input_profile">Input Profile</string>
-    <string name="game_properties_tab_summary">Summary</string>
-    <string name="game_properties_tab_game_settings">Game Settings</string>
-    <string name="game_properties_tab_controller_settings">Controller Settings</string>
-    <string name="settings_audio_resampling">Audio Resampling</string>
-    <string name="settings_summary_audio_resampling">When running outside of 100% speed, resamples audio from the target speed instead of dropping frames. Produces much nicer fast forward/slowdown audio at a small cost to performance.</string>
-    <string name="settings_general_sync_to_host_refresh_rate">Sync To Host Refresh Rate</string>
-    <string name="settings_summary_general_sync_to_host_refresh_rate">Adjusts the emulation speed so the console\'s refresh rate matches the host\'s refresh rate, when VSync and Audio Resampling is enabled. This results in the smoothest animations possible, at the cost of potentially increasing the emulation speed by less than 1%.</string>
-    <string name="settings_sustained_performance_mode">Sustained Performance Mode</string>
-    <string name="settings_summary_sustained_performance_mode">Enables Android\'s sustained performance mode. May result in more consistent framerates for long sessions on some devices.</string>
-    <string name="title_activity_game_directories">Edit Game Directories</string>
-    <string name="settings_game_directories">Game Directories</string>
-    <string name="settings_summary_game_directories">Change the list of directories used to search for games.</string>
-    <string name="game_directories_scanning_subdirectories">Scanning subdirectories.</string>
-    <string name="game_directories_not_scanning_subdirectories">Not scanning subdirectories.</string>
-    <string name="settings_display_all_frames">Optimal Frame Pacing</string>
-    <string name="settings_summary_display_all_frames">Enable this option will ensure every frame the console renders is displayed to the screen, for optimal frame pacing. If you are having difficulties maintaining full speed, or are getting audio glitches, try disabling this option.</string>
-    <string name="menu_edit_game_directories_add_directory">Add Directory</string>
-    <string name="menu_edit_game_directories_add_path">Add Path</string>
-    <string name="edit_game_directories_add_path">Add Path</string>
-    <string name="edit_game_directories_add_path_summary">Enter the full path to the directory with games.\n\nYou can get this from a file manager app.\n\nExample: /storage/emulated/0/games</string>
-    <string name="save_state_info_slot_is_empty">Slot Is Empty</string>
-    <string name="save_state_info_game_save_n">Game Save %d</string>
-    <string name="save_state_info_global_save_n">Global Save %d</string>
-    <string name="save_state_info_quick_save">Quick Save</string>
-    <string name="settings_osd_show_show_resolution">Show Resolution</string>
-    <string name="settings_summary_osd_show_resolution">Shows the resolution the game is rendering at in the top-right corner of the display.</string>
-    <string name="settings_summary_display_stretch">Stretches the active display to fill the screen.</string>
-    <string name="settings_display_stretch">Stretch To Fill</string>
-    <string name="settings_category_global">Global Settings</string>
-    <string name="settings_category_display">Display Settings</string>
-    <string name="settings_category_audio">Audio Settings</string>
-    <string name="settings_category_console">Console Settings</string>
-    <string name="settings_category_cpu">CPU Settings</string>
-    <string name="settings_category_gpu">GPU Settings</string>
-    <string name="settings_category_logging">Logging Settings</string>
-    <string name="dialog_done">Done</string>
-    <string name="dialog_touchscreen_controller_type">Touchscreen Controller Type</string>
-    <string name="dialog_touchscreen_controller_opacity">Touchscreen Controller Opacity</string>
-    <string name="dialog_touchscreen_controller_buttons">Touchscreen Controller Buttons</string>
-    <string name="dialog_touchscreen_controller_settings">Touchscreen Controller Settings</string>
-    <string name="settings_summary_console_tty_output">Logs debug messages printed by games.</string>
-    <string name="action_show_game_list">List View</string>
-    <string name="action_show_game_grid">Grid View</string>
-    <string name="settings_touch_gliding">Touch Gliding</string>
-    <string name="settings_summary_touch_gliding">Allows you to press multiple controller face buttons by dragging your finger along the screen.</string>
-    <string name="menu_game_list_entry_game_properties">Game Properties</string>
-    <string name="emulation_activity_change_disc_select_new_file">Select New File...</string>
-    <string name="settings_achievements_enable">Enable RetroAchievements</string>
-    <string name="settings_summary_achievements_enable">When enabled and logged in, DuckStation will scan for achievements on startup.</string>
-    <string name="settings_achievements_challenge_mode">Enable Hardcore Mode</string>
-    <string name="settings_summary_achievements_challenge_mode">Challenge mode. Disables save states, patch code, and slowdown functions, but you receive double the achievement points. Cannot be toggled while ingame.</string>
-    <string name="settings_achievements_rich_presence">Enable Rich Presence</string>
-    <string name="settings_summary_achievements_rich_presence">Rich presence information will be collected and sent to the server where supported.</string>
-    <string name="settings_achievements_username">User Name</string>
-    <string name="settings_achievements_token_generation_time">Token Generation Time</string>
-    <string name="settings_achievements_login">Login</string>
-    <string name="settings_summary_achievements_login">Logs in to your account to record achievements.</string>
-    <string name="settings_achievements_register">Register</string>
-    <string name="settings_summary_achievements_register">Opens a link to create a new account.</string>
-    <string name="settings_achievements_logout">Logout</string>
-    <string name="settings_summary_achievements_logout">Logs out of your account. No new achievements will be recorded.</string>
-    <string name="settings_achievements_view_profile">View Profile</string>
-    <string name="settings_summary_achievements_view_profile">Opens a link to your profile.</string>
-    <string name="settings_achievements_test_mode">Enable Test Mode</string>
-    <string name="settings_summary_achievements_test_mode">When enabled, DuckStation will assume all achievements are locked and not send any unlock notifications to the server.</string>
-    <string name="settings_achievements_use_first_disc_from_playlist">Use First Disc From Playlist</string>
-    <string name="settings_summary_achievements_use_first_disc_from_playlist">When enabled, the first disc in a playlist will be used for achievements, regardless of which disc is active.</string>
-    <string name="achievement_settings_login_title">RetroAchievements Login</string>
-    <string name="achievement_settings_login_help">Please enter user name and password for retroachievements.org below. Your password will not be saved in DuckStation, an access token will be generated and used instead.</string>
-    <string name="achievement_settings_login_username_hint">Username</string>
-    <string name="achievement_settings_login_password_hint">Password</string>
-    <string name="achievement_settings_login_login_button">Login</string>
-    <string name="achievement_settings_login_cancel_button">Cancel</string>
-    <string name="achievement_settings_login_failed">Login failed. Please check your username and password, and try again.</string>
-    <string name="achievement_points_format_string">%d points</string>
-    <string name="achievement_summary_format_string">You have unlocked %1$d of %2$d achievements, earning %3$d of %4$d possible points.</string>
-    <string name="achievement_title_challenge_mode_format_string">%s (Hardcore Mode)</string>
-    <string name="settings_achievements_disclaimer">DuckStation uses RetroAchievements (retroachievements.org) as an achievement database and for tracking progress.</string>
-    <string name="settings_achievements_confirm_logout_title">Confirm Logout</string>
-    <string name="settings_achievements_confirm_logout_message">After logging out, no more achievements will be unlocked until you log back in again. Achievements already unlocked will not be lost.</string>
-    <string name="controller_binding_device_for_vibration">Device for Vibration</string>
-    <string name="controller_settings_tab_settings">Settings</string>
-    <string name="controller_settings_tab_hotkeys">Hotkeys</string>
-    <string name="controller_settings_category_button_bindings">Button Bindings</string>
-    <string name="controller_settings_category_axis_bindings">Axis Bindings</string>
-    <string name="controller_settings_category_settings">Settings</string>
-    <string name="controller_settings_category_touchscreen_controller">Touchscreen Controller</string>
-    <string name="controller_settings_category_ports">Ports</string>
-    <string name="controller_settings_main_port_format">Port %d</string>
-    <string name="controller_settings_sub_port_format">Port %1$d%2$c</string>
-    <string name="action_switch_view">Switch View</string>
-    <string name="title_activity_memory_card_editor">Memory Card Editor</string>
-    <string name="action_memory_card_editor">Memory Card Editor</string>
-    <string name="action_memory_card_editor_import_card">Import Card</string>
-    <string name="action_memory_card_editor_open_card">Open Card</string>
-    <string name="action_memory_card_editor_new_card">New Card</string>
-    <string name="action_memory_card_editor_format_card">Format Card</string>
-    <string name="action_memory_card_editor_delete_card">Delete Card</string>
-    <string name="memory_card_editor_no_cards_found">No memory cards found.</string>
-    <string name="memory_card_editor_card_already_open">This card is already open.</string>
-    <string name="memory_card_editor_failed_to_open_card">Failed to open or read memory card.</string>
-    <string name="memory_card_editor_must_have_at_least_two_cards_to_copy">Must have at least two cards open to copy.</string>
-    <string name="memory_card_editor_copy_save_to">Copy %s to...</string>
-    <string name="memory_card_editor_select_card">Select Card</string>
-    <string name="memory_card_editor_error">Error</string>
-    <string name="memory_card_editor_copy_insufficient_blocks">This file requires %1$d blocks, but only %2$d blocks are free.</string>
-    <string name="memory_card_editor_copy_already_exists">File \'%s\' already exists on destination card.</string>
-    <string name="memory_card_editor_copy_read_failed">Failed to read file \'%s\' from source card.</string>
-    <string name="memory_card_editor_copy_write_failed">Failed to write file \'%s\' to destination card.</string>
-    <string name="memory_card_editor_copy_success">Copied \'%1$s\' to \'%2$s\'.</string>
-    <string name="memory_card_editor_delete_confirm">Are you sure you want to delete the save \'%s\'?</string>
-    <string name="memory_card_editor_delete_success">Deleted save \'%s\'.</string>
-    <string name="memory_card_editor_delete_failed">Failed to delete file \'%s\'.</string>
-    <string name="memory_card_editor_no_card_selected">No card is selected.</string>
-    <string name="memory_card_editor_import_failed">Failed to import card. It may not be a supported format.</string>
-    <string name="memory_card_editor_delete_card_confirm_message">Memory card \'%s\' will be deleted, and cannot be recovered. Are you sure you want to delete this card?</string>
-    <string name="memory_card_editor_delete_card_failed">Failed to delete \'%s\'.</string>
-    <string name="memory_card_editor_delete_card_success">Deleted card \'%s\'.</string>
-    <string name="memory_card_editor_format_card_confirm_message">Memory card \'%s\' will be formatted, clearing all saves. Are you sure you want to format this card?</string>
-    <string name="memory_card_editor_format_card_failed">Failed to format \'%s\'.</string>
-    <string name="memory_card_editor_format_card_success">Formatted card \'%s\'.</string>
-    <string name="memory_card_editor_import_card_confirm_message">Importing \'%1$s\' will remove all saves in \'%2$s\'. Do you want to continue?</string>
-    <string name="memory_card_editor_import_card_read_failed">Failed to read \'%s\'.</string>
-    <string name="memory_card_editor_import_card_failed">Failed to import card \'%s\'. It may not be a supported format.</string>
-    <string name="memory_card_editor_import_card_success">Imported card \'%s\'.</string>
-    <string name="menu_game_list_entry_choose_cover_image">Choose Cover Image</string>
-    <string name="controller_settings_vibration_unsupported">The selected device does not support vibration.</string>
-    <string name="controller_settings_automatic_mapping">Perform Automatic Mapping</string>
-    <string name="controller_settings_summary_automatic_mapping">Attempts to automatically bind all buttons/axes to a connected controller.</string>
-    <string name="controller_settings_clear_controller_bindings">Clear Bindings</string>
-    <string name="controller_settings_summary_clear_controller_bindings">Unbinds all buttons/axes for this controller.</string>
-    <string name="controller_settings_clear_controller_bindings_confirm">Are you sure you want to clear all bindings? This cannot be reversed.</string>
-    <string name="controller_settings_clear_controller_bindings_done">All bindings cleared for Controller %d.</string>
-    <string name="controller_auto_mapping_no_devices">No suitable devices found. Automatic binding only supports gamepad devices, but you can still bind other device types manually.</string>
-    <string name="controller_auto_mapping_select_device">Select Device</string>
-    <string name="controller_auto_mapping_results">Automatic Binding Results</string>
-    <string name="main_activity_empty_game_list_title">No games were found. Please add a directory with games to begin.</string>
-    <string name="main_activity_empty_game_list_supported_formats">Supported formats are:\n\n%s\n\nGames in bin format require a cuesheet (.cue) to start.</string>
-    <string name="main_activity_empty_game_list_add_directory">Add Game Directory</string>
-    <string name="main_activity_empty_game_list_start_file">Start File</string>
-    <string name="update_notes_title">Update Notes</string>
-    <string name="update_notes_message_version_controller_update">This DuckStation update includes support for multiple controllers with vibration, and binding devices such as keyboards/volume buttons.\n\nYou must re-bind your controllers, otherwise they will no longer function. Do you want to do this now?</string>
-    <string name="settings_osd_show_show_inputs">Show Controller Input</string>
-    <string name="settings_summary_osd_show_inputs">Shows the current controller state of the system in the bottom-left corner of the display.</string>
-    <string name="touchscreen_controller_edit_menu">Edit Menu</string>
-    <string name="settings_achievements_category">Account</string>
-    <string name="settings_achievements_global_settings">Global Settings</string>
-    <string name="settings_category_achievements">Achievement Settings</string>
-    <string name="settings_multitap_mode">Multitap Mode</string>
-    <string name="settings_touchscreen_controller_port">Touchscreen Controller Port</string>
-    <string name="emulation_menu_load_state">Load State</string>
-    <string name="emulation_menu_save_state">Save State</string>
-    <string name="emulation_menu_toggle_fast_forward">Toggle Fast Forward</string>
-    <string name="emulation_menu_achievements">Achievements</string>
-    <string name="emulation_menu_patch_codes">Patch Codes</string>
-    <string name="emulation_menu_change_disc">Change Disc</string>
-    <string name="emulation_menu_touchscreen_controller_settings">Touchscreen Controller Settings</string>
-    <string name="emulation_menu_toggle_analog_mode">Toggle Controller Analog Mode</string>
-    <string name="emulation_menu_reset_console">Reset Console</string>
-    <string name="emulation_menu_exit_game">Exit Game</string>
-    <string name="settings_use_software_renderer_for_readbacks">Use Software Renderer For Readbacks</string>
-    <string name="settings_summary_use_software_renderer_for_readbacks">Runs the software renderer in parallel for VRAM readbacks. On some devices, this may result in greater performance when using graphical enhancements with the hardware renderer.</string>
-    <string name="settings_use_software_renderer">Use Software Renderer</string>
-    <string name="settings_disable_widescreen">Disable Widescreen</string>
-    <string name="settings_cdrom_seek_speedup">CD-ROM Seek Speedup</string>
-    <string name="settings_summary_cdrom_seek_speedup">Speeds up CD-ROM seeks by the specified factor. May improve loading speeds in some games, at the cost of breaking others.</string>
-    <string name="settings_custom_aspect_ratio">Custom Aspect Ratio</string>
-    <string name="settings_summary_custom_aspect_ratio">Used when aspect ratio is set to Custom.</string>
-    <string name="controller_settings_category_auto_fire_buttons">Auto Fire Buttons</string>
-    <string name="controller_settings_category_auto_fire_bindings">Auto Fire Triggers</string>
-    <string name="controller_settings_auto_fire_n_button">Auto Fire %d Button</string>
-    <string name="controller_settings_auto_fire_n_frequency">Auto Fire %d Frequency/Interval</string>
-    <string name="controller_binding_auto_fire_n">Auto Fire %d</string>
-    <string name="settings_category_cdrom">CD-ROM Settings</string>
-    <string name="settings_cdrom_read_thread">Use Read Thread (Asynchronous)</string>
-    <string name="settings_summary_read_thread">Reduces hitches in emulation by reading/decompressing CD data asynchronously on a worker thread.</string>
-    <string name="settings_cdrom_load_image_patches">Apply Image Patches</string>
-    <string name="settings_summary_load_image_patches">Automatically applies patches to disc images when they are present, currently only PPF is supported.</string>
-    <string name="menu_edit_game_directories_force_saf">Force Scoped Storage</string>
-    <string name="settings_expand_to_cutout">Expand To Cutout Area</string>
-    <string name="settings_summary_expand_to_cutout">Expands the display area to include the cutout (or notch) area.</string>
-</resources>
diff --git a/android/app/src/main/res/values/styles.xml b/android/app/src/main/res/values/styles.xml
deleted file mode 100644
index 83f0c72bb..000000000
--- a/android/app/src/main/res/values/styles.xml
+++ /dev/null
@@ -1,45 +0,0 @@
-<resources>
-
-    <!-- Base application theme. -->
-    <style name="AppTheme" parent="Theme.AppCompat.DayNight.DarkActionBar">
-        <!-- Customize your theme here. -->
-        <item name="colorPrimary">@color/colorPrimary</item>
-        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
-        <item name="colorAccent">@color/colorAccent</item>
-        <item name="android:navigationBarColor">@color/colorNavigation</item>
-    </style>
-
-    <style name="AppTheme.NoActionBar">
-        <item name="windowActionBar">false</item>
-        <item name="windowNoTitle">true</item>
-    </style>
-
-    <style name="AppTheme.AppBarOverlay" parent="ThemeOverlay.AppCompat.Dark.ActionBar" />
-
-    <style name="AppTheme.PopupOverlay" parent="ThemeOverlay.AppCompat.DayNight" />
-
-    <style name="FullscreenTheme" parent="AppTheme">
-        <item name="android:actionBarStyle">@style/FullscreenActionBarStyle</item>
-        <item name="android:windowActionBarOverlay">true</item>
-        <item name="android:windowBackground">@null</item>
-        <item name="metaButtonBarStyle">?android:attr/buttonBarStyle</item>
-        <item name="metaButtonBarButtonStyle">?android:attr/buttonBarButtonStyle</item>
-    </style>
-
-    <style name="FullscreenActionBarStyle" parent="Widget.AppCompat.ActionBar">
-        <item name="android:background">@color/black_overlay</item>
-    </style>
-
-    <style name="TabTextAppearance" parent="TextAppearance.Design.Tab">
-        <item name="textAllCaps">false</item>
-        <item name="android:textAllCaps">false</item>
-    </style>
-
-    <style name="EmulationActivityOverlay" parent="ThemeOverlay.AppCompat.Dark">
-        <item name="android:windowNoTitle">true</item>
-        <item name="android:windowBackground">@color/emulationActivityPauseBackground</item>
-        <item name="android:colorBackgroundCacheHint">@null</item>
-        <item name="android:windowIsTranslucent">true</item>
-        <item name="android:windowAnimationStyle">@android:style/Animation.Dialog</item>
-    </style>
-</resources>
diff --git a/android/app/src/main/res/xml/achievement_preferences.xml b/android/app/src/main/res/xml/achievement_preferences.xml
deleted file mode 100644
index 29901275b..000000000
--- a/android/app/src/main/res/xml/achievement_preferences.xml
+++ /dev/null
@@ -1,59 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<PreferenceScreen xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:android="http://schemas.android.com/apk/res/android">
-
-    <PreferenceCategory app:title="@string/settings_achievements_global_settings" app:iconSpaceReserved="false">
-        <SwitchPreferenceCompat
-            app:key="Cheevos/Enabled"
-            app:title="@string/settings_achievements_enable"
-            app:summary="@string/settings_summary_achievements_enable"
-            app:defaultValue="false"
-            app:iconSpaceReserved="false" />
-        <SwitchPreferenceCompat
-            app:key="Cheevos/ChallengeMode"
-            app:title="@string/settings_achievements_challenge_mode"
-            app:summary="@string/settings_summary_achievements_challenge_mode"
-            app:dependency="Cheevos/Enabled"
-            app:defaultValue="false"
-            app:iconSpaceReserved="false" />
-        <SwitchPreferenceCompat
-            app:key="Cheevos/RichPresence"
-            app:title="@string/settings_achievements_rich_presence"
-            app:summary="@string/settings_summary_achievements_rich_presence"
-            app:dependency="Cheevos/Enabled"
-            app:defaultValue="true"
-            app:iconSpaceReserved="false" />
-    </PreferenceCategory>
-
-    <PreferenceCategory app:title="@string/settings_achievements_category" app:iconSpaceReserved="false">
-        <Preference
-            app:key="Cheevos/Username"
-            app:title="@string/settings_achievements_username"
-            app:iconSpaceReserved="false" />
-        <Preference
-            app:key="Cheevos/LoginTokenTime"
-            app:title="@string/settings_achievements_token_generation_time"
-            app:iconSpaceReserved="false" />
-        <PreferenceScreen
-            app:key="Cheevos/Login"
-            app:title="@string/settings_achievements_login"
-            app:summary="@string/settings_summary_achievements_login"
-            app:iconSpaceReserved="false" />
-        <PreferenceScreen
-            app:key="Cheevos/Register"
-            app:title="@string/settings_achievements_register"
-            app:summary="@string/settings_summary_achievements_register"
-            app:iconSpaceReserved="false" />
-        <PreferenceScreen
-            app:key="Cheevos/Logout"
-            app:title="@string/settings_achievements_logout"
-            app:summary="@string/settings_summary_achievements_logout"
-            app:iconSpaceReserved="false" />
-        <PreferenceScreen
-            app:key="Cheevos/ViewProfile"
-            app:title="@string/settings_achievements_view_profile"
-            app:summary="@string/settings_summary_achievements_view_profile"
-            app:iconSpaceReserved="false" />
-    </PreferenceCategory>
-    <PreferenceCategory app:title="@string/settings_achievements_disclaimer" app:iconSpaceReserved="false">
-    </PreferenceCategory>
-</PreferenceScreen>
\ No newline at end of file
diff --git a/android/app/src/main/res/xml/advanced_preferences.xml b/android/app/src/main/res/xml/advanced_preferences.xml
deleted file mode 100644
index 7187e34c9..000000000
--- a/android/app/src/main/res/xml/advanced_preferences.xml
+++ /dev/null
@@ -1,256 +0,0 @@
-<!--
-  ~ Copyright 2018 The app Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-  -->
-
-<PreferenceScreen xmlns:app="http://schemas.android.com/apk/res-auto">
-    <PreferenceCategory app:title="@string/settings_category_global" app:iconSpaceReserved="false">
-        <SwitchPreferenceCompat
-            app:key="Main/AutoLoadCheats"
-            app:title="@string/settings_load_patch_codes"
-            app:defaultValue="true"
-            app:summary="@string/settings_summary_load_patch_codes"
-            app:iconSpaceReserved="false" />
-        <SwitchPreferenceCompat
-            app:key="Main/ApplyGameSettings"
-            app:title="@string/settings_apply_compatibility_settings"
-            app:defaultValue="true"
-            app:summary="@string/settings_summary_apply_compatibility_settings"
-            app:iconSpaceReserved="false" />
-        <SwitchPreferenceCompat
-            app:key="Main/DisableAllEnhancements"
-            app:title="@string/settings_disable_all_enhancements"
-            app:defaultValue="false"
-            app:summary="@string/settings_summary_disable_all_enhancements"
-            app:iconSpaceReserved="false" />
-        <SwitchPreferenceCompat
-            app:key="Main/SustainedPerformanceMode"
-            app:title="@string/settings_sustained_performance_mode"
-            app:defaultValue="false"
-            app:summary="@string/settings_summary_sustained_performance_mode"
-            app:iconSpaceReserved="false" />
-    </PreferenceCategory>
-
-    <PreferenceCategory app:title="@string/settings_category_display" app:iconSpaceReserved="false">
-        <SwitchPreferenceCompat
-            app:key="Display/VSync"
-            app:title="@string/settings_video_sync"
-            app:defaultValue="false"
-            app:summary="@string/settings_summary_video_sync"
-            app:iconSpaceReserved="false" />
-        <SwitchPreferenceCompat
-            app:key="Main/SyncToHostRefreshRate"
-            app:title="@string/settings_general_sync_to_host_refresh_rate"
-            app:defaultValue="false"
-            app:summary="@string/settings_summary_general_sync_to_host_refresh_rate"
-            app:dependency="Display/VSync"
-            app:iconSpaceReserved="false" />
-        <SwitchPreferenceCompat
-            app:key="Display/DisplayAllFrames"
-            app:title="@string/settings_display_all_frames"
-            app:defaultValue="false"
-            app:summary="@string/settings_summary_display_all_frames"
-            app:iconSpaceReserved="false" />
-        <ListPreference
-            app:key="Display/MaxFPS"
-            app:title="@string/settings_presented_frame_limit"
-            app:defaultValue="60"
-            app:entries="@array/settings_advanced_display_fps_limit_entries"
-            app:entryValues="@array/settings_advanced_display_fps_limit_values"
-            app:useSimpleSummaryProvider="true"
-            app:iconSpaceReserved="false" />
-        <SwitchPreferenceCompat
-            app:key="GPU/UseSoftwareRendererForReadbacks"
-            app:title="@string/settings_use_software_renderer_for_readbacks"
-            app:defaultValue="false"
-            app:summary="@string/settings_summary_use_software_renderer_for_readbacks"
-            app:iconSpaceReserved="false" />
-    </PreferenceCategory>
-
-    <PreferenceCategory app:title="@string/settings_category_audio" app:iconSpaceReserved="false">
-        <ListPreference
-            app:key="Audio/Backend"
-            app:title="@string/settings_audio_backend"
-            app:entries="@array/settings_audio_backend_entries"
-            app:entryValues="@array/settings_audio_backend_values"
-            app:defaultValue="OpenSLES"
-            app:useSimpleSummaryProvider="true"
-            app:iconSpaceReserved="false" />
-        <ListPreference
-            app:key="Audio/BufferSize"
-            app:title="@string/settings_audio_buffer_size"
-            app:entries="@array/settings_audio_buffer_size_entries"
-            app:entryValues="@array/settings_audio_buffer_size_values"
-            app:defaultValue="2048"
-            app:summary="@string/settings_summary_audio_buffer_size"
-            app:useSimpleSummaryProvider="true"
-            app:iconSpaceReserved="false" />
-        <SwitchPreferenceCompat
-            app:key="Audio/Sync"
-            app:title="@string/settings_audio_sync"
-            app:defaultValue="true"
-            app:summary="@string/settings_summary_audio_sync"
-            app:iconSpaceReserved="false" />
-        <SwitchPreferenceCompat
-            app:key="Audio/Resampling"
-            app:title="@string/settings_audio_resampling"
-            app:defaultValue="true"
-            app:summary="@string/settings_summary_audio_resampling"
-            app:iconSpaceReserved="false" />
-    </PreferenceCategory>
-
-    <PreferenceCategory app:title="@string/settings_category_console" app:iconSpaceReserved="false">
-        <ListPreference
-            app:key="Console/Region"
-            app:title="@string/settings_console_region"
-            app:entries="@array/settings_console_region_entries"
-            app:entryValues="@array/settings_console_region_values"
-            app:defaultValue="Auto"
-            app:useSimpleSummaryProvider="true"
-            app:iconSpaceReserved="false" />
-    </PreferenceCategory>
-
-    <PreferenceCategory app:title="@string/settings_category_cdrom" app:iconSpaceReserved="false">
-        <SwitchPreferenceCompat
-            app:key="CDROM/ReadThread"
-            app:title="@string/settings_cdrom_read_thread"
-            app:defaultValue="true"
-            app:summary="@string/settings_summary_read_thread"
-            app:iconSpaceReserved="false" />
-        <SwitchPreferenceCompat
-            app:key="CDROM/RegionCheck"
-            app:title="@string/settings_cdrom_region_check"
-            app:defaultValue="false"
-            app:summary="@string/settings_summary_cdrom_region_check"
-            app:iconSpaceReserved="false" />
-        <SwitchPreferenceCompat
-            app:key="CDROM/LoadImageToRAM"
-            app:title="@string/settings_cdrom_preload_image_to_ram"
-            app:defaultValue="false"
-            app:summary="@string/settings_summary_preload_image_to_ram"
-            app:iconSpaceReserved="false" />
-        <SwitchPreferenceCompat
-            app:key="CDROM/LoadImagePatches"
-            app:title="@string/settings_cdrom_load_image_patches"
-            app:defaultValue="false"
-            app:summary="@string/settings_summary_load_image_patches"
-            app:iconSpaceReserved="false" />
-    </PreferenceCategory>
-
-    <PreferenceCategory app:title="@string/settings_category_cpu" app:iconSpaceReserved="false">
-        <ListPreference
-            app:key="CPU/ExecutionMode"
-            app:title="@string/settings_cpu_execution_mode"
-            app:entries="@array/settings_cpu_execution_mode_entries"
-            app:entryValues="@array/settings_cpu_execution_mode_values"
-            app:defaultValue="Recompiler"
-            app:useSimpleSummaryProvider="true"
-            app:iconSpaceReserved="false" />
-        <ListPreference
-            app:key="CPU/Overclock"
-            app:title="@string/settings_cpu_overclocking"
-            app:defaultValue="100"
-            app:entries="@array/settings_advanced_cpu_overclock_entries"
-            app:entryValues="@array/settings_advanced_cpu_overclock_values"
-            app:useSimpleSummaryProvider="true"
-            app:iconSpaceReserved="false" />
-        <SwitchPreferenceCompat
-            app:key="CPU/RecompilerICache"
-            app:title="@string/settings_cpu_recompiler_icache"
-            app:defaultValue="false"
-            app:summary="@string/settings_summary_cpu_recompiler_icache"
-            app:iconSpaceReserved="false" />
-        <ListPreference
-            app:key="CPU/FastmemMode"
-            app:title="@string/settings_cpu_recompiler_fastmem"
-            app:entries="@array/settings_cpu_fastmem_mode_entries"
-            app:entryValues="@array/settings_cpu_fastmem_mode_values"
-            app:useSimpleSummaryProvider="true"
-            app:defaultValue="MMap"
-            app:summary="@string/settings_summary_cpu_recompiler_fastmem"
-            app:iconSpaceReserved="false" />
-    </PreferenceCategory>
-
-    <PreferenceCategory app:title="@string/settings_category_gpu" app:iconSpaceReserved="false">
-        <SwitchPreferenceCompat
-            app:key="GPU/UseThread"
-            app:title="@string/settings_gpu_thread"
-            app:defaultValue="true"
-            app:summary="@string/settings_summary_gpu_thread"
-            app:iconSpaceReserved="false" />
-        <SwitchPreferenceCompat
-            app:key="GPU/ThreadedPresentation"
-            app:title="@string/settings_gpu_threaded_presentation"
-            app:defaultValue="true"
-            app:summary="@string/settings_summary_gpu_threaded_presentation"
-            app:iconSpaceReserved="false" />
-        <SwitchPreferenceCompat
-            app:key="GPU/PGXPVertexCache"
-            app:title="@string/settings_pgxp_vertex_cache"
-            app:defaultValue="false"
-            app:summary="@string/settings_summary_pgxp_vertex_cache"
-            app:iconSpaceReserved="false" />
-        <SwitchPreferenceCompat
-            app:key="GPU/PGXPCPU"
-            app:title="@string/settings_pgxp_cpu_mode"
-            app:defaultValue="false"
-            app:summary="@string/settings_summary_pgxp_cpu_mode"
-            app:iconSpaceReserved="false" />
-    </PreferenceCategory>
-
-    <PreferenceCategory app:title="@string/settings_category_logging" app:iconSpaceReserved="false">
-        <ListPreference
-            app:key="Logging/LogLevel"
-            app:title="@string/settings_logging_level"
-            app:defaultValue="Warning"
-            app:entries="@array/settings_log_level_entries"
-            app:entryValues="@array/settings_log_level_values"
-            app:useSimpleSummaryProvider="true"
-            app:iconSpaceReserved="false" />
-        <SwitchPreferenceCompat
-            app:key="Logging/LogToFile"
-            app:title="@string/settings_log_to_file"
-            app:defaultValue="false"
-            app:summary="@string/settings_summary_log_to_file"
-            app:iconSpaceReserved="false" />
-        <SwitchPreferenceCompat
-            app:key="Logging/LogToDebug"
-            app:title="@string/settings_log_to_logcat"
-            app:defaultValue="false"
-            app:summary="@string/settings_summary_log_to_logcat"
-            app:iconSpaceReserved="false" />
-        <SwitchPreferenceCompat
-            app:key="BIOS/PatchTTYEnable"
-            app:title="@string/settings_console_tty_output"
-            app:defaultValue="false"
-            app:summary="@string/settings_summary_console_tty_output"
-            app:iconSpaceReserved="false" />
-    </PreferenceCategory>
-
-    <PreferenceCategory app:title="@string/settings_category_achievements" app:iconSpaceReserved="false">
-        <SwitchPreferenceCompat
-            app:key="Cheevos/TestMode"
-            app:title="@string/settings_achievements_test_mode"
-            app:summary="@string/settings_summary_achievements_test_mode"
-            app:defaultValue="false"
-            app:iconSpaceReserved="false" />
-        <SwitchPreferenceCompat
-            app:key="Cheevos/UseFirstDiscFromPlaylist"
-            app:title="@string/settings_achievements_use_first_disc_from_playlist"
-            app:summary="@string/settings_summary_achievements_use_first_disc_from_playlist"
-            app:defaultValue="true"
-            app:iconSpaceReserved="false" />
-    </PreferenceCategory>
-
-</PreferenceScreen>
diff --git a/android/app/src/main/res/xml/audio_preferences.xml b/android/app/src/main/res/xml/audio_preferences.xml
deleted file mode 100644
index 53e64ca38..000000000
--- a/android/app/src/main/res/xml/audio_preferences.xml
+++ /dev/null
@@ -1,51 +0,0 @@
-<!--
-  ~ Copyright 2018 The app Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-  -->
-
-<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:app="http://schemas.android.com/apk/res-auto">
-
-    <SeekBarPreference
-        app:key="Audio/OutputVolume"
-        app:title="@string/settings_volume"
-        app:summary="@string/settings_summary_volume"
-        app:defaultValue="100"
-        android:max="100"
-        app:min="0"
-        app:iconSpaceReserved="false"
-        app:showSeekBarValue="true" />
-    <SeekBarPreference
-        app:key="Audio/FastForwardVolume"
-        app:title="@string/settings_fast_forward_volume"
-        app:summary="@string/settings_summary_fast_forward_volume"
-        app:defaultValue="100"
-        android:max="100"
-        app:min="0"
-        app:iconSpaceReserved="false"
-        app:showSeekBarValue="true" />
-    <SwitchPreferenceCompat
-        app:key="Audio/OutputMuted"
-        app:title="@string/settings_mute_all_sound"
-        app:defaultValue="false"
-        app:summary="@string/settings_summary_mute_all_sound"
-        app:iconSpaceReserved="false" />
-    <SwitchPreferenceCompat
-        app:key="CDROM/MuteCDAudio"
-        app:title="@string/settings_mute_cd_audio"
-        app:defaultValue="false"
-        app:summary="@string/settings_summary_mute_cd_audio"
-        app:iconSpaceReserved="false" />
-
-</PreferenceScreen>
diff --git a/android/app/src/main/res/xml/controllers_preferences.xml b/android/app/src/main/res/xml/controllers_preferences.xml
deleted file mode 100644
index 8b0654dcc..000000000
--- a/android/app/src/main/res/xml/controllers_preferences.xml
+++ /dev/null
@@ -1,93 +0,0 @@
-<!--
-  ~ Copyright 2018 The app Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-  -->
-
-<PreferenceScreen xmlns:app="http://schemas.android.com/apk/res-auto">
-
-    <PreferenceCategory
-        app:iconSpaceReserved="false"
-        app:title="@string/controller_settings_category_touchscreen_controller">
-        <ListPreference
-            app:defaultValue="digital"
-            app:entries="@array/settings_touchscreen_controller_view_entries"
-            app:entryValues="@array/settings_touchscreen_controller_view_values"
-            app:iconSpaceReserved="false"
-            app:key="Controller1/TouchscreenControllerView"
-            app:title="@string/settings_touchscreen_controller_view"
-            app:useSimpleSummaryProvider="true" />
-        <ListPreference
-            app:defaultValue="0"
-            app:entries="@array/settings_touchscreen_controller_port_entries"
-            app:entryValues="@array/settings_touchscreen_controller_port_values"
-            app:iconSpaceReserved="false"
-            app:key="TouchscreenController/PortIndex"
-            app:title="@string/settings_touchscreen_controller_port"
-            app:useSimpleSummaryProvider="true" />
-        <SwitchPreferenceCompat
-            app:defaultValue="false"
-            app:iconSpaceReserved="false"
-            app:key="Controller1/AutoHideTouchscreenController"
-            app:summary="@string/settings_summary_auto_hide_touchscreen_controller"
-            app:title="@string/settings_auto_hide_touchscreen_controller" />
-        <SwitchPreferenceCompat
-            app:defaultValue="false"
-            app:iconSpaceReserved="false"
-            app:key="Controller1/TouchGliding"
-            app:summary="@string/settings_summary_touch_gliding"
-            app:title="@string/settings_touch_gliding" />
-        <SwitchPreferenceCompat
-            app:defaultValue="false"
-            app:iconSpaceReserved="false"
-            app:key="Controller1/HapticFeedback"
-            app:summary="@string/settings_summary_vibrate_on_press"
-            app:title="@string/settings_vibrate_on_press" />
-        <SwitchPreferenceCompat
-            app:defaultValue="false"
-            app:iconSpaceReserved="false"
-            app:key="Controller1/Vibration"
-            app:summary="@string/settings_summary_enable_vibration"
-            app:title="@string/settings_enable_vibration" />
-    </PreferenceCategory>
-
-    <PreferenceCategory
-        app:iconSpaceReserved="false"
-        app:title="@string/controller_settings_category_ports">
-        <ListPreference
-            app:defaultValue="Disabled"
-            app:entries="@array/settings_multitap_mode_entries"
-            app:entryValues="@array/settings_multitap_mode_values"
-            app:iconSpaceReserved="false"
-            app:key="ControllerPorts/MultitapMode"
-            app:title="@string/settings_multitap_mode"
-            app:useSimpleSummaryProvider="true" />
-        <ListPreference
-            app:defaultValue="PerGameTitle"
-            app:entries="@array/settings_memory_card_mode_entries"
-            app:entryValues="@array/settings_memory_card_mode_values"
-            app:iconSpaceReserved="false"
-            app:key="MemoryCards/Card1Type"
-            app:title="@string/settings_memory_card_1_type"
-            app:useSimpleSummaryProvider="true" />
-        <ListPreference
-            app:defaultValue="None"
-            app:entries="@array/settings_memory_card_mode_entries"
-            app:entryValues="@array/settings_memory_card_mode_values"
-            app:iconSpaceReserved="false"
-            app:key="MemoryCards/Card2Type"
-            app:title="@string/settings_memory_card_2_type"
-            app:useSimpleSummaryProvider="true" />
-    </PreferenceCategory>
-
-</PreferenceScreen>
diff --git a/android/app/src/main/res/xml/display_preferences.xml b/android/app/src/main/res/xml/display_preferences.xml
deleted file mode 100644
index 2d55a57ed..000000000
--- a/android/app/src/main/res/xml/display_preferences.xml
+++ /dev/null
@@ -1,129 +0,0 @@
-<!--
-  ~ Copyright 2018 The app Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-  -->
-
-<PreferenceScreen xmlns:app="http://schemas.android.com/apk/res-auto">
-
-    <ListPreference
-        app:key="Display/CropMode"
-        app:title="@string/settings_crop_mode"
-        app:entries="@array/settings_display_crop_mode_entries"
-        app:entryValues="@array/settings_display_crop_mode_values"
-        app:defaultValue="Overscan"
-        app:useSimpleSummaryProvider="true"
-        app:iconSpaceReserved="false" />
-
-    <ListPreference
-        app:key="Display/AspectRatio"
-        app:title="@string/settings_aspect_ratio"
-        app:entries="@array/settings_display_aspect_ratio_names"
-        app:entryValues="@array/settings_display_aspect_ratio_values"
-        app:defaultValue="Auto (Game Native)"
-        app:useSimpleSummaryProvider="true"
-        app:iconSpaceReserved="false" />
-
-    <com.github.stenzek.duckstation.RatioPreference
-        numeratorKey="Display/CustomAspectRatioNumerator"
-        defaultNumerator="4"
-        minimumNumerator="1"
-        maximumNunerator="100"
-        denominatorKey="Display/CustomAspectRatioDenominator"
-        defaultDenominator="3"
-        minimumDenominator="1"
-        maximumDenominator="100"
-        app:title="@string/settings_custom_aspect_ratio"
-        app:summary="@string/settings_summary_custom_aspect_ratio"
-        app:useSimpleSummaryProvider="true"
-        app:iconSpaceReserved="false" />
-
-    <ListPreference
-        app:key="GPU/DownsampleMode"
-        app:title="@string/settings_downsample_mode"
-        app:entries="@array/settings_downsample_mode_entries"
-        app:entryValues="@array/settings_downsample_mode_values"
-        app:defaultValue="Disabled"
-        app:useSimpleSummaryProvider="true"
-        app:iconSpaceReserved="false" />
-
-    <SwitchPreferenceCompat
-        app:key="Display/IntegerScaling"
-        app:title="@string/settings_integer_upscaling"
-        app:defaultValue="false"
-        app:disableDependentsState="true"
-        app:summary="@string/settings_summary_integer_upscaling"
-        app:iconSpaceReserved="false" />
-
-    <SwitchPreferenceCompat
-        app:key="Display/LinearFiltering"
-        app:title="@string/settings_linear_upscaling"
-        app:defaultValue="true"
-        app:dependency="Display/IntegerScaling"
-        app:summary="@string/settings_summary_linear_upscaling"
-        app:iconSpaceReserved="false" />
-
-    <SwitchPreferenceCompat
-        app:key="Display/Stretch"
-        app:title="@string/settings_display_stretch"
-        app:defaultValue="false"
-        app:dependency="Display/IntegerScaling"
-        app:summary="@string/settings_summary_display_stretch"
-        app:iconSpaceReserved="false" />
-
-    <SwitchPreferenceCompat
-        app:key="Display/ExpandToCutout"
-        app:title="@string/settings_expand_to_cutout"
-        app:defaultValue="false"
-        app:summary="@string/settings_summary_expand_to_cutout"
-        app:iconSpaceReserved="false" />
-
-    <SwitchPreferenceCompat
-        app:key="Display/ShowOSDMessages"
-        app:title="@string/settings_osd_show_messages"
-        app:defaultValue="true"
-        app:summary="@string/settings_summary_osd_show_messages"
-        app:iconSpaceReserved="false" />
-
-    <SwitchPreferenceCompat
-        app:key="Display/ShowSpeed"
-        app:title="@string/settings_osd_show_speed"
-        app:defaultValue="false"
-        app:summary="@string/settings_summary_osd_show_speed"
-        app:iconSpaceReserved="false" />
-    <SwitchPreferenceCompat
-        app:key="Display/ShowVPS"
-        app:title="@string/settings_osd_show_show_vps"
-        app:defaultValue="false"
-        app:summary="@string/settings_summary_osd_show_vps"
-        app:iconSpaceReserved="false" />
-    <SwitchPreferenceCompat
-        app:key="Display/ShowFPS"
-        app:title="@string/settings_osd_show_show_fps"
-        app:defaultValue="false"
-        app:summary="@string/settings_summary_osd_show_fps"
-        app:iconSpaceReserved="false" />
-    <SwitchPreferenceCompat
-        app:key="Display/ShowResolution"
-        app:title="@string/settings_osd_show_show_resolution"
-        app:defaultValue="false"
-        app:summary="@string/settings_summary_osd_show_resolution"
-        app:iconSpaceReserved="false" />
-    <SwitchPreferenceCompat
-        app:key="Display/ShowInputs"
-        app:title="@string/settings_osd_show_show_inputs"
-        app:defaultValue="false"
-        app:summary="@string/settings_summary_osd_show_inputs"
-        app:iconSpaceReserved="false" />
-
-</PreferenceScreen>
diff --git a/android/app/src/main/res/xml/enhancements_preferences.xml b/android/app/src/main/res/xml/enhancements_preferences.xml
deleted file mode 100644
index a0621cfd9..000000000
--- a/android/app/src/main/res/xml/enhancements_preferences.xml
+++ /dev/null
@@ -1,154 +0,0 @@
-<!--
-  ~ Copyright 2018 The app Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-  -->
-
-<PreferenceScreen xmlns:app="http://schemas.android.com/apk/res-auto">
-    <ListPreference
-        app:key="CDROM/ReadSpeedup"
-        app:title="@string/settings_cdrom_read_speedup"
-        app:entries="@array/settings_cdrom_read_speedup_entries"
-        app:entryValues="@array/settings_cdrom_read_speedup_values"
-        app:defaultValue="1"
-        app:summary="@string/settings_summary_cdrom_read_speedup"
-        app:useSimpleSummaryProvider="true"
-        app:iconSpaceReserved="false" />
-    <ListPreference
-        app:key="CDROM/SeekSpeedup"
-        app:title="@string/settings_cdrom_seek_speedup"
-        app:entries="@array/settings_cdrom_seek_speedup_entries"
-        app:entryValues="@array/settings_cdrom_seek_speedup_values"
-        app:defaultValue="1"
-        app:summary="@string/settings_summary_cdrom_seek_speedup"
-        app:useSimpleSummaryProvider="true"
-        app:iconSpaceReserved="false" />
-    <SwitchPreferenceCompat
-        app:key="BIOS/PatchFastBoot"
-        app:title="@string/settings_console_fast_boot"
-        app:defaultValue="true"
-        app:summary="@string/settings_summary_console_fast_boot"
-        app:iconSpaceReserved="false" />
-    <ListPreference
-        app:key="GPU/ResolutionScale"
-        app:title="@string/settings_gpu_resolution_scale"
-        app:entries="@array/settings_gpu_resolution_scale_entries"
-        app:entryValues="@array/settings_gpu_resolution_scale_values"
-        app:defaultValue="1"
-        app:useSimpleSummaryProvider="true"
-        app:iconSpaceReserved="false" />
-    <ListPreference
-        app:key="GPU/MSAA"
-        app:title="@string/settings_msaa"
-        app:entries="@array/settings_gpu_msaa_entries"
-        app:entryValues="@array/settings_gpu_msaa_values"
-        app:defaultValue="1"
-        app:useSimpleSummaryProvider="true"
-        app:iconSpaceReserved="false" />
-    <SwitchPreferenceCompat
-        app:key="GPU/TrueColor"
-        app:title="@string/settings_true_color"
-        app:summary="@string/settings_summary_true_color"
-        app:iconSpaceReserved="false" />
-
-    <SwitchPreferenceCompat
-        app:key="GPU/ScaledDithering"
-        app:title="@string/settings_scaled_dithering"
-        app:defaultValue="true"
-        app:summary="@string/settings_summary_scaled_dithering"
-        app:iconSpaceReserved="false" />
-
-    <SwitchPreferenceCompat
-        app:key="GPU/DisableInterlacing"
-        app:title="@string/settings_disable_interlacing"
-        app:defaultValue="true"
-        app:summary="@string/settings_summary_disable_interlacing"
-        app:iconSpaceReserved="false" />
-
-    <ListPreference
-        app:key="GPU/TextureFilter"
-        app:title="@string/settings_texture_filtering"
-        app:entries="@array/settings_gpu_texture_filter_names"
-        app:entryValues="@array/settings_gpu_texture_filter_values"
-        app:defaultValue="Nearest"
-        app:useSimpleSummaryProvider="true"
-        app:iconSpaceReserved="false" />
-
-    <SwitchPreferenceCompat
-        app:key="GPU/ForceNTSCTimings"
-        app:title="@string/settings_force_ntsc_timings"
-        app:defaultValue="false"
-        app:summary="@string/settings_summary_force_ntsc_timings"
-        app:iconSpaceReserved="false" />
-
-    <SwitchPreferenceCompat
-        app:key="GPU/WidescreenHack"
-        app:title="@string/settings_widescreen_hack"
-        app:defaultValue="false"
-        app:summary="@string/settings_summary_widescreen_hack"
-        app:iconSpaceReserved="false" />
-
-    <SwitchPreferenceCompat
-        app:key="Display/Force4_3For24Bit"
-        app:title="@string/settings_force_4_3_for_24bit"
-        app:defaultValue="false"
-        app:summary="@string/settings_summary_force_4_3_for_24bit"
-        app:iconSpaceReserved="false" />
-
-    <SwitchPreferenceCompat
-        app:key="GPU/ChromaSmoothing24Bit"
-        app:title="@string/settings_chroma_smoothing_24bit"
-        app:defaultValue="false"
-        app:summary="@string/settings_summary_chrome_smoothing_24bit"
-        app:iconSpaceReserved="false" />
-
-    <SwitchPreferenceCompat
-        app:key="GPU/PGXPEnable"
-        app:title="@string/settings_pgxp_geometry_correction"
-        app:defaultValue="false"
-        app:summary="@string/settings_summary_pgxp_geometry_correction"
-        app:iconSpaceReserved="false" />
-
-    <SwitchPreferenceCompat
-        app:key="GPU/PGXPCulling"
-        app:title="@string/settings_pgxp_culling_correction"
-        app:dependency="GPU/PGXPEnable"
-        app:defaultValue="true"
-        app:summary="@string/settings_summary_pgxp_culling_correction"
-        app:iconSpaceReserved="false" />
-
-    <SwitchPreferenceCompat
-        app:key="GPU/PGXPTextureCorrection"
-        app:title="@string/settings_pgxp_texture_correction"
-        app:dependency="GPU/PGXPEnable"
-        app:defaultValue="true"
-        app:summary="@string/settings_summary_pgxp_texture_correction"
-        app:iconSpaceReserved="false" />
-
-    <SwitchPreferenceCompat
-        app:key="GPU/PGXPPreserveProjFP"
-        app:title="@string/settings_pgxp_preserve_projection_precision"
-        app:dependency="GPU/PGXPEnable"
-        app:defaultValue="false"
-        app:summary="@string/settings_summary_pgxp_preserve_projection_precision"
-        app:iconSpaceReserved="false" />
-
-    <SwitchPreferenceCompat
-        app:key="GPU/PGXPDepthBuffer"
-        app:title="@string/settings_pgxp_depth_buffer"
-        app:dependency="GPU/PGXPEnable"
-        app:defaultValue="false"
-        app:summary="@string/settings_summary_pgxp_depth_buffer"
-        app:iconSpaceReserved="false" />
-
-</PreferenceScreen>
diff --git a/android/app/src/main/res/xml/general_preferences.xml b/android/app/src/main/res/xml/general_preferences.xml
deleted file mode 100644
index 917b543f2..000000000
--- a/android/app/src/main/res/xml/general_preferences.xml
+++ /dev/null
@@ -1,83 +0,0 @@
-<!--
-  ~ Copyright 2018 The app Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-  -->
-
-<PreferenceScreen xmlns:app="http://schemas.android.com/apk/res-auto"
-    xmlns:android="http://schemas.android.com/apk/res/android">
-    <Preference
-        app:title="@string/settings_game_directories"
-        app:summary="@string/settings_summary_game_directories"
-        app:iconSpaceReserved="false">
-        <intent
-            android:action="android.intent.action.VIEW"
-            android:targetClass="com.github.stenzek.duckstation.GameDirectoriesActivity"
-            android:targetPackage="com.github.stenzek.duckstation" />
-    </Preference>
-    <ListPreference
-        app:key="Main/EmulationSpeed"
-        app:title="@string/settings_emulation_speed"
-        app:entries="@array/settings_emulation_speed_entries"
-        app:entryValues="@array/settings_emulation_speed_values"
-        app:defaultValue="1.0"
-        app:useSimpleSummaryProvider="true"
-        app:iconSpaceReserved="false" />
-    <ListPreference
-        app:key="Main/FastForwardSpeed"
-        app:title="@string/settings_fast_forward_speed"
-        app:entries="@array/settings_emulation_speed_entries"
-        app:entryValues="@array/settings_emulation_speed_values"
-        app:defaultValue="0.0"
-        app:useSimpleSummaryProvider="true"
-        app:iconSpaceReserved="false" />
-    <ListPreference
-        app:key="Main/EmulationScreenOrientation"
-        app:title="@string/settings_emulation_screen_orientation"
-        app:entries="@array/settings_emulation_screen_orientation_entries"
-        app:entryValues="@array/settings_emulation_screen_orientation_values"
-        app:defaultValue="unspecified"
-        app:useSimpleSummaryProvider="true"
-        app:iconSpaceReserved="false" />
-    <SwitchPreferenceCompat
-        app:key="Main/SaveStateOnExit"
-        app:title="@string/settings_save_state_on_exit"
-        app:defaultValue="true"
-        app:summary="@string/settings_summary_save_state_on_exit"
-        app:iconSpaceReserved="false" />
-    <ListPreference
-        app:key="GPU/Renderer"
-        app:title="@string/settings_gpu_renderer"
-        app:entries="@array/gpu_renderer_entries"
-        app:entryValues="@array/gpu_renderer_values"
-        app:defaultValue="OpenGL"
-        app:useSimpleSummaryProvider="true"
-        app:iconSpaceReserved="false" />
-    <ListPreference
-        app:key="Main/Language"
-        app:title="@string/settings_language"
-        app:defaultValue="none"
-        app:entries="@array/settings_language_entries"
-        app:entryValues="@array/settings_language_values"
-        app:useSimpleSummaryProvider="true"
-        app:iconSpaceReserved="false" />
-    <ListPreference
-        app:key="Main/Theme"
-        app:title="@string/settings_theme"
-        app:entries="@array/settings_theme_entries"
-        app:entryValues="@array/settings_theme_values"
-        app:defaultValue="follow_system"
-        app:useSimpleSummaryProvider="true"
-        app:iconSpaceReserved="false" />
-
-</PreferenceScreen>
diff --git a/android/app/src/main/res/xml/network_security_config.xml b/android/app/src/main/res/xml/network_security_config.xml
deleted file mode 100644
index f86a16beb..000000000
--- a/android/app/src/main/res/xml/network_security_config.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<network-security-config>
-    <domain-config cleartextTrafficPermitted="true">
-        <domain includeSubdomains="true">i.retroachievements.org</domain>
-    </domain-config>
-</network-security-config>
diff --git a/android/app/src/test/java/com/github/stenzek/duckstation/ExampleUnitTest.java b/android/app/src/test/java/com/github/stenzek/duckstation/ExampleUnitTest.java
deleted file mode 100644
index b90ac4a49..000000000
--- a/android/app/src/test/java/com/github/stenzek/duckstation/ExampleUnitTest.java
+++ /dev/null
@@ -1,17 +0,0 @@
-package com.github.stenzek.duckstation;
-
-import org.junit.Test;
-
-import static org.junit.Assert.*;
-
-/**
- * Example local unit test, which will execute on the development machine (host).
- *
- * @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
- */
-public class ExampleUnitTest {
-    @Test
-    public void addition_isCorrect() {
-        assertEquals(4, 2 + 2);
-    }
-}
\ No newline at end of file
diff --git a/android/build.gradle b/android/build.gradle
deleted file mode 100644
index 0be6f99d2..000000000
--- a/android/build.gradle
+++ /dev/null
@@ -1,25 +0,0 @@
-// Top-level build file where you can add configuration options common to all sub-projects/modules.
-
-buildscript {
-    repositories {
-        google()
-        mavenCentral()
-    }
-    dependencies {
-        classpath 'com.android.tools.build:gradle:4.2.1'
-        
-        // NOTE: Do not place your application dependencies here; they belong
-        // in the individual module build.gradle files
-    }
-}
-
-allprojects {
-    repositories {
-        google()
-        mavenCentral()
-    }
-}
-
-task clean(type: Delete) {
-    delete rootProject.buildDir
-}
diff --git a/android/gradle.properties b/android/gradle.properties
deleted file mode 100644
index 199d16ede..000000000
--- a/android/gradle.properties
+++ /dev/null
@@ -1,20 +0,0 @@
-# Project-wide Gradle settings.
-# IDE (e.g. Android Studio) users:
-# Gradle settings configured through the IDE *will override*
-# any settings specified in this file.
-# For more details on how to configure your build environment visit
-# http://www.gradle.org/docs/current/userguide/build_environment.html
-# Specifies the JVM arguments used for the daemon process.
-# The setting is particularly useful for tweaking memory settings.
-org.gradle.jvmargs=-Xmx1536m
-# When configured, Gradle will run in incubating parallel mode.
-# This option should only be used with decoupled projects. More details, visit
-# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
-# org.gradle.parallel=true
-# AndroidX package structure to make it clearer which packages are bundled with the
-# Android operating system, and which are packaged with your app's APK
-# https://developer.android.com/topic/libraries/support-library/androidx-rn
-android.useAndroidX=true
-# Automatically convert third-party libraries to use AndroidX
-android.enableJetifier=true
-
diff --git a/android/gradle/wrapper/gradle-wrapper.jar b/android/gradle/wrapper/gradle-wrapper.jar
deleted file mode 100644
index f6b961fd5..000000000
Binary files a/android/gradle/wrapper/gradle-wrapper.jar and /dev/null differ
diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties
deleted file mode 100644
index 7b61d1ea9..000000000
--- a/android/gradle/wrapper/gradle-wrapper.properties
+++ /dev/null
@@ -1,6 +0,0 @@
-#Sun Jun 06 12:33:06 AEST 2021
-distributionBase=GRADLE_USER_HOME
-distributionPath=wrapper/dists
-zipStoreBase=GRADLE_USER_HOME
-zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-7.0.2-all.zip
diff --git a/android/gradlew b/android/gradlew
deleted file mode 100755
index cccdd3d51..000000000
--- a/android/gradlew
+++ /dev/null
@@ -1,172 +0,0 @@
-#!/usr/bin/env sh
-
-##############################################################################
-##
-##  Gradle start up script for UN*X
-##
-##############################################################################
-
-# Attempt to set APP_HOME
-# Resolve links: $0 may be a link
-PRG="$0"
-# Need this for relative symlinks.
-while [ -h "$PRG" ] ; do
-    ls=`ls -ld "$PRG"`
-    link=`expr "$ls" : '.*-> \(.*\)$'`
-    if expr "$link" : '/.*' > /dev/null; then
-        PRG="$link"
-    else
-        PRG=`dirname "$PRG"`"/$link"
-    fi
-done
-SAVED="`pwd`"
-cd "`dirname \"$PRG\"`/" >/dev/null
-APP_HOME="`pwd -P`"
-cd "$SAVED" >/dev/null
-
-APP_NAME="Gradle"
-APP_BASE_NAME=`basename "$0"`
-
-# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
-DEFAULT_JVM_OPTS=""
-
-# Use the maximum available, or set MAX_FD != -1 to use that value.
-MAX_FD="maximum"
-
-warn () {
-    echo "$*"
-}
-
-die () {
-    echo
-    echo "$*"
-    echo
-    exit 1
-}
-
-# OS specific support (must be 'true' or 'false').
-cygwin=false
-msys=false
-darwin=false
-nonstop=false
-case "`uname`" in
-  CYGWIN* )
-    cygwin=true
-    ;;
-  Darwin* )
-    darwin=true
-    ;;
-  MINGW* )
-    msys=true
-    ;;
-  NONSTOP* )
-    nonstop=true
-    ;;
-esac
-
-CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
-
-# Determine the Java command to use to start the JVM.
-if [ -n "$JAVA_HOME" ] ; then
-    if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
-        # IBM's JDK on AIX uses strange locations for the executables
-        JAVACMD="$JAVA_HOME/jre/sh/java"
-    else
-        JAVACMD="$JAVA_HOME/bin/java"
-    fi
-    if [ ! -x "$JAVACMD" ] ; then
-        die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
-
-Please set the JAVA_HOME variable in your environment to match the
-location of your Java installation."
-    fi
-else
-    JAVACMD="java"
-    which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
-
-Please set the JAVA_HOME variable in your environment to match the
-location of your Java installation."
-fi
-
-# Increase the maximum file descriptors if we can.
-if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
-    MAX_FD_LIMIT=`ulimit -H -n`
-    if [ $? -eq 0 ] ; then
-        if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
-            MAX_FD="$MAX_FD_LIMIT"
-        fi
-        ulimit -n $MAX_FD
-        if [ $? -ne 0 ] ; then
-            warn "Could not set maximum file descriptor limit: $MAX_FD"
-        fi
-    else
-        warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
-    fi
-fi
-
-# For Darwin, add options to specify how the application appears in the dock
-if $darwin; then
-    GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
-fi
-
-# For Cygwin, switch paths to Windows format before running java
-if $cygwin ; then
-    APP_HOME=`cygpath --path --mixed "$APP_HOME"`
-    CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
-    JAVACMD=`cygpath --unix "$JAVACMD"`
-
-    # We build the pattern for arguments to be converted via cygpath
-    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
-    SEP=""
-    for dir in $ROOTDIRSRAW ; do
-        ROOTDIRS="$ROOTDIRS$SEP$dir"
-        SEP="|"
-    done
-    OURCYGPATTERN="(^($ROOTDIRS))"
-    # Add a user-defined pattern to the cygpath arguments
-    if [ "$GRADLE_CYGPATTERN" != "" ] ; then
-        OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
-    fi
-    # Now convert the arguments - kludge to limit ourselves to /bin/sh
-    i=0
-    for arg in "$@" ; do
-        CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
-        CHECK2=`echo "$arg"|egrep -c "^-"`                                 ### Determine if an option
-
-        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition
-            eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
-        else
-            eval `echo args$i`="\"$arg\""
-        fi
-        i=$((i+1))
-    done
-    case $i in
-        (0) set -- ;;
-        (1) set -- "$args0" ;;
-        (2) set -- "$args0" "$args1" ;;
-        (3) set -- "$args0" "$args1" "$args2" ;;
-        (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
-        (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
-        (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
-        (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
-        (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
-        (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
-    esac
-fi
-
-# Escape application args
-save () {
-    for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
-    echo " "
-}
-APP_ARGS=$(save "$@")
-
-# Collect all arguments for the java command, following the shell quoting and substitution rules
-eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
-
-# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
-if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
-  cd "$(dirname "$0")"
-fi
-
-exec "$JAVACMD" "$@"
diff --git a/android/gradlew.bat b/android/gradlew.bat
deleted file mode 100644
index e95643d6a..000000000
--- a/android/gradlew.bat
+++ /dev/null
@@ -1,84 +0,0 @@
-@if "%DEBUG%" == "" @echo off
-@rem ##########################################################################
-@rem
-@rem  Gradle startup script for Windows
-@rem
-@rem ##########################################################################
-
-@rem Set local scope for the variables with windows NT shell
-if "%OS%"=="Windows_NT" setlocal
-
-set DIRNAME=%~dp0
-if "%DIRNAME%" == "" set DIRNAME=.
-set APP_BASE_NAME=%~n0
-set APP_HOME=%DIRNAME%
-
-@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
-set DEFAULT_JVM_OPTS=
-
-@rem Find java.exe
-if defined JAVA_HOME goto findJavaFromJavaHome
-
-set JAVA_EXE=java.exe
-%JAVA_EXE% -version >NUL 2>&1
-if "%ERRORLEVEL%" == "0" goto init
-
-echo.
-echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
-echo.
-echo Please set the JAVA_HOME variable in your environment to match the
-echo location of your Java installation.
-
-goto fail
-
-:findJavaFromJavaHome
-set JAVA_HOME=%JAVA_HOME:"=%
-set JAVA_EXE=%JAVA_HOME%/bin/java.exe
-
-if exist "%JAVA_EXE%" goto init
-
-echo.
-echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
-echo.
-echo Please set the JAVA_HOME variable in your environment to match the
-echo location of your Java installation.
-
-goto fail
-
-:init
-@rem Get command-line arguments, handling Windows variants
-
-if not "%OS%" == "Windows_NT" goto win9xME_args
-
-:win9xME_args
-@rem Slurp the command line arguments.
-set CMD_LINE_ARGS=
-set _SKIP=2
-
-:win9xME_args_slurp
-if "x%~1" == "x" goto execute
-
-set CMD_LINE_ARGS=%*
-
-:execute
-@rem Setup the command line
-
-set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
-
-@rem Execute Gradle
-"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
-
-:end
-@rem End local scope for the variables with windows NT shell
-if "%ERRORLEVEL%"=="0" goto mainEnd
-
-:fail
-rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
-rem the _cmd.exe /c_ return code!
-if  not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
-exit /b 1
-
-:mainEnd
-if "%OS%"=="Windows_NT" endlocal
-
-:omega
diff --git a/android/settings.gradle b/android/settings.gradle
deleted file mode 100644
index 7f5ee4013..000000000
--- a/android/settings.gradle
+++ /dev/null
@@ -1,2 +0,0 @@
-include ':app'
-rootProject.name='DuckStation'